- ARCHITECTURE.md: main architecture document - api-spec.yaml: full OpenAPI 3.0 spec - folder-structure.md: detailed folder layout - data-format.md: JSON schemas for .meta.json, .library.json, .tag-index.json - env-template.md: environment variables documentation - cli-protocol.md: CLI-to-API communication protocol
878 lines
24 KiB
YAML
878 lines
24 KiB
YAML
openapi: 3.0.3
|
|
info:
|
|
title: SimpleNote API
|
|
description: REST API for SimpleNote document management system
|
|
version: 1.0.0
|
|
contact:
|
|
name: SimpleNote Team
|
|
|
|
servers:
|
|
- url: http://localhost:3000/api/v1
|
|
description: Local development server
|
|
|
|
tags:
|
|
- name: Auth
|
|
description: Authentication and token management
|
|
- name: Documents
|
|
description: Document CRUD operations
|
|
- name: Libraries
|
|
description: Library (folder) management
|
|
- name: Tags
|
|
description: Tag-based search and management
|
|
|
|
paths:
|
|
# ============ AUTH ============
|
|
/auth/token:
|
|
post:
|
|
tags: [Auth]
|
|
summary: Generate a new API token
|
|
description: Admin-only endpoint to generate a new bearer token
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
required: [label]
|
|
properties:
|
|
label:
|
|
type: string
|
|
description: Human-readable label for the token
|
|
example: "cli-default"
|
|
responses:
|
|
'200':
|
|
description: Token generated successfully
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
token:
|
|
type: string
|
|
example: "snk_a1b2c3d4e5f6..."
|
|
label:
|
|
type: string
|
|
example: "cli-default"
|
|
createdAt:
|
|
type: string
|
|
format: date-time
|
|
'401':
|
|
description: Unauthorized - invalid admin token
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Error'
|
|
'400':
|
|
description: Missing required fields
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Error'
|
|
|
|
/auth/verify:
|
|
get:
|
|
tags: [Auth]
|
|
summary: Verify current token is valid
|
|
security:
|
|
- BearerAuth: []
|
|
responses:
|
|
'200':
|
|
description: Token is valid
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
valid:
|
|
type: boolean
|
|
example: true
|
|
token:
|
|
type: string
|
|
example: "snk_a1b2c3d4e5f6..."
|
|
'401':
|
|
description: Token is invalid or missing
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Error'
|
|
|
|
# ============ DOCUMENTS ============
|
|
/documents:
|
|
get:
|
|
tags: [Documents]
|
|
summary: List all documents
|
|
security:
|
|
- BearerAuth: []
|
|
parameters:
|
|
- name: tag
|
|
in: query
|
|
description: Filter by tag
|
|
schema:
|
|
type: string
|
|
example: "backend"
|
|
- name: library
|
|
in: query
|
|
description: Filter by library ID
|
|
schema:
|
|
type: string
|
|
example: "550e8400-e29b-41d4-a716-446655440000"
|
|
- name: type
|
|
in: query
|
|
description: Filter by document type
|
|
schema:
|
|
type: string
|
|
enum: [requirement, note, spec, general]
|
|
example: "requirement"
|
|
- name: status
|
|
in: query
|
|
description: Filter by status
|
|
schema:
|
|
type: string
|
|
enum: [draft, approved, implemented]
|
|
example: "draft"
|
|
- name: limit
|
|
in: query
|
|
description: Max results to return
|
|
schema:
|
|
type: integer
|
|
default: 50
|
|
example: 20
|
|
- name: offset
|
|
in: query
|
|
description: Skip first N results
|
|
schema:
|
|
type: integer
|
|
default: 0
|
|
example: 0
|
|
responses:
|
|
'200':
|
|
description: List of documents
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
documents:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/Document'
|
|
total:
|
|
type: integer
|
|
example: 42
|
|
limit:
|
|
type: integer
|
|
example: 20
|
|
offset:
|
|
type: integer
|
|
example: 0
|
|
'401':
|
|
description: Unauthorized
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Error'
|
|
|
|
post:
|
|
tags: [Documents]
|
|
summary: Create a new document
|
|
security:
|
|
- BearerAuth: []
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
required: [title, libraryId]
|
|
properties:
|
|
title:
|
|
type: string
|
|
description: Document title
|
|
example: "API Authentication Design"
|
|
libraryId:
|
|
type: string
|
|
description: Target library ID
|
|
example: "550e8400-e29b-41d4-a716-446655440000"
|
|
content:
|
|
type: string
|
|
description: Markdown content (optional, defaults to template)
|
|
example: "# API Authentication\n\n## Description\n..."
|
|
tags:
|
|
type: array
|
|
items:
|
|
type: string
|
|
example: ["backend", "api", "auth"]
|
|
type:
|
|
type: string
|
|
enum: [requirement, note, spec, general]
|
|
default: general
|
|
priority:
|
|
type: string
|
|
enum: [high, medium, low]
|
|
default: medium
|
|
status:
|
|
type: string
|
|
enum: [draft, approved, implemented]
|
|
default: draft
|
|
responses:
|
|
'201':
|
|
description: Document created
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Document'
|
|
'400':
|
|
description: Invalid request body
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Error'
|
|
'401':
|
|
description: Unauthorized
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Error'
|
|
'404':
|
|
description: Library not found
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Error'
|
|
|
|
/documents/{id}:
|
|
get:
|
|
tags: [Documents]
|
|
summary: Get a document by ID
|
|
security:
|
|
- BearerAuth: []
|
|
parameters:
|
|
- name: id
|
|
in: path
|
|
required: true
|
|
description: Document UUID
|
|
schema:
|
|
type: string
|
|
example: "550e8400-e29b-41d4-a716-446655440001"
|
|
responses:
|
|
'200':
|
|
description: Document found
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Document'
|
|
'404':
|
|
description: Document not found
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Error'
|
|
'401':
|
|
description: Unauthorized
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Error'
|
|
|
|
put:
|
|
tags: [Documents]
|
|
summary: Update a document
|
|
security:
|
|
- BearerAuth: []
|
|
parameters:
|
|
- name: id
|
|
in: path
|
|
required: true
|
|
description: Document UUID
|
|
schema:
|
|
type: string
|
|
example: "550e8400-e29b-41d4-a716-446655440001"
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
title:
|
|
type: string
|
|
example: "Updated Title"
|
|
content:
|
|
type: string
|
|
example: "# Updated Content\n\nNew markdown..."
|
|
tags:
|
|
type: array
|
|
items:
|
|
type: string
|
|
example: ["backend", "api"]
|
|
type:
|
|
type: string
|
|
enum: [requirement, note, spec, general]
|
|
priority:
|
|
type: string
|
|
enum: [high, medium, low]
|
|
status:
|
|
type: string
|
|
enum: [draft, approved, implemented]
|
|
responses:
|
|
'200':
|
|
description: Document updated
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Document'
|
|
'400':
|
|
description: Invalid request body
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Error'
|
|
'404':
|
|
description: Document not found
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Error'
|
|
'401':
|
|
description: Unauthorized
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Error'
|
|
|
|
delete:
|
|
tags: [Documents]
|
|
summary: Delete a document
|
|
security:
|
|
- BearerAuth: []
|
|
parameters:
|
|
- name: id
|
|
in: path
|
|
required: true
|
|
description: Document UUID
|
|
schema:
|
|
type: string
|
|
example: "550e8400-e29b-41d4-a716-446655440001"
|
|
responses:
|
|
'200':
|
|
description: Document deleted
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
deleted:
|
|
type: boolean
|
|
example: true
|
|
id:
|
|
type: string
|
|
example: "550e8400-e29b-41d4-a716-446655440001"
|
|
'404':
|
|
description: Document not found
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Error'
|
|
'401':
|
|
description: Unauthorized
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Error'
|
|
|
|
/documents/{id}/export:
|
|
get:
|
|
tags: [Documents]
|
|
summary: Export document as raw Markdown
|
|
security:
|
|
- BearerAuth: []
|
|
parameters:
|
|
- name: id
|
|
in: path
|
|
required: true
|
|
description: Document UUID
|
|
schema:
|
|
type: string
|
|
example: "550e8400-e29b-41d4-a716-446655440001"
|
|
responses:
|
|
'200':
|
|
description: Raw Markdown file
|
|
content:
|
|
text/markdown:
|
|
schema:
|
|
type: string
|
|
example: |
|
|
---
|
|
id: REQ-001
|
|
title: API Authentication
|
|
---
|
|
# API Authentication
|
|
|
|
## Description
|
|
...
|
|
'404':
|
|
description: Document not found
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Error'
|
|
'401':
|
|
description: Unauthorized
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Error'
|
|
|
|
/documents/{id}/tags:
|
|
post:
|
|
tags: [Tags]
|
|
summary: Add tags to a document
|
|
security:
|
|
- BearerAuth: []
|
|
parameters:
|
|
- name: id
|
|
in: path
|
|
required: true
|
|
description: Document UUID
|
|
schema:
|
|
type: string
|
|
example: "550e8400-e29b-41d4-a716-446655440001"
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
required: [tags]
|
|
properties:
|
|
tags:
|
|
type: array
|
|
items:
|
|
type: string
|
|
example: ["new-tag", "another-tag"]
|
|
responses:
|
|
'200':
|
|
description: Tags added
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Document'
|
|
'400':
|
|
description: Invalid tags array
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Error'
|
|
'404':
|
|
description: Document not found
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Error'
|
|
'401':
|
|
description: Unauthorized
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Error'
|
|
|
|
# ============ LIBRARIES ============
|
|
/libraries:
|
|
get:
|
|
tags: [Libraries]
|
|
summary: List root-level libraries
|
|
security:
|
|
- BearerAuth: []
|
|
responses:
|
|
'200':
|
|
description: List of root libraries
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
libraries:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/Library'
|
|
'401':
|
|
description: Unauthorized
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Error'
|
|
|
|
post:
|
|
tags: [Libraries]
|
|
summary: Create a new library
|
|
security:
|
|
- BearerAuth: []
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
required: [name]
|
|
properties:
|
|
name:
|
|
type: string
|
|
description: Library name
|
|
example: "Backend Requirements"
|
|
parentId:
|
|
type: string
|
|
nullable: true
|
|
description: Parent library ID for nesting (null for root)
|
|
example: "550e8400-e29b-41d4-a716-446655440000"
|
|
responses:
|
|
'201':
|
|
description: Library created
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Library'
|
|
'400':
|
|
description: Invalid request body
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Error'
|
|
'404':
|
|
description: Parent library not found
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Error'
|
|
'401':
|
|
description: Unauthorized
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Error'
|
|
|
|
/libraries/{id}:
|
|
get:
|
|
tags: [Libraries]
|
|
summary: Get library contents (documents and sub-libraries)
|
|
security:
|
|
- BearerAuth: []
|
|
parameters:
|
|
- name: id
|
|
in: path
|
|
required: true
|
|
description: Library UUID
|
|
schema:
|
|
type: string
|
|
example: "550e8400-e29b-41d4-a716-446655440000"
|
|
responses:
|
|
'200':
|
|
description: Library contents
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
library:
|
|
$ref: '#/components/schemas/Library'
|
|
documents:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/Document'
|
|
subLibraries:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/Library'
|
|
'404':
|
|
description: Library not found
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Error'
|
|
'401':
|
|
description: Unauthorized
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Error'
|
|
|
|
/libraries/{id}/tree:
|
|
get:
|
|
tags: [Libraries]
|
|
summary: Get full subtree of a library
|
|
security:
|
|
- BearerAuth: []
|
|
parameters:
|
|
- name: id
|
|
in: path
|
|
required: true
|
|
description: Library UUID
|
|
schema:
|
|
type: string
|
|
example: "550e8400-e29b-41d4-a716-446655440000"
|
|
responses:
|
|
'200':
|
|
description: Full library tree
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/LibraryTree'
|
|
'404':
|
|
description: Library not found
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Error'
|
|
'401':
|
|
description: Unauthorized
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Error'
|
|
|
|
/libraries/{id}/documents:
|
|
get:
|
|
tags: [Documents]
|
|
summary: List documents in a specific library
|
|
security:
|
|
- BearerAuth: []
|
|
parameters:
|
|
- name: id
|
|
in: path
|
|
required: true
|
|
description: Library UUID
|
|
schema:
|
|
type: string
|
|
example: "550e8400-e29b-41d4-a716-446655440000"
|
|
responses:
|
|
'200':
|
|
description: List of documents in library
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
libraryId:
|
|
type: string
|
|
documents:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/Document'
|
|
'404':
|
|
description: Library not found
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Error'
|
|
'401':
|
|
description: Unauthorized
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Error'
|
|
|
|
# ============ TAGS ============
|
|
/tags:
|
|
get:
|
|
tags: [Tags]
|
|
summary: List all tags with document counts
|
|
security:
|
|
- BearerAuth: []
|
|
responses:
|
|
'200':
|
|
description: All tags with counts
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
tags:
|
|
type: array
|
|
items:
|
|
type: object
|
|
properties:
|
|
name:
|
|
type: string
|
|
example: "backend"
|
|
count:
|
|
type: integer
|
|
example: 5
|
|
total:
|
|
type: integer
|
|
example: 15
|
|
'401':
|
|
description: Unauthorized
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Error'
|
|
|
|
/tags/{tag}:
|
|
get:
|
|
tags: [Tags]
|
|
summary: Get all documents with a specific tag
|
|
security:
|
|
- BearerAuth: []
|
|
parameters:
|
|
- name: tag
|
|
in: path
|
|
required: true
|
|
description: Tag name
|
|
schema:
|
|
type: string
|
|
example: "backend"
|
|
responses:
|
|
'200':
|
|
description: Documents with tag
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
tag:
|
|
type: string
|
|
example: "backend"
|
|
documents:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/Document'
|
|
count:
|
|
type: integer
|
|
example: 5
|
|
'404':
|
|
description: Tag not found
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Error'
|
|
'401':
|
|
description: Unauthorized
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Error'
|
|
|
|
components:
|
|
securitySchemes:
|
|
BearerAuth:
|
|
type: http
|
|
scheme: bearer
|
|
bearerFormat: JWT
|
|
description: API token with `snk_` prefix
|
|
|
|
schemas:
|
|
Error:
|
|
type: object
|
|
properties:
|
|
error:
|
|
type: string
|
|
example: "Document not found"
|
|
code:
|
|
type: string
|
|
example: "NOT_FOUND"
|
|
|
|
Document:
|
|
type: object
|
|
properties:
|
|
id:
|
|
type: string
|
|
format: uuid
|
|
example: "550e8400-e29b-41d4-a716-446655440001"
|
|
title:
|
|
type: string
|
|
example: "API Authentication Design"
|
|
path:
|
|
type: string
|
|
example: "/libraries/550e8400/.../documents/550e8401/index.md"
|
|
content:
|
|
type: string
|
|
description: Raw markdown content
|
|
example: "# API Authentication\n\n## Description\n..."
|
|
tags:
|
|
type: array
|
|
items:
|
|
type: string
|
|
example: ["backend", "api", "auth"]
|
|
type:
|
|
type: string
|
|
enum: [requirement, note, spec, general]
|
|
example: "requirement"
|
|
status:
|
|
type: string
|
|
enum: [draft, approved, implemented]
|
|
example: "draft"
|
|
priority:
|
|
type: string
|
|
enum: [high, medium, low]
|
|
example: "high"
|
|
libraryId:
|
|
type: string
|
|
format: uuid
|
|
example: "550e8400-e29b-41d4-a716-446655440000"
|
|
createdBy:
|
|
type: string
|
|
description: Agent or user ID who created the document
|
|
example: "agent-001"
|
|
createdAt:
|
|
type: string
|
|
format: date-time
|
|
example: "2026-03-28T10:00:00Z"
|
|
updatedAt:
|
|
type: string
|
|
format: date-time
|
|
example: "2026-03-28T12:30:00Z"
|
|
|
|
Library:
|
|
type: object
|
|
properties:
|
|
id:
|
|
type: string
|
|
format: uuid
|
|
example: "550e8400-e29b-41d4-a716-446655440000"
|
|
name:
|
|
type: string
|
|
example: "Backend Requirements"
|
|
parentId:
|
|
type: string
|
|
nullable: true
|
|
format: uuid
|
|
description: Parent library ID, null for root
|
|
example: null
|
|
path:
|
|
type: string
|
|
description: Absolute path to library folder
|
|
example: "/data/libraries/550e8400"
|
|
documentCount:
|
|
type: integer
|
|
description: Total documents in this library (excludes sub-libraries)
|
|
example: 12
|
|
createdAt:
|
|
type: string
|
|
format: date-time
|
|
example: "2026-03-28T09:00:00Z"
|
|
updatedAt:
|
|
type: string
|
|
format: date-time
|
|
example: "2026-03-28T09:00:00Z"
|
|
|
|
LibraryTree:
|
|
type: object
|
|
properties:
|
|
id:
|
|
type: string
|
|
format: uuid
|
|
name:
|
|
type: string
|
|
documents:
|
|
type: array
|
|
items:
|
|
type: object
|
|
properties:
|
|
id:
|
|
type: string
|
|
title:
|
|
type: string
|
|
subLibraries:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/LibraryTree'
|