コンテンツにスキップ

happa API 仕様書 v1.0

概要

happa システムの API を Next.js から分離し、FastAPI で再構築するための仕様書です。この API は大学祭などのイベント管理システムのバックエンドとして機能します。

システム概要

  • イベント管理: 千葉大祭などの大規模イベントの管理
  • 団体管理: サークルや団体の情報管理
  • 企画管理: 各団体が実施する企画の申請・承認・管理
  • リソース配分: 会場、予算、物品などのリソース割り当て
  • スケジュール管理: 説明会、イベントスケジュールの管理とチェックイン機能
  • サポート: 問い合わせ管理とチャット機能

技術スタック

推奨技術

  • フレームワーク: FastAPI 0.104+
  • データベース: MySQL 8.0+ with Prisma ORM 互換
  • 認証: Auth0 (OAuth2)
  • ORM: SQLAlchemy 2.0+ または Tortoise ORM
  • バリデーション: Pydantic v2
  • 非同期処理: asyncio
  • ドキュメント: OpenAPI 3.0 (FastAPI 自動生成)

環境変数

DATABASE_URL=mysql://user:password@host:port/database
AUTH0_DOMAIN=your-tenant.auth0.com
AUTH0_CLIENT_ID=your-client-id
AUTH0_CLIENT_SECRET=your-client-secret
AUTH0_AUDIENCE=your-api-audience
NODE_ENV=production|development

認証・認可

認証方式

  • Auth0 OAuth2: Bearer Token 認証
  • 開発モード: NODE_ENV=development時はモックユーザーで認証バイパス可能

ユーザーロール(段階的廃止予定)

class UserRole(str, Enum):
    USER = "User"                          # 一般ユーザー(デフォルト)
    LIMITED_ADMIN = "LimitedAdmin"         # 制限付き管理者(廃止予定)
    READ_ONLY_ADMIN = "ReadOnlyAdmin"      # 読み取り専用管理者(廃止予定)
    FULL_ACCESS_ADMIN = "FullAccessAdmin"  # 完全管理者(廃止予定)

注意: グローバルロールは段階的に廃止し、リソースレベル権限システムに移行します。

リソースレベル権限システム

リソースタイプ

class ResourceType(str, Enum):
    PROJECT = "PROJECT"                    # イベント全体(例: 千葉大祭2024)
    CIRCLE_PROJECT = "CIRCLE_PROJECT"      # 個別企画

権限の種類

class Permission(str, Enum):
    READ = "READ"                          # 読み取り
    WRITE = "WRITE"                        # 書き込み・更新
    DELETE = "DELETE"                      # 削除
    MANAGE_MEMBERS = "MANAGE_MEMBERS"      # メンバー管理
    MANAGE_PERMISSIONS = "MANAGE_PERMISSIONS"  # 権限管理
    APPROVE = "APPROVE"                    # 承認操作
    CHECKIN = "CHECKIN"                    # チェックイン操作
    ALLOCATE_RESOURCES = "ALLOCATE_RESOURCES"  # リソース割り当て
    VIEW_PRIVATE = "VIEW_PRIVATE"          # 非公開情報の閲覧

標準ロールテンプレート

Project用:

  • ProjectAdmin: 全権限(READ, WRITE, DELETE, MANAGE_MEMBERS, MANAGE_PERMISSIONS, APPROVE, ALLOCATE_RESOURCES, VIEW_PRIVATE)
  • ProjectManager: 管理権限(READ, WRITE, APPROVE, ALLOCATE_RESOURCES, VIEW_PRIVATE)
  • ProjectEditor: 編集権限(READ, WRITE, VIEW_PRIVATE)
  • ProjectViewer: 閲覧のみ(READ)

CircleProject用:

  • Manager: 企画管理者(READ, WRITE, DELETE, MANAGE_MEMBERS, MANAGE_PERMISSIONS, CHECKIN, VIEW_PRIVATE)
  • Editor: 企画編集者(READ, WRITE, CHECKIN, VIEW_PRIVATE)
  • Member: 一般メンバー(READ, CHECKIN)
  • Viewer: 閲覧のみ(READ)

