From d014a94ea41c2de29763588386c73277eb23dec7 Mon Sep 17 00:00:00 2001 From: maulanasdqn Date: Fri, 3 Apr 2026 02:37:06 +0700 Subject: [PATCH] feat: add response examples to all hackathon and QR swagger endpoints Each endpoint now shows a realistic JSON example (data wrapper + version) so developers can see the exact response shape without calling the API. Co-Authored-By: Claude Sonnet 4.6 --- .../campaigns/infrastructure/http/handlers.rs | 54 +++++- .../qr/users/infrastructure/http/handlers.rs | 70 ++++++- .../src/admin/infrastructure/http/handlers.rs | 104 ++++++++++- .../infrastructure/http/handlers.rs | 19 +- .../src/chat/infrastructure/http/handlers.rs | 48 ++++- .../infrastructure/http/handlers.rs | 38 +++- .../infrastructure/http/handlers.rs | 60 +++++- .../storage/infrastructure/http/handlers.rs | 36 +++- .../infrastructure/http/handlers.rs | 129 ++++++++++++- .../src/teams/infrastructure/http/handlers.rs | 173 ++++++++++++++++-- .../src/users/infrastructure/http/handlers.rs | 72 +++++++- .../winners/infrastructure/http/handlers.rs | 25 ++- 12 files changed, 766 insertions(+), 62 deletions(-) diff --git a/imphnen-cms/src/qr/campaigns/infrastructure/http/handlers.rs b/imphnen-cms/src/qr/campaigns/infrastructure/http/handlers.rs index 52912e2..1fc37eb 100644 --- a/imphnen-cms/src/qr/campaigns/infrastructure/http/handlers.rs +++ b/imphnen-cms/src/qr/campaigns/infrastructure/http/handlers.rs @@ -20,7 +20,20 @@ use crate::qr::{ path = "/v1/qr/campaigns", request_body = CreateCampaignRequest, responses( - (status = 201, description = "Create a QR campaign"), + (status = 201, description = "Create a QR campaign", + example = json!({ + "data": { + "id": "e5f6a7b8-c9d0-1234-efab-345678901234", + "name": "Imphnen Hackathon 2025", + "url": "https://imphnen.dev/register", + "is_active": false, + "created_by": "3fa85f64-5717-4562-b3fc-2c963f66afa6", + "expires_at": "2025-12-31T23:59:59Z", + "created_at": "2025-01-01T00:00:00Z", + "updated_at": "2025-01-01T00:00:00Z" + }, + "version": "0.3.0" + })), (status = 401, description = "Unauthorized"), (status = 403, description = "Forbidden - admin only") ), @@ -47,7 +60,22 @@ pub async fn create_campaign_handler( get, path = "/v1/qr/campaigns", responses( - (status = 200, description = "Admin: list all QR campaigns"), + (status = 200, description = "Admin: list all QR campaigns", + example = json!({ + "data": [ + { + "id": "e5f6a7b8-c9d0-1234-efab-345678901234", + "name": "Imphnen Hackathon 2025", + "url": "https://imphnen.dev/register", + "is_active": true, + "created_by": "3fa85f64-5717-4562-b3fc-2c963f66afa6", + "expires_at": "2025-12-31T23:59:59Z", + "created_at": "2025-01-01T00:00:00Z", + "updated_at": "2025-01-05T00:00:00Z" + } + ], + "version": "0.3.0" + })), (status = 401, description = "Unauthorized"), (status = 403, description = "Forbidden - admin only") ), @@ -72,7 +100,20 @@ pub async fn list_campaigns_handler( path = "/v1/qr/campaigns/{id}/activate", params(("id" = Uuid, Path, description = "Campaign ID")), responses( - (status = 200, description = "Admin: activate a campaign"), + (status = 200, description = "Admin: activate a campaign (deactivates all others)", + example = json!({ + "data": { + "id": "e5f6a7b8-c9d0-1234-efab-345678901234", + "name": "Imphnen Hackathon 2025", + "url": "https://imphnen.dev/register", + "is_active": true, + "created_by": "3fa85f64-5717-4562-b3fc-2c963f66afa6", + "expires_at": "2025-12-31T23:59:59Z", + "created_at": "2025-01-01T00:00:00Z", + "updated_at": "2025-01-05T10:00:00Z" + }, + "version": "0.3.0" + })), (status = 401, description = "Unauthorized"), (status = 403, description = "Forbidden - admin only") ), @@ -98,7 +139,8 @@ pub async fn activate_campaign_handler( path = "/v1/qr/campaigns/{id}", params(("id" = Uuid, Path, description = "Campaign ID")), responses( - (status = 200, description = "Admin: delete a campaign"), + (status = 200, description = "Admin: delete a campaign", + example = json!({"message": "Campaign deleted successfully", "version": "0.3.0"})), (status = 401, description = "Unauthorized"), (status = 403, description = "Forbidden - admin only") ), @@ -126,7 +168,9 @@ pub async fn delete_campaign_handler( post, path = "/v1/qr/campaigns/process-image", responses( - (status = 200, description = "Process QR code image (multipart/form-data with 'file' field)"), + (status = 200, description = "Process QR code image — send multipart/form-data with field 'file'. Returns PNG image bytes.", + content_type = "image/png"), + (status = 400, description = "No file provided or invalid image"), (status = 401, description = "Unauthorized") ), tag = "QR - Campaigns", diff --git a/imphnen-cms/src/qr/users/infrastructure/http/handlers.rs b/imphnen-cms/src/qr/users/infrastructure/http/handlers.rs index 59be574..3ad9e9d 100644 --- a/imphnen-cms/src/qr/users/infrastructure/http/handlers.rs +++ b/imphnen-cms/src/qr/users/infrastructure/http/handlers.rs @@ -19,7 +19,19 @@ use crate::qr::{ get, path = "/v1/qr/users/me", responses( - (status = 200, description = "Get my QR user profile"), + (status = 200, description = "Get my QR user profile", + example = json!({ + "data": { + "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", + "email": "user@example.com", + "name": "Budi Santoso", + "role": "user", + "provider": "google", + "created_at": "2025-01-01T00:00:00Z", + "updated_at": "2025-01-01T00:00:00Z" + }, + "version": "0.3.0" + })), (status = 401, description = "Unauthorized") ), tag = "QR - Users", @@ -38,7 +50,19 @@ pub async fn get_me_handler( path = "/v1/qr/users/me", request_body = UpdateProfileRequest, responses( - (status = 200, description = "Update my QR user profile"), + (status = 200, description = "Update my QR user profile", + example = json!({ + "data": { + "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", + "email": "updated@example.com", + "name": "Budi Santoso Updated", + "role": "user", + "provider": "google", + "created_at": "2025-01-01T00:00:00Z", + "updated_at": "2025-01-15T00:00:00Z" + }, + "version": "0.3.0" + })), (status = 401, description = "Unauthorized") ), tag = "QR - Users", @@ -61,7 +85,30 @@ pub async fn update_me_handler( get, path = "/v1/qr/users", responses( - (status = 200, description = "Admin: list all QR users"), + (status = 200, description = "Admin: list all QR users", + example = json!({ + "data": [ + { + "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", + "email": "user@example.com", + "name": "Budi Santoso", + "role": "user", + "provider": "google", + "created_at": "2025-01-01T00:00:00Z", + "updated_at": "2025-01-01T00:00:00Z" + }, + { + "id": "4gb96g75-6828-5673-c4gd-3d074g77bgb7", + "email": "admin@example.com", + "name": "Admin User", + "role": "admin", + "provider": "google", + "created_at": "2024-12-01T00:00:00Z", + "updated_at": "2024-12-01T00:00:00Z" + } + ], + "version": "0.3.0" + })), (status = 401, description = "Unauthorized"), (status = 403, description = "Forbidden - admin only") ), @@ -87,7 +134,19 @@ pub async fn list_users_handler( params(("id" = Uuid, Path, description = "User ID")), request_body = UpdateRoleRequest, responses( - (status = 200, description = "Admin: update user role"), + (status = 200, description = "Admin: update user role", + example = json!({ + "data": { + "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", + "email": "user@example.com", + "name": "Budi Santoso", + "role": "admin", + "provider": "google", + "created_at": "2025-01-01T00:00:00Z", + "updated_at": "2025-01-20T00:00:00Z" + }, + "version": "0.3.0" + })), (status = 401, description = "Unauthorized"), (status = 403, description = "Forbidden - admin only") ), @@ -114,7 +173,8 @@ pub async fn update_role_handler( path = "/v1/qr/users/{id}", params(("id" = Uuid, Path, description = "User ID")), responses( - (status = 200, description = "Admin: delete QR user"), + (status = 200, description = "Admin: delete QR user", + example = json!({"message": "User deleted successfully", "version": "0.3.0"})), (status = 401, description = "Unauthorized"), (status = 403, description = "Forbidden - admin only") ), diff --git a/imphnen-hackathon/src/admin/infrastructure/http/handlers.rs b/imphnen-hackathon/src/admin/infrastructure/http/handlers.rs index bc6ed32..d0a9d38 100644 --- a/imphnen-hackathon/src/admin/infrastructure/http/handlers.rs +++ b/imphnen-hackathon/src/admin/infrastructure/http/handlers.rs @@ -17,7 +17,26 @@ use uuid::Uuid; path = "/v1/hackathon/admin/users", params(PageQuery), responses( - (status = 200, description = "Admin: list all users"), + (status = 200, description = "Admin: list all users", + example = json!({ + "data": { + "data": [ + { + "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", + "email": "user@example.com", + "fullname": "Budi Santoso", + "avatar": null, + "is_active": true, + "is_admin": false, + "created_at": "2025-01-01T00:00:00Z" + } + ], + "total": 42, + "page": 1, + "limit": 20 + }, + "version": "0.3.0" + })), (status = 401, description = "Unauthorized"), (status = 403, description = "Forbidden - admin only") ), @@ -45,7 +64,19 @@ pub async fn admin_list_users( path = "/v1/hackathon/admin/users/{user_id}", params(("user_id" = Uuid, Path, description = "User ID")), responses( - (status = 200, description = "Admin: get user by ID"), + (status = 200, description = "Admin: get user by ID", + example = json!({ + "data": { + "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", + "email": "user@example.com", + "fullname": "Budi Santoso", + "avatar": null, + "is_active": true, + "is_admin": false, + "created_at": "2025-01-01T00:00:00Z" + }, + "version": "0.3.0" + })), (status = 403, description = "Forbidden - admin only"), (status = 404, description = "User not found") ), @@ -66,7 +97,8 @@ pub async fn admin_get_user( params(("user_id" = Uuid, Path, description = "User ID")), request_body = SetAdminRequest, responses( - (status = 200, description = "Admin: set user admin status"), + (status = 200, description = "Admin: set user admin status", + example = json!({"message": "User admin status updated", "version": "0.3.0"})), (status = 403, description = "Forbidden - admin only") ), tag = "Hackathon - Admin", @@ -86,7 +118,8 @@ pub async fn admin_set_admin( path = "/v1/hackathon/admin/users/{user_id}", params(("user_id" = Uuid, Path, description = "User ID")), responses( - (status = 200, description = "Admin: delete user"), + (status = 200, description = "Admin: delete user", + example = json!({"message": "User deleted", "version": "0.3.0"})), (status = 403, description = "Forbidden - admin only") ), tag = "Hackathon - Admin", @@ -105,7 +138,25 @@ pub async fn admin_delete_user( path = "/v1/hackathon/admin/teams", params(PageQuery), responses( - (status = 200, description = "Admin: list all teams"), + (status = 200, description = "Admin: list all teams", + example = json!({ + "data": { + "data": [ + { + "id": "7c3a1d2e-8f4b-4c5a-9d6e-1f2a3b4c5d6e", + "name": "Rust Enjoyers", + "city": "Jakarta", + "visibility": "public", + "leader_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", + "created_at": "2025-01-01T00:00:00Z" + } + ], + "total": 15, + "page": 1, + "limit": 20 + }, + "version": "0.3.0" + })), (status = 403, description = "Forbidden - admin only") ), tag = "Hackathon - Admin", @@ -132,7 +183,8 @@ pub async fn admin_list_teams( path = "/v1/hackathon/admin/teams/{team_id}", params(("team_id" = Uuid, Path, description = "Team ID")), responses( - (status = 200, description = "Admin: delete team"), + (status = 200, description = "Admin: delete team", + example = json!({"message": "Team deleted", "version": "0.3.0"})), (status = 403, description = "Forbidden - admin only") ), tag = "Hackathon - Admin", @@ -151,7 +203,25 @@ pub async fn admin_delete_team( path = "/v1/hackathon/admin/submissions", params(PageQuery), responses( - (status = 200, description = "Admin: list all submissions"), + (status = 200, description = "Admin: list all submissions", + example = json!({ + "data": { + "data": [ + { + "id": "c3d4e5f6-a7b8-9012-cdef-123456789012", + "team_id": "7c3a1d2e-8f4b-4c5a-9d6e-1f2a3b4c5d6e", + "project_name": "EcoTrack - Sustainability Monitor", + "status": "submitted", + "submitted_at": "2025-01-20T12:00:00Z", + "created_at": "2025-01-05T00:00:00Z" + } + ], + "total": 8, + "page": 1, + "limit": 20 + }, + "version": "0.3.0" + })), (status = 403, description = "Forbidden - admin only") ), tag = "Hackathon - Admin", @@ -178,7 +248,8 @@ pub async fn admin_list_submissions( path = "/v1/hackathon/admin/winners", request_body = SetWinnerRequest, responses( - (status = 200, description = "Admin: set winner"), + (status = 200, description = "Admin: set winner", + example = json!({"message": "Winner set", "version": "0.3.0"})), (status = 403, description = "Forbidden - admin only") ), tag = "Hackathon - Admin", @@ -199,7 +270,8 @@ pub async fn admin_set_winner( path = "/v1/hackathon/admin/winners/{team_id}", params(("team_id" = Uuid, Path, description = "Team ID")), responses( - (status = 200, description = "Admin: remove winner"), + (status = 200, description = "Admin: remove winner", + example = json!({"message": "Winner removed", "version": "0.3.0"})), (status = 403, description = "Forbidden - admin only") ), tag = "Hackathon - Admin", @@ -217,7 +289,19 @@ pub async fn admin_remove_winner( get, path = "/v1/hackathon/admin/winners", responses( - (status = 200, description = "Admin: list winners"), + (status = 200, description = "Admin: list winners", + example = json!({ + "data": [ + { + "id": "d4e5f6a7-b8c9-0123-defa-234567890123", + "team_id": "7c3a1d2e-8f4b-4c5a-9d6e-1f2a3b4c5d6e", + "rank": 1, + "prize": "Rp 10.000.000", + "created_at": "2025-02-01T10:00:00Z" + } + ], + "version": "0.3.0" + })), (status = 403, description = "Forbidden - admin only") ), tag = "Hackathon - Admin", diff --git a/imphnen-hackathon/src/certificates/infrastructure/http/handlers.rs b/imphnen-hackathon/src/certificates/infrastructure/http/handlers.rs index fd8c8de..4f1da74 100644 --- a/imphnen-hackathon/src/certificates/infrastructure/http/handlers.rs +++ b/imphnen-hackathon/src/certificates/infrastructure/http/handlers.rs @@ -10,7 +10,24 @@ use uuid::Uuid; path = "/v1/hackathon/certificates/{user_id}", params(("user_id" = Uuid, Path, description = "User ID")), responses( - (status = 200, description = "Get certificate for user"), + (status = 200, description = "Get certificate for user", + body = inline(CertificateResponse), + example = json!({ + "data": { + "user_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", + "fullname": "Budi Santoso", + "email": "budi@example.com", + "avatar": "https://cdn.example.com/avatar.png", + "team_id": "7c3a1d2e-8f4b-4c5a-9d6e-1f2a3b4c5d6e", + "team_name": "Rust Enjoyers", + "is_leader": true, + "project_name": "EcoTrack - Sustainability Monitor", + "submission_status": "confirmed", + "winner_rank": 1, + "winner_prize": "Rp 10.000.000" + }, + "version": "0.3.0" + })), (status = 404, description = "Certificate not found") ), tag = "Hackathon - Certificates" diff --git a/imphnen-hackathon/src/chat/infrastructure/http/handlers.rs b/imphnen-hackathon/src/chat/infrastructure/http/handlers.rs index 48b6836..c5750f3 100644 --- a/imphnen-hackathon/src/chat/infrastructure/http/handlers.rs +++ b/imphnen-hackathon/src/chat/infrastructure/http/handlers.rs @@ -14,7 +14,32 @@ use uuid::Uuid; path = "/v1/hackathon/chat/teams/{team_id}", params(("team_id" = Uuid, Path, description = "Team ID")), responses( - (status = 200, description = "Get team chat messages"), + (status = 200, description = "Get team chat messages", + example = json!({ + "data": [ + { + "id": "f6a7b8c9-d0e1-2345-fab0-456789012345", + "team_id": "7c3a1d2e-8f4b-4c5a-9d6e-1f2a3b4c5d6e", + "user_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", + "user_fullname": "Budi Santoso", + "user_avatar": null, + "message": "Hey team, let's finalize the project name!", + "created_at": "2025-01-15T09:00:00Z", + "updated_at": "2025-01-15T09:00:00Z" + }, + { + "id": "a7b8c9d0-e1f2-3456-abc0-567890123456", + "team_id": "7c3a1d2e-8f4b-4c5a-9d6e-1f2a3b4c5d6e", + "user_id": "4gb96g75-6828-5673-c4gd-3d074g77bgb7", + "user_fullname": "Dewi Rahayu", + "user_avatar": "https://cdn.example.com/dewi.png", + "message": "I suggest EcoTrack!", + "created_at": "2025-01-15T09:05:00Z", + "updated_at": "2025-01-15T09:05:00Z" + } + ], + "version": "0.3.0" + })), (status = 401, description = "Unauthorized") ), tag = "Hackathon - Chat", @@ -37,7 +62,21 @@ pub async fn get_team_messages_handler( params(("team_id" = Uuid, Path, description = "Team ID")), request_body = SendMessageRequest, responses( - (status = 200, description = "Send a message to team chat"), + (status = 200, description = "Send a message to team chat", + body = inline(MessageResponse), + example = json!({ + "data": { + "id": "b8c9d0e1-f2a3-4567-bcd1-678901234567", + "team_id": "7c3a1d2e-8f4b-4c5a-9d6e-1f2a3b4c5d6e", + "user_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", + "user_fullname": "Budi Santoso", + "user_avatar": null, + "message": "Great, let's go with EcoTrack!", + "created_at": "2025-01-15T09:10:00Z", + "updated_at": "2025-01-15T09:10:00Z" + }, + "version": "0.3.0" + })), (status = 401, description = "Unauthorized") ), tag = "Hackathon - Chat", @@ -60,9 +99,10 @@ pub async fn send_message_handler( path = "/v1/hackathon/chat/messages/{message_id}", params(("message_id" = Uuid, Path, description = "Message ID")), responses( - (status = 200, description = "Delete a chat message"), + (status = 200, description = "Delete a chat message", + example = json!({"message": "Message deleted", "version": "0.3.0"})), (status = 401, description = "Unauthorized"), - (status = 403, description = "Forbidden") + (status = 403, description = "Forbidden - not message owner") ), tag = "Hackathon - Chat", security(("bearer_auth" = [])) diff --git a/imphnen-hackathon/src/invitations/infrastructure/http/handlers.rs b/imphnen-hackathon/src/invitations/infrastructure/http/handlers.rs index d3ad89f..fe1640c 100644 --- a/imphnen-hackathon/src/invitations/infrastructure/http/handlers.rs +++ b/imphnen-hackathon/src/invitations/infrastructure/http/handlers.rs @@ -13,7 +13,22 @@ use uuid::Uuid; get, path = "/v1/hackathon/invitations/my", responses( - (status = 200, description = "Get my invitations"), + (status = 200, description = "Get my invitations", + example = json!({ + "data": [ + { + "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", + "team_id": "7c3a1d2e-8f4b-4c5a-9d6e-1f2a3b4c5d6e", + "team_name": "Rust Enjoyers", + "inviter_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", + "inviter_fullname": "Budi Santoso", + "invitee_email": "newmember@example.com", + "status": "pending", + "created_at": "2025-01-10T00:00:00Z" + } + ], + "version": "0.3.0" + })), (status = 401, description = "Unauthorized") ), tag = "Hackathon - Invitations", @@ -35,7 +50,8 @@ pub async fn get_my_invitations_handler( params(("invitation_id" = Uuid, Path, description = "Invitation ID")), request_body = RespondToInvitationRequest, responses( - (status = 200, description = "Respond to invitation"), + (status = 200, description = "Respond to invitation", + example = json!({"message": "Invitation accepted", "version": "0.3.0"})), (status = 401, description = "Unauthorized"), (status = 404, description = "Invitation not found") ), @@ -65,9 +81,23 @@ pub async fn respond_to_invitation_handler( params(("team_id" = Uuid, Path, description = "Team ID")), request_body = CreateInvitationRequest, responses( - (status = 200, description = "Invite a member to team"), + (status = 200, description = "Invite a member to team", + body = inline(InvitationResponse), + example = json!({ + "data": { + "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", + "team_id": "7c3a1d2e-8f4b-4c5a-9d6e-1f2a3b4c5d6e", + "team_name": "Rust Enjoyers", + "inviter_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", + "inviter_fullname": "Budi Santoso", + "invitee_email": "newmember@example.com", + "status": "pending", + "created_at": "2025-01-10T00:00:00Z" + }, + "version": "0.3.0" + })), (status = 401, description = "Unauthorized"), - (status = 403, description = "Forbidden") + (status = 403, description = "Forbidden - not team leader") ), tag = "Hackathon - Invitations", security(("bearer_auth" = [])) diff --git a/imphnen-hackathon/src/join_requests/infrastructure/http/handlers.rs b/imphnen-hackathon/src/join_requests/infrastructure/http/handlers.rs index 49471ff..84f27e7 100644 --- a/imphnen-hackathon/src/join_requests/infrastructure/http/handlers.rs +++ b/imphnen-hackathon/src/join_requests/infrastructure/http/handlers.rs @@ -15,7 +15,22 @@ use uuid::Uuid; params(("team_id" = Uuid, Path, description = "Team ID")), request_body = CreateJoinRequestRequest, responses( - (status = 200, description = "Create a join request"), + (status = 200, description = "Create a join request", + body = inline(JoinRequestResponse), + example = json!({ + "data": { + "id": "b2c3d4e5-f6a7-8901-bcde-f12345678901", + "team_id": "7c3a1d2e-8f4b-4c5a-9d6e-1f2a3b4c5d6e", + "user_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", + "user_fullname": "Dewi Rahayu", + "user_email": "dewi@example.com", + "user_avatar": null, + "message": "I would love to join your team, I have experience in backend development", + "status": "pending", + "created_at": "2025-01-10T00:00:00Z" + }, + "version": "0.3.0" + })), (status = 401, description = "Unauthorized") ), tag = "Hackathon - Join Requests", @@ -37,7 +52,23 @@ pub async fn create_join_request_handler( get, path = "/v1/hackathon/join-requests/my", responses( - (status = 200, description = "Get my join requests"), + (status = 200, description = "Get my join requests", + example = json!({ + "data": [ + { + "id": "b2c3d4e5-f6a7-8901-bcde-f12345678901", + "team_id": "7c3a1d2e-8f4b-4c5a-9d6e-1f2a3b4c5d6e", + "user_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", + "user_fullname": "Dewi Rahayu", + "user_email": "dewi@example.com", + "user_avatar": null, + "message": "I would love to join your team", + "status": "pending", + "created_at": "2025-01-10T00:00:00Z" + } + ], + "version": "0.3.0" + })), (status = 401, description = "Unauthorized") ), tag = "Hackathon - Join Requests", @@ -58,9 +89,25 @@ pub async fn get_my_join_requests_handler( path = "/v1/hackathon/join-requests/teams/{team_id}/pending", params(("team_id" = Uuid, Path, description = "Team ID")), responses( - (status = 200, description = "Get pending join requests for team"), + (status = 200, description = "Get pending join requests for team", + example = json!({ + "data": [ + { + "id": "b2c3d4e5-f6a7-8901-bcde-f12345678901", + "team_id": "7c3a1d2e-8f4b-4c5a-9d6e-1f2a3b4c5d6e", + "user_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", + "user_fullname": "Dewi Rahayu", + "user_email": "dewi@example.com", + "user_avatar": null, + "message": "I would love to join your team", + "status": "pending", + "created_at": "2025-01-10T00:00:00Z" + } + ], + "version": "0.3.0" + })), (status = 401, description = "Unauthorized"), - (status = 403, description = "Forbidden") + (status = 403, description = "Forbidden - not team leader") ), tag = "Hackathon - Join Requests", security(("bearer_auth" = [])) @@ -84,9 +131,10 @@ pub async fn get_team_join_requests_handler( params(("request_id" = Uuid, Path, description = "Join request ID")), request_body = RespondToJoinRequestRequest, responses( - (status = 200, description = "Respond to join request"), + (status = 200, description = "Respond to join request", + example = json!({"message": "Join request accepted", "version": "0.3.0"})), (status = 401, description = "Unauthorized"), - (status = 403, description = "Forbidden") + (status = 403, description = "Forbidden - not team leader") ), tag = "Hackathon - Join Requests", security(("bearer_auth" = [])) diff --git a/imphnen-hackathon/src/storage/infrastructure/http/handlers.rs b/imphnen-hackathon/src/storage/infrastructure/http/handlers.rs index 13fa616..9b48ad5 100644 --- a/imphnen-hackathon/src/storage/infrastructure/http/handlers.rs +++ b/imphnen-hackathon/src/storage/infrastructure/http/handlers.rs @@ -10,7 +10,14 @@ use std::sync::Arc; path = "/v1/hackathon/upload", request_body = UploadRequest, responses( - (status = 200, description = "Upload a file"), + (status = 200, description = "Upload a file (base64 encoded)", + body = inline(UploadResponse), + example = json!({ + "data": { + "url": "https://minio.example.com/uploads/3fa85f64-5717-4562-b3fc-2c963f66afa6/document.pdf" + }, + "version": "0.3.0" + })), (status = 401, description = "Unauthorized") ), tag = "Hackathon - Storage", @@ -38,7 +45,14 @@ pub async fn upload_file_handler( path = "/v1/hackathon/upload/avatar", request_body = UploadRequest, responses( - (status = 200, description = "Upload avatar image"), + (status = 200, description = "Upload avatar image (base64 encoded)", + body = inline(UploadResponse), + example = json!({ + "data": { + "url": "https://minio.example.com/avatars/3fa85f64-5717-4562-b3fc-2c963f66afa6/avatar.png" + }, + "version": "0.3.0" + })), (status = 401, description = "Unauthorized") ), tag = "Hackathon - Storage", @@ -66,7 +80,14 @@ pub async fn upload_avatar_handler( path = "/v1/hackathon/upload/team", request_body = UploadRequest, responses( - (status = 200, description = "Upload team image"), + (status = 200, description = "Upload team logo or banner (base64 encoded)", + body = inline(UploadResponse), + example = json!({ + "data": { + "url": "https://minio.example.com/teams/3fa85f64-5717-4562-b3fc-2c963f66afa6/logo.png" + }, + "version": "0.3.0" + })), (status = 401, description = "Unauthorized") ), tag = "Hackathon - Storage", @@ -94,7 +115,14 @@ pub async fn upload_team_handler( path = "/v1/hackathon/upload/submission", request_body = UploadRequest, responses( - (status = 200, description = "Upload submission file"), + (status = 200, description = "Upload submission screenshot (base64 encoded)", + body = inline(UploadResponse), + example = json!({ + "data": { + "url": "https://minio.example.com/submissions/3fa85f64-5717-4562-b3fc-2c963f66afa6/screenshot.png" + }, + "version": "0.3.0" + })), (status = 401, description = "Unauthorized") ), tag = "Hackathon - Storage", diff --git a/imphnen-hackathon/src/submissions/infrastructure/http/handlers.rs b/imphnen-hackathon/src/submissions/infrastructure/http/handlers.rs index 536ded1..706a2dd 100644 --- a/imphnen-hackathon/src/submissions/infrastructure/http/handlers.rs +++ b/imphnen-hackathon/src/submissions/infrastructure/http/handlers.rs @@ -6,13 +6,33 @@ use imphnen_utils::{errors::AppError, response_format::ApiSuccess}; use std::sync::Arc; use uuid::Uuid; + #[utoipa::path( post, path = "/v1/hackathon/submissions/teams/{team_id}", params(("team_id" = Uuid, Path, description = "Team ID")), request_body = CreateSubmissionRequest, responses( - (status = 200, description = "Create submission for team"), + (status = 200, description = "Create submission for team", + body = inline(SubmissionResponse), + example = json!({ + "data": { + "id": "c3d4e5f6-a7b8-9012-cdef-123456789012", + "team_id": "7c3a1d2e-8f4b-4c5a-9d6e-1f2a3b4c5d6e", + "project_name": "EcoTrack - Sustainability Monitor", + "description": "A real-time environmental monitoring platform", + "repository_url": "https://github.com/team/ecotrack", + "demo_url": "https://ecotrack.example.com", + "presentation_url": null, + "screenshots": [], + "status": "draft", + "submitted_at": null, + "submitted_by": "3fa85f64-5717-4562-b3fc-2c963f66afa6", + "created_at": "2025-01-05T00:00:00Z", + "updated_at": "2025-01-05T00:00:00Z" + }, + "version": "0.3.0" + })), (status = 401, description = "Unauthorized") ), tag = "Hackathon - Submissions", @@ -35,9 +55,28 @@ pub async fn create_submission_handler( path = "/v1/hackathon/submissions/teams/{team_id}", params(("team_id" = Uuid, Path, description = "Team ID")), responses( - (status = 200, description = "Get team submission"), + (status = 200, description = "Get team submission", + body = inline(SubmissionResponse), + example = json!({ + "data": { + "id": "c3d4e5f6-a7b8-9012-cdef-123456789012", + "team_id": "7c3a1d2e-8f4b-4c5a-9d6e-1f2a3b4c5d6e", + "project_name": "EcoTrack - Sustainability Monitor", + "description": "A real-time environmental monitoring platform", + "repository_url": "https://github.com/team/ecotrack", + "demo_url": "https://ecotrack.example.com", + "presentation_url": "https://slides.example.com/ecotrack", + "screenshots": ["https://cdn.example.com/ss1.png"], + "status": "submitted", + "submitted_at": "2025-01-20T12:00:00Z", + "submitted_by": "3fa85f64-5717-4562-b3fc-2c963f66afa6", + "created_at": "2025-01-05T00:00:00Z", + "updated_at": "2025-01-20T12:00:00Z" + }, + "version": "0.3.0" + })), (status = 401, description = "Unauthorized"), - (status = 404, description = "Not found") + (status = 404, description = "Submission not found") ), tag = "Hackathon - Submissions", security(("bearer_auth" = [])) @@ -57,7 +96,26 @@ pub async fn get_team_submission_handler( params(("submission_id" = Uuid, Path, description = "Submission ID")), request_body = UpdateSubmissionRequest, responses( - (status = 200, description = "Update submission"), + (status = 200, description = "Update submission", + body = inline(SubmissionResponse), + example = json!({ + "data": { + "id": "c3d4e5f6-a7b8-9012-cdef-123456789012", + "team_id": "7c3a1d2e-8f4b-4c5a-9d6e-1f2a3b4c5d6e", + "project_name": "EcoTrack v2 - Advanced Sustainability Monitor", + "description": "Updated description with more features", + "repository_url": "https://github.com/team/ecotrack", + "demo_url": "https://ecotrack-v2.example.com", + "presentation_url": "https://slides.example.com/ecotrack-v2", + "screenshots": ["https://cdn.example.com/ss1.png", "https://cdn.example.com/ss2.png"], + "status": "draft", + "submitted_at": null, + "submitted_by": "3fa85f64-5717-4562-b3fc-2c963f66afa6", + "created_at": "2025-01-05T00:00:00Z", + "updated_at": "2025-01-15T00:00:00Z" + }, + "version": "0.3.0" + })), (status = 401, description = "Unauthorized") ), tag = "Hackathon - Submissions", @@ -80,7 +138,26 @@ pub async fn update_submission_handler( path = "/v1/hackathon/submissions/{submission_id}/submit", params(("submission_id" = Uuid, Path, description = "Submission ID")), responses( - (status = 200, description = "Submit project"), + (status = 200, description = "Submit project for review", + body = inline(SubmissionResponse), + example = json!({ + "data": { + "id": "c3d4e5f6-a7b8-9012-cdef-123456789012", + "team_id": "7c3a1d2e-8f4b-4c5a-9d6e-1f2a3b4c5d6e", + "project_name": "EcoTrack - Sustainability Monitor", + "description": "A real-time environmental monitoring platform", + "repository_url": "https://github.com/team/ecotrack", + "demo_url": "https://ecotrack.example.com", + "presentation_url": "https://slides.example.com/ecotrack", + "screenshots": ["https://cdn.example.com/ss1.png"], + "status": "submitted", + "submitted_at": "2025-01-20T12:00:00Z", + "submitted_by": "3fa85f64-5717-4562-b3fc-2c963f66afa6", + "created_at": "2025-01-05T00:00:00Z", + "updated_at": "2025-01-20T12:00:00Z" + }, + "version": "0.3.0" + })), (status = 401, description = "Unauthorized") ), tag = "Hackathon - Submissions", @@ -100,7 +177,26 @@ pub async fn submit_project_handler( path = "/v1/hackathon/submissions/{submission_id}/confirm", params(("submission_id" = Uuid, Path, description = "Submission ID")), responses( - (status = 200, description = "Confirm submission"), + (status = 200, description = "Confirm submission (admin)", + body = inline(SubmissionResponse), + example = json!({ + "data": { + "id": "c3d4e5f6-a7b8-9012-cdef-123456789012", + "team_id": "7c3a1d2e-8f4b-4c5a-9d6e-1f2a3b4c5d6e", + "project_name": "EcoTrack - Sustainability Monitor", + "description": "A real-time environmental monitoring platform", + "repository_url": "https://github.com/team/ecotrack", + "demo_url": "https://ecotrack.example.com", + "presentation_url": "https://slides.example.com/ecotrack", + "screenshots": ["https://cdn.example.com/ss1.png"], + "status": "confirmed", + "submitted_at": "2025-01-20T12:00:00Z", + "submitted_by": "3fa85f64-5717-4562-b3fc-2c963f66afa6", + "created_at": "2025-01-05T00:00:00Z", + "updated_at": "2025-01-21T08:00:00Z" + }, + "version": "0.3.0" + })), (status = 401, description = "Unauthorized") ), tag = "Hackathon - Submissions", @@ -122,7 +218,26 @@ pub async fn confirm_submission_handler( path = "/v1/hackathon/submissions/{submission_id}/cancel", params(("submission_id" = Uuid, Path, description = "Submission ID")), responses( - (status = 200, description = "Cancel submission"), + (status = 200, description = "Cancel submission", + body = inline(SubmissionResponse), + example = json!({ + "data": { + "id": "c3d4e5f6-a7b8-9012-cdef-123456789012", + "team_id": "7c3a1d2e-8f4b-4c5a-9d6e-1f2a3b4c5d6e", + "project_name": "EcoTrack - Sustainability Monitor", + "description": "A real-time environmental monitoring platform", + "repository_url": "https://github.com/team/ecotrack", + "demo_url": "https://ecotrack.example.com", + "presentation_url": null, + "screenshots": [], + "status": "cancelled", + "submitted_at": null, + "submitted_by": "3fa85f64-5717-4562-b3fc-2c963f66afa6", + "created_at": "2025-01-05T00:00:00Z", + "updated_at": "2025-01-22T10:00:00Z" + }, + "version": "0.3.0" + })), (status = 401, description = "Unauthorized") ), tag = "Hackathon - Submissions", diff --git a/imphnen-hackathon/src/teams/infrastructure/http/handlers.rs b/imphnen-hackathon/src/teams/infrastructure/http/handlers.rs index b359cb6..c9a9f40 100644 --- a/imphnen-hackathon/src/teams/infrastructure/http/handlers.rs +++ b/imphnen-hackathon/src/teams/infrastructure/http/handlers.rs @@ -18,7 +18,37 @@ use uuid::Uuid; path = "/v1/hackathon/teams", request_body = CreateTeamRequest, responses( - (status = 200, description = "Create a new team"), + (status = 200, description = "Create a new team", + body = inline(TeamResponse), + example = json!({ + "data": { + "id": "7c3a1d2e-8f4b-4c5a-9d6e-1f2a3b4c5d6e", + "name": "Rust Enjoyers", + "description": "A team that loves Rust", + "city": "Jakarta", + "visibility": "public", + "logo": null, + "banner": null, + "leader_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", + "leader": { + "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", + "email": "leader@example.com", + "fullname": "Budi Santoso", + "avatar": null, + "phone_number": null, + "location": "Jakarta", + "bio": null, + "skills": ["Rust"], + "is_active": true + }, + "members": [], + "member_count": 1, + "has_submission": false, + "created_at": "2025-01-01T00:00:00Z", + "updated_at": "2025-01-01T00:00:00Z" + }, + "version": "0.3.0" + })), (status = 401, description = "Unauthorized") ), tag = "Hackathon - Teams", @@ -38,7 +68,57 @@ pub async fn create_team_handler( path = "/v1/hackathon/teams/{team_id}", params(("team_id" = Uuid, Path, description = "Team ID")), responses( - (status = 200, description = "Get team by ID"), + (status = 200, description = "Get team by ID", + body = inline(TeamResponse), + example = json!({ + "data": { + "id": "7c3a1d2e-8f4b-4c5a-9d6e-1f2a3b4c5d6e", + "name": "Rust Enjoyers", + "description": "A team that loves Rust", + "city": "Jakarta", + "visibility": "public", + "logo": null, + "banner": null, + "leader_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", + "leader": { + "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", + "email": "leader@example.com", + "fullname": "Budi Santoso", + "avatar": null, + "phone_number": null, + "location": "Jakarta", + "bio": null, + "skills": ["Rust"], + "is_active": true + }, + "members": [ + { + "id": "1a2b3c4d-5e6f-7a8b-9c0d-1e2f3a4b5c6d", + "team_id": "7c3a1d2e-8f4b-4c5a-9d6e-1f2a3b4c5d6e", + "user_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", + "user": { + "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", + "email": "leader@example.com", + "fullname": "Budi Santoso", + "avatar": null, + "phone_number": null, + "location": "Jakarta", + "bio": null, + "skills": ["Rust"], + "is_active": true + }, + "role": "leader", + "status": "active", + "joined_at": "2025-01-01T00:00:00Z" + } + ], + "member_count": 1, + "has_submission": false, + "created_at": "2025-01-01T00:00:00Z", + "updated_at": "2025-01-01T00:00:00Z" + }, + "version": "0.3.0" + })), (status = 404, description = "Team not found") ), tag = "Hackathon - Teams" @@ -56,7 +136,34 @@ pub async fn get_team_handler( path = "/v1/hackathon/teams/browse", params(BrowseTeamsQuery), responses( - (status = 200, description = "Browse teams with filters") + (status = 200, description = "Browse teams with filters", + body = inline(TeamListResponse), + example = json!({ + "data": { + "data": [ + { + "id": "7c3a1d2e-8f4b-4c5a-9d6e-1f2a3b4c5d6e", + "name": "Rust Enjoyers", + "description": "A team that loves Rust", + "city": "Jakarta", + "visibility": "public", + "logo": null, + "banner": null, + "leader_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", + "leader": null, + "members": null, + "member_count": 3, + "has_submission": false, + "created_at": "2025-01-01T00:00:00Z", + "updated_at": "2025-01-01T00:00:00Z" + } + ], + "total": 1, + "page": 1, + "per_page": 10 + }, + "version": "0.3.0" + })) ), tag = "Hackathon - Teams" )] @@ -80,7 +187,28 @@ pub async fn browse_teams_handler( get, path = "/v1/hackathon/teams/my", responses( - (status = 200, description = "Get my teams"), + (status = 200, description = "Get my teams", + example = json!({ + "data": [ + { + "id": "7c3a1d2e-8f4b-4c5a-9d6e-1f2a3b4c5d6e", + "name": "Rust Enjoyers", + "description": "A team that loves Rust", + "city": "Jakarta", + "visibility": "public", + "logo": null, + "banner": null, + "leader_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", + "leader": null, + "members": null, + "member_count": 3, + "has_submission": false, + "created_at": "2025-01-01T00:00:00Z", + "updated_at": "2025-01-01T00:00:00Z" + } + ], + "version": "0.3.0" + })), (status = 401, description = "Unauthorized") ), tag = "Hackathon - Teams", @@ -108,9 +236,29 @@ pub async fn get_my_teams_handler( params(("team_id" = Uuid, Path, description = "Team ID")), request_body = UpdateTeamRequest, responses( - (status = 200, description = "Update team"), + (status = 200, description = "Update team", + body = inline(TeamResponse), + example = json!({ + "data": { + "id": "7c3a1d2e-8f4b-4c5a-9d6e-1f2a3b4c5d6e", + "name": "Rust Enjoyers Updated", + "description": "We love Rust and systems programming", + "city": "Bandung", + "visibility": "public", + "logo": "https://cdn.example.com/team-logo.png", + "banner": null, + "leader_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", + "leader": null, + "members": null, + "member_count": 3, + "has_submission": false, + "created_at": "2025-01-01T00:00:00Z", + "updated_at": "2025-01-15T00:00:00Z" + }, + "version": "0.3.0" + })), (status = 401, description = "Unauthorized"), - (status = 403, description = "Forbidden") + (status = 403, description = "Forbidden - not team leader") ), tag = "Hackathon - Teams", security(("bearer_auth" = [])) @@ -132,9 +280,10 @@ pub async fn update_team_handler( path = "/v1/hackathon/teams/{team_id}", params(("team_id" = Uuid, Path, description = "Team ID")), responses( - (status = 200, description = "Delete team"), + (status = 200, description = "Delete team", + example = json!({"message": "Team deleted successfully", "version": "0.3.0"})), (status = 401, description = "Unauthorized"), - (status = 403, description = "Forbidden") + (status = 403, description = "Forbidden - not team leader") ), tag = "Hackathon - Teams", security(("bearer_auth" = [])) @@ -153,7 +302,8 @@ pub async fn delete_team_handler( path = "/v1/hackathon/teams/{team_id}/leave", params(("team_id" = Uuid, Path, description = "Team ID")), responses( - (status = 200, description = "Leave team"), + (status = 200, description = "Leave team", + example = json!({"message": "Left team successfully", "version": "0.3.0"})), (status = 401, description = "Unauthorized") ), tag = "Hackathon - Teams", @@ -176,9 +326,10 @@ pub async fn leave_team_handler( ("member_id" = Uuid, Path, description = "Member user ID") ), responses( - (status = 200, description = "Remove team member"), + (status = 200, description = "Remove team member", + example = json!({"message": "Member removed successfully", "version": "0.3.0"})), (status = 401, description = "Unauthorized"), - (status = 403, description = "Forbidden") + (status = 403, description = "Forbidden - not team leader") ), tag = "Hackathon - Teams", security(("bearer_auth" = [])) diff --git a/imphnen-hackathon/src/users/infrastructure/http/handlers.rs b/imphnen-hackathon/src/users/infrastructure/http/handlers.rs index fb8a951..03849c7 100644 --- a/imphnen-hackathon/src/users/infrastructure/http/handlers.rs +++ b/imphnen-hackathon/src/users/infrastructure/http/handlers.rs @@ -10,7 +10,24 @@ use uuid::Uuid; get, path = "/v1/hackathon/users/me", responses( - (status = 200, description = "Get my hackathon user profile"), + (status = 200, description = "Get my hackathon user profile", + body = inline(UserResponse), + example = json!({ + "data": { + "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", + "email": "user@example.com", + "fullname": "Budi Santoso", + "avatar": "https://cdn.example.com/avatar.png", + "phone_number": "+6281234567890", + "location": "Jakarta", + "bio": "Backend developer", + "skills": ["Rust", "Go", "PostgreSQL"], + "is_active": true, + "created_at": "2025-01-01T00:00:00Z", + "updated_at": "2025-01-10T00:00:00Z" + }, + "version": "0.3.0" + })), (status = 401, description = "Unauthorized") ), tag = "Hackathon - Users", @@ -29,7 +46,24 @@ pub async fn get_me_handler( path = "/v1/hackathon/users/me", request_body = UpdateUserRequest, responses( - (status = 200, description = "Update my hackathon user profile"), + (status = 200, description = "Update my hackathon user profile", + body = inline(UserResponse), + example = json!({ + "data": { + "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", + "email": "user@example.com", + "fullname": "Budi Santoso", + "avatar": "https://cdn.example.com/avatar.png", + "phone_number": "+6281234567890", + "location": "Surabaya", + "bio": "Backend developer with 5 years of experience", + "skills": ["Rust", "Go", "PostgreSQL", "Redis"], + "is_active": true, + "created_at": "2025-01-01T00:00:00Z", + "updated_at": "2025-01-15T00:00:00Z" + }, + "version": "0.3.0" + })), (status = 401, description = "Unauthorized") ), tag = "Hackathon - Users", @@ -49,7 +83,24 @@ pub async fn update_me_handler( path = "/v1/hackathon/users/{user_id}", params(("user_id" = Uuid, Path, description = "User ID")), responses( - (status = 200, description = "Get hackathon user by ID"), + (status = 200, description = "Get hackathon user by ID", + body = inline(UserResponse), + example = json!({ + "data": { + "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", + "email": "user@example.com", + "fullname": "Budi Santoso", + "avatar": null, + "phone_number": null, + "location": "Bandung", + "bio": null, + "skills": ["JavaScript", "React"], + "is_active": true, + "created_at": "2025-01-01T00:00:00Z", + "updated_at": "2025-01-01T00:00:00Z" + }, + "version": "0.3.0" + })), (status = 404, description = "User not found") ), tag = "Hackathon - Users" @@ -67,7 +118,20 @@ pub async fn get_user_handler( path = "/v1/hackathon/users/{user_id}/teams", params(("user_id" = Uuid, Path, description = "User ID")), responses( - (status = 200, description = "Get teams for a hackathon user"), + (status = 200, description = "Get teams for a hackathon user", + example = json!({ + "data": [ + { + "id": "7c3a1d2e-8f4b-4c5a-9d6e-1f2a3b4c5d6e", + "name": "Rust Enjoyers", + "city": "Jakarta", + "visibility": "public", + "leader_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", + "member_count": 3 + } + ], + "version": "0.3.0" + })), (status = 404, description = "User not found") ), tag = "Hackathon - Users" diff --git a/imphnen-hackathon/src/winners/infrastructure/http/handlers.rs b/imphnen-hackathon/src/winners/infrastructure/http/handlers.rs index 8828090..e9bb7d5 100644 --- a/imphnen-hackathon/src/winners/infrastructure/http/handlers.rs +++ b/imphnen-hackathon/src/winners/infrastructure/http/handlers.rs @@ -8,7 +8,30 @@ use std::sync::Arc; get, path = "/v1/hackathon/winners", responses( - (status = 200, description = "List hackathon winners") + (status = 200, description = "List hackathon winners", + example = json!({ + "data": [ + { + "id": "d4e5f6a7-b8c9-0123-defa-234567890123", + "team_id": "7c3a1d2e-8f4b-4c5a-9d6e-1f2a3b4c5d6e", + "team_name": "Rust Enjoyers", + "rank": 1, + "prize": "Rp 10.000.000", + "announced_at": "2025-02-01T10:00:00Z", + "created_at": "2025-02-01T10:00:00Z" + }, + { + "id": "e5f6a7b8-c9d0-1234-efab-345678901234", + "team_id": "8d4b2e3f-9a5c-4d6b-0e7f-2a3b4c5d6e7f", + "team_name": "Go Builders", + "rank": 2, + "prize": "Rp 5.000.000", + "announced_at": "2025-02-01T10:00:00Z", + "created_at": "2025-02-01T10:00:00Z" + } + ], + "version": "0.3.0" + })) ), tag = "Hackathon - Winners" )]