Update of documentation
This commit is contained in:
1056
docs/API.md
Normal file
1056
docs/API.md
Normal file
File diff suppressed because it is too large
Load Diff
263
docs/DATA_MODEL.md
Normal file
263
docs/DATA_MODEL.md
Normal file
@@ -0,0 +1,263 @@
|
||||
# StoryCove Data Model Documentation
|
||||
|
||||
## Overview
|
||||
|
||||
StoryCove uses PostgreSQL as its primary database with UUID-based primary keys throughout. The data model is designed to support a personal library of short stories with rich metadata, author information, and flexible organization through tags and series.
|
||||
|
||||
## Entity Relationship Diagram
|
||||
|
||||
```
|
||||
┌─────────────┐ ┌──────────────┐ ┌─────────────┐
|
||||
│ Authors │────│ Stories │────│ Series │
|
||||
│ │ │ │ │ │
|
||||
│ - id (PK) │ │ - id (PK) │ │ - id (PK) │
|
||||
│ - name │ │ - title │ │ - name │
|
||||
│ - notes │ │ - content* │ │ - desc │
|
||||
│ - rating │ │ - rating │ │ │
|
||||
│ - avatar │ │ - volume │ │ │
|
||||
└─────────────┘ │ - cover │ └─────────────┘
|
||||
│ │ - word_count │
|
||||
│ │ - source_url │
|
||||
│ │ - timestamps │
|
||||
│ └──────────────┘
|
||||
│ │
|
||||
│ │
|
||||
┌─────────────┐ │ ┌─────────────┐
|
||||
│ Author_URLs │ │ │ Tags │
|
||||
│ │ │ │ │
|
||||
│ - author_id │ │ │ - id (PK) │
|
||||
│ - url │ │ │ - name │
|
||||
└─────────────┘ │ └─────────────┘
|
||||
│ │
|
||||
│ │
|
||||
┌─────────────┐ │
|
||||
│ Story_Tags │─────────┘
|
||||
│ │
|
||||
│ - story_id │
|
||||
│ - tag_id │
|
||||
└─────────────┘
|
||||
```
|
||||
|
||||
## Detailed Entity Specifications
|
||||
|
||||
### Stories Table
|
||||
|
||||
**Table Name**: `stories`
|
||||
|
||||
| Column | Type | Constraints | Description |
|
||||
|--------|------|-------------|-------------|
|
||||
| id | UUID | PRIMARY KEY, NOT NULL | Unique identifier |
|
||||
| title | VARCHAR(255) | NOT NULL | Story title |
|
||||
| summary | TEXT | NULL | Optional story summary |
|
||||
| description | VARCHAR(1000) | NULL | Optional description |
|
||||
| content_html | TEXT | NULL | HTML content of the story |
|
||||
| content_plain | TEXT | NULL | Plain text version (auto-generated) |
|
||||
| source_url | VARCHAR(255) | NULL | Source URL where story was found |
|
||||
| cover_path | VARCHAR(255) | NULL | Path to cover image file |
|
||||
| word_count | INTEGER | NOT NULL, DEFAULT 0 | Word count (auto-calculated) |
|
||||
| rating | INTEGER | NULL, CHECK (rating >= 1 AND rating <= 5) | Story rating |
|
||||
| volume | INTEGER | NULL | Volume number if part of series |
|
||||
| author_id | UUID | FOREIGN KEY | Reference to authors table |
|
||||
| series_id | UUID | FOREIGN KEY, NULL | Reference to series table |
|
||||
| created_at | TIMESTAMP | NOT NULL, DEFAULT CURRENT_TIMESTAMP | Creation timestamp |
|
||||
| updated_at | TIMESTAMP | NOT NULL, DEFAULT CURRENT_TIMESTAMP | Last update timestamp |
|
||||
|
||||
**Indexes:**
|
||||
- Primary key on `id`
|
||||
- Foreign key index on `author_id`
|
||||
- Foreign key index on `series_id`
|
||||
- Index on `created_at` for recent stories queries
|
||||
- Index on `rating` for top-rated queries
|
||||
- Unique constraint on `source_url` where not null
|
||||
|
||||
**Business Rules:**
|
||||
- Word count is automatically calculated from `content_plain` or `content_html`
|
||||
- Plain text content is automatically extracted from HTML content using Jsoup
|
||||
- Volume is only meaningful when series_id is set
|
||||
- Rating must be between 1-5 if provided
|
||||
|
||||
### Authors Table
|
||||
|
||||
**Table Name**: `authors`
|
||||
|
||||
| Column | Type | Constraints | Description |
|
||||
|--------|------|-------------|-------------|
|
||||
| id | UUID | PRIMARY KEY, NOT NULL | Unique identifier |
|
||||
| name | VARCHAR(255) | NOT NULL, UNIQUE | Author name |
|
||||
| notes | TEXT | NULL | Notes about the author |
|
||||
| author_rating | INTEGER | NULL, CHECK (author_rating >= 1 AND author_rating <= 5) | Author rating |
|
||||
| avatar_image_path | VARCHAR(255) | NULL | Path to avatar image |
|
||||
| created_at | TIMESTAMP | NOT NULL, DEFAULT CURRENT_TIMESTAMP | Creation timestamp |
|
||||
| updated_at | TIMESTAMP | NOT NULL, DEFAULT CURRENT_TIMESTAMP | Last update timestamp |
|
||||
|
||||
**Indexes:**
|
||||
- Primary key on `id`
|
||||
- Unique index on `name`
|
||||
- Index on `author_rating` for top-rated queries
|
||||
|
||||
**Business Rules:**
|
||||
- Author names must be unique across the system
|
||||
- Rating must be between 1-5 if provided
|
||||
- Author statistics (story count, average rating) are calculated dynamically
|
||||
|
||||
### Author URLs Table
|
||||
|
||||
**Table Name**: `author_urls`
|
||||
|
||||
| Column | Type | Constraints | Description |
|
||||
|--------|------|-------------|-------------|
|
||||
| author_id | UUID | FOREIGN KEY, NOT NULL | Reference to authors table |
|
||||
| url | VARCHAR(255) | NOT NULL | URL associated with author |
|
||||
|
||||
**Indexes:**
|
||||
- Foreign key index on `author_id`
|
||||
- Composite index on `(author_id, url)` for uniqueness
|
||||
|
||||
**Business Rules:**
|
||||
- One author can have multiple URLs
|
||||
- URLs are stored as simple strings without validation
|
||||
- Duplicate URLs for the same author are prevented by application logic
|
||||
|
||||
### Series Table
|
||||
|
||||
**Table Name**: `series`
|
||||
|
||||
| Column | Type | Constraints | Description |
|
||||
|--------|------|-------------|-------------|
|
||||
| id | UUID | PRIMARY KEY, NOT NULL | Unique identifier |
|
||||
| name | VARCHAR(255) | NOT NULL, UNIQUE | Series name |
|
||||
| description | VARCHAR(1000) | NULL | Series description |
|
||||
| created_at | TIMESTAMP | NOT NULL, DEFAULT CURRENT_TIMESTAMP | Creation timestamp |
|
||||
|
||||
**Indexes:**
|
||||
- Primary key on `id`
|
||||
- Unique index on `name`
|
||||
|
||||
**Business Rules:**
|
||||
- Series names must be unique
|
||||
- Stories in a series are ordered by volume number
|
||||
- Series without stories are allowed (placeholder series)
|
||||
|
||||
### Tags Table
|
||||
|
||||
**Table Name**: `tags`
|
||||
|
||||
| Column | Type | Constraints | Description |
|
||||
|--------|------|-------------|-------------|
|
||||
| id | UUID | PRIMARY KEY, NOT NULL | Unique identifier |
|
||||
| name | VARCHAR(100) | NOT NULL, UNIQUE | Tag name |
|
||||
| created_at | TIMESTAMP | NOT NULL, DEFAULT CURRENT_TIMESTAMP | Creation timestamp |
|
||||
|
||||
**Indexes:**
|
||||
- Primary key on `id`
|
||||
- Unique index on `name`
|
||||
- Index on `name` for autocomplete queries
|
||||
|
||||
**Business Rules:**
|
||||
- Tag names must be unique and are stored in lowercase
|
||||
- Tags are created automatically when referenced by stories
|
||||
- Tag usage statistics are calculated dynamically
|
||||
|
||||
### Story Tags Junction Table
|
||||
|
||||
**Table Name**: `story_tags`
|
||||
|
||||
| Column | Type | Constraints | Description |
|
||||
|--------|------|-------------|-------------|
|
||||
| story_id | UUID | FOREIGN KEY, NOT NULL | Reference to stories table |
|
||||
| tag_id | UUID | FOREIGN KEY, NOT NULL | Reference to tags table |
|
||||
|
||||
**Constraints:**
|
||||
- Primary key on `(story_id, tag_id)`
|
||||
- Foreign key to `stories(id)` with CASCADE DELETE
|
||||
- Foreign key to `tags(id)` with CASCADE DELETE
|
||||
|
||||
**Indexes:**
|
||||
- Composite primary key index
|
||||
- Index on `tag_id` for reverse lookups
|
||||
|
||||
## Data Types and Conventions
|
||||
|
||||
### UUID Strategy
|
||||
- All primary keys use UUID (Universally Unique Identifier)
|
||||
- Generated using `GenerationType.UUID` in Hibernate
|
||||
- Provides natural uniqueness across distributed systems
|
||||
- 36-character string representation (e.g., `123e4567-e89b-12d3-a456-426614174000`)
|
||||
|
||||
### Timestamp Management
|
||||
- All entities have `created_at` timestamp
|
||||
- Stories and Authors have `updated_at` timestamp (automatically updated)
|
||||
- Series and Tags only have `created_at` (they're rarely modified)
|
||||
- All timestamps use `LocalDateTime` in Java, stored as `TIMESTAMP` in PostgreSQL
|
||||
|
||||
### Text Fields
|
||||
- **VARCHAR(n)**: For constrained text fields (names, paths, URLs)
|
||||
- **TEXT**: For unlimited text content (story content, notes, descriptions)
|
||||
- **HTML Content**: Stored as-is but sanitized on input and output
|
||||
- **Plain Text**: Automatically extracted from HTML using Jsoup
|
||||
|
||||
### Validation Rules
|
||||
- **Required Fields**: Entity names/titles are always required
|
||||
- **Length Limits**: Names limited to 255 characters, descriptions to 1000
|
||||
- **Rating Range**: All ratings constrained to 1-5 range
|
||||
- **URL Format**: No format validation at database level
|
||||
- **Uniqueness**: Names are unique within their entity type
|
||||
|
||||
## Relationships and Cascading
|
||||
|
||||
### One-to-Many Relationships
|
||||
- **Author → Stories**: Lazy loaded, cascade ALL operations
|
||||
- **Series → Stories**: Lazy loaded, ordered by volume, cascade ALL
|
||||
- **Author → Author URLs**: Eager loaded via `@ElementCollection`
|
||||
|
||||
### Many-to-Many Relationships
|
||||
- **Stories ↔ Tags**: Via `story_tags` junction table
|
||||
- Managed bidirectionally with helper methods
|
||||
- Cascade DELETE on both sides
|
||||
|
||||
### Foreign Key Constraints
|
||||
- All foreign keys have proper referential integrity
|
||||
- DELETE operations cascade appropriately
|
||||
- No orphaned records are allowed
|
||||
|
||||
## Performance Considerations
|
||||
|
||||
### Indexing Strategy
|
||||
- Primary keys automatically indexed
|
||||
- Foreign keys have dedicated indexes
|
||||
- Frequently queried fields (rating, created_at) are indexed
|
||||
- Unique constraints automatically create indexes
|
||||
|
||||
### Query Optimization
|
||||
- Lazy loading prevents N+1 queries
|
||||
- Pagination used for large result sets
|
||||
- Specialized queries for common access patterns
|
||||
- Typesense search engine for full-text search (separate from PostgreSQL)
|
||||
|
||||
### Data Volume Estimates
|
||||
- **Stories**: Expected 1K-10K records per user
|
||||
- **Authors**: Expected 100-1K records per user
|
||||
- **Tags**: Expected 50-500 records per user
|
||||
- **Series**: Expected 10-100 records per user
|
||||
- **Join Tables**: Scale with story count and tagging usage
|
||||
|
||||
## Backup and Migration Considerations
|
||||
|
||||
### Schema Evolution
|
||||
- Uses Hibernate `ddl-auto: update` for development
|
||||
- Production should use controlled migration tools (Flyway/Liquibase)
|
||||
- UUID keys allow safe data migration between environments
|
||||
|
||||
### Data Integrity
|
||||
- Foreign key constraints ensure referential integrity
|
||||
- Check constraints validate data ranges
|
||||
- Application-level validation provides user-friendly error messages
|
||||
- Unique constraints prevent duplicate data
|
||||
|
||||
### Backup Strategy
|
||||
- Full PostgreSQL dumps for complete backup
|
||||
- Image files stored separately in filesystem
|
||||
- Consider incremental backups for large installations
|
||||
- Test restore procedures regularly
|
||||
|
||||
This data model provides a solid foundation for personal story library management with room for future enhancements while maintaining data integrity and performance.
|
||||
147
docs/README.md
Normal file
147
docs/README.md
Normal file
@@ -0,0 +1,147 @@
|
||||
# StoryCove Documentation
|
||||
|
||||
Welcome to the StoryCove documentation! This directory contains comprehensive documentation for the StoryCove application.
|
||||
|
||||
## 📚 Documentation Files
|
||||
|
||||
### **[API Documentation](API.md)**
|
||||
Complete REST API reference with detailed endpoint descriptions, request/response examples, authentication details, and error handling.
|
||||
|
||||
**Contents:**
|
||||
- Authentication endpoints
|
||||
- Story management (CRUD, search, images)
|
||||
- Author management (profiles, avatars, URLs)
|
||||
- Tag system (creation, autocomplete, statistics)
|
||||
- Series management (organization, navigation)
|
||||
- File upload/download (images, validation)
|
||||
- Search and indexing (Typesense integration)
|
||||
- Configuration endpoints
|
||||
- Data Transfer Objects (DTOs)
|
||||
- Error handling and status codes
|
||||
|
||||
### **[Data Model Documentation](DATA_MODEL.md)**
|
||||
Detailed database schema documentation including entity relationships, constraints, indexes, and business rules.
|
||||
|
||||
**Contents:**
|
||||
- Entity Relationship Diagram
|
||||
- Detailed table specifications
|
||||
- Field types and constraints
|
||||
- Relationship mappings
|
||||
- Performance considerations
|
||||
- Backup and migration strategy
|
||||
|
||||
### **[OpenAPI Specification](openapi.yaml)**
|
||||
Machine-readable API specification in OpenAPI 3.0 format for API testing tools, code generation, and integration.
|
||||
|
||||
**Usage:**
|
||||
- Import into Postman, Insomnia, or similar tools
|
||||
- Generate client SDKs
|
||||
- API documentation hosting (Swagger UI)
|
||||
- Contract testing
|
||||
|
||||
## 🛠️ How to Use This Documentation
|
||||
|
||||
### **For Developers**
|
||||
1. Start with the [API Documentation](API.md) for endpoint details
|
||||
2. Reference [Data Model](DATA_MODEL.md) for database understanding
|
||||
3. Use [OpenAPI spec](openapi.yaml) for testing and integration
|
||||
4. See main [README](../README.md) for setup instructions
|
||||
|
||||
### **For API Integration**
|
||||
1. Review authentication flow in [API docs](API.md)
|
||||
2. Import [OpenAPI spec](openapi.yaml) into your API client
|
||||
3. Test endpoints using the provided examples
|
||||
4. Implement error handling based on documented responses
|
||||
|
||||
### **For Database Work**
|
||||
1. Study [Data Model](DATA_MODEL.md) for schema understanding
|
||||
2. Review relationship constraints and business rules
|
||||
3. Use entity diagrams for system architecture planning
|
||||
4. Follow migration guidelines for schema changes
|
||||
|
||||
### **For System Administration**
|
||||
1. Reference main [README](../README.md) for deployment instructions
|
||||
2. Use environment configuration examples
|
||||
3. Review backup strategies in [Data Model](DATA_MODEL.md)
|
||||
4. Monitor API health using documented endpoints
|
||||
|
||||
## 🔗 External Resources
|
||||
|
||||
### **Related Documentation**
|
||||
- **[Main README](../README.md)**: Project overview, setup, and deployment
|
||||
- **[Technical Specification](../storycove-spec.md)**: Comprehensive technical specification
|
||||
- **Environment Files**: `.env.example`, `.env.development`, `.env.production`
|
||||
|
||||
### **Technology Documentation**
|
||||
- **[Spring Boot](https://spring.io/projects/spring-boot)**: Backend framework
|
||||
- **[Next.js](https://nextjs.org/)**: Frontend framework
|
||||
- **[PostgreSQL](https://www.postgresql.org/docs/)**: Database system
|
||||
- **[Typesense](https://typesense.org/docs/)**: Search engine
|
||||
- **[Docker](https://docs.docker.com/)**: Containerization
|
||||
|
||||
## 📝 Documentation Standards
|
||||
|
||||
### **API Documentation**
|
||||
- All endpoints documented with examples
|
||||
- Request/response schemas included
|
||||
- Error scenarios covered
|
||||
- Authentication requirements specified
|
||||
|
||||
### **Code Examples**
|
||||
- JSON examples use realistic data
|
||||
- UUIDs formatted correctly
|
||||
- Timestamps in ISO 8601 format
|
||||
- Error responses include helpful messages
|
||||
|
||||
### **Data Model**
|
||||
- All tables and relationships documented
|
||||
- Constraints and validation rules specified
|
||||
- Performance implications noted
|
||||
- Migration considerations included
|
||||
|
||||
## 🤝 Contributing to Documentation
|
||||
|
||||
When updating the application:
|
||||
|
||||
1. **API Changes**: Update [API.md](API.md) and [openapi.yaml](openapi.yaml)
|
||||
2. **Database Changes**: Update [DATA_MODEL.md](DATA_MODEL.md)
|
||||
3. **Feature Changes**: Update main [README](../README.md) features section
|
||||
4. **Deployment Changes**: Update environment configuration examples
|
||||
|
||||
### **Documentation Checklist**
|
||||
- [ ] API endpoints documented with examples
|
||||
- [ ] Database schema changes reflected
|
||||
- [ ] OpenAPI specification updated
|
||||
- [ ] Error handling documented
|
||||
- [ ] Authentication requirements specified
|
||||
- [ ] Performance implications noted
|
||||
- [ ] Migration steps documented
|
||||
|
||||
## 📋 Quick Reference
|
||||
|
||||
### **Base URLs**
|
||||
- **Development**: `http://localhost:6925/api`
|
||||
- **Production**: `https://yourdomain.com/api`
|
||||
|
||||
### **Authentication**
|
||||
- **Method**: JWT tokens via httpOnly cookies
|
||||
- **Login**: `POST /api/auth/login`
|
||||
- **Token Expiry**: 24 hours
|
||||
|
||||
### **Key Endpoints**
|
||||
- **Stories**: `/api/stories`
|
||||
- **Authors**: `/api/authors`
|
||||
- **Tags**: `/api/tags`
|
||||
- **Series**: `/api/series`
|
||||
- **Search**: `/api/stories/search`
|
||||
- **Files**: `/api/files`
|
||||
|
||||
### **Common Response Codes**
|
||||
- **200**: Success
|
||||
- **201**: Created
|
||||
- **400**: Bad Request
|
||||
- **401**: Unauthorized
|
||||
- **404**: Not Found
|
||||
- **500**: Server Error
|
||||
|
||||
This documentation is maintained alongside the codebase to ensure accuracy and completeness. For questions or clarifications, please refer to the appropriate documentation file or create an issue in the project repository.
|
||||
583
docs/openapi.yaml
Normal file
583
docs/openapi.yaml
Normal file
@@ -0,0 +1,583 @@
|
||||
openapi: 3.0.3
|
||||
info:
|
||||
title: StoryCove API
|
||||
description: |
|
||||
StoryCove is a self-hosted web application for storing, organizing, and reading short stories from various internet sources.
|
||||
|
||||
## Features
|
||||
- Story management with HTML content support
|
||||
- Author profiles with ratings and metadata
|
||||
- Tag-based categorization and series organization
|
||||
- Full-text search powered by Typesense
|
||||
- Image upload for covers and avatars
|
||||
- JWT-based authentication
|
||||
|
||||
## Authentication
|
||||
All endpoints (except `/api/auth/login`) require JWT authentication via httpOnly cookies.
|
||||
|
||||
version: 1.0.0
|
||||
contact:
|
||||
name: StoryCove
|
||||
license:
|
||||
name: MIT
|
||||
|
||||
servers:
|
||||
- url: http://localhost:6925/api
|
||||
description: Local development server
|
||||
- url: https://storycove.hardegger.io/api
|
||||
description: Production server
|
||||
|
||||
security:
|
||||
- cookieAuth: []
|
||||
|
||||
paths:
|
||||
# Authentication endpoints
|
||||
/auth/login:
|
||||
post:
|
||||
tags: [Authentication]
|
||||
summary: Login with password
|
||||
description: Authenticate with application password and receive JWT token
|
||||
security: [] # No authentication required
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
required: [password]
|
||||
properties:
|
||||
password:
|
||||
type: string
|
||||
description: Application password
|
||||
responses:
|
||||
'200':
|
||||
description: Authentication successful
|
||||
headers:
|
||||
Set-Cookie:
|
||||
description: JWT token cookie
|
||||
schema:
|
||||
type: string
|
||||
example: token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...; HttpOnly; Max-Age=86400
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
message:
|
||||
type: string
|
||||
example: Authentication successful
|
||||
token:
|
||||
type: string
|
||||
example: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
|
||||
'401':
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
|
||||
/auth/logout:
|
||||
post:
|
||||
tags: [Authentication]
|
||||
summary: Logout and clear token
|
||||
description: Clear authentication token and logout
|
||||
responses:
|
||||
'200':
|
||||
description: Logout successful
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/MessageResponse'
|
||||
|
||||
/auth/verify:
|
||||
get:
|
||||
tags: [Authentication]
|
||||
summary: Verify token validity
|
||||
description: Check if current JWT token is valid
|
||||
responses:
|
||||
'200':
|
||||
description: Token is valid
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/MessageResponse'
|
||||
'401':
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
|
||||
# Story endpoints
|
||||
/stories:
|
||||
get:
|
||||
tags: [Stories]
|
||||
summary: List all stories
|
||||
description: Get paginated list of all stories
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/PageParam'
|
||||
- $ref: '#/components/parameters/SizeParam'
|
||||
- $ref: '#/components/parameters/SortByParam'
|
||||
- $ref: '#/components/parameters/SortDirParam'
|
||||
responses:
|
||||
'200':
|
||||
description: Stories retrieved successfully
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/PagedStories'
|
||||
'401':
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
|
||||
post:
|
||||
tags: [Stories]
|
||||
summary: Create new story
|
||||
description: Create a new story with optional author, series, and tags
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/CreateStoryRequest'
|
||||
responses:
|
||||
'201':
|
||||
description: Story created successfully
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/StoryDto'
|
||||
'400':
|
||||
$ref: '#/components/responses/BadRequest'
|
||||
'401':
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
|
||||
/stories/{id}:
|
||||
get:
|
||||
tags: [Stories]
|
||||
summary: Get story by ID
|
||||
description: Retrieve a specific story by its UUID
|
||||
parameters:
|
||||
- name: id
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
description: Story UUID
|
||||
responses:
|
||||
'200':
|
||||
description: Story retrieved successfully
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/StoryDto'
|
||||
'404':
|
||||
$ref: '#/components/responses/NotFound'
|
||||
'401':
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
|
||||
put:
|
||||
tags: [Stories]
|
||||
summary: Update story
|
||||
description: Update an existing story
|
||||
parameters:
|
||||
- name: id
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/UpdateStoryRequest'
|
||||
responses:
|
||||
'200':
|
||||
description: Story updated successfully
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/StoryDto'
|
||||
'400':
|
||||
$ref: '#/components/responses/BadRequest'
|
||||
'404':
|
||||
$ref: '#/components/responses/NotFound'
|
||||
'401':
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
|
||||
delete:
|
||||
tags: [Stories]
|
||||
summary: Delete story
|
||||
description: Delete a story and all its relationships
|
||||
parameters:
|
||||
- name: id
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
responses:
|
||||
'200':
|
||||
description: Story deleted successfully
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/MessageResponse'
|
||||
'404':
|
||||
$ref: '#/components/responses/NotFound'
|
||||
'401':
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
|
||||
/stories/search:
|
||||
get:
|
||||
tags: [Stories]
|
||||
summary: Search stories
|
||||
description: Search stories using Typesense full-text search
|
||||
parameters:
|
||||
- name: query
|
||||
in: query
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
description: Search query
|
||||
- $ref: '#/components/parameters/PageParam'
|
||||
- $ref: '#/components/parameters/SizeParam'
|
||||
- name: authors
|
||||
in: query
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
description: Filter by author names
|
||||
- name: tags
|
||||
in: query
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
description: Filter by tag names
|
||||
- name: minRating
|
||||
in: query
|
||||
schema:
|
||||
type: integer
|
||||
minimum: 1
|
||||
maximum: 5
|
||||
- name: maxRating
|
||||
in: query
|
||||
schema:
|
||||
type: integer
|
||||
minimum: 1
|
||||
maximum: 5
|
||||
responses:
|
||||
'200':
|
||||
description: Search results
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/SearchResult'
|
||||
'401':
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
|
||||
components:
|
||||
securitySchemes:
|
||||
cookieAuth:
|
||||
type: apiKey
|
||||
in: cookie
|
||||
name: token
|
||||
|
||||
parameters:
|
||||
PageParam:
|
||||
name: page
|
||||
in: query
|
||||
schema:
|
||||
type: integer
|
||||
minimum: 0
|
||||
default: 0
|
||||
description: Page number (0-based)
|
||||
|
||||
SizeParam:
|
||||
name: size
|
||||
in: query
|
||||
schema:
|
||||
type: integer
|
||||
minimum: 1
|
||||
maximum: 100
|
||||
default: 20
|
||||
description: Page size
|
||||
|
||||
SortByParam:
|
||||
name: sortBy
|
||||
in: query
|
||||
schema:
|
||||
type: string
|
||||
default: createdAt
|
||||
description: Field to sort by
|
||||
|
||||
SortDirParam:
|
||||
name: sortDir
|
||||
in: query
|
||||
schema:
|
||||
type: string
|
||||
enum: [asc, desc]
|
||||
default: desc
|
||||
description: Sort direction
|
||||
|
||||
schemas:
|
||||
StoryDto:
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
format: uuid
|
||||
title:
|
||||
type: string
|
||||
summary:
|
||||
type: string
|
||||
nullable: true
|
||||
description:
|
||||
type: string
|
||||
nullable: true
|
||||
contentHtml:
|
||||
type: string
|
||||
nullable: true
|
||||
contentPlain:
|
||||
type: string
|
||||
nullable: true
|
||||
sourceUrl:
|
||||
type: string
|
||||
nullable: true
|
||||
coverPath:
|
||||
type: string
|
||||
nullable: true
|
||||
wordCount:
|
||||
type: integer
|
||||
rating:
|
||||
type: integer
|
||||
minimum: 1
|
||||
maximum: 5
|
||||
nullable: true
|
||||
volume:
|
||||
type: integer
|
||||
nullable: true
|
||||
authorId:
|
||||
type: string
|
||||
format: uuid
|
||||
nullable: true
|
||||
authorName:
|
||||
type: string
|
||||
nullable: true
|
||||
seriesId:
|
||||
type: string
|
||||
format: uuid
|
||||
nullable: true
|
||||
seriesName:
|
||||
type: string
|
||||
nullable: true
|
||||
tags:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/TagDto'
|
||||
createdAt:
|
||||
type: string
|
||||
format: date-time
|
||||
updatedAt:
|
||||
type: string
|
||||
format: date-time
|
||||
|
||||
CreateStoryRequest:
|
||||
type: object
|
||||
required: [title]
|
||||
properties:
|
||||
title:
|
||||
type: string
|
||||
maxLength: 255
|
||||
summary:
|
||||
type: string
|
||||
description:
|
||||
type: string
|
||||
maxLength: 1000
|
||||
contentHtml:
|
||||
type: string
|
||||
sourceUrl:
|
||||
type: string
|
||||
volume:
|
||||
type: integer
|
||||
authorId:
|
||||
type: string
|
||||
format: uuid
|
||||
authorName:
|
||||
type: string
|
||||
seriesId:
|
||||
type: string
|
||||
format: uuid
|
||||
seriesName:
|
||||
type: string
|
||||
tagNames:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
|
||||
UpdateStoryRequest:
|
||||
type: object
|
||||
properties:
|
||||
title:
|
||||
type: string
|
||||
maxLength: 255
|
||||
summary:
|
||||
type: string
|
||||
description:
|
||||
type: string
|
||||
maxLength: 1000
|
||||
contentHtml:
|
||||
type: string
|
||||
sourceUrl:
|
||||
type: string
|
||||
volume:
|
||||
type: integer
|
||||
authorId:
|
||||
type: string
|
||||
format: uuid
|
||||
seriesId:
|
||||
type: string
|
||||
format: uuid
|
||||
tagNames:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
|
||||
TagDto:
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
format: uuid
|
||||
name:
|
||||
type: string
|
||||
storyCount:
|
||||
type: integer
|
||||
createdAt:
|
||||
type: string
|
||||
format: date-time
|
||||
updatedAt:
|
||||
type: string
|
||||
format: date-time
|
||||
|
||||
PagedStories:
|
||||
type: object
|
||||
properties:
|
||||
content:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/StoryDto'
|
||||
pageable:
|
||||
$ref: '#/components/schemas/Pageable'
|
||||
totalElements:
|
||||
type: integer
|
||||
totalPages:
|
||||
type: integer
|
||||
last:
|
||||
type: boolean
|
||||
first:
|
||||
type: boolean
|
||||
numberOfElements:
|
||||
type: integer
|
||||
size:
|
||||
type: integer
|
||||
number:
|
||||
type: integer
|
||||
empty:
|
||||
type: boolean
|
||||
|
||||
Pageable:
|
||||
type: object
|
||||
properties:
|
||||
sort:
|
||||
$ref: '#/components/schemas/Sort'
|
||||
pageNumber:
|
||||
type: integer
|
||||
pageSize:
|
||||
type: integer
|
||||
offset:
|
||||
type: integer
|
||||
paged:
|
||||
type: boolean
|
||||
unpaged:
|
||||
type: boolean
|
||||
|
||||
Sort:
|
||||
type: object
|
||||
properties:
|
||||
sorted:
|
||||
type: boolean
|
||||
unsorted:
|
||||
type: boolean
|
||||
|
||||
SearchResult:
|
||||
type: object
|
||||
properties:
|
||||
results:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/StoryDto'
|
||||
totalHits:
|
||||
type: integer
|
||||
format: int64
|
||||
page:
|
||||
type: integer
|
||||
perPage:
|
||||
type: integer
|
||||
query:
|
||||
type: string
|
||||
searchTimeMs:
|
||||
type: integer
|
||||
format: int64
|
||||
|
||||
MessageResponse:
|
||||
type: object
|
||||
properties:
|
||||
message:
|
||||
type: string
|
||||
|
||||
ErrorResponse:
|
||||
type: object
|
||||
properties:
|
||||
error:
|
||||
type: string
|
||||
details:
|
||||
type: object
|
||||
additionalProperties:
|
||||
type: string
|
||||
|
||||
responses:
|
||||
BadRequest:
|
||||
description: Bad request - validation error
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
|
||||
Unauthorized:
|
||||
description: Authentication required or invalid token
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
|
||||
NotFound:
|
||||
description: Resource not found
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
|
||||
tags:
|
||||
- name: Authentication
|
||||
description: Authentication endpoints
|
||||
- name: Stories
|
||||
description: Story management endpoints
|
||||
- name: Authors
|
||||
description: Author management endpoints
|
||||
- name: Tags
|
||||
description: Tag management endpoints
|
||||
- name: Series
|
||||
description: Series management endpoints
|
||||
- name: Files
|
||||
description: File upload and management endpoints
|
||||
- name: Search
|
||||
description: Search and indexing endpoints
|
||||
- name: Configuration
|
||||
description: Application configuration endpoints
|
||||
Reference in New Issue
Block a user