suhail
spoecs
9eafd9f
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:
- email
- 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:
- email
- 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