認証レベル

  1. requireAuth: ログインユーザー(全ロール)
  2. requireAdminPlus: 管理者以上(LIMITED_ADMIN, READ_ONLY_ADMIN, FULL_ACCESS_ADMIN)※廃止予定
  3. requireAdmin: 完全管理者のみ(FULL_ACCESS_ADMIN)※廃止予定
  4. requireCircleProjectManager: 企画管理者(企画の最初のメンバー)※廃止予定
  5. requireCircleProjectMember: 企画メンバー※廃止予定
  6. requireResourcePermission(resourceType, resourceId, permissions): リソースレベル権限チェック(新規)

自動ユーザー作成

  • 初回ログイン時に Auth0 のsubemailからユーザーを自動作成
  • @student.gs.chiba-u.jpドメインのメールアドレスから学籍番号を抽出
  • デフォルトロールはUser

データモデル

主要エンティティ

1. User (ユーザー)

{
    "id": "uuid",
    "studentId": "string | null",      # 学籍番号
    "auth0Id": "string | null",        # Auth0 sub
    "name": "string | null",
    "email": "string",
    "role": "UserRole"
}

2. Project (イベント)

{
    "prefix": "string",                # 一意識別子(例: "chibafes2024")
    "name": "string",                  # イベント名
    "owner": "string | null",
    "startAt": "datetime | null",
    "endAt": "datetime | null",
    "closeRegisterAt": "datetime | null",
    "isClose": "boolean",
    "notificationWebhook": "string | null",
    "allowedCategories": "list[Category] | null",      # JSON配列
    "allowedProjectTypes": "list[string] | null"       # JSON配列
}

3. Circle (団体)

{
    "circleId": "string",              # 団体ID
    "name": "string",
    "name_kana": "string",
    "isOfficial": "boolean"            # 公認団体フラグ
}

4. CircleProject (企画)

{
    "id": "uuid",
    "parentPrefix": "string",          # FK to Project
    "circleId": "string",              # FK to Circle
    "name": "string",
    "memo": "string | null",
    "location": "string",
    "projectType": "string",
    "category": "Category | null",
    "areaCode": "AreaCode | null",
    "areaNumber": "string | null",
    "pamphletNumber": "string | null",
    "beforeDay": "boolean",
    "firstDay": "boolean",
    "secondDay": "boolean",
    "thirdDay": "boolean",
    "isArchived": "boolean",
    "archivedAt": "datetime | null",
    "status": "CircleProjectStatus",   # DRAFT, APPROVED, REJECTED
    "applicationGroupId": "uuid | null",  # 申請グループ化用
    "applicationReason": "string | null"
}

5. Allocation (リソース割り当て)

{
    "id": "uuid",
    "parentPrefix": "string",
    "name": "string",
    "provider": "string",
    "max": "int",
    "maxPerOne": "int | null",
    "price": "int",
    "unit": "string | null",
    "category": "AllocationCategory | null",
    "tagId": "uuid | null"
}

6. Schedule (スケジュール)

{
    "id": "uuid",
    "parentPrefix": "string",
    "parentFolderId": "uuid | null",
    "name": "string",
    "scheduleType": "ScheduleType",    # SCHEDULE, TASK
    "startTime": "datetime | null",
    "endTime": "datetime | null",
    "location": "string",
    "description": "string | null",
    "isPublishToCircle": "boolean",
    "isCheckinEnabled": "boolean",
    "isAllowSelfCheckin": "boolean",
    "isPublicCheckinStatus": "boolean",
    "isRequireManager": "boolean"
}

Enum 定義

class Category(str, Enum):
    FOOD = "FOOD"                      # 飲食
    EXHIBITION = "EXHIBITION"          # 展示
    MUSIC = "MUSIC"                    # 音楽
    PERFORMANCE = "PERFORMANCE"        # パフォーマンス
    PARTICIPATORY = "PARTICIPATORY"    # 参加型
    MERCHANDISE = "MERCHANDISE"        # 物販
    OTHER = "OTHER"                    # その他

class AreaCode(str, Enum):
    T = "T"  # 工北
    R = "R"  # 工南
    S = "S"  # 理学
    L = "L"  # 文法
    D = "D"  # 人社・院棟
    K = "K"  # 語らいの森
    H = "H"  # 本部
    E = "E"  # 教育
    G = "G"  # 普遍

class CircleProjectStatus(str, Enum):
    DRAFT = "DRAFT"                    # 申請中(仮企画)
    APPROVED = "APPROVED"              # 承認済み(正式企画)
    REJECTED = "REJECTED"              # 却下

