HSH-Phira バックエンドリメイク版
実行方法
開発環境
本プロジェクトは uv を使用して管理されています。リポジトリ(完全版)を HSNPhira ディレクトリにクローンし、uv をインストール済みであることを前提とします。以下のコマンドを順に実行してください:
# バックエンドディレクトリに移動
cd HSNPhira/backend
# 依存関係をインストール
uv sync
# データベースを初期化(初回サーバー実行前のみ)
uv run flask seed_db
# 実行
uv run flask run --debug --host=0.0.0.0 --port=5000本番環境
準備中。
API ドキュメント
ユーザー管理 API
ユーザー権限
本プロジェクトはユーザーグループによる権限管理を実装しています。各グループは permissions 属性を持ち、これはビットマスクです。主な値は以下の通りです:
| 識別子 | 値 | 説明 |
|---|---|---|
NONE | 0 | 権限なし |
ALL | 0xffffffff | すべての権限 |
IMPORT | 0x00000001 | 重要ユーザー |
USER_MANAGEMENT | 0x00000002 | ユーザー管理権限 |
GROUP_MANAGEMENT | 0x00000004 | ユーザーグループ管理権限 |
初期状態では1人のユーザーと3つのユーザーグループが作成されます:
| ユーザー名 | ユーザー ID | 所属グループ |
|---|---|---|
| root | 1 | super_admin |
| グループ名 | グループ ID | 保有権限 |
|---|---|---|
| root | 1 | ALL |
| admin | 2 | IMPORTANT、USER_MANAGEMENT |
| user | 3 | NONE |
POST /api/auth/login
説明:ユーザーログイン
リクエストデータ形式:
{
"username": /*文字列、ユーザー名*/,
"password": /*文字列、パスワード*/,
"remember": /*ブール値、ユーザーを記憶するかどうか*/
}レスポンスデータ形式:ログインユーザー情報、形式は /api/auth/me を参照。
POST /api/auth/logout
説明:ユーザーログアウト
GET /api/auth/me
説明:現在のユーザー情報を取得
レスポンスデータ形式:
{
"id": /*整数、ユーザー ID*/,
"group_id": /*整数、ユーザーが所属するグループ ID*/,
"username": /*文字列、ユーザー名*/,
"phira_id": /*整数、ユーザーに紐づけられた Phira アカウント ID*/,
"phira_username": /*文字列、ユーザーの Phira ユーザー名*/,
"phira_rks": /*浮動小数点数、ユーザーの Phira rks*/,
"phira_avatar": /*文字列、ユーザーの Phira アバターリンク*/,
"register_time": /*時刻文字列、ユーザー登録時間*/,
"last_login_time": /*時刻文字列、ユーザー最終ログイン時間*/,
"last_sync_time": /*時刻文字列、ユーザー最終 Phira アカウントデータ同期時間*/
}POST /api/auth/users
説明:ユーザー作成
リクエストデータ形式:
{
"group_id": /*整数、オプション、ユーザー所属グループ ID、デフォルト値は 3(user グループ)*/,
"username": /*文字列、ユーザー名*/,
"phira_id_or_username": /*文字列、ユーザーが紐づけようとする Phira アカウント ID(文字列形式)または Phira ユーザー名*/,
"password": /*文字列、ユーザーパスワード*/
}レスポンスデータ形式:SSE イベントストリームを返します。形式は以下のいずれかです:
event: validating data: <文字列、検証に使用する token>説明:このイベントはリクエスト直後に1回送信されます。その後ユーザーは5分以内に、紐づけようとする Phira アカウントで token を名前に持つルームを作成して検証を完了する必要があります。
event: timeout説明:タイムアウト後に送信され、その後ストリームは閉じられます。
event: success data: <JSON 形式文字列、/api/auth/me と同じ形式、新規登録ユーザー情報>説明:検証成功後に送信され、その後ストリームは閉じられます。
event: error data: <文字列、エラーメッセージ>説明:サーバーエラー発生時に送信され、その後ストリームは閉じられます。
: heartbeat説明:クライアントの生存確認用で、実際の意味はありません。ブラウザは通常これを無視します。
特別な説明:group_id フィールドが指定された場合、リクエスト元は GROUP_MANAGEMENT 権限を持っている必要があります。
GET /api/auth/users
説明:ユーザー一覧を取得
レスポンスデータ形式:
[
{ /*各項目は /api/auth/me のレスポンス形式に準拠したオブジェクト*/ }
]GET /api/auth/users/<int:id>
説明:ユーザー ID が id のユーザー情報を取得
レスポンスデータ形式:/api/auth/me のレスポンス形式に準拠したオブジェクト
PATCH /api/auth/users/<int:id>
説明:ユーザー ID が id のユーザー情報を変更
リクエストデータ形式:
{
"current_password": /*文字列、リクエスト元アカウントの現在のパスワード*/,
"group_id": /*整数、オプション、ユーザー所属グループ ID、デフォルト値は 3(user グループ)*/,
"username": /*文字列、オプション、ユーザー名*/,
"phira_id": /*整数、オプション、ユーザーに紐づけられた Phira アカウント ID*/,
"password": /*文字列、オプション、ユーザーパスワード*/
}レスポンスデータ形式:変更後のユーザー情報、形式は /api/auth/me を参照。
DELETE /api/auth/users/<int:id>
説明:ユーザー ID が id のユーザーを削除
レスポンスデータ形式:
{
"message": "success"
}GET /api/auth/groups
説明:ユーザーグループ一覧を取得
レスポンスデータ形式:
[
{
"id": /*整数、ユーザーグループ ID*/,
"name": /*文字列、ユーザーグループ名*/,
"permissions": /*整数、ユーザーグループのビットマスク値*/
},
/*各項目は上記形式に準拠したオブジェクト*/
]POST /api/auth/groups
説明:ユーザーグループを作成
リクエストデータ形式:
{
"name": /*文字列、ユーザーグループ名*/,
"permissions": /*整数、ユーザーグループ権限*/
}特別な説明:GROUP_MANAGEMENT 権限が必要です。
GET /api/auth/groups/<int:id>
説明:グループ ID が id のユーザーグループ情報を取得
レスポンスデータ形式:/api/auth/groups の各項目と同じ形式のオブジェクト
PATCH /api/auth/groups/<int:id>
説明:グループ ID が id のユーザーグループ情報を変更
リクエストデータ形式:
{
"current_password": /*文字列、リクエスト元ユーザーの現在のパスワード*/,
"name": /*文字列、ユーザーグループ名*/,
"permissions": /*整数、ユーザーグループ権限*/
}レスポンスデータ形式:変更後のグループ情報、形式は /api/auth/groups の各項目を参照。
DELETE /api/auth/groups/<int:id>
説明:グループ ID が id のユーザーグループを削除
レスポンスデータ形式:
{
"message": "success"
}GET /api/auth/visited
説明:これまでサーバーを利用したことのある Phira ユーザー一覧を取得
レスポンスデータ形式:
[
{
"phira_id": /*整数、ユーザーの Phira ID*/
},
/*各項目は上記形式に準拠したオブジェクト*/
]GET /api/auth/visited/count
説明:これまでサーバーを利用したことのある Phira ユーザー数を取得
レスポンスデータ形式:
/*整数、ユーザー数を表す*/ルーム管理 API
GET /api/rooms/info
説明:ルーム一覧を取得
レスポンスデータ形式:
[
{
"name": /*文字列、ルーム名*/,
"data": { // ルームデータ
"host": /*整数、ルームホストの Phira ID*/,
"users": /*リスト、ルーム内全ユーザーの Phira ID*/,
"lock": /*ブール値、ルームがロックされているか*/,
"cycle": /*ブール値、ルームがサイクルモードか*/,
"chart": /*整数または null、ルームで現在選択中の譜面 ID*/,
"state": /*文字列、SELECTING_CHART または WAITING_FOR_READY または PLAYING*/,
"playing_users": /*リスト、現在プレイ中のユーザー ID*/,
"rounds": [ // ルームで行われた全ラウンドの情報
{
"chart": /*整数、該当ラウンドの譜面 ID*/,
"records": [ // 該当ラウンドのプレイヤー成績情報
{
"id": /*整数、レコード ID*/,
"player": /*整数、プレイヤー ID*/,
"score": /*整数、スコア*/,
"perfect": /*整数、Perfect 数*/,
"good": /*整数、Good 数*/,
"bad": /*整数、Bad 数*/,
"miss": /*整数、Miss 数*/,
"max_combo": /*整数、最大コンボ数*/,
"accuracy": /*浮動小数点数、精度*/,
"full_combo": /*ブール値、フルコンボかどうか*/,
"std": /*浮動小数点数、無瑕度*/,
"std_score": /*浮動小数点数、無瑕度スコア*/
},
/*各項目は上記形式に準拠したオブジェクト*/
]
},
/*各項目は上記形式に準拠したオブジェクト*/
],
}
},
/*各項目は上記形式に準拠したオブジェクト*/
]GET /api/rooms/info/<string:name>
説明:ルーム名が name のルーム情報を取得
レスポンスデータ形式:/api/rooms/info の各項目と同じ形式のオブジェクト
GET /api/rooms/user/<int:user_id>
説明:ユーザー ID が user_id のユーザーが所属するルーム情報を取得
レスポンスデータ形式:/api/rooms/info/<string:name> のレスポンス形式に準拠したオブジェクト
GET /api/rooms/listen
説明:ルーム情報の更新を監視
レスポンスデータ形式:SSE イベントストリーム。各イベントの形式は以下の通り:
event: /*文字列、イベントタイプ*/
data: /*文字列、JSON オブジェクトとしてパース可能*/特別な説明:このインターフェースは Server-Sent Events(SSE)プロトコルを使用します。クライアントは SSE をサポートしている必要があります。イベントタイプは以下の通り:
| イベントタイプ | データ形式 | 説明 |
|---|---|---|
create_room | {"room": /*文字列、ルーム名*/, "data": /*ルームデータ、形式は上記参照*/} | 新規ルーム |
update_room | {"room": /*文字列、ルーム名*/, "data": /*部分的なルームデータ*/} | ルームデータ更新 |
join_room | {"room": /*文字列、ルーム名*/, "user": /*整数、ユーザーの Phira ID*/} | ユーザーがルームに参加 |
leave_room | {"room": /*文字列、ルーム名*/, "user": /*整数、ユーザーの Phira ID*/} | ユーザーがルームから退出 |
player_score | {"room": /*文字列、ルーム名*/, "record": /*レコードデータ、形式は上記参照*/} | プレイヤーがゲームを完了 |
start_round | {"room": /*文字列、ルーム名*/} | ルームが新ラウンドを開始 |