Skip to content

Requirements: 投票フロー

概要

本サイトは 有料投票のみ を扱い、無料投票は持たない。投票は決済の対価として、選択候補者へ「合計票数分」の投票を即時成立させる単一トランザクションとして表現される。事前に「投票券」を購入してから消費するモデルではなく、決済 = 投票 のワンショット。

購入画面では 複数の票数パッケージを数量付きで組み合わせて 合計金額を計算し、ニックネームを入力し、決済モーダルでオンライン決済を行う。決済成功と同時に該当候補者へ合計票数分の投票が一括で確定する。

ログイン機能を持たないため、ユーザーは購入のたびにニックネームを確認(初回は入力)するだけで参加できる。

関連UI

  • 票数パッケージ組み合わせ購入モーダル(複数パッケージの数量入力 + ニックネーム入力 + 合計表示)
  • 決済モーダル(決済プロバイダのワンクリック決済を優先 + カードフォールバック)

投票アクションのボタンラベル(「投票する」「投票期間外」)は候補者詳細・候補者カード側の UI 表現として candidate-detail/requirements.md で定義する。期間内/外の受付可否そのものはプロダクト全体の業務ルールとして steering/product.md「投票期間」で定義する。本 spec は購入フロー本体に責務を限定する。


機能仕様

Feature 1: 有料投票の成立

Purpose: 決済の完了と引き換えに、任意候補者へ合計票数分の投票を即時成立させる。残数として票を保持する仕組みは持たず、決済 = 投票 のワンショットを保証する。 Scope: 候補者を指定した「決済 → 投票」の単一トランザクション規約と、その受付可否のサーバー側判定。

Acceptance Criteria (EARS)

  • WHEN ユーザーが有料投票を要求した THEN システムは候補者選択、票数パッケージの組み合わせ選択、ニックネーム入力、および決済の完了をひとつのフローとして扱う
  • WHEN 決済が成功した THEN システムは購入の合計票数分を該当候補者に即時加算する
  • WHEN 決済が失敗または中断された THEN システムは投票を成立させない
  • THE SYSTEM SHALL 決済の対価としての投票のみを許可し、事前に取得済みの「投票券残数」を消費する操作は提供しない
  • WHEN ユーザーが購入アクションを連続実行しようとした THEN システムは進行中の決済が完了するまで追加のアクションを受け付けない
  • WHEN 投票期間外に決済・購入要求を受信した THEN システムはサーバー側で要求を拒否する(UI による事前抑止が回避された場合も含めて受け付けない。期間内/外の判定規則は steering/product.md「投票期間」を参照)

Feature 2: 購入モーダルの表示

Purpose: 候補者を選択した状態で有料投票を要求されたとき、購入モーダルを起動し、閉じた際は選択状態を確実にリセットする。 Scope: 購入モーダルの開閉制御。

Acceptance Criteria (EARS)

  • WHEN ユーザーが有料投票を要求した AND 候補者が選択されている THEN システムは購入モーダルを表示する
  • WHEN ユーザーがモーダルを閉じる操作をした THEN システムはモーダルを閉じ、選択中候補者をリセットする
  • WHEN ユーザーが決済処理中である THEN システムはモーダルを閉じる操作を無効化する

Feature 3: 購入モーダルのコンテンツ

Purpose: 投票対象候補者・選択可能な票数パッケージ・現在の組み合わせ・合計票数・合計金額・ニックネーム入力を一画面で完結して提示する。 Scope: 購入モーダル内コンテンツ。

Acceptance Criteria (EARS)

  • THE SYSTEM SHALL モーダル内に以下の情報を含める:
    • 対象候補者名と有料投票画面であることが分かる見出し
    • 票数パッケージ一覧と各パッケージの数量入力手段
    • 現在の組み合わせの合計票数および合計金額
    • 投票者ニックネームの入力フィールド
    • 「決済へ進む」アクション

Feature 4: 票数パッケージの取得と提示

Purpose: 運営が管理する有効な票数パッケージを表示順に従って一覧表示し、ユーザーが数量を入力できるようにする。 Scope: 票数パッケージ一覧の取得と表示順序の反映。

Acceptance Criteria (EARS)

  • THE SYSTEM SHALL 運営が有効化している票数パッケージを表示順に従って一覧表示する
  • THE SYSTEM SHALL 各パッケージについて票数・価格(税込)をユーザーに提示する
  • THE SYSTEM SHALL 具体的な票数・価格の値は運営の管理対象とし、本仕様では固定しない

Feature 5: パッケージの数量入力と組み合わせ

Purpose: ユーザーが各パッケージの購入数量を 0 以上の整数で指定し、複数パッケージを組み合わせて 1 回の決済で購入できるようにする。 Scope: パッケージごとの数量入力 UI とその集計。

Acceptance Criteria (EARS)

  • THE SYSTEM SHALL 各パッケージに数量(0 以上の整数)を入力できる手段を提供する
  • THE SYSTEM SHALL 数量の増減ボタン(+ / −)とテキスト入力の両方を提供する
  • WHEN ユーザーが数量を変更した THEN システムは即時に合計票数および合計金額を更新する
  • THE SYSTEM SHALL 数量の合計が 0 のとき「決済へ進む」アクションを無効化する
  • THE SYSTEM SHALL 合計票数および合計金額の計算をクライアント側で表示する一方、最終的な金額確定はサーバー側で再計算し、改竄を許容しない

Feature 6: ニックネーム入力