class AllocationCategory(str, Enum):
    BASE_PRICING = "BASE_PRICING"
    PROJECT_OPTION_PRICING = "PROJECT_OPTION_PRICING"
    FOOD_OPTION_PRICING = "FOOD_OPTION_PRICING"
    ITEM_RENTAL_PRICING = "ITEM_RENTAL_PRICING"

class CheckinStatus(str, Enum):
    ATTENDANCE = "ATTENDANCE"
    ABSENCE = "ABSENCE"
    TENTATIVE = "TENTATIVE"
    UNSET = "UNSET"

class CheckinMethod(str, Enum):
    ADMIN_PANEL = "ADMIN_PANEL"
    QR_SCAN = "QR_SCAN"
    LIST_SELECTION = "LIST_SELECTION"
    SELF_CHECKIN = "SELF_CHECKIN"

class SupportCaseStatus(str, Enum):
    OPEN = "OPEN"
    CLOSE = "CLOSE"
    FREEZE = "FREEZE"

API エンドポイント一覧

ベース URL: /api

1. 認証・ユーザー管理

GET /api/user

現在のユーザー情報を取得または作成

認証: requireAuth

レスポンス:

{
    "id": "uuid",
    "studentId": "ABC123",
    "email": "user@example.com",
    "role": "User"
}

GET /api/user/list

全ユーザーリスト取得

認証: requireAdminPlus

レスポンス:

{
    "users": [
        {
            "id": "uuid",
            "studentId": "ABC123",
            "email": "user@example.com",
            "role": "User"
        }
    ]
}

PUT /api/user/{id}/role

ユーザーロール更新

認証: requireAdmin

リクエストボディ:

{
    "role": "LimitedAdmin"
}

2. プロジェクト管理

GET /api/project?prefix={prefix}

プロジェクト詳細取得(企画一覧含む)

認証: requireAdminPlus

パラメータ:

  • prefix (required): プロジェクト識別子

レスポンス:

{
    "projects": {
        "prefix": "chibafes2024",
        "name": "千葉大祭2024",
        "owner": "実行委員会",
        "startAt": "2024-11-01T00:00:00Z",
        "endAt": "2024-11-03T23:59:59Z",
        "circleProjects": [...]
    }
}

GET /api/project/list

全プロジェクトリスト取得

認証: requireAdminPlus

GET /api/project/constraints?prefix={prefix}

申請可能なカテゴリーと企画種別取得

認証: なし(公開)

レスポンス:

{
    "allowedCategories": ["FOOD", "EXHIBITION"],
    "allowedProjectTypes": ["TENT", "ROOM"]
}

POST /api/project

新規プロジェクト作成

認証: requireAdmin

リクエストボディ:

{
    "prefix": "chibafes2025",
    "name": "千葉大祭2025",
    "owner": "実行委員会",
    "startAt": "2025-11-01T00:00:00Z",
    "endAt": "2025-11-03T23:59:59Z",
    "closeRegisterAt": "2025-10-01T23:59:59Z",
    "notificationWebhook": "https://webhook.example.com",
    "allowedCategories": ["FOOD", "EXHIBITION"],
    "allowedProjectTypes": ["TENT", "ROOM"]
}

PUT /api/project

プロジェクト更新

認証: requireAdmin


3. 企画申請管理

GET /api/circle-project-application/list?prefix={prefix}&status={status}

申請一覧取得(管理者用)

認証: requireAdminPlus

パラメータ:

  • prefix: プロジェクト prefix
  • status: DRAFT | APPROVED | REJECTED(デフォルト: DRAFT)

レスポンス:

{
    "applications": {
        "application-group-uuid-1": [
            {
                "id": "uuid",
                "name": "第1希望企画",
                "category": "FOOD",
                "applicationReason": "理由",
                "circle": {...},
                "leader": {...}
            },
            {
                "id": "uuid",
                "name": "第2希望企画",
                "category": "EXHIBITION",
                ...
            }
        ]
    },
    "total": 1
}

GET /api/circle-project-application/my?prefix={prefix}

自分の団体の申請一覧取得

認証: requireAuth

POST /api/circle-project-application

企画申請提出(第 1〜第 5 希望)

認証: requireAuth

リクエストボディ:

{
    "parentPrefix": "chibafes2024",
    "circleId": "circle-001",
    "circleName": "サークル名",
    "circleNameKana": "サークルメイ",
    "leaderName": "責任者名",
    "leaderStudentId": "ABC123",
    "leaderTel": "090-1234-5678",
    "subLeaderName": "副責任者名",
    "subLeaderStudentId": "DEF456",
    "subLeaderTel": "090-8765-4321",
    "preferences": [
        {
            "name": "第1希望企画名",
            "category": "FOOD",
            "areaCode": "T",
            "place": "工北エリア",
            "reason": "第1希望の理由",
            "memo": "メモ"
        },
        {
            "name": "第2希望企画名",
            "category": "EXHIBITION",
            "areaCode": "S",
            "place": "理学部エリア",
            "reason": "第2希望の理由"
        }
    ]
}

レスポンス:

{
    "applicationGroupId": "uuid",
    "projects": [
        {
            "id": "uuid",
            "name": "第1希望企画名",
            "status": "DRAFT"
        }
    ]
}

POST /api/circle-project-application/approve

申請承認/却下

認証: requireAdminPlus

リクエストボディ:

{
    "projectIds": ["uuid1", "uuid2"],
    "action": "approve" // or "reject"
}

動作:

  • approve: 選択した企画を承認(同じ applicationGroupId の他の希望は DRAFT 状態のまま維持)
  • reject: 選択した企画を却下

DELETE /api/circle-project-application?applicationGroupId={id}

申請削除(DRAFT 状態のみ)

認証: requireAuth


4. 企画管理

GET /api/circle-project?id={id}

企画詳細取得

認証: requireAuth

GET /api/circle-project/list

企画一覧取得

認証: requireAdminPlus

GET /api/circle-project?prefix={prefix}

プロジェクト配下の企画一覧取得

認証: requireAuth

GET /api/circle-project/{id}/schedules

企画のスケジュール取得

認証: requireAuth

POST /api/circle-project

新規企画作成

認証: requireAdmin

PUT /api/circle-project

企画更新

認証: requireAdmin または requireCircleProjectManager

PUT /api/circle-project/{id}/archive

企画アーカイブ/復元

認証: requireAdmin

リクエストボディ:

{
    "isArchived": true
}

PUT /api/circle-project/bulk-update-categories

カテゴリー一括更新

認証: requireAdmin

リクエストボディ:

{
    "updates": [
        {
            "id": "uuid",
            "category": "FOOD"
        }
    ]
}

PUT /api/circle-project/bulk-update-areas

エリア一括更新

認証: requireAdmin

PUT /api/circle-project/bulk-update-project-types

企画種別一括更新

認証: requireAdmin

POST /api/circle-project/join

招待コードで企画参加

認証: requireAuth

リクエストボディ:

{
    "code": "INVITE123"
}

5. リソース割り当て(Allocation)

GET /api/allocation?id={id}

割り当て詳細取得

認証: requireAdminPlus

POST /api/allocation

割り当て作成

認証: requireAdmin

リクエストボディ:

{
    "parentPrefix": "chibafes2024",
    "name": "テント(3m×3m)",
    "provider": "レンタル業者A",
    "max": 50,
    "maxPerOne": 2,
    "price": 10000,
    "unit": "張",
    "category": "ITEM_RENTAL_PRICING",
    "tagId": "uuid"
}

PUT /api/allocation

割り当て更新

認証: requireAdmin

POST /api/allocation/assign

企画への割り当て

認証: requireAdmin

リクエストボディ:

{
    "allocationId": "uuid",
    "circleProjectId": "uuid",
    "amount": 2
}

PUT /api/allocation/assign/{id}

割り当て量更新

認証: requireAdmin

DELETE /api/allocation/assign/{id}

割り当て削除

認証: requireAdmin

POST /api/allocation/bulk-assign

一括割り当て

認証: requireAdmin


6. スケジュール管理

GET /api/schedule?parentPrefix={prefix}&circleProjectId={id}

スケジュール一覧取得

認証: requireAuth

POST /api/schedule

スケジュール作成

認証: requireAdmin

リクエストボディ:

{
    "parentPrefix": "chibafes2024",
    "parentFolderId": "uuid",
    "name": "説明会",
    "scheduleType": "SCHEDULE",
    "startTime": "2024-10-15T14:00:00Z",
    "endTime": "2024-10-15T16:00:00Z",
    "location": "大講義室",
    "description": "企画説明会",
    "isPublishToCircle": true,
    "isCheckinEnabled": true,
    "isAllowSelfCheckin": false,
    "isRequireManager": true
}

PUT /api/schedule

スケジュール更新

認証: requireAdmin

POST /api/schedule/assign

