Spaces:
Running
Running
| openapi: 3.0.3 | |
| info: | |
| title: Phase II Todo Web App - API Reference | |
| description: | | |
| Complete API reference for the Full-Stack Todo Web Application. | |
| This document references existing endpoints from Specs 1 (Task CRUD) and 2 (Authentication & API Security). | |
| **Base URL**: http://localhost:8000 | |
| **Authentication**: All task endpoints require JWT Bearer token in Authorization header. | |
| **Note**: This is a reference document for integration purposes. No new endpoints are introduced in Spec 002. | |
| version: 1.0.0 | |
| contact: | |
| name: Phase II Todo Web App | |
| servers: | |
| - url: http://localhost:8000 | |
| description: Local development server | |
| tags: | |
| - name: Authentication | |
| description: User signup, signin, and profile endpoints (Spec 2) | |
| - name: Tasks | |
| description: Task CRUD operations (Spec 1) | |
| security: | |
| - BearerAuth: [] | |
| paths: | |
| /api/auth/signup: | |
| post: | |
| tags: | |
| - Authentication | |
| summary: Register new user account | |
| description: Creates a new user account with email, password, and name. Password is hashed with bcrypt before storage. | |
| operationId: signup | |
| security: [] | |
| requestBody: | |
| required: true | |
| content: | |
| application/json: | |
| schema: | |
| $ref: '#/components/schemas/SignupRequest' | |
| example: | |
| email: user@example.com | |
| password: SecurePass123 | |
| name: John Doe | |
| responses: | |
| '201': | |
| description: User created successfully | |
| content: | |
| application/json: | |
| schema: | |
| $ref: '#/components/schemas/SignupResponse' | |
| example: | |
| id: 1 | |
| email: user@example.com | |
| name: John Doe | |
| created_at: "2026-01-09T10:00:00Z" | |
| '400': | |
| description: Validation error (invalid email, weak password) | |
| content: | |
| application/json: | |
| schema: | |
| $ref: '#/components/schemas/ErrorResponse' | |
| example: | |
| detail: Password must be at least 8 characters with uppercase, lowercase, and number | |
| error_code: VALIDATION_ERROR | |
| '409': | |
| description: Email already registered | |
| content: | |
| application/json: | |
| schema: | |
| $ref: '#/components/schemas/ErrorResponse' | |
| example: | |
| detail: Email already registered | |
| error_code: EMAIL_EXISTS | |
| /api/auth/signin: | |
| post: | |
| tags: | |
| - Authentication | |
| summary: Authenticate user and issue JWT token | |
| description: Verifies email and password, returns JWT token with 7-day expiration. | |
| operationId: signin | |
| security: [] | |
| requestBody: | |
| required: true | |
| content: | |
| application/json: | |
| schema: | |
| $ref: '#/components/schemas/SigninRequest' | |
| example: | |
| email: user@example.com | |
| password: SecurePass123 | |
| responses: | |
| '200': | |
| description: Authentication successful | |
| content: | |
| application/json: | |
| schema: | |
| $ref: '#/components/schemas/TokenResponse' | |
| example: | |
| access_token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... | |
| token_type: bearer | |
| expires_in: 604800 | |
| user: | |
| id: 1 | |
| email: user@example.com | |
| name: John Doe | |
| created_at: "2026-01-09T10:00:00Z" | |
| '401': | |
| description: Invalid credentials | |
| content: | |
| application/json: | |
| schema: | |
| $ref: '#/components/schemas/ErrorResponse' | |
| example: | |
| detail: Invalid email or password | |
| error_code: INVALID_CREDENTIALS | |
| /api/auth/me: | |
| get: | |
| tags: | |
| - Authentication | |
| summary: Get current user profile | |
| description: Returns profile information for the authenticated user. | |
| operationId: getCurrentUser | |
| responses: | |
| '200': | |
| description: User profile retrieved successfully | |
| content: | |
| application/json: | |
| schema: | |
| $ref: '#/components/schemas/UserProfile' | |
| example: | |
| id: 1 | |
| email: user@example.com | |
| name: John Doe | |
| created_at: "2026-01-09T10:00:00Z" | |
| '401': | |
| description: Not authenticated or invalid token | |
| content: | |
| application/json: | |
| schema: | |
| $ref: '#/components/schemas/ErrorResponse' | |
| example: | |
| detail: Not authenticated | |
| error_code: TOKEN_MISSING | |
| /api/tasks: | |
| get: | |
| tags: | |
| - Tasks | |
| summary: List user's tasks with filtering and sorting | |
| description: Returns all tasks for the authenticated user. Supports filtering by completion status and sorting. | |
| operationId: getTasks | |
| parameters: | |
| - name: completed | |
| in: query | |
| description: Filter by completion status (true/false/null for all) | |
| required: false | |
| schema: | |
| type: boolean | |
| nullable: true | |
| - name: sort | |
| in: query | |
| description: Sort field | |
| required: false | |
| schema: | |
| type: string | |
| enum: [created_at, updated_at] | |
| default: created_at | |
| - name: order | |
| in: query | |
| description: Sort order | |
| required: false | |
| schema: | |
| type: string | |
| enum: [asc, desc] | |
| default: desc | |
| - name: limit | |
| in: query | |
| description: Maximum number of results | |
| required: false | |
| schema: | |
| type: integer | |
| minimum: 1 | |
| maximum: 100 | |
| default: 50 | |
| - name: offset | |
| in: query | |
| description: Number of results to skip | |
| required: false | |
| schema: | |
| type: integer | |
| minimum: 0 | |
| default: 0 | |
| responses: | |
| '200': | |
| description: Tasks retrieved successfully | |
| content: | |
| application/json: | |
| schema: | |
| $ref: '#/components/schemas/TaskListResponse' | |
| example: | |
| tasks: | |
| - id: 1 | |
| user_id: 1 | |
| title: Buy groceries | |
| description: Milk, eggs, bread | |
| completed: false | |
| created_at: "2026-01-09T10:00:00Z" | |
| updated_at: "2026-01-09T10:00:00Z" | |
| - id: 2 | |
| user_id: 1 | |
| title: Finish project | |
| description: null | |
| completed: true | |
| created_at: "2026-01-08T15:30:00Z" | |
| updated_at: "2026-01-09T09:00:00Z" | |
| total: 2 | |
| limit: 50 | |
| offset: 0 | |
| '401': | |
| $ref: '#/components/responses/UnauthorizedError' | |
| post: | |
| tags: | |
| - Tasks | |
| summary: Create new task | |
| description: Creates a new task for the authenticated user. | |
| operationId: createTask | |
| requestBody: | |
| required: true | |
| content: | |
| application/json: | |
| schema: | |
| $ref: '#/components/schemas/TaskCreate' | |
| example: | |
| title: Buy groceries | |
| description: Milk, eggs, bread | |
| responses: | |
| '201': | |
| description: Task created successfully | |
| content: | |
| application/json: | |
| schema: | |
| $ref: '#/components/schemas/Task' | |
| example: | |
| id: 1 | |
| user_id: 1 | |
| title: Buy groceries | |
| description: Milk, eggs, bread | |
| completed: false | |
| created_at: "2026-01-09T10:00:00Z" | |
| updated_at: "2026-01-09T10:00:00Z" | |
| '400': | |
| description: Validation error | |
| content: | |
| application/json: | |
| schema: | |
| $ref: '#/components/schemas/ErrorResponse' | |
| example: | |
| detail: Title is required | |
| error_code: VALIDATION_ERROR | |
| '401': | |
| $ref: '#/components/responses/UnauthorizedError' | |
| /api/tasks/{task_id}: | |
| get: | |
| tags: | |
| - Tasks | |
| summary: Get single task | |
| description: Returns a specific task if it belongs to the authenticated user. | |
| operationId: getTask | |
| parameters: | |
| - name: task_id | |
| in: path | |
| required: true | |
| schema: | |
| type: integer | |
| responses: | |
| '200': | |
| description: Task retrieved successfully | |
| content: | |
| application/json: | |
| schema: | |
| $ref: '#/components/schemas/Task' | |
| '401': | |
| $ref: '#/components/responses/UnauthorizedError' | |
| '404': | |
| description: Task not found or doesn't belong to user | |
| content: | |
| application/json: | |
| schema: | |
| $ref: '#/components/schemas/ErrorResponse' | |
| example: | |
| detail: Task not found | |
| error_code: NOT_FOUND | |
| put: | |
| tags: | |
| - Tasks | |
| summary: Update task (replace all fields) | |
| description: Replaces all task fields. All fields are required. | |
| operationId: updateTask | |
| parameters: | |
| - name: task_id | |
| in: path | |
| required: true | |
| schema: | |
| type: integer | |
| requestBody: | |
| required: true | |
| content: | |
| application/json: | |
| schema: | |
| $ref: '#/components/schemas/TaskUpdate' | |
| example: | |
| title: Buy groceries (updated) | |
| description: Milk, eggs, bread, cheese | |
| completed: false | |
| responses: | |
| '200': | |
| description: Task updated successfully | |
| content: | |
| application/json: | |
| schema: | |
| $ref: '#/components/schemas/Task' | |
| '400': | |
| description: Validation error | |
| content: | |
| application/json: | |
| schema: | |
| $ref: '#/components/schemas/ErrorResponse' | |
| '401': | |
| $ref: '#/components/responses/UnauthorizedError' | |
| '404': | |
| $ref: '#/components/responses/NotFoundError' | |
| patch: | |
| tags: | |
| - Tasks | |
| summary: Partially update task | |
| description: Updates only the provided fields. Other fields remain unchanged. | |
| operationId: patchTask | |
| parameters: | |
| - name: task_id | |
| in: path | |
| required: true | |
| schema: | |
| type: integer | |
| requestBody: | |
| required: true | |
| content: | |
| application/json: | |
| schema: | |
| $ref: '#/components/schemas/TaskPatch' | |
| example: | |
| completed: true | |
| responses: | |
| '200': | |
| description: Task updated successfully | |
| content: | |
| application/json: | |
| schema: | |
| $ref: '#/components/schemas/Task' | |
| '400': | |
| description: Validation error | |
| content: | |
| application/json: | |
| schema: | |
| $ref: '#/components/schemas/ErrorResponse' | |
| '401': | |
| $ref: '#/components/responses/UnauthorizedError' | |
| '404': | |
| $ref: '#/components/responses/NotFoundError' | |
| delete: | |
| tags: | |
| - Tasks | |
| summary: Delete task | |
| description: Permanently deletes a task if it belongs to the authenticated user. | |
| operationId: deleteTask | |
| parameters: | |
| - name: task_id | |
| in: path | |
| required: true | |
| schema: | |
| type: integer | |
| responses: | |
| '204': | |
| description: Task deleted successfully | |
| '401': | |
| $ref: '#/components/responses/UnauthorizedError' | |
| '404': | |
| $ref: '#/components/responses/NotFoundError' | |
| components: | |
| securitySchemes: | |
| BearerAuth: | |
| type: http | |
| scheme: bearer | |
| bearerFormat: JWT | |
| description: JWT token obtained from /api/auth/signin | |
| schemas: | |
| SignupRequest: | |
| type: object | |
| required: | |
| - password | |
| - name | |
| properties: | |
| email: | |
| type: string | |
| format: email | |
| description: Valid email address (RFC 5322) | |
| password: | |
| type: string | |
| minLength: 8 | |
| maxLength: 100 | |
| description: Min 8 chars with uppercase, lowercase, and number | |
| name: | |
| type: string | |
| minLength: 1 | |
| maxLength: 100 | |
| description: User's display name | |
| SignupResponse: | |
| type: object | |
| properties: | |
| id: | |
| type: integer | |
| email: | |
| type: string | |
| name: | |
| type: string | |
| created_at: | |
| type: string | |
| format: date-time | |
| SigninRequest: | |
| type: object | |
| required: | |
| - password | |
| properties: | |
| email: | |
| type: string | |
| format: email | |
| password: | |
| type: string | |
| TokenResponse: | |
| type: object | |
| properties: | |
| access_token: | |
| type: string | |
| description: JWT token | |
| token_type: | |
| type: string | |
| enum: [bearer] | |
| expires_in: | |
| type: integer | |
| description: Token expiration in seconds (604800 = 7 days) | |
| user: | |
| $ref: '#/components/schemas/UserProfile' | |
| UserProfile: | |
| type: object | |
| properties: | |
| id: | |
| type: integer | |
| email: | |
| type: string | |
| name: | |
| type: string | |
| created_at: | |
| type: string | |
| format: date-time | |
| Task: | |
| type: object | |
| properties: | |
| id: | |
| type: integer | |
| user_id: | |
| type: integer | |
| title: | |
| type: string | |
| maxLength: 200 | |
| description: | |
| type: string | |
| maxLength: 1000 | |
| nullable: true | |
| completed: | |
| type: boolean | |
| created_at: | |
| type: string | |
| format: date-time | |
| updated_at: | |
| type: string | |
| format: date-time | |
| TaskCreate: | |
| type: object | |
| required: | |
| - title | |
| properties: | |
| title: | |
| type: string | |
| minLength: 1 | |
| maxLength: 200 | |
| description: | |
| type: string | |
| maxLength: 1000 | |
| nullable: true | |
| TaskUpdate: | |
| type: object | |
| required: | |
| - title | |
| - completed | |
| properties: | |
| title: | |
| type: string | |
| minLength: 1 | |
| maxLength: 200 | |
| description: | |
| type: string | |
| maxLength: 1000 | |
| nullable: true | |
| completed: | |
| type: boolean | |
| TaskPatch: | |
| type: object | |
| properties: | |
| title: | |
| type: string | |
| minLength: 1 | |
| maxLength: 200 | |
| description: | |
| type: string | |
| maxLength: 1000 | |
| nullable: true | |
| completed: | |
| type: boolean | |
| TaskListResponse: | |
| type: object | |
| properties: | |
| tasks: | |
| type: array | |
| items: | |
| $ref: '#/components/schemas/Task' | |
| total: | |
| type: integer | |
| limit: | |
| type: integer | |
| offset: | |
| type: integer | |
| ErrorResponse: | |
| type: object | |
| properties: | |
| detail: | |
| type: string | |
| description: Human-readable error message | |
| error_code: | |
| type: string | |
| description: Machine-readable error code | |
| enum: | |
| - VALIDATION_ERROR | |
| - EMAIL_EXISTS | |
| - INVALID_CREDENTIALS | |
| - TOKEN_MISSING | |
| - TOKEN_EXPIRED | |
| - TOKEN_INVALID | |
| - NOT_FOUND | |
| field_errors: | |
| type: object | |
| additionalProperties: | |
| type: array | |
| items: | |
| type: string | |
| description: Field-specific validation errors | |
| responses: | |
| UnauthorizedError: | |
| description: Not authenticated or invalid token | |
| content: | |
| application/json: | |
| schema: | |
| $ref: '#/components/schemas/ErrorResponse' | |
| example: | |
| detail: Not authenticated | |
| error_code: TOKEN_MISSING | |
| NotFoundError: | |
| description: Resource not found or doesn't belong to user | |
| content: | |
| application/json: | |
| schema: | |
| $ref: '#/components/schemas/ErrorResponse' | |
| example: | |
| detail: Task not found | |
| error_code: NOT_FOUND | |