Purpose: 投票者を識別するニックネームを必須入力として受け取り、応援者ランキング集計のキーとして使用する。再入力負荷を下げるため、ブラウザに永続化して次回以降は自動補完する。 Scope: 購入モーダル内のニックネーム入力フィールドとローカル永続化。

Acceptance Criteria (EARS)

  • THE SYSTEM SHALL ニックネーム入力フィールドを購入モーダル内に必須項目として表示する
  • WHEN ユーザーが過去にニックネームを入力済み THEN システムは保存済みの値をフィールドへ自動補完する
  • THE SYSTEM SHALL ニックネームは 1 文字以上 32 文字以下とし、未入力・空白のみの入力は無効とする
  • WHEN ニックネームが未入力または無効である THEN システムは「決済へ進む」アクションを無効化し、入力エラーを表示する
  • WHEN 決済が成立した THEN システムはそのニックネームをブラウザ側に永続化し、次回の購入で再利用できるようにする
  • THE SYSTEM SHALL 同一文字列のニックネームは応援者ランキング上で同一支援者として集計される旨を、ユーザーへ補助テキストで明示する

Feature 7: 決済モーダル: フォーム

Purpose: 決済に必要な入力 UI を決済プロバイダ提供の埋め込みコンポーネント経由で提供し、カード情報を当アプリ側で保持しない構成にする。ワンクリック決済を優先候補としつつ、未登録ユーザーはカード入力でフォールバックできるようにする。 Scope: 決済モーダルの入力フィールド。

Acceptance Criteria (EARS)

  • WHEN 決済モーダルが開く THEN システムは決済プロバイダ提供の埋め込み決済 UI を用いて以下を提示する:
    • 登録済みユーザー向けのワンクリック決済
    • クレジットカード入力(ワンクリック未登録ユーザー向けフォールバック)
    • モバイルウォレット等の追加決済手段(プロバイダ側が利用環境に応じて自動で出し分ける)
  • THE SYSTEM SHALL カード番号・有効期限・CVC のフォーマット整形・桁数制限・ブランド別バリデーションは決済プロバイダ提供の入力 UI に委譲する
  • THE SYSTEM SHALL 当アプリ側にカード番号などの機微情報を保持しない

Feature 8: 決済モーダル: 決済情報の提示

Purpose: 決済金額と購入対象、安全性の根拠をユーザーへ明示する。 Scope: 決済モーダルの情報表示領域。

Acceptance Criteria (EARS)

  • THE SYSTEM SHALL 決済金額(税込・円表記)と投票内容(対象候補者名、合計票数、パッケージ内訳)を明示する
  • THE SYSTEM SHALL 第三者の決済プロバイダによる安全な決済であることをユーザーに伝達する

Feature 9: 決済実行

Purpose: 決済確定操作から決済成功までの状態遷移を管理し、成功時に投票加算とモーダルクローズを連動させる。 Scope: 決済シーケンス。

Acceptance Criteria (EARS)

  • WHEN ユーザーが決済確定を要求した THEN システムは決済処理中状態に遷移し、追加入力を受け付けない
  • WHEN 決済プロバイダ側で決済が成功した THEN システムは決済成功状態に遷移し、成功フィードバックを一定時間表示する
  • WHEN 成功表示が完了した THEN システムは投票数を加算しモーダルを閉じる

Feature 10: 決済成功後の処理と投票成功フィードバック

Purpose: 決済成功時に合計票数分の投票成立・成功表示・モーダルクローズ・選択リセット・ニックネーム永続化を一連のフローとして完了させる。 Scope: 決済成功後の後処理シーケンスと投票成功時の視覚フィードバック。

Acceptance Criteria (EARS)

  • WHEN 決済が成功した THEN システムは以下を順次実行する:
    1. 決済した合計票数分の投票を該当候補者に加算する(各投票には入力されたニックネームを保存する)
    2. ニックネームをブラウザ側に永続化する
    3. ユーザーに視覚的な成功フィードバックを一定時間提示する
    4. モーダルを閉じる
    5. 選択中候補者をリセットする
  • THE SYSTEM SHALL 該当候補者の得票数を加算する(加算量 = 決済した合計票数)
  • WHEN フィードバック表示が終了した THEN システムは選択中候補者をリセットする

Feature 11: モーダル閉じ時のリセット

Purpose: 購入モーダル・決済モーダルを閉じる際に入力値と状態をリセットし、処理中の意図しない中断を防ぐ。 Scope: 各モーダルのライフサイクル管理。

Acceptance Criteria (EARS)

  • WHEN ユーザーが購入モーダルを閉じた THEN システムは選択中の数量・合計値・選択中候補者をリセットする(ニックネーム入力値はブラウザ側に保存済みの値に従って次回自動補完される)
  • WHEN ユーザーが決済モーダルを閉じた THEN システムは決済状態をリセットする
  • WHEN 決済処理中 THEN システムは閉じる操作を無効化する

非機能要件

  • トランザクション: 決済成功時の決済記録と得票数加算は原子性を保つ(同一トランザクション内で実施)
  • 冪等性: 決済プロバイダからの決済完了通知が重複配信された場合でも、合計票数を超える投票記録が生成されないこと

依存仕様

  • data-model/requirements.md(票数パッケージ・購入記録・投票記録・ニックネーム正規化)
  • steering/product.md「投票期間」(期間内/外の受付可否を定義する横断業務ルール)

投票アクションのボタンラベル文言は candidate-detail/requirements.md で UI として定義されるが、本 spec はラベル文言自体に依存しないため依存仕様には含めない。