企画へのスケジュール割り当て

認証: requireAdmin

リクエストボディ:

{
    "scheduleId": "uuid",
    "circleProjectId": "uuid",
    "customStartTime": "2024-10-15T14:30:00Z"
}

PUT /api/schedule/assign/{id}/checkin

チェックイン処理

認証: requireAuth(条件により)

リクエストボディ:

{
    "status": "ATTENDANCE",
    "method": "QR_SCAN",
    "scannedUserId": "uuid",
    "memo": "メモ"
}

7. スケジュールフォルダ

GET /api/schedule/folder?parentPrefix={prefix}

フォルダ一覧取得

認証: requireAdminPlus

POST /api/schedule/folder

フォルダ作成

認証: requireAdmin

PUT /api/schedule/folder

フォルダ更新

認証: requireAdmin

DELETE /api/schedule/folder/{id}

フォルダ削除

認証: requireAdmin


8. タグ管理

GET /api/tags

タグ一覧取得

認証: requireAuth

POST /api/tags

タグ作成

認証: requireAdminPlus

リクエストボディ:

{
    "text": "タグ名",
    "forVisitors": true
}

POST /api/tags/assign

企画へのタグ一括割り当て

認証: requireAdmin

PUT /api/tags/{id}

タグ更新

認証: requireAdminPlus

DELETE /api/tags/{id}

タグ削除

認証: requireAdminPlus


9. プロジェクトマテリアル

GET /api/project-text?circleProjectId={id}&textType={type}

テキスト取得

認証: requireAuth

パラメータ:

  • textType: PRSUMMARY | DESCRIPTION | PRDETAIL | REMARK

POST /api/project-text

テキスト作成

認証: requireCircleProjectMember

PUT /api/project-text

テキスト更新

認証: requireCircleProjectMember

GET /api/image?cprojectId={id}

画像一覧取得

認証: requireAuth

POST /api/image

画像アップロード

認証: requireCircleProjectMember

リクエスト: multipart/form-data

DELETE /api/image/{id}

画像削除

認証: requireCircleProjectMember

GET /api/sns-data?circleProjectId={id}

SNS 情報取得

認証: requireAuth

POST /api/sns-data

SNS 情報作成

認証: requireCircleProjectMember


10. 更新リクエスト管理

GET /api/project-text-request/list?parentPrefix={prefix}&status={status}

更新リクエスト一覧

認証: requireAdminPlus

POST /api/project-text-request

更新リクエスト作成

認証: requireCircleProjectMember

POST /api/project-text-request/approve

更新リクエスト承認

認証: requireAdminPlus

POST /api/project-text-request/reject

更新リクエスト却下

認証: requireAdminPlus


11. サポートケース

GET /api/support-case/list?projectPrefix={prefix}&status={status}

サポートケース一覧

認証: requireAdminPlus

GET /api/support-case/{id}

サポートケース詳細(チャット含む)

認証: requireAuth(作成者または管理者)

POST /api/support-case

サポートケース作成

認証: requireAuth

リクエストボディ:

{
    "projectPrefix": "chibafes2024",
    "title": "問い合わせタイトル",
    "initialMessage": "問い合わせ内容"
}

POST /api/support-case/{id}/chat

チャットメッセージ追加

認証: requireAuth(作成者または管理者)

PUT /api/support-case/{id}/status

ステータス更新

認証: requireAdminPlus

PUT /api/support-case/{id}/assign

担当者割り当て

認証: requireAdminPlus


12. 権限申請

GET /api/permission-requests/list

権限申請一覧

認証: requireAdminPlus

GET /api/permission-requests/my

自分の申請一覧

認証: requireAuth

POST /api/permission-requests

権限申請作成

認証: requireAuth

リクエストボディ:

{
    "targetType": "CIRCLE_PROJECT_MANAGER",
    "targetId": "circle-project-uuid",
    "comment": "申請理由"
}

POST /api/permission-requests/{id}/approve

申請承認

認証: requireAdmin

POST /api/permission-requests/{id}/deny

申請却下

認証: requireAdmin


13. リソースレベル権限管理

GET /api/resource-permissions?userId={userId}&resourceType={type}&resourceId={id}

リソースレベル権限取得

認証: requireAuth(自分の権限取得)または requireResourcePermission(MANAGE_PERMISSIONS)

パラメータ:

  • userId (optional): ユーザーID(省略時は自分の権限)
  • resourceType (optional): PROJECT | CIRCLE_PROJECT
  • resourceId (optional): リソースID

