Add comprehensive specifications and planning documents for Reference Board Viewer application. Include detailed data model, API contracts, quickstart guide, and task breakdown for implementation. Ensure all artifacts are aligned with project objectives and constitutional principles.

This commit is contained in:
Danilo Reyes
2025-11-01 22:19:39 -06:00
parent d5a1819e2f
commit 58f463867e
8 changed files with 4371 additions and 475 deletions

View File

@@ -0,0 +1,921 @@
openapi: 3.0.3
info:
title: Reference Board Viewer API
description: |
REST API for the Reference Board Viewer application - a web-based tool for artists
to collect, organize, and manipulate visual reference images.
version: 1.0.0
contact:
name: API Support
servers:
- url: http://localhost:8000/api/v1
description: Development server
- url: https://webref.example.com/api/v1
description: Production server
tags:
- name: Auth
description: Authentication and user management
- name: Boards
description: Board operations
- name: Images
description: Image upload and management
- name: Canvas
description: Canvas operations (positioning, transformations)
- name: Groups
description: Image grouping
- name: Sharing
description: Board sharing
security:
- BearerAuth: []
paths:
# ==================== Authentication ====================
/auth/register:
post:
tags: [Auth]
summary: Register new user
security: []
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [email, password]
properties:
email:
type: string
format: email
example: user@example.com
password:
type: string
minLength: 8
example: SecurePass123
responses:
'201':
description: User registered successfully
content:
application/json:
schema:
$ref: '#/components/schemas/UserResponse'
'400':
$ref: '#/components/responses/BadRequest'
'409':
$ref: '#/components/responses/Conflict'
/auth/login:
post:
tags: [Auth]
summary: Login user
security: []
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [email, password]
properties:
email:
type: string
format: email
password:
type: string
responses:
'200':
description: Login successful
content:
application/json:
schema:
type: object
properties:
access_token:
type: string
example: eyJhbGciOiJIUzI1NiIs...
token_type:
type: string
example: bearer
user:
$ref: '#/components/schemas/UserResponse'
'401':
$ref: '#/components/responses/Unauthorized'
/auth/me:
get:
tags: [Auth]
summary: Get current user
responses:
'200':
description: Current user details
content:
application/json:
schema:
$ref: '#/components/schemas/UserResponse'
'401':
$ref: '#/components/responses/Unauthorized'
# ==================== Boards ====================
/boards:
get:
tags: [Boards]
summary: List user's boards
parameters:
- name: limit
in: query
schema:
type: integer
default: 50
maximum: 100
- name: offset
in: query
schema:
type: integer
default: 0
responses:
'200':
description: List of boards
content:
application/json:
schema:
type: object
properties:
boards:
type: array
items:
$ref: '#/components/schemas/BoardSummary'
total:
type: integer
limit:
type: integer
offset:
type: integer
post:
tags: [Boards]
summary: Create new board
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [title]
properties:
title:
type: string
minLength: 1
maxLength: 255
example: Character Design References
description:
type: string
example: References for fantasy knight character
responses:
'201':
description: Board created
content:
application/json:
schema:
$ref: '#/components/schemas/BoardDetail'
'400':
$ref: '#/components/responses/BadRequest'
/boards/{board_id}:
parameters:
- $ref: '#/components/parameters/BoardId'
get:
tags: [Boards]
summary: Get board details
responses:
'200':
description: Board details with all images
content:
application/json:
schema:
$ref: '#/components/schemas/BoardDetail'
'404':
$ref: '#/components/responses/NotFound'
patch:
tags: [Boards]
summary: Update board
requestBody:
content:
application/json:
schema:
type: object
properties:
title:
type: string
description:
type: string
viewport_state:
$ref: '#/components/schemas/ViewportState'
responses:
'200':
description: Board updated
content:
application/json:
schema:
$ref: '#/components/schemas/BoardDetail'
'404':
$ref: '#/components/responses/NotFound'
delete:
tags: [Boards]
summary: Delete board
responses:
'204':
description: Board deleted
'404':
$ref: '#/components/responses/NotFound'
# ==================== Images ====================
/boards/{board_id}/images:
parameters:
- $ref: '#/components/parameters/BoardId'
post:
tags: [Images]
summary: Upload image(s) to board
requestBody:
required: true
content:
multipart/form-data:
schema:
type: object
required: [files]
properties:
files:
type: array
items:
type: string
format: binary
maxItems: 50
position:
type: string
description: JSON string of default position
example: '{"x": 0, "y": 0}'
responses:
'201':
description: Images uploaded
content:
application/json:
schema:
type: object
properties:
images:
type: array
items:
$ref: '#/components/schemas/BoardImage'
'400':
$ref: '#/components/responses/BadRequest'
'413':
description: File too large
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/boards/{board_id}/images/{image_id}:
parameters:
- $ref: '#/components/parameters/BoardId'
- $ref: '#/components/parameters/ImageId'
patch:
tags: [Canvas]
summary: Update image position/transformations
requestBody:
content:
application/json:
schema:
type: object
properties:
position:
$ref: '#/components/schemas/Position'
transformations:
$ref: '#/components/schemas/Transformations'
z_order:
type: integer
group_id:
type: string
format: uuid
nullable: true
responses:
'200':
description: Image updated
content:
application/json:
schema:
$ref: '#/components/schemas/BoardImage'
'404':
$ref: '#/components/responses/NotFound'
delete:
tags: [Canvas]
summary: Remove image from board
responses:
'204':
description: Image removed from board
'404':
$ref: '#/components/responses/NotFound'
/boards/{board_id}/images/bulk:
parameters:
- $ref: '#/components/parameters/BoardId'
patch:
tags: [Canvas]
summary: Bulk update multiple images
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [image_ids, updates]
properties:
image_ids:
type: array
items:
type: string
format: uuid
updates:
type: object
properties:
position_delta:
type: object
properties:
dx:
type: number
dy:
type: number
transformations:
$ref: '#/components/schemas/Transformations'
z_order_delta:
type: integer
responses:
'200':
description: Images updated
content:
application/json:
schema:
type: object
properties:
updated_count:
type: integer
'400':
$ref: '#/components/responses/BadRequest'
# ==================== Groups ====================
/boards/{board_id}/groups:
parameters:
- $ref: '#/components/parameters/BoardId'
get:
tags: [Groups]
summary: List board groups
responses:
'200':
description: List of groups
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/Group'
post:
tags: [Groups]
summary: Create group
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [name, color, image_ids]
properties:
name:
type: string
example: Armor References
color:
type: string
pattern: '^#[0-9A-Fa-f]{6}$'
example: '#FF5733'
annotation:
type: string
example: Blue plate armor designs
image_ids:
type: array
items:
type: string
format: uuid
responses:
'201':
description: Group created
content:
application/json:
schema:
$ref: '#/components/schemas/Group'
'400':
$ref: '#/components/responses/BadRequest'
/boards/{board_id}/groups/{group_id}:
parameters:
- $ref: '#/components/parameters/BoardId'
- $ref: '#/components/parameters/GroupId'
patch:
tags: [Groups]
summary: Update group
requestBody:
content:
application/json:
schema:
type: object
properties:
name:
type: string
color:
type: string
annotation:
type: string
responses:
'200':
description: Group updated
content:
application/json:
schema:
$ref: '#/components/schemas/Group'
delete:
tags: [Groups]
summary: Delete group (ungroups images)
responses:
'204':
description: Group deleted
'404':
$ref: '#/components/responses/NotFound'
# ==================== Sharing ====================
/boards/{board_id}/share-links:
parameters:
- $ref: '#/components/parameters/BoardId'
get:
tags: [Sharing]
summary: List board share links
responses:
'200':
description: List of share links
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/ShareLink'
post:
tags: [Sharing]
summary: Create share link
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [permission_level]
properties:
permission_level:
type: string
enum: [view-only, view-comment]
expires_at:
type: string
format: date-time
nullable: true
responses:
'201':
description: Share link created
content:
application/json:
schema:
$ref: '#/components/schemas/ShareLink'
/boards/{board_id}/share-links/{link_id}:
parameters:
- $ref: '#/components/parameters/BoardId'
- name: link_id
in: path
required: true
schema:
type: string
format: uuid
delete:
tags: [Sharing]
summary: Revoke share link
responses:
'204':
description: Share link revoked
'404':
$ref: '#/components/responses/NotFound'
/shared/{token}:
parameters:
- name: token
in: path
required: true
schema:
type: string
get:
tags: [Sharing]
summary: Access shared board
security: []
responses:
'200':
description: Shared board details
content:
application/json:
schema:
type: object
properties:
board:
$ref: '#/components/schemas/BoardDetail'
permission_level:
type: string
enum: [view-only, view-comment]
'404':
description: Invalid or expired token
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
# ==================== Export ====================
/boards/{board_id}/export:
parameters:
- $ref: '#/components/parameters/BoardId'
post:
tags: [Boards]
summary: Export board
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [format]
properties:
format:
type: string
enum: [zip, composite]
resolution:
type: integer
enum: [1, 2, 4]
default: 1
description: Resolution multiplier (for composite)
responses:
'200':
description: Export file
content:
application/zip:
schema:
type: string
format: binary
image/png:
schema:
type: string
format: binary
'400':
$ref: '#/components/responses/BadRequest'
# ==================== Image Library ====================
/library/images:
get:
tags: [Images]
summary: List user's image library
parameters:
- name: search
in: query
schema:
type: string
- name: limit
in: query
schema:
type: integer
default: 50
- name: offset
in: query
schema:
type: integer
default: 0
responses:
'200':
description: Image library
content:
application/json:
schema:
type: object
properties:
images:
type: array
items:
$ref: '#/components/schemas/ImageMetadata'
total:
type: integer
# ==================== Components ====================
components:
securitySchemes:
BearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
parameters:
BoardId:
name: board_id
in: path
required: true
schema:
type: string
format: uuid
ImageId:
name: image_id
in: path
required: true
schema:
type: string
format: uuid
GroupId:
name: group_id
in: path
required: true
schema:
type: string
format: uuid
schemas:
UserResponse:
type: object
properties:
id:
type: string
format: uuid
email:
type: string
format: email
created_at:
type: string
format: date-time
BoardSummary:
type: object
properties:
id:
type: string
format: uuid
title:
type: string
description:
type: string
nullable: true
image_count:
type: integer
thumbnail_url:
type: string
nullable: true
created_at:
type: string
format: date-time
updated_at:
type: string
format: date-time
BoardDetail:
allOf:
- $ref: '#/components/schemas/BoardSummary'
- type: object
properties:
viewport_state:
$ref: '#/components/schemas/ViewportState'
images:
type: array
items:
$ref: '#/components/schemas/BoardImage'
groups:
type: array
items:
$ref: '#/components/schemas/Group'
ViewportState:
type: object
properties:
x:
type: number
example: 0
y:
type: number
example: 0
zoom:
type: number
minimum: 0.1
maximum: 5.0
example: 1.0
rotation:
type: number
minimum: 0
maximum: 360
example: 0
ImageMetadata:
type: object
properties:
id:
type: string
format: uuid
filename:
type: string
file_size:
type: integer
mime_type:
type: string
width:
type: integer
height:
type: integer
thumbnail_urls:
type: object
properties:
low:
type: string
medium:
type: string
high:
type: string
created_at:
type: string
format: date-time
reference_count:
type: integer
BoardImage:
allOf:
- $ref: '#/components/schemas/ImageMetadata'
- type: object
properties:
position:
$ref: '#/components/schemas/Position'
transformations:
$ref: '#/components/schemas/Transformations'
z_order:
type: integer
group_id:
type: string
format: uuid
nullable: true
Position:
type: object
properties:
x:
type: number
y:
type: number
Transformations:
type: object
properties:
scale:
type: number
minimum: 0.01
maximum: 10.0
default: 1.0
rotation:
type: number
minimum: 0
maximum: 360
default: 0
opacity:
type: number
minimum: 0.0
maximum: 1.0
default: 1.0
flipped_h:
type: boolean
default: false
flipped_v:
type: boolean
default: false
crop:
type: object
nullable: true
properties:
x:
type: number
y:
type: number
width:
type: number
height:
type: number
greyscale:
type: boolean
default: false
Group:
type: object
properties:
id:
type: string
format: uuid
name:
type: string
color:
type: string
pattern: '^#[0-9A-Fa-f]{6}$'
annotation:
type: string
nullable: true
member_count:
type: integer
created_at:
type: string
format: date-time
ShareLink:
type: object
properties:
id:
type: string
format: uuid
token:
type: string
permission_level:
type: string
enum: [view-only, view-comment]
url:
type: string
example: https://webref.example.com/shared/abc123...
created_at:
type: string
format: date-time
expires_at:
type: string
format: date-time
nullable: true
access_count:
type: integer
is_revoked:
type: boolean
Error:
type: object
properties:
error:
type: object
properties:
message:
type: string
code:
type: string
details:
type: object
nullable: true
responses:
BadRequest:
description: Bad request
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
Unauthorized:
description: Unauthorized
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
NotFound:
description: Resource not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
Conflict:
description: Resource conflict
content:
application/json:
schema:
$ref: '#/components/schemas/Error'