- Initialize Git repository with main branch - Create comprehensive .gitignore for Node.js, React, and environment files - Set up directory structure (frontend/, backend/, docs/) - Create detailed README.md with project overview and setup instructions - Add .env.example with all required environment variables - Configure Prettier for consistent code formatting All acceptance criteria met: ✅ Git repository initialized with appropriate .gitignore ✅ Directory structure matches Technical Assumptions ✅ README.md created with project overview and setup docs ✅ .env.example file with all required environment variables ✅ Prettier config files added for code formatting consistency 🤖 Generated with Claude Code (https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
408 lines
11 KiB
Markdown
408 lines
11 KiB
Markdown
# API Specification
|
|
|
|
## REST API Specification
|
|
|
|
```yaml
|
|
openapi: 3.0.0
|
|
info:
|
|
title: Book Reading Tracker API
|
|
version: 1.0.0
|
|
description: REST API for tracking book reading progress and calculating reading pace to meet deadlines
|
|
|
|
servers:
|
|
- url: http://localhost:3000/api
|
|
description: Local development server
|
|
- url: https://books.yourdomain.com/api
|
|
description: Production server (Coolify deployment)
|
|
|
|
paths:
|
|
/health:
|
|
get:
|
|
summary: Health check endpoint
|
|
description: Returns API status and timestamp for monitoring
|
|
responses:
|
|
'200':
|
|
description: API is healthy
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
status:
|
|
type: string
|
|
example: "ok"
|
|
timestamp:
|
|
type: string
|
|
format: date-time
|
|
|
|
/books/search:
|
|
get:
|
|
summary: Search for books
|
|
description: Search Open Library API for books by title, author, or ISBN
|
|
parameters:
|
|
- name: q
|
|
in: query
|
|
required: true
|
|
schema:
|
|
type: string
|
|
maxLength: 200
|
|
description: Search query (title, author, or ISBN)
|
|
responses:
|
|
'200':
|
|
description: Search results
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
results:
|
|
type: array
|
|
items:
|
|
type: object
|
|
properties:
|
|
olid:
|
|
type: string
|
|
title:
|
|
type: string
|
|
author:
|
|
type: string
|
|
publishYear:
|
|
type: integer
|
|
coverUrl:
|
|
type: string
|
|
totalPages:
|
|
type: integer
|
|
'400':
|
|
$ref: '#/components/responses/BadRequest'
|
|
'500':
|
|
$ref: '#/components/responses/ServerError'
|
|
|
|
/books:
|
|
get:
|
|
summary: Get all active books
|
|
description: Retrieve all books with status='reading' including progress calculations
|
|
responses:
|
|
'200':
|
|
description: List of active books with progress
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
books:
|
|
type: array
|
|
items:
|
|
allOf:
|
|
- $ref: '#/components/schemas/Book'
|
|
- type: object
|
|
properties:
|
|
currentPage:
|
|
type: integer
|
|
pagesRemaining:
|
|
type: integer
|
|
daysRemaining:
|
|
type: integer
|
|
requiredPace:
|
|
type: number
|
|
actualPace:
|
|
type: number
|
|
nullable: true
|
|
status:
|
|
type: string
|
|
enum: [on-track, slightly-behind, behind]
|
|
'500':
|
|
$ref: '#/components/responses/ServerError'
|
|
|
|
post:
|
|
summary: Add a new book
|
|
description: Add a book to the user's reading list with a deadline
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
required:
|
|
- title
|
|
- totalPages
|
|
- deadlineDate
|
|
properties:
|
|
title:
|
|
type: string
|
|
maxLength: 500
|
|
author:
|
|
type: string
|
|
maxLength: 500
|
|
nullable: true
|
|
totalPages:
|
|
type: integer
|
|
minimum: 1
|
|
coverUrl:
|
|
type: string
|
|
maxLength: 1000
|
|
nullable: true
|
|
deadlineDate:
|
|
type: string
|
|
format: date
|
|
responses:
|
|
'201':
|
|
description: Book created successfully
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Book'
|
|
'400':
|
|
$ref: '#/components/responses/BadRequest'
|
|
'500':
|
|
$ref: '#/components/responses/ServerError'
|
|
|
|
/books/{bookId}:
|
|
get:
|
|
summary: Get book by ID
|
|
description: Retrieve a specific book with full details
|
|
parameters:
|
|
- $ref: '#/components/parameters/BookId'
|
|
responses:
|
|
'200':
|
|
description: Book details
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Book'
|
|
'404':
|
|
$ref: '#/components/responses/NotFound'
|
|
'500':
|
|
$ref: '#/components/responses/ServerError'
|
|
|
|
delete:
|
|
summary: Delete a book
|
|
description: Remove a book and all associated reading logs
|
|
parameters:
|
|
- $ref: '#/components/parameters/BookId'
|
|
responses:
|
|
'204':
|
|
description: Book deleted successfully
|
|
'404':
|
|
$ref: '#/components/responses/NotFound'
|
|
'500':
|
|
$ref: '#/components/responses/ServerError'
|
|
|
|
/books/{bookId}/progress:
|
|
get:
|
|
summary: Get book progress
|
|
description: Calculate and return reading progress with pace metrics
|
|
parameters:
|
|
- $ref: '#/components/parameters/BookId'
|
|
responses:
|
|
'200':
|
|
description: Progress calculations
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/ProgressCalculation'
|
|
'404':
|
|
$ref: '#/components/responses/NotFound'
|
|
'500':
|
|
$ref: '#/components/responses/ServerError'
|
|
|
|
/books/{bookId}/logs:
|
|
get:
|
|
summary: Get reading logs for a book
|
|
description: Retrieve all reading logs for a specific book
|
|
parameters:
|
|
- $ref: '#/components/parameters/BookId'
|
|
responses:
|
|
'200':
|
|
description: Reading logs
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
logs:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/ReadingLog'
|
|
'404':
|
|
$ref: '#/components/responses/NotFound'
|
|
'500':
|
|
$ref: '#/components/responses/ServerError'
|
|
|
|
post:
|
|
summary: Log reading progress
|
|
description: Create or update a reading log entry for a specific date
|
|
parameters:
|
|
- $ref: '#/components/parameters/BookId'
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
required:
|
|
- currentPage
|
|
properties:
|
|
currentPage:
|
|
type: integer
|
|
minimum: 1
|
|
logDate:
|
|
type: string
|
|
format: date
|
|
description: Date of the log (defaults to today if not provided)
|
|
responses:
|
|
'201':
|
|
description: Log created successfully
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/ReadingLog'
|
|
'200':
|
|
description: Log updated successfully (if log already existed for this date)
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/ReadingLog'
|
|
'400':
|
|
$ref: '#/components/responses/BadRequest'
|
|
'404':
|
|
$ref: '#/components/responses/NotFound'
|
|
'500':
|
|
$ref: '#/components/responses/ServerError'
|
|
|
|
components:
|
|
schemas:
|
|
Book:
|
|
type: object
|
|
properties:
|
|
id:
|
|
type: integer
|
|
title:
|
|
type: string
|
|
author:
|
|
type: string
|
|
nullable: true
|
|
totalPages:
|
|
type: integer
|
|
coverUrl:
|
|
type: string
|
|
nullable: true
|
|
deadlineDate:
|
|
type: string
|
|
format: date
|
|
isPrimary:
|
|
type: boolean
|
|
status:
|
|
type: string
|
|
enum: [reading, finished, paused]
|
|
createdAt:
|
|
type: string
|
|
format: date-time
|
|
updatedAt:
|
|
type: string
|
|
format: date-time
|
|
|
|
ReadingLog:
|
|
type: object
|
|
properties:
|
|
id:
|
|
type: integer
|
|
bookId:
|
|
type: integer
|
|
logDate:
|
|
type: string
|
|
format: date
|
|
currentPage:
|
|
type: integer
|
|
createdAt:
|
|
type: string
|
|
format: date-time
|
|
updatedAt:
|
|
type: string
|
|
format: date-time
|
|
|
|
ProgressCalculation:
|
|
type: object
|
|
properties:
|
|
bookId:
|
|
type: integer
|
|
currentPage:
|
|
type: integer
|
|
totalPages:
|
|
type: integer
|
|
pagesRemaining:
|
|
type: integer
|
|
deadlineDate:
|
|
type: string
|
|
format: date
|
|
daysRemaining:
|
|
type: integer
|
|
requiredPace:
|
|
type: number
|
|
format: float
|
|
actualPace:
|
|
type: number
|
|
format: float
|
|
nullable: true
|
|
status:
|
|
type: string
|
|
enum: [on-track, slightly-behind, behind]
|
|
lastLoggedDate:
|
|
type: string
|
|
format: date
|
|
nullable: true
|
|
|
|
Error:
|
|
type: object
|
|
properties:
|
|
error:
|
|
type: string
|
|
description: Error message
|
|
details:
|
|
type: object
|
|
description: Additional error details
|
|
nullable: true
|
|
|
|
parameters:
|
|
BookId:
|
|
name: bookId
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: integer
|
|
description: Unique book identifier
|
|
|
|
responses:
|
|
BadRequest:
|
|
description: Invalid request
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Error'
|
|
example:
|
|
error: "Validation failed"
|
|
details:
|
|
field: "deadlineDate"
|
|
message: "Deadline must be in the future"
|
|
|
|
NotFound:
|
|
description: Resource not found
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Error'
|
|
example:
|
|
error: "Book not found"
|
|
|
|
ServerError:
|
|
description: Internal server error
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Error'
|
|
example:
|
|
error: "Internal server error"
|
|
details: null
|
|
```
|
|
|
|
---
|