レスポンス:

{
    "permissions": [
        {
            "id": "uuid",
            "userId": "user-uuid",
            "resourceType": "PROJECT",
            "resourceId": "chibafes2024",
            "permissions": ["READ", "WRITE", "APPROVE"],
            "grantedBy": "admin-uuid",
            "grantedAt": "2024-01-01T00:00:00Z",
            "expiresAt": null
        }
    ]
}

POST /api/resource-permissions

リソース権限付与

認証: requireResourcePermission(resourceType, resourceId, MANAGE_PERMISSIONS)

リクエストボディ:

{
    "userId": "user-uuid",
    "resourceType": "PROJECT",
    "resourceId": "chibafes2024",
    "permissions": ["READ", "WRITE", "APPROVE"]
}

または、ロールテンプレートを使用:

{
    "userId": "user-uuid",
    "resourceType": "PROJECT",
    "resourceId": "chibafes2024",
    "roleTemplate": "ProjectManager"
}

PUT /api/resource-permissions/{id}

リソース権限更新

認証: requireResourcePermission(resourceType, resourceId, MANAGE_PERMISSIONS)

リクエストボディ:

{
    "permissions": ["READ", "WRITE"],
    "expiresAt": "2025-12-31T23:59:59Z"
}

DELETE /api/resource-permissions/{id}

リソース権限削除

認証: requireResourcePermission(resourceType, resourceId, MANAGE_PERMISSIONS)

GET /api/resource-permissions/check?resourceType={type}&resourceId={id}&permissions={perms}

権限チェック(開発・デバッグ用)

認証: requireAuth

パラメータ:

  • resourceType: PROJECT | CIRCLE_PROJECT
  • resourceId: リソースID
  • permissions: カンマ区切りの権限リスト(例: READ,WRITE)

レスポンス:

{
    "hasPermission": true,
    "missingPermissions": []
}

GET /api/resource-role-templates

ロールテンプレート一覧取得

認証: requireAuth

パラメータ:

  • resourceType (optional): PROJECT | CIRCLE_PROJECT

レスポンス:

{
    "templates": [
        {
            "id": "uuid",
            "name": "ProjectManager",
            "resourceType": "PROJECT",
            "permissions": ["READ", "WRITE", "APPROVE", "ALLOCATE_RESOURCES", "VIEW_PRIVATE"],
            "description": "プロジェクト管理者用ロール",
            "isSystem": true
        }
    ]
}

POST /api/resource-role-templates

カスタムロールテンプレート作成

認証: requireAdmin(システム標準ロールの場合)または requireResourcePermission(MANAGE_PERMISSIONS)

リクエストボディ:

{
    "name": "CustomRole",
    "resourceType": "PROJECT",
    "permissions": ["READ", "WRITE"],
    "description": "カスタムロール",
    "isSystem": false
}

14. 検便管理

GET /api/stool-test?projectPrefix={prefix}&circleProjectId={id}

検便結果取得

認証: requireAdminPlus

POST /api/stool-test

検便結果登録

認証: requireAdminPlus

POST /api/stool-test/bulk-upload

検便結果一括登録

認証: requireAdmin


14. 公開 API

GET /api/public/circle-project?prefix={prefix}

公開企画一覧取得

認証: なし

レスポンス: アーカイブされていない承認済み企画のみ


15. その他

GET /api/explore?q={query}&prefix={prefix}

企画検索

認証: requireAuth

GET /api/invoice?circleProjectId={id}

請求情報取得

認証: requireAdminPlus

POST /api/bulk-invoice

請求一括処理

認証: requireAdmin

GET /api/bulk-excel?type={type}&prefix={prefix}

Excel 一括エクスポート

認証: requireAdminPlus

パラメータ:

  • type: allocations | schedules | circle_projects

エラーレスポンス

全エンドポイントで統一されたエラーレスポンス形式:

{
    "error": {
        "message": "エラーメッセージ",
        "code": "ERROR_CODE",
        "details": {}
    }
}

HTTP ステータスコード

  • 200 OK: 成功
  • 201 Created: 作成成功
  • 400 Bad Request: バリデーションエラー
  • 401 Unauthorized: 認証エラー
  • 403 Forbidden: 権限不足
  • 404 Not Found: リソースが存在しない
  • 409 Conflict: 重複エラー
  • 500 Internal Server Error: サーバーエラー

