Skip to content

イベント申し込み・キャンセル機能の実装 #5

@oumelab

Description

@oumelab

Issue #5: イベント申し込み・キャンセル機能の実装

概要

認証済みユーザーがイベントに申し込み、キャンセルできる機能を実装する。申し込み履歴の確認も含め、イベント参加管理の核心機能を提供する。

目的

  • 認証済みユーザーのみがイベントへの参加を申し込める
  • 認証済みユーザーは申し込み済みのイベントをキャンセルできる
  • 認証済みユーザーは自分のイベント申し込み履歴を確認できる
  • 定員管理と重複申し込み防止を実現する
  • イベント参加のライフサイクル全体をサポートする

依存関係

前提条件

以下のIssueが完了していることが前提:

後続Issue

このIssueの完了は以下のIssueの前提条件となる:

実装内容

1. バックエンドAPI実装

  • 申し込みAPI: POST /api/events/[id]/apply

    • 認証チェック(ログイン済みユーザーのみ)
    • 定員チェック(満員の場合エラー)
    • 重複チェック(同一ユーザーの重複申し込み防止)
    • attendeesテーブルへのレコード挿入
    • レスポンス返却
  • キャンセルAPI: DELETE /api/events/[id]/cancel

    • 認証チェック(申し込み者本人のみ)
    • キャンセル可能期間チェック(イベント開始前のみ)
    • attendeesテーブルからのレコード削除
    • 定員数の自動更新
  • 申し込み履歴API: GET /api/user/registrations

    • 認証チェック
    • ユーザーの申し込み履歴取得
    • イベント情報との結合
    • キャンセル可能フラグの付与

2. データベース設計

  • attendeesテーブルの拡張
    -- user_idカラムが未追加の場合
    ALTER TABLE attendees ADD COLUMN user_id TEXT REFERENCES users(id);
    
    -- インデックス追加
    CREATE INDEX idx_attendees_user_id ON attendees(user_id);
    CREATE INDEX idx_attendees_event_user ON attendees(event_id, user_id);

3. フロントエンド実装

  • 申し込み機能UI

    • イベント詳細ページでの申し込みボタン
    • 認証状態に基づく表示制御
    • 申し込み済み・満員時の状態表示
    • ローディング・エラー状態の表示
  • キャンセル機能UI

    • 申し込み履歴ページでのキャンセルボタン
    • キャンセル確認ダイアログ
    • キャンセル理由選択(オプション)
    • 処理中・完了状態の表示
  • 申し込み履歴ページ

    • ユーザーの申し込みイベント一覧
    • イベント情報の表示
    • 申し込み日時の表示
    • キャンセル可能状態の判定・表示

4. 状態管理・API統合

  • TanStack Queryによるデータ管理

    • 申し込み状態のキャッシュ管理
    • 楽観的更新の実装
    • エラー時のロールバック
    • 関連データの自動更新
  • Zustandとの連携

    • 申し込み状態の グローバル管理
    • UI状態の同期
    • ユーザー体験の向上

技術的詳細

API設計例

// 申し込みAPI
POST /api/events/[id]/apply
Request: {}
Response: {
  success: boolean;
  message: string;
  registration: {
    id: string;
    event_id: string;
    user_id: string;
    email: string;
    created_at: number;
  };
}

// キャンセルAPI  
DELETE /api/events/[id]/cancel
Response: {
  success: boolean;
  message: string;
  cancelled_registration_id: string;
}

// 申し込み履歴API
GET /api/user/registrations
Response: {
  registrations: Array<{
    id: string;
    event: Event;
    registered_at: number;
    can_cancel: boolean;
  }>;
}

フロントエンド実装例

// 申し込み処理
const applyMutation = useMutation({
  mutationFn: (eventId: string) => applyToEvent(eventId),
  onSuccess: () => {
    toast.success('イベントに申し込みました');
    queryClient.invalidateQueries(['events']);
    queryClient.invalidateQueries(['user-registrations']);
  },
  onError: (error) => {
    toast.error(error.message);
  },
});

// キャンセル処理
const cancelMutation = useMutation({
  mutationFn: (eventId: string) => cancelEventRegistration(eventId),
  onSuccess: () => {
    toast.success('申し込みをキャンセルしました');
    queryClient.invalidateQueries(['events']);
    queryClient.invalidateQueries(['user-registrations']);
  },
});

ユーザーストーリー

申し込みフロー

  1. 未認証ユーザー:イベント詳細でログイン促進メッセージ表示
  2. 認証済みユーザー:「申し込む」ボタン表示
  3. ボタンクリック → API呼び出し → 成功/エラー表示
  4. 申し込み済み表示に変更
  5. 参加者数の更新

キャンセルフロー

  1. 申し込み履歴ページにアクセス
  2. キャンセル可能なイベントに「キャンセル」ボタン表示
  3. ボタンクリック → 確認ダイアログ表示
  4. 確認 → API呼び出し → 処理完了通知
  5. 履歴から削除、イベント詳細の参加者数更新

受け入れ基準

  • 未認証ユーザーはイベント情報の閲覧のみ可能
  • 未認証ユーザーには申し込みボタンの代わりにログイン促進メッセージが表示される
  • 認証済みユーザーのみがイベントに申し込むことができる
  • 定員に達したイベントには申し込めない
  • 同一ユーザーによる重複申し込みは防止される
  • 認証済みユーザーは申し込み済みイベントをキャンセルできる
  • イベント開始後のキャンセルは不可
  • 認証済みユーザーは自分の申し込み履歴を一覧で確認できる
  • ユーザーIDが申し込み情報に正しく紐付けられている
  • 申し込み・キャンセル時に定員数が正確に更新される
  • エラーケースで適切なエラーメッセージが表示される

テスト計画

  • 正常系テスト

    • 申し込み → キャンセルの一連フロー
    • 定員管理の動作確認
    • 申し込み履歴の正確性
  • 異常系テスト

    • 未認証でのアクセス
    • 重複申し込み試行
    • 満員イベントへの申し込み
    • 他人のイベントキャンセル試行
    • イベント開始後のキャンセル試行
  • UI/UXテスト

    • レスポンシブ対応
    • ローディング状態
    • エラー状態表示
    • 楽観的更新の動作

見積もり

  • 実装時間: 10-14日
  • テスト時間: 2-3日
  • 合計: 12-17日

ブランチ

feature/issue-5-event-registration-cancel

備考

Metadata

Metadata

Assignees

No one assigned

    Labels

    blocked他の機能の実装完了後までblocking他の Issue をブロック中feature新機能の追加priority: medium中優先度

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions