1. ひとことで

Student 2 は、学生が「今やりたいこと・空き時間・場所」を登録すると、 説明可能なルールベーススコアで相性のよいグループを組み、 条件を満たすときだけ Micro Event を生成し、根拠を AI ログに残す担当です。 ML / LLM / SNN は使いません。

現状の到達点: What Now 保存〜マッチング〜生成〜候補ログ API〜What Now 画面の最小接続〜評価用計測関数まで完了。 実 Event(Student 1)/実 Beacon(Student 3)は Fake Port のまま。 テストは unit 63 + API 16 = 79 passed(2026-08-21)。

2. システム全体図(ブロック)

HALO 全体の中で、Student 2 が所有する箱と、他担当との境界です。

flowchart TB
  subgraph FE["フロントエンド"]
    ST["/app/status
What Now UI"] end subgraph S2["Student 2(本ドキュメントの範囲)"] API1["POST/GET /student/status"] API2["POST /ai/micro-events/generate"] API3["GET /ai/micro-events/candidates"] ORCH["MicroEventOrchestration"] MATCH["matching_service
純粋ロジック"] GEN["micro_event_generator"] STORE["StatusStore + AiEventLogStore"] end subgraph EXT["他担当 / 外部(契約待ち)"] S1["Student 1
Event Core"] S3["Student 3
Beacon / Check-in"] S4["Student 4
Friends / UX"] end DB[(PostgreSQL)] FAKE[["Fake EventCreator
Fake BeaconCatalog"]] ST --> API1 ST --> API2 API1 --> STORE API2 --> ORCH ORCH --> MATCH ORCH --> GEN MATCH --> FAKE GEN --> FAKE STORE --> DB API3 --> DB FAKE -. 契約後に差替 .-> S1 FAKE -. 契約後に差替 .-> S3 GEN -. 候補は自動Joinしない .-> S1 S4 -. Home / My Events 表示 .-> S1

図 1 — Student 2 の箱と他モジュール境界。実線は現行、点線は契約後の接続。

3. 完了範囲チェック

フェーズ内容状態
0仕様読解・設計判断完了
1環境・Compose・seed 基準確認完了
2What Now 状態の保存・取得完了
3説明可能なマッチング完了
4Micro Event 自動生成 + AI ログ完了
5生成/候補 API・What Now 最小接続完了
6評価指標・不足試験・デモ手順完了

必須 API(仕様どおり実装済み)

  • POST /student/status — What Now 登録(旧行は同一 TX で即時失効)
  • GET /student/status/me — 自分の有効ステータス取得
  • POST /ai/micro-events/generate — マッチング→生成の手動トリガ
  • GET /ai/micro-events/candidates — 評価ロール向け AI ログ閲覧

4. エンドツーエンド・データフロー

生成ボタンを押したあとの一本化された処理です(フェーズ 5 オーケストレーション)。

flowchart LR
  A["有効な
student_current_status"] --> B["MatchingCandidate
へ変換"] B --> C["除外ゲート"] C --> D["ペア採点"] D --> E["貪欲グループ形成
2〜5人"] E --> F["カテゴリ・時間・場所・manager 決定"] F --> G{"生成条件 OK?"} G -->|Yes| H["EventCreator.create
(現状 Fake)"] G -->|No| I["skipped / failed"] H --> J["ai_event_logs
created"] I --> K["ai_event_logs
skipped/failed"] J --> L["DB commit
(ログ)"] K --> L

図 2 — Generate 実行時の主データフロー。

sequenceDiagram
  participant UI as /app/status
  participant API as FastAPI
  participant Orch as Orchestration
  participant Match as matching_service
  participant Gen as micro_event_generator
  participant Log as AiEventLogStore
  participant Fake as Fake EventCreator

  UI->>API: POST /student/status
  API->>API: 旧 status 失効 + 新行 INSERT
  UI->>API: POST /ai/micro-events/generate
  API->>Orch: run()
  Orch->>Orch: list_active_statuses
  Orch->>Fake: ACTIVE 候補集合
  Orch->>Match: run_matching(+ duplicate sets)
  Match-->>Orch: groups / exclusions
  Orch->>Gen: run_micro_event_generation
  Gen->>Fake: create MICRO event
  Gen->>Log: flush created/skipped/failed
  Orch->>Orch: commit (AI logs)
  API-->>UI: data = 作成イベント配列 or null
        

図 3 — 画面操作からレスポンスまでのシーケンス。

5. What Now(状態保存)

学生の「今」を短命な行として保存します。送信のたびに新行を INSERT し、 同じ学生の有効な旧行は同一トランザクションで expires_at = now() にして即時失効させます。

flowchart TB
  IN["入力
intents / periods / custom time
location / note_to_ai"] --> VAL["検証
intent≥1, 終了時刻, Beacon ACTIVE"] VAL --> NORM["空き時間の正規化・結合
Asia/Tokyo → UTC"] NORM --> EXP["expires_at 決定
最終空き終了 or 当日末"] EXP --> TX["同一 TX"] TX --> OLD["旧有効行を now で失効"] TX --> NEW["新行 INSERT"] NEW --> OUT["GET /status/me
expires_at > now の最新1件"]

図 4 — What Now 保存ブロック図。

項目ルール(実装済み)
有効判定expires_at > now()。同一学生は created_at 最新の1件
時限仮時限表(1st〜6th)。登録日の Asia/Tokyo として解釈
自由入力HH:MM-HH:MMcustom_available_time
空きなし保存は可。マッチングでは NO_AVAILABILITY 除外
認証(暫定)X-Student-Id(未指定時 user_001)。未知 ID は POST で 401

6. 説明可能なマッチング

matching_service.py は DB/HTTP/Event 生成に依存しない純粋ロジックです。 「なぜそのスコアか」を score_detail に残します。

除外ゲート → 採点 → グループ

flowchart TD
  CAND["候補スナップショット"] --> G1{"status 有効?
空き時間あり?"} G1 -->|No| X1["除外ログ"] G1 -->|Yes| G2{"準備15分後に
共通30分以上?"} G2 -->|No| X2["除外"] G2 -->|Yes| G3{"適合 Beacon あり?
定員・並行OK?"} G3 -->|No| X3["除外"] G3 -->|Yes| G4{"重複 ACTIVE
候補集合でない?"} G4 -->|No| X4["除外"] G4 -->|Yes| PAIR["全ペアを加重採点"] PAIR --> TH1{"ペア ≥ 0.60?"} TH1 -->|No| DROP["辺を捨てる"] TH1 -->|Yes| GRP["貪欲グループ 2〜5人
selection_score 順"] GRP --> TH2{"グループ matching_score ≥ 0.70?"} TH2 -->|No| DROP2["不採用"] TH2 -->|Yes| OUT["MatchedGroup + score_detail"]

図 5 — マッチングのゲートと閾値。

スコア要因(重み合計 1.00)

intent 一致
0.30
空き時間一致
0.25
場所一致・近接
0.15
興味一致
0.10
定員適合
0.10
学科一致
0.05
承認済み友人
0.05
  • グループの公開点は要因の加重和(ペア平均 + グループ共通時間・選定 Beacon)。
  • selection_score = matching_score + size_bonus(2人=0、+1人ごと +0.02、最大 +0.06)。
  • 同一実行内で学生を再利用しない。同点は安定した ID 順でタイブレーク。
  • 現状 InterestSource は常に unknown → interest 一致は 0.50 固定

7. Micro Event 生成

マッチングで得たグループごとに、カテゴリ・開催時間・manager・場所を決め、 条件 NG ならスキップ、OK なら Event を作ります。候補学生は自動 Join しません

flowchart TB
  G["MatchedGroup"] --> INT{"共有 intent → カテゴリ?"}
  INT -->|なし| S1["skip: no_shared_event_intent"]
  INT -->|あり| CAT["優先順で1カテゴリ
study → language_exchange → wellness → lunch → social"] CAT --> TIME["開始 = now+15分
長さ = 30/45/60分"] TIME --> MGR["manager 選定
can_facilitate 優先"] MGR --> PLACE["Beacon 採点
近接0.70 + 定員0.30"] PLACE --> DUP{"generation_key
重複 ACTIVE?"} DUP -->|Yes| S2["skip: duplicate"] DUP -->|No| CR["create MICRO / AI / ACTIVE
approval_required=false"] CR --> LOG["ai_event_logs + score_detail"] S1 --> LOG2["ai_event_logs skipped"] S2 --> LOG2

図 6 — 生成パイプライン。

項目実装内容
イベント属性event_type=MICRO, created_by_type=AI, status=ACTIVE, approval_required=false
開催時間残り共通 30–44→30分、45–59→45分、60+→60分
重複防止順序なし候補集合 + カテゴリの決定論的 generation_key
note_to_ai制御キーワードのみ抽出。生テキストはログに残さない
レスポンス作成イベントの配列。0件時は data: null

8. Port / Adapter 境界

マッチング本体は共有 DB/API を直接呼ばず、Port 経由で事実を受け取ります。 差し替え可能な境界として設計済みです。

flowchart LR
  CORE["純粋コア
availability / matching / generator"] CORE --- P1["StatusStore"] CORE --- P2["BeaconCatalog"] CORE --- P3["ProfileReader"] CORE --- P4["InterestSource"] CORE --- P5["EventCreator"] CORE --- P6["AiEventLogStore"] CORE --- P7["IdCodec"] P1 --> R1["SQLAlchemy 本実装"] P2 --> F2["Fixture / Fake"] P3 --> F3["Fixture"] P4 --> F4["AlwaysUnknown"] P5 --> F5["Process Fake"] P6 --> R6["SQLAlchemy flush"] P7 --> F7["no-op"]

図 7 — Port と現行 Adapter。緑系=本実装、茶系=Fake。

Port状態意味
StatusStore本実装PostgreSQL student_current_status
AiEventLogStore本実装flush のみ。commit はオーケストレーション
EventCreatorFakeプロセス内メモリ。実 Event 行と未接続
BeaconCatalogFixtureStudent 3 契約後に差替
ProfileReaderFixture学科・友人・can_facilitate
InterestSourceAlwaysUnknowninterest スコア 0.50 固定
IdCodecno-opUUID 決定後に変換層へ

9. API と画面の接続

flowchart TB
  subgraph StudentUI["学生 UI"]
    A["/app/status"]
  end
  subgraph Eval["評価・管理"]
    B["candidates API
X-Student-Id: user_eval_admin"] end subgraph Endpoints["Student 2 エンドポイント"] E1["POST /student/status"] E2["GET /student/status/me"] E3["POST /ai/micro-events/generate"] E4["GET /ai/micro-events/candidates"] end A --> E1 A --> E2 A --> E3 B --> E4

図 8 — 画面と API の配線(フェーズ 5 の最小接続)。

デモ注意: Fake ACTIVE 集合はプロセス生存中クリアされません。同じ候補で再度「生成成功」を見せる前に reset_process_fake_event_creator() または docker compose restart backend が必要です。

10. データの流れ(保存物)

flowchart LR
  subgraph Persist["PostgreSQL に永続"]
    S["student_current_status"]
    L["ai_event_logs"]
  end
  subgraph Memory["プロセスメモリ(Fake)"]
    E["Fake MICRO events"]
    D["ACTIVE duplicate sets"]
  end

  POST1["POST /student/status"] --> S
  GEN["generate"] --> E
  GEN --> L
  E --> D
  D --> GEN
  CAND["GET /candidates"] --> L
        

図 9 — 何が DB に残り、何が Fake メモリか。

AI ログに入れる / 入れない

含める含めない(プライバシー)
学生 ID・status ID、正規化時間、intent、Beacon ID、共通キーワード、候補 ID、理由コード、設定版/ハッシュ、score_detail 氏名、メール、住所、note_to_ai 原文

11. 評価・テスト

flowchart TB
  subgraph Measurable["今測れる"]
    M1["created / skipped / failed 件数"]
    M2["score_detail の内訳"]
    M3["candidates API"]
  end
  subgraph Later["実 Event 結合後"]
    L1["Join rate"]
    L2["Check-in rate"]
    L3["No-show rate"]
    L4["Micro Event success rate"]
  end
  subgraph Out["初期版では未測定"]
    O1["学生満足度スコア"]
  end

  FN["micro_event_metrics.py
純関数"] --> Later

図 10 — 評価指標の測定可否。

  • テスト結果(2026-08-21): 79 passed(unit 63 / API 16)
  • 指標の純関数は実装済み。公開集計 API は追加していない
  • 満足度は承認済みアンケート設計がないため未測定と明記

12. 未結合・チーム確認待ち

事項暫定状態
ID 型当面 stropen
interest データ源常に不明 → 0.50open
正式時限表Student 2 仮スロットopen
Event / Beacon 契約Fake adapteropen
実結合時の方針(1C): Student 1 の Event 作成と AI ログを同一 DB トランザクションに載せる。 現状の commit 対象は AI ログのみ(Fake Event はメモリ)。

13. 主要ファイル一覧

コア
backend/app/student2/(config, availability, ports, adapters, status_store, ai_event_log_store, fixtures)
backend/app/services/matching_service.py
backend/app/services/micro_event_generator.py
backend/app/services/micro_event_orchestration.py
backend/app/services/micro_event_metrics.py
backend/app/services/status_service.py

API
backend/app/api/student_status.py
backend/app/api/micro_events.py

画面
frontend/app/app/status/page.tsx

仕様メモ(エンジニア向け正本)
docs/ja/student-2-design-decisions.md
docs/ja/student-2-progress-report.md

この HTML は説明用です。API パス・フィールド名・閾値の契約正本は docs/api-contract.md と設計決定書を優先してください。