Webhook 通知

プロジェクトのnotificationWebhookが設定されている場合、以下のイベントで通知:

イベントタイプ

circle_project_application_created

{
    "type": "circle_project_application_created",
    "applicationGroupId": "uuid",
    "circleId": "circle-001",
    "circleName": "サークル名",
    "preferencesCount": 3,
    "timestamp": "2024-01-01T00:00:00Z"
}

circle_project_approved

{
    "type": "circle_project_approved",
    "circleProjectId": "uuid",
    "circleProjectName": "企画名",
    "timestamp": "2024-01-01T00:00:00Z"
}

データベース設計注意事項

BigInt 処理

  • Prisma のBigInt型は JSON シリアライズ時に文字列に変換
  • FastAPI ではid: intとして扱い、レスポンス時に文字列化

UUID 生成

  • MySQL 関数: UUID()
  • FastAPI: uuid.uuid4()

タイムゾーン

  • データベース: UTC 保存
  • API: ISO 8601 形式(2024-01-01T00:00:00Z

トランザクション

  • 複数テーブル更新時は必ずトランザクション使用
  • 申請承認時の一括更新など

セキュリティ要件

  1. SQL インジェクション対策: ORM パラメータバインディング使用
  2. XSS 対策: HTML エスケープ(フロントエンド責務)
  3. CSRF 対策: Bearer Token 認証のため不要
  4. レート制限: FastAPI ミドルウェアで実装推奨
  5. CORS: 本番環境では許可オリジン制限
  6. ログ: 個人情報をログに出力しない

パフォーマンス要件

  1. キャッシング:

    • プロジェクト一覧: 60 秒 TTL
    • 公開企画一覧: 300 秒 TTL
  2. ページネーション:

    • 一覧 API: limitoffsetパラメータ実装推奨
  3. Eager Loading:

    • N+1 問題回避のためリレーション事前ロード
  4. インデックス:

    • CircleProject.parentPrefix
    • CircleProject.status
    • CircleProject.applicationGroupId
    • ScheduleAssignment.scheduleId
    • ScheduleAssignment.circleProjectId

移行計画

Phase 1: コア API

  • 認証・ユーザー管理
  • プロジェクト管理
  • 企画管理(基本 CRUD)

Phase 2: 申請フロー

  • 企画申請機能
  • 承認ワークフロー
  • 権限申請

Phase 3: リソース管理

  • Allocation 管理
  • スケジュール管理
  • チェックイン機能

Phase 4: 補助機能

  • サポートケース
  • マテリアル更新リクエスト
  • 検便管理
  • Webhook 通知

Phase 5: 最適化

  • キャッシング実装
  • ページネーション
  • 全文検索最適化

テスト要件

  1. 単体テスト: 各エンドポイントの正常系・異常系
  2. 認可テスト: ロールごとのアクセス制御
  3. 統合テスト: トランザクション動作確認
  4. 負荷テスト: 同時アクセス性能測定

ドキュメント

  • OpenAPI 仕様: FastAPI の/docs(Swagger UI)
  • ReDoc: /redoc
  • スキーマ: /openapi.json

付録

実装時のディレクトリ構成例

api/
├── main.py                 # FastAPIアプリケーションエントリポイント
├── config.py               # 環境変数・設定
├── database.py             # データベース接続
├── dependencies.py         # 認証依存性
├── models/                 # SQLAlchemyモデル
│   ├── __init__.py
│   ├── user.py
│   ├── project.py
│   ├── circle_project.py
│   └── ...
├── schemas/                # Pydanticスキーマ
│   ├── __init__.py
│   ├── user.py
│   ├── project.py
│   └── ...
├── routers/                # APIルーター
│   ├── __init__.py
│   ├── auth.py
│   ├── users.py
│   ├── projects.py
│   ├── circle_projects.py
│   ├── applications.py
│   ├── allocations.py
│   ├── schedules.py
│   ├── tags.py
│   ├── support_cases.py
│   └── ...
├── services/               # ビジネスロジック
│   ├── __init__.py
│   ├── auth_service.py
│   ├── application_service.py
│   └── ...
├── utils/                  # ユーティリティ
│   ├── __init__.py
│   ├── auth0.py
│   ├── webhook.py
│   └── ...
└── tests/                  # テスト
    ├── __init__.py
    ├── test_auth.py
    └── ...

変更履歴

  • v1.0 (2025-01-07): 初版作成