From 9185367fcd7d95af89fac36dd892d8b064dbd94f Mon Sep 17 00:00:00 2001 From: nsfisis Date: Sat, 14 Feb 2026 20:32:47 +0900 Subject: feat(openapi): generate OpenAPI specs from TypeSpec sources Migrate hand-written OpenAPI YAML to TypeSpec (.tsp) source files. TypeSpec compiles to OpenAPI 3.0 YAML, enabling type-safe API definitions. - Add typespec/ directory with api-server and fortee definitions - Integrate TypeSpec build into `just gen` and `just build` pipelines - Update backend handler code to match new generated type names (inlined error responses, separate GameType/ProblemLanguage enums) - Regenerate frontend TypeScript types from new OpenAPI output Co-Authored-By: Claude Opus 4.6 --- typespec/api-server/models.tsp | 119 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 119 insertions(+) create mode 100644 typespec/api-server/models.tsp (limited to 'typespec/api-server/models.tsp') diff --git a/typespec/api-server/models.tsp b/typespec/api-server/models.tsp new file mode 100644 index 0000000..47519be --- /dev/null +++ b/typespec/api-server/models.tsp @@ -0,0 +1,119 @@ +using TypeSpec.Http; +using TypeSpec.OpenAPI; + +namespace AlbatrossApi; + +// ---------- Error ---------- + +model Error { + message: string; +} + +// ---------- Error Responses ---------- + +@error +model UnauthorizedError { + @statusCode statusCode: 401; + @body body: Error; +} + +@error +model ForbiddenError { + @statusCode statusCode: 403; + @body body: Error; +} + +@error +model NotFoundError { + @statusCode statusCode: 404; + @body body: Error; +} + +// ---------- Enums ---------- + +enum GameType { + `1v1`, + multiplayer, +} + +enum ProblemLanguage { + php, + swift, +} + +enum ExecutionStatus { + none, + running, + success, + wrong_answer, + timeout, + compile_error, + runtime_error, + internal_error, +} + +// ---------- Models ---------- + +model User { + user_id: integer; + username: string; + display_name: string; + icon_path?: string; + is_admin: boolean; + label: string | null; +} + +model Problem { + problem_id: integer; + title: string; + description: string; + language: ProblemLanguage; + sample_code: string; +} + +model Game { + game_id: integer; + game_type: GameType; + is_public: boolean; + display_name: string; + duration_seconds: integer; + + @extension("x-go-type", "int64") + started_at?: integer; + + problem: Problem; + main_players: User[]; +} + +model LatestGameState { + code: string; + score: integer | null; + + @extension("x-go-type", "int64") + best_score_submitted_at: integer | null; + + status: ExecutionStatus; +} + +model RankingEntry { + player: User; + score: integer; + + @extension("x-go-type", "int64") + submitted_at: integer; + + code: string | null; +} + +model Tournament { + matches: TournamentMatch[]; +} + +model TournamentMatch { + game_id: integer; + player1?: User; + player2?: User; + player1_score?: integer; + player2_score?: integer; + winner?: integer; +} -- cgit v1.3.1