セッションライフサイクル
この文書は、セッション管理の実装を クライアント側とサーバー側に分けて説明します。
1. 管理責務の分離
| 管理面 | 主な保存先 | 主な責務 |
|---|---|---|
| クライアント | localStorage (starkBallotSession) | 画面遷移フェーズ、クライアント TTL、UI 復元 |
| サーバー | VoteStore 実装(Mock/File/Amplify) | 投票データ、掲示板、集計結果、検証結果 |
クライアントとサーバーは X-Session-ID で紐づきます(ただし全エンドポイントで必須ではありません)。
2. クライアント側フェーズ
クライアントセッション(src/lib/session/client.ts)のフェーズは以下の 3 つです。
votingfinalizingverifying
主な遷移トリガー:
POST /api/session後にgenerateSessionId(...)でvoting開始aggregate画面で非同期集計のpending/runningを検知するとsaveSessionData({ phase: 'finalizing' })- 集計結果を保存すると
saveSessionData({ finalizeResult, phase: 'verifying' })
3. クライアント TTL 実装
SESSION_PHASE_TIMEOUTS_MS:
voting: 30 分finalizing: 30 分verifying: 24 時間
TTL 更新の実装ポイント:
generateSessionId(...): 新規作成saveSessionData(...): フェーズを加味してexpiresAtを再計算updateLastActivity(...): 現在フェーズでexpiresAtを再延長
期限切れ判定:
checkTimeout()またはgetSessionData()が有効期限超過を検出するとclearSession()を実行
補足:
- 専用 heartbeat API はありません。
- 60 秒間隔の
updateLastActivity()は現行実装では verify 画面で実行されています。
4. サーバー側セッション状態
サーバーは SessionData に以下を保持します。
- 投票(
votes,userVoteIndex,botCount) - 集計状態(
finalizationState) - 集計結果(
finalizationResult) - 最終活動時刻(
lastActivity)
finalizationState.status は以下を取り得ます。
pendingrunningsucceededfailedtimeout
5. サーバー側 TTL / 失効の実装差分
サーバー側の失効挙動はストア実装で異なります。
| ストア | 失効/TTL の実装 |
|---|---|
MockSessionStore | getActiveSessionCount() 呼び出し時に lastActivity から 5 分超を掃除 |
FileMockSessionStore | getActiveSessionCount() 呼び出し時に同様に 5 分超を掃除 |
AmplifySessionStore | TTL 属性を保存。初期は AMPLIFY_DATA_TTL_SECONDS(既定 1800 秒)、finalized 更新時は AMPLIFY_DATA_VERIFICATION_TTL_SECONDS(既定 86400 秒)を使用 |
重要事項:
- 「同時セッション上限 100」を強制するロジックは、現行の
/api/session実装には入っていません。
6. X-Session-ID スコープ
X-Session-ID の要否はエンドポイントごとに異なります。
ヘッダー必須の代表例:
/api/vote,/api/progress,/api/finalize,/api/finalize/cancel/api/verify,/api/verification/run/api/bulletin,/api/bulletin/:voteId,/api/bulletin/:voteId/proof,/api/bulletin/consistency-proof/api/botdata/:id,/api/sth
ヘッダー不要の代表例:
/api/sessions/:sessionId/status(パスパラメータ)/api/verification/bundles/:sessionId/:executionId(パスパラメータ)/api/zkvm-input-hash(クエリsessionId)
実装依存:
/api/bitmap-proof(Mock/File は省略可、Amplify は実質必須)
7. マルチタブ時の実務上の注意
localStorage は同一オリジンで共有されるため、タブ間でセッション情報が競合します。
代表的な結果:
- 片方のタブで投票済み後、別タブで再投票すると
ALREADY_VOTED - 片方のタブで集計完了後、別タブで再集計すると
SESSION_ALREADY_FINALIZED - セッション作成を並行すると、最後に保存した
starkBallotSessionが有効になる