Guide Operations · Admin Console × LINE LIFF

ガイド統合管理で
できること

ガイドの名簿・在籍状態・稼働状態を一元管理し、ツアーの手配と募集、個別連絡と全体アナウンス、 経費の申請から承認・精算までを 1 つの画面で回す——その「管理者ができること」「ガイドができること」を、 画面操作・API・データモデルまで含めてまとめた機能リファレンス。管理は 管理コンソール、ガイド本人は LINE 内の LIFF ページから操作します。

FastAPI /api/guides SQLite guides / guide_expenses / guide_messages / guide_payments LINE push / LIFF IDトークン 管理コンソール ガイド管理タブ

目次

01概要 — 全体像と登場人物

ガイド統合管理は、予約台帳(Booking)と地続きの「ガイド運用」レイヤです。誰が在籍していて、いま稼働できるのは誰か、どのツアーを誰に手配したか、その経費をいくら払うか——を、管理者とガイドの両側から扱います。

👤 管理者(管理コンソール)

ブラウザの管理コンソール(app/templates/admin/index.htmlガイド管理タブ)から操作。 認証は既存の管理画面と同じプレーン運用。名簿・状態管理・手配と募集・連絡・経費の承認/却下/精算・実績の確認まで担当します。

🧭 ガイド本人(LINE LIFF)

LINE 内に開く LIFF ページdocs/guide.html)から操作。 LINE IDトークンで本人を特定するため、ログイン=認証。稼働状態の変更・担当ツアーの確認・経費申請ができます。

ガイド管理 API はすべて FastAPI ルータ app/api/guide_admin.pyprefix="/api/guides")に集約されます。管理コンソール用は /api/guides/profile/*/api/guides/expenses*/api/guides/message(s) のように静的セグメントで構成し、既存の app/api/guides.py(募集系:"" / /recruitments / /recruit/{booking_id})と衝突しないようにしています。ガイド本人向けは別系統の /api/guide-liff/* で、各リクエストの先頭で IDトークンを検証して line_user_id から本人を解決します。

2 つの「状態」を持つのがポイント。 ガイドには status在籍/離脱:active / inactive)と availability稼働状態:available / busy / off)の別々の軸があります。 在籍していても「今日は休止(off)」はあり得るし、離脱したガイドはそもそも募集対象から外れる——役割が違うので両方を独立に持ちます。

用語の整理

用語意味取りうる値
在籍状態 status名簿上の在籍/離脱。離脱者は募集・一斉連絡の対象外active 在籍 / inactive 離脱
稼働状態 availabilityいま仕事を受けられるか。ガイド本人が LIFF で切り替え可能available 稼働可 / busy 多忙 / off 休止
手配特定の予約に対してガイドを直接指名して割り当てる(管理者)
募集予約に対し全在籍ガイドへ一斉送信し、先着 1 名で確定する(既存 /recruitopen / filled / cancelled
経費 GuideExpenseガイドが立て替えた費用。申請→承認/却下→精算で状態遷移submitted / approved / rejected / reimbursed
連絡 GuideMessage管理者からの個別連絡・全体アナウンスの送信ログ

02管理者ができること

管理コンソールのガイド管理タブから扱える機能。名簿・状態・手配と募集・連絡・経費・実績・給与・CSV移行の領域をカバーします。

📇ガイド名簿の管理

登録済みガイドの一覧と詳細を確認。氏名・電話・メール・対応言語・管理メモを編集できます。LINE セルフ登録(「登録 名前」)で入った人を、後から肉付けする運用。

GET /api/guides · GET /PATCH /api/guides/profile/{gid}

🔀ステータス管理

在籍状態(active / inactive)と稼働状態(available / busy / off)を切り替え。離脱処理や、ガイドに代わって稼働状態を直すこともできます。

PATCH /api/guides/profile/{gid} {status, availability}

🧗手配と募集

手配=予約にガイドを直接指名(既存 /api/admin/guides/assign)。募集=全在籍ガイドへ一斉送信して先着確定(既存 /api/guides/recruit/{booking_id})。詳細画面から担当中ツアーも一覧できます。

POST /api/admin/guides/assign · POST /api/guides/recruit/{booking_id}

📣個別連絡と全体アナウンス

特定ガイドへの個別連絡、または全在籍ガイドへの一斉アナウンスを LINE push で送信。送信結果(成功/失敗件数)と全文を GuideMessage に記録します。

POST /api/guides/message · GET /api/guides/messages

🧾経費の承認 / 却下 / 精算

ガイドが申請した経費を一覧・集計し、承認却下(理由つき)精算済みへ遷移。管理者による代理登録も可能。操作は監査ログ(AuditLog)にも残ります。

GET /api/guides/expenses · POST /api/guides/expenses/{eid}/review

📊実績・勤務データの確認

ガイド詳細の勤務実績タブで、担当した全ツアーの履歴・累計案内人数・ツアー別の担当回数を表示。予約台帳(Booking.guide_name)から自動集計します。

GET /api/guides/profile/{gid} · GET /api/guides/work/{gid}

💴給与・支払通知書の発行

ガイドにランクツアー単価(pay_rateを設定し、詳細の給与・支払タブで対象期間を指定すると、期間内の担当ツアー報酬(単価×件数)+承認済み経費の精算+調整額を自動集計。支払通知書を発行し、印刷/PDF 用の整形ページを別タブで開けます。「支払済」にすると紐づく経費も精算済みへ進みます。

POST /api/guides/payroll/preview · POST /api/guides/payroll/issue · GET /api/guides/payment/{pid}/notice

📥個人情報の CSV 移行

GAS 管理のスプレッドシートを CSV / タブ区切りで書き出し、ヘッダごと貼り付けて一括取り込み。氏名・電話・ランク・単価・銀行口座・対応言語などの列を自動認識し、氏名(または LINE ID)で既存ガイドと突合して upsert します。取り込み前に必ずプレビューで確認。

POST /api/guides/import {csv, dry_run}

経費の状態遷移(承認 / 却下 / 精算)

経費は申請(submitted)を起点に、レビュー API(action)で状態が変わります。承認後にのみ精算へ進めるのがルールです。

submitted — approve → approved — reimburse → reimbursed
submitted — reject → rejected (却下理由 reject_reason を保存)
代理登録について。 ガイドが LINE を使えない・領収書だけ渡してきた、といったケースでは管理者が POST /api/guides/expenses で経費を代理登録できます。guide_id から氏名を解決し、状態は submitted で起票されるので、その後は通常どおり承認フローに乗ります。

03ガイドができること(LIFF)

ガイド本人は LINE 内の LIFF ページから操作。LINE IDトークンで本人確認するため、別途ログインや ID 入力は不要です。できることは 3 つ。

🟢稼働状態の変更

「稼働可 / 多忙 / 休止」をワンタップで切り替え。ここで off にすると、管理者側の名簿でも休止として見え、稼働可能なガイドの把握に反映されます。

POST /api/guide-liff/availability {availability}

🗓️担当ツアーの確認

自分が割り当てられている担当中ツアーの一覧を表示(予約台帳 Booking.guide_name が自分の名前のもの)。日付・時刻・人数・ツアー名を確認できます。

POST /api/guide-liff/me → assigned[]

🧾経費の申請

立て替えた費用を申請。カテゴリ(交通/食事/チケット/備品/その他)・金額・発生日・メモ・領収書 URL を入力。状態は submitted で起票され、自分の申請履歴も /me で確認できます。

POST /api/guide-liff/expense → status: submitted
本人確認の仕組み。 LIFF ページは liff.initliff.getIDToken() で取得した id_token を毎リクエストの body に載せます。サーバは app/api/liff.py_verify_id_token() を再利用して検証し、sub(= line_user_id)から Guide を引き当てます。経費申請時の guide_id / guide_name はトークンから解決するので、ガイドが他人になりすまして申請することはできません。

ガイドが POST /api/guide-liff/me を最初に叩くと、本人情報(id / 名前 / 稼働状態)・担当中ツアー・自分の経費が 1 回でまとめて返ります。LIFF ページはこの結果で画面を組み立てます。

04画面と操作手順

管理コンソールのガイド管理タブと、ガイド向け LIFF ページ、それぞれの代表的な操作の流れ。

管理コンソール — ガイド管理タブ管理者

  1. 名簿を開く — 管理コンソールの「ガイド管理」タブで登録済みガイドの一覧を表示(在籍/稼働の状態バッジつき)。
  2. 詳細を見る — 行をクリックすると GET /api/guides/profile/{gid} で詳細を取得。プロフィール・担当中ツアー一覧・経費(件数/未精算額)・統計が出ます。
  3. プロフィール/状態を更新 — 氏名・電話・メール・言語・メモを編集、または在籍/稼働状態を変更して保存(PATCH /api/guides/profile/{gid})。
  4. 手配 / 募集 — 予約に対しガイドを指名(/api/admin/guides/assign)、または募集を一斉送信(/api/guides/recruit/{booking_id}、先着確定)。
  5. 連絡する — 個別ガイドまたは全在籍ガイドへメッセージを送信(POST /api/guides/message)。送信ログは GET /api/guides/messages で確認。
  6. 経費を捌く — 経費一覧(GET /api/guides/expenses、状態/ガイドで絞り込み)から、承認・却下・精算(POST /api/guides/expenses/{eid}/review)。サマリーは /expenses/summary

ガイド向け LIFF ページガイド本人

  1. LINE で開く — リッチメニューや送られたリンクから LIFF ページ(docs/guide.html)を開く。liff.init 後、未ログインなら liff.login()
  2. 本人を読み込むliff.getIDToken() で取得した id_tokenPOST /api/guide-liff/me に送り、本人情報・担当中ツアー・自分の経費を取得して表示。
  3. 稼働状態を変える — 「稼働可 / 多忙 / 休止」をタップ(POST /api/guide-liff/availability)。即時に反映。
  4. 経費を申請する — カテゴリ・金額・発生日・メモ・領収書 URL を入力して送信(POST /api/guide-liff/expense)。submitted として申請され、履歴に追加されます。
未存在・エラーの扱い。 すべてのエンドポイントは未存在や不正入力を安全に処理します(404 / 400、または {ok:false, error})。ガイドが未登録の line_user_id でアクセスした場合などは、エラー応答で画面側が案内を出せるようになっています。

05API エンドポイント一覧

ガイド管理は app/api/guide_admin.py に新設。管理コンソール用は /api/guides/*(プレーン認証)、ガイド本人用は /api/guide-liff/*(IDトークン検証)。既存の募集系 API も参照のため併記します。web=管理画面 / token=LINE IDトークン必須。

app/api/guide_admin.py — 管理コンソール用

Methodパス用途認証
GET/api/guides/profile/{gid}ガイド詳細+サマリー(担当中ツアー一覧/経費の件数・未精算額/統計)web
PATCH/api/guides/profile/{gid}プロフィール/状態更新(name? / phone? / email? / languages? / availability? / status? / note?)web
GET/api/guides/expenses経費一覧(query: status? / guide_id?)。新しい順web
POST/api/guides/expenses経費を新規登録(管理者の代理登録。guide_id / booking_id? / category / amount / incurred_on? / memo? / receipt_url?)web
POST/api/guides/expenses/{eid}/review状態遷移(action: approve / reject / reimburse、reason? / reviewer?)。AuditLog へも記録web
GET/api/guides/expenses/summary状態別サマリー(submitted / approved / reimbursed の件数・合計、rejected 件数)web
POST/api/guides/message個別/全体連絡(guide_id?(空=全在籍)/ text)。LINE push 送信+GuideMessage 記録。{sent, failed} を返すweb
GET/api/guides/messages連絡の送信ログ(最新 50 件)web

app/api/guide_admin.py — ガイド本人用(LIFF)

Methodパス用途認証
POST/api/guide-liff/me本人ダッシュボード。body:{id_token} → {ok, guide:{id,name,availability}, assigned:[担当中ツアー], expenses:[自分の経費]}token
POST/api/guide-liff/expense経費申請。body:{id_token, booking_id?, category, amount, incurred_on?, memo?, receipt_url?}(guide_id/name はトークンから解決、status="submitted")token
POST/api/guide-liff/availability稼働状態を更新。body:{id_token, availability}(available / busy / off)token

参考: 既存のガイド募集 APIapp/api/guides.py / app/api/admin.py(本機能で新設しない)

Methodパス用途認証
GET/api/guidesガイド一覧(id / name / line_user_id / status / created_at)web
GET/api/guides/recruitments募集一覧(最新 50 件、確定ガイド名つき)web
POST/api/guides/recruit/{booking_id}募集を出す(全在籍ガイドへ一斉送信、先着 1 名で確定)web
GET/api/admin/guides/statsガイド統計web
POST/api/admin/guides/assignガイドを予約に手動割り当て(指名手配)web
ルーティングの注意。 新設 API は既存 app/api/guides.py"" / /recruitments / /recruit/{booking_id} と衝突しないよう、動的 /{id} を使わず profile/{gid}expensesmessage(s) のような静的セグメント先頭で定義しています。ガイド本人向けは prefix 自体を /api/guide-liff に分けて完全に分離。

06データモデル

SQLAlchemy 2.0 の宣言的マッピング(Mapped / mapped_column)。app/db/models.py に追記。新規テーブルは起動時 Base.metadata.create_all で自動生成され、Guide の追加列は SQLite のため NULL 許容で足します。

Guide(拡張)__tablename__ = "guides"

既存列(id / name / line_user_id / status / created_at)は維持し、連絡先・稼働状態・実績・メモを追加します。

カラム説明
idint PK主キー(既存)
namestr氏名(既存)
line_user_idstr uniqueLINE ユーザー ID。本人特定の鍵(既存)
statusstr = "active"在籍状態:active 在籍 / inactive 離脱(既存)
phonestr | None (40)電話番号(追加)
emailstr | None (200)メールアドレス(追加)
languagesstr | None (200)対応言語。カンマ区切り 例 "日本語,英語"(追加)
availabilitystr = "available"稼働状態:available 稼働可 / busy 多忙 / off 休止(追加)
ratingfloat | None5 段階の平均評価(追加)
tours_doneint = 0担当完了数(追加)
noteText | None管理メモ(追加)
created_atdatetime登録日時(既存)
updated_atdatetime更新日時。default / onupdate = utcnow(追加)
status と availability は別物。 status は名簿上の在籍/離脱、availability は「いま受けられるか」。離脱者は募集対象から外れ、稼働状態は在籍中の本人が LIFF で随時切り替えます。役割が違うので両方を保持します。

GuideExpense(新規)__tablename__ = "guide_expenses"

ガイドが立て替えた費用。申請(submitted)→ 承認/却下 → 精算(reimbursed)の状態を持つ。

カラム説明
idint PK主キー
guide_idint (index)申請ガイドの ID
guide_namestr (100)申請時のガイド名(スナップショット)
booking_idstr | None (100)関連する予約番号(任意)
tour_namestr | None (100)関連ツアー名(任意)
categorystr (30)transport / meal / ticket / supply / other(交通/食事/チケット/備品/その他)
amountint金額(円)
incurred_onstr | None (20)発生日 "M/D" または ISO
memoText | Noneメモ
receipt_urlstr | None (500)領収書 URL
statusstr = "submitted"submitted / approved / rejected / reimbursed
reject_reasonText | None却下理由
reviewerstr | None (120)レビュー担当
reviewed_atdatetime | Noneレビュー日時
created_atdatetime申請日時。default = utcnow

GuideMessage(新規)__tablename__ = "guide_messages"

管理者からの個別連絡・全体アナウンスの送信ログ。guide_idNone なら全体アナウンス。

カラム説明
idint PK主キー
guide_idint | None (index)宛先ガイド ID。None=全体アナウンス
guide_namestr | None (100)宛先ガイド名(個別時)
bodyText本文
channelstr = "line"送信チャネル
sent_bystr = "web"送信元(管理画面など)
okbool = True送信成否
created_atdatetime送信日時。default = utcnow

関連する既存モデル

ガイド管理は以下の既存テーブルと連携します(本機能では変更しません)。

テーブル役割連携ポイント
bookings受付台帳guide_name が「担当中ツアー」の引き当てキー。手配/募集確定で更新される
tour_recruitmentsガイド募集予約への一斉募集と先着確定(open → filled)。確定で bookings.guide_name に反映
audit_logs操作監査ログ経費レビューを action="expense_<action>"booking_iddetail(金額/カテゴリ)で記録
テーブル生成は自動。 新規テーブル(guide_expenses / guide_messages)は app/db/database.py の起動時 init_dbBase.metadata.create_all)で作成されます。Guide への追加列は SQLite のため NULL 許容で足し、既存データへの影響なく拡張できます。