- Add feature to select city in team detail modal using CityFilterSelect component - Add feature to change team logo and banner - Add API contract documentation for hackathon teams in backoffice
23 KiB
Hackathon Backoffice API Contract
GET /api/v1/admin/dashboard
Purpose
Single endpoint delivering aggregated metrics for the IMPHNEN x Kolosal.ai Hackathon dashboard.
Authentication & Authorization
- Requires admin (backoffice) scope: e.g.
role=admin - 401 if unauthenticated, 403 if authenticated but lacking required scope.
Examples
GET /api/v1/admin/dashboard
Response Schema
{
"data": {
"total_participants": 1261,
"total_teams": 206,
"total_submissions": 0 // Total project submitted
}
}
Field Types
| Path | Type | Notes |
|---|---|---|
data.total_participants |
integer | >= 0 |
data.total_teams |
integer | >= 0 |
data.total_submissions |
integer | <= data.total_teams |
Errors
| Status | Code | Message | Notes |
|---|---|---|---|
| 401 | unauthorized |
authentication required |
Missing/invalid token |
| 403 | forbidden |
insufficient permissions |
Lacks required scope |
| 429 | rate_limited |
too many dashboard requests |
Rate limiting |
| 500 | internal_error |
unexpected server error |
Unhandled exception |
GET /api/v1/admin/users
Purpose
Retrieve paginated list of hackathon participants with filtering, searching, and sorting capabilities for backoffice user management.
Authentication & Authorization
- Requires admin (backoffice) scope: e.g.
role=admin - 401 if unauthenticated, 403 if authenticated but lacking required scope.
Query Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
page |
integer | No | 1 | Page number (1-based) |
limit |
integer | No | 10 | Items per page (1-100) |
search |
string | No | - | Search by name or location (case-insensitive) |
status |
string | No | all |
Filter by status: all, active, inactive |
location |
string | No | all |
Filter by location or all |
skills |
string | No | - | Comma-separated skill filters |
sort_by |
string | No | created_at |
Sort field: fullname, location, is_active, created_at |
sort_order |
string | No | desc |
Sort order: asc, desc |
Examples
GET /api/v1/admin/users
GET /api/v1/admin/users?page=2&limit=10
GET /api/v1/admin/users?search=john&status=active
GET /api/v1/admin/users?location=Jakarta&skills=Frontend Developer,UI/UX Designer
GET /api/v1/admin/users?sort_by=fullname&sort_order=asc
Response Schema
{
"data": {
"users": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"avatar": "https://example.com/avatars/user1.jpg", // Optional
"fullname": "Budi Santoso",
"bio": "Passionate developer with 5+ years experience", // Optional
"location": "Jakarta",
"is_active": true,
"skills": ["Frontend Developer", "UI/UX Designer"], // Optional
"created_at": "2024-11-15T08:30:00Z",
"updated_at": "2024-11-30T14:22:00Z"
}
// ... more users
],
"pagination": {
"current_page": 1,
"total_pages": 15,
"total_items": 287,
"items_per_page": 20,
"has_next": true,
"has_prev": false
},
"filters": {
"available_locations": ["Jakarta", "Bandung", "Surabaya", "Medan", "Yogyakarta"],
"available_skills": ["Frontend Developer", "Backend Developer", "Full Stack Developer", "DevOps Engineer", "UI/UX Designer", "Product Manager", "Data Scientist", "Mobile Developer"]
}
}
}
Field Types
| Path | Type | Notes |
|---|---|---|
data.users[].id |
string | UUID format |
data.users[].avatar |
string | URL, nullable |
data.users[].fullname |
string | Required |
data.users[].bio |
string | Optional, max 500 chars |
data.users[].location |
string | Required, from predefined list |
data.users[].is_active |
boolean | Account status |
data.users[].skills |
array | Array of skill strings |
data.users[].created_at |
string | ISO 8601 timestamp |
data.users[].updated_at |
string | ISO 8601 timestamp |
data.pagination.* |
integer | Pagination metadata |
GET /api/v1/admin/users/{user_id}
Purpose
Retrieve detailed information for a specific user by ID.
Authentication & Authorization
- Requires admin (backoffice) scope: e.g.
role=admin
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
user_id |
string | Yes | User UUID |
Examples
GET /api/v1/admin/users/550e8400-e29b-41d4-a716-446655440000
Response Schema
{
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"avatar": "https://example.com/avatars/user1.jpg",
"fullname": "Budi Santoso",
"bio": "Passionate developer with 5+ years experience",
"location": "Jakarta",
"is_active": true,
"skills": ["Frontend Developer", "UI/UX Designer"],
"created_at": "2024-11-15T08:30:00Z",
"updated_at": "2024-11-30T14:22:00Z"
}
}
POST /api/v1/admin/users
Purpose
Create a new user account in the hackathon system.
Authentication & Authorization
- Requires admin (backoffice) scope: e.g.
role=admin
Request Body Schema
{
"fullname": "Jane Doe", // Required, 1-100 chars
"bio": "Experienced developer", // Optional, max 500 chars
"location": "Jakarta", // Required, from predefined list
"is_active": true, // Required, boolean
"skills": ["Backend Developer"], // Optional, array of valid skills
"avatar": "https://example.com/images/..." // Optional, URL
}
Examples
POST /api/v1/admin/users
Content-Type: application/json
{
"fullname": "Jane Doe",
"bio": "Experienced developer passionate about AI and machine learning",
"location": "Jakarta",
"is_active": true,
"skills": ["Backend Developer", "Data Scientist"],
"avatar": "https://example.com/images/..."
}
Response Schema
{
"data": {
"id": "550e8400-e29b-41d4-a716-446655440001",
"avatar": "https://example.com/avatars/generated_url.jpg",
"fullname": "Jane Doe",
"bio": "Experienced developer passionate about AI and machine learning",
"location": "Jakarta",
"is_active": true,
"skills": ["Backend Developer", "Data Scientist"],
"created_at": "2024-12-01T10:30:00Z",
"updated_at": "2024-12-01T10:30:00Z"
}
}
PUT /api/v1/admin/users/{user_id}
Purpose
Update an existing user's profile information.
Authentication & Authorization
- Requires admin (backoffice) scope: e.g.
role=admin
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
user_id |
string | Yes | User UUID |
Request Body Schema
{
"fullname": "Jane Smith", // Optional, 1-100 chars
"bio": "Senior developer", // Optional, max 500 chars, null to clear
"location": "Bandung", // Optional, from predefined list
"is_active": false, // Optional, boolean
"skills": ["Full Stack Developer"], // Optional, array of valid skills
"avatar": "https://example.com/images/..." // Optional, URL, null to remove
}
Examples
PUT /api/v1/admin/users/550e8400-e29b-41d4-a716-446655440000
Content-Type: application/json
{
"fullname": "Jane Smith",
"location": "Bandung",
"is_active": false,
"skills": ["Full Stack Developer", "Product Manager"]
}
Response Schema
{
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"avatar": "https://example.com/avatars/user1.jpg",
"fullname": "Jane Smith",
"bio": "Experienced developer passionate about AI and machine learning",
"location": "Bandung",
"is_active": false,
"skills": ["Full Stack Developer", "Product Manager"],
"created_at": "2024-11-15T08:30:00Z",
"updated_at": "2024-12-01T10:45:00Z"
}
}
DELETE /api/v1/admin/users/{user_id}
Purpose
(Soft) Delete a user account from the hackathon system.
Authentication & Authorization
- Requires admin (backoffice) scope: e.g.
role=admin
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
user_id |
string | Yes | User UUID |
Examples
DELETE /api/v1/admin/users/550e8400-e29b-41d4-a716-446655440000
Response Schema
{
"data": {
"message": "User successfully deleted",
"deleted_user_id": "550e8400-e29b-41d4-a716-446655440000",
"deleted_at": "2024-12-01T10:50:00Z"
}
}
Common Error Responses
User Management Endpoints
| Status | Code | Message | Notes |
|---|---|---|---|
| 400 | validation_error |
Invalid request data |
Field validation failures |
| 401 | unauthorized |
Authentication required |
Missing/invalid token |
| 403 | forbidden |
Insufficient permissions |
Lacks required scope |
| 404 | user_not_found |
User not found |
Invalid user ID |
| 409 | user_already_exists |
User with email already exists |
Duplicate user creation |
| 413 | payload_too_large |
Avatar file too large |
Avatar exceeds size limit |
| 422 | invalid_skill |
Invalid skill specified |
Skill not in allowed list |
| 422 | invalid_location |
Invalid location specified |
Location not in allowed list |
| 429 | rate_limited |
Too many requests |
Rate limiting |
| 500 | internal_error |
Unexpected server error |
Unhandled exception |
Validation Error Details
{
"error": {
"code": "validation_error",
"message": "Invalid request data",
"details": [
{
"field": "fullname",
"code": "required",
"message": "Full name is required"
},
{
"field": "location",
"code": "invalid_choice",
"message": "Location must be one of: Jakarta, Bandung, Surabaya, Medan, Yogyakarta"
}
]
}
}
Rate Limiting
- Dashboard: 30 requests / minute / admin user
- User Management: 100 requests / minute / admin user
- File Upload: 10 avatar uploads / minute / admin user
- Return 429 with
Retry-Afterheader
Avatar Handling
- Supported formats: JPEG, PNG, WebP
- Max file size: 5MB
- Recommended dimensions: 400x400px
- Storage: Uploaded avatars are processed and stored with generated URLs
- URL response: Always return publicly accessible HTTPS URLs
GET /api/v1/admin/teams
Purpose
Retrieve paginated list of hackathon teams with filtering, searching, and sorting capabilities for backoffice team management.
Authentication & Authorization
- Requires admin (backoffice) scope: e.g.
role=admin - 401 if unauthenticated, 403 if authenticated but lacking required scope.
Query Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
page |
integer | No | 1 | Page number (1-based) |
limit |
integer | No | 10 | Items per page (1-100) |
search |
string | No | - | Search by team name, city, or leader name (case-insensitive) |
visibility |
string | No | all |
Filter by visibility: all, public, private |
city |
string | No | all |
Filter by city or all |
submission |
string | No | all |
Filter by submission status: all, submitted, not_submitted |
member_count |
string | No | all |
Filter by member count: all, 1, 2, 3, 4, 5 |
sort_by |
string | No | created_at |
Sort field: name, city, visibility, member_count, has_submission, created_at |
sort_order |
string | No | desc |
Sort order: asc, desc |
Examples
GET /api/v1/admin/teams
GET /api/v1/admin/teams?page=2&limit=10
GET /api/v1/admin/teams?search=innovators&visibility=public
GET /api/v1/admin/teams?city=Jakarta&submission=submitted&member_count=3
GET /api/v1/admin/teams?sort_by=name&sort_order=asc
Response Schema
{
"data": {
"teams": [
{
"id": "team-001",
"name": "Team Innovators",
"description": "Building innovative solutions for modern problems", // Optional
"city": "Jakarta",
"banner": "https://example.com/banners/team1.jpg", // Optional
"logo": "https://example.com/logos/team1.jpg", // Optional
"visibility": "public", // "public" | "private"
"member_count": 3,
"has_submission": true,
"created_at": "2024-11-15T08:30:00Z",
"updated_at": "2024-11-30T14:22:00Z",
"leader_id": "leader-team-001",
"members": [
{
"id": "member-team-001-0",
"joined_at": "2024-11-15T08:30:00Z",
"role": "leader", // "leader" | "member"
"status": "accepted", // "pending" | "accepted" | "rejected"
"team_id": "team-001",
"user_id": "leader-team-001",
"user": {
"id": "leader-team-001",
"avatar": "https://ui-avatars.com/api/?name=John+Doe", // Optional
"bio": "Passionate developer with 5+ years experience", // Optional
"created_at": "2024-10-01T08:30:00Z",
"email": "john.doe@example.com",
"fullname": "John Doe",
"is_active": true,
"location": "Jakarta",
"phone_number": "+6281234567890", // Optional
"skills": ["Frontend Developer", "UI/UX Designer"],
"updated_at": "2024-11-30T14:22:00Z"
}
}
// ... more members
]
}
// ... more teams
],
"pagination": {
"current_page": 1,
"total_pages": 15,
"total_items": 147,
"items_per_page": 10,
"has_next": true,
"has_prev": false
},
"filters": {
"available_cities": ["Jakarta", "Bandung", "Surabaya", "Medan", "Yogyakarta"],
"available_skills": ["Frontend Developer", "Backend Developer", "Full Stack Developer", "DevOps Engineer", "UI/UX Designer", "Product Manager", "Data Scientist", "Mobile Developer"]
}
}
}
GET /api/v1/admin/teams/{team_id}
Purpose
Retrieve detailed information for a specific team by ID.
Authentication & Authorization
- Requires admin (backoffice) scope: e.g.
role=admin
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
team_id |
string | Yes | Team ID |
Examples
GET /api/v1/admin/teams/team-001
Response Schema
{
"data": {
"id": "team-001",
"name": "Team Innovators",
"description": "Building innovative solutions for modern problems",
"city": "Jakarta",
"banner": "https://example.com/banners/team1.jpg",
"logo": "https://example.com/logos/team1.jpg",
"visibility": "public",
"member_count": 3,
"has_submission": true,
"created_at": "2024-11-15T08:30:00Z",
"updated_at": "2024-11-30T14:22:00Z",
"leader_id": "leader-team-001",
"members": [
{
"id": "member-team-001-0",
"joined_at": "2024-11-15T08:30:00Z",
"role": "leader",
"status": "accepted",
"team_id": "team-001",
"user_id": "leader-team-001",
"user": {
"id": "leader-team-001",
"avatar": "https://ui-avatars.com/api/?name=John+Doe",
"bio": "Passionate developer with 5+ years experience",
"created_at": "2024-10-01T08:30:00Z",
"email": "john.doe@example.com",
"fullname": "John Doe",
"is_active": true,
"location": "Jakarta",
"phone_number": "+6281234567890",
"skills": ["Frontend Developer", "UI/UX Designer"],
"updated_at": "2024-11-30T14:22:00Z"
}
}
// ... all team members
]
}
}
POST /api/v1/admin/teams
Purpose
Create a new team in the hackathon system.
Authentication & Authorization
- Requires admin (backoffice) scope: e.g.
role=admin
Request Body Schema
{
"name": "Team New Innovators", // Required, 1-100 chars
"description": "Building next-gen solutions", // Optional, max 500 chars
"city": "Jakarta", // Required, from predefined list
"visibility": "public", // Required, "public" | "private"
"leader_id": "user-123", // Required, existing user ID
"banner": "https://example.com/banners/new.jpg", // Optional, URL
"logo": "https://example.com/logos/new.jpg" // Optional, URL
}
Response Schema
{
"data": {
"id": "team-new-001",
"name": "Team New Innovators",
"description": "Building next-gen solutions",
"city": "Jakarta",
"banner": "https://example.com/banners/new.jpg",
"logo": "https://example.com/logos/new.jpg",
"visibility": "public",
"member_count": 1,
"has_submission": false,
"created_at": "2024-12-02T10:30:00Z",
"updated_at": "2024-12-02T10:30:00Z",
"leader_id": "user-123",
"members": [
{
"id": "member-new-001-0",
"joined_at": "2024-12-02T10:30:00Z",
"role": "leader",
"status": "accepted",
"team_id": "team-new-001",
"user_id": "user-123",
"user": {
"id": "user-123",
"fullname": "John Doe",
"email": "john.doe@example.com",
"location": "Jakarta",
"is_active": true,
"skills": ["Frontend Developer"],
"created_at": "2024-10-01T08:30:00Z",
"updated_at": "2024-12-02T10:30:00Z"
}
}
]
}
}
PUT /api/v1/admin/teams/{team_id}
Purpose
Update an existing team's information.
Authentication & Authorization
- Requires admin (backoffice) scope: e.g.
role=admin
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
team_id |
string | Yes | Team ID |
Request Body Schema
{
"name": "Team Updated Name", // Optional, 1-100 chars
"description": "Updated description", // Optional, max 500 chars, null to clear
"city": "Bandung", // Optional, from predefined list
"visibility": "private", // Optional, "public" | "private"
"banner": "https://example.com/banners/updated.jpg", // Optional, URL, null to remove
"logo": "https://example.com/logos/updated.jpg" // Optional, URL, null to remove
}
Response Schema
Same as GET /api/v1/admin/teams/{team_id} with updated values.
DELETE /api/v1/admin/teams/{team_id}
Purpose
Delete a team from the hackathon system.
Authentication & Authorization
- Requires admin (backoffice) scope: e.g.
role=admin
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
team_id |
string | Yes | Team ID |
Response Schema
{
"data": {
"message": "Team successfully deleted",
"deleted_team_id": "team-001",
"deleted_at": "2024-12-02T10:50:00Z"
}
}
GET /api/v1/admin/teams/{team_id}/submission
Purpose
Retrieve submission details for a specific team.
Authentication & Authorization
- Requires admin (backoffice) scope: e.g.
role=admin
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
team_id |
string | Yes | Team ID |
Response Schema
{
"data": {
"team_id": "team-001",
"team_name": "Team Innovators",
"project_name": "EcoTrack - Smart Waste Management",
"project_description": "An AI-powered waste management solution that helps cities optimize collection routes and reduce environmental impact.",
"repository_url": "https://github.com/team-innovators/ecotrack",
"demo_url": "https://ecotrack-demo.vercel.app",
"presentation_url": "https://docs.google.com/presentation/d/team-innovators-pitch/edit",
"submitted_at": "2024-12-01T15:30:00Z",
"updated_at": "2024-12-01T16:45:00Z"
}
}
Common Error Responses
Team Management Endpoints
| Status | Code | Message | Notes |
|---|---|---|---|
| 400 | validation_error |
Invalid request data |
Field validation failures |
| 401 | unauthorized |
Authentication required |
Missing/invalid token |
| 403 | forbidden |
Insufficient permissions |
Lacks required scope |
| 404 | team_not_found |
Team not found |
Invalid team ID |
| 404 | submission_not_found |
Team submission not found |
Team has no submission |
| 409 | team_already_exists |
Team with name already exists |
Duplicate team name |
| 413 | payload_too_large |
Banner/logo file too large |
Image exceeds size limit |
| 422 | invalid_city |
Invalid city specified |
City not in allowed list |
| 422 | invalid_leader |
Invalid leader user ID |
Leader user does not exist |
| 429 | rate_limited |
Too many requests |
Rate limiting |
| 500 | internal_error |
Unexpected server error |
Unhandled exception |
Revision History
- v1.0.0 (2025-11-30): Initial contract drafted.
- v2.0.0 (2025-12-01): Added user management endpoints with filtering, pagination, CRUD operations, and avatar handling.
- v3.0.0 (2025-12-02): Added team management endpoints based on backoffice implementation with team members, submissions, and comprehensive filtering.