448 lines
16 KiB
Markdown
448 lines
16 KiB
Markdown
# StoryCove
|
|
|
|
A self-hosted web application for storing, organizing, and reading short stories from various internet sources.
|
|
|
|
## Quick Start
|
|
|
|
### Option 1: Using Environment-Specific Deployment (Recommended)
|
|
|
|
1. Deploy for your environment:
|
|
```bash
|
|
# For development
|
|
./deploy.sh development
|
|
|
|
# For staging
|
|
./deploy.sh staging
|
|
|
|
# For production (edit .env.production first with your values)
|
|
./deploy.sh production
|
|
```
|
|
|
|
2. Edit the environment file (`.env.development`, `.env.staging`, or `.env.production`) with your specific configuration
|
|
|
|
### Option 2: Manual Configuration
|
|
|
|
1. Copy environment variables:
|
|
```bash
|
|
cp .env.example .env
|
|
```
|
|
|
|
2. Edit `.env` with secure values for all variables
|
|
|
|
3. Start the application:
|
|
```bash
|
|
docker-compose up -d
|
|
```
|
|
|
|
4. Access the application at the URL specified in your environment configuration (default: http://localhost:6925)
|
|
|
|
## Architecture
|
|
|
|
- **Frontend**: Next.js (Port 3000)
|
|
- **Backend**: Spring Boot (Port 8080)
|
|
- **Database**: PostgreSQL (Port 5432)
|
|
- **Search**: Typesense (Port 8108)
|
|
- **Proxy**: Nginx (Port 80)
|
|
|
|
## Environment Configuration
|
|
|
|
StoryCove supports different deployment environments with specific configuration files:
|
|
|
|
### Environment Files
|
|
|
|
- `.env.development` - Local development with Docker
|
|
- `.env.staging` - Staging/testing environment
|
|
- `.env.production` - Production deployment
|
|
- `.env.example` - Template with all available options
|
|
|
|
### Key Environment Variables
|
|
|
|
- `STORYCOVE_PUBLIC_URL` - The public URL where your app is accessible
|
|
- `STORYCOVE_CORS_ALLOWED_ORIGINS` - Comma-separated list of allowed CORS origins
|
|
- `DB_PASSWORD` - PostgreSQL database password
|
|
- `JWT_SECRET` - Secret key for JWT token signing (minimum 32 characters)
|
|
- `APP_PASSWORD` - Application login password
|
|
- `TYPESENSE_API_KEY` - API key for Typesense search service
|
|
- `NEXT_PUBLIC_API_URL` - Frontend API URL (for development only)
|
|
|
|
### Deployment Examples
|
|
|
|
For a production deployment at `https://stories.example.com`:
|
|
```bash
|
|
# Edit .env.production
|
|
STORYCOVE_PUBLIC_URL=https://stories.example.com
|
|
STORYCOVE_CORS_ALLOWED_ORIGINS=https://stories.example.com
|
|
|
|
# Deploy
|
|
./deploy.sh production
|
|
```
|
|
|
|
For local development:
|
|
```bash
|
|
./deploy.sh development
|
|
```
|
|
|
|
## Development
|
|
|
|
### Frontend Development
|
|
```bash
|
|
cd frontend
|
|
npm install
|
|
npm run dev
|
|
```
|
|
|
|
### Backend Development
|
|
```bash
|
|
cd backend
|
|
./mvnw spring-boot:run
|
|
```
|
|
|
|
### Commands
|
|
- `docker-compose up -d` - Start all services
|
|
- `docker-compose down` - Stop all services
|
|
- `docker-compose logs -f [service]` - View logs
|
|
- `docker-compose build` - Rebuild containers
|
|
|
|
## ✨ Features
|
|
|
|
### 📚 **Story Management**
|
|
- **Rich Text Support**: HTML content with automatic plain text extraction
|
|
- **Content Sanitization**: Secure HTML processing with customizable sanitization rules
|
|
- **Metadata Management**: Title, summary, description, source URL tracking
|
|
- **Rating System**: 5-star rating system for stories
|
|
- **Word Count**: Automatic word count calculation
|
|
- **Cover Images**: Upload and manage story cover images
|
|
- **Series Support**: Organize stories into series with volume numbers
|
|
|
|
### 👤 **Author Management**
|
|
- **Author Profiles**: Comprehensive author information with notes
|
|
- **Avatar Images**: Upload and manage author profile pictures
|
|
- **URL Collections**: Track multiple URLs per author (websites, social media, etc.)
|
|
- **Author Ratings**: Rate authors with 5-star system
|
|
- **Statistics**: View author statistics and story counts
|
|
|
|
### 🏷️ **Organization & Discovery**
|
|
- **Tag System**: Flexible tagging with autocomplete
|
|
- **Series Organization**: Group related stories with volume ordering
|
|
- **Search & Filter**: Full-text search powered by Typesense
|
|
- **Advanced Filtering**: Filter by author, tags, ratings, and more
|
|
- **Smart Suggestions**: Auto-complete for tags and search queries
|
|
|
|
### 🎨 **User Experience**
|
|
- **Dark/Light Mode**: Automatic theme switching with system preference detection
|
|
- **Responsive Design**: Optimized for desktop, tablet, and mobile
|
|
- **Reading Mode**: Distraction-free reading interface with real-time progress tracking
|
|
- **Reading Position Memory**: Character-based position tracking with smooth auto-scroll restoration
|
|
- **Smart Tag Filtering**: Dynamic tag filters with live story counts in library view
|
|
- **Keyboard Navigation**: Full keyboard accessibility
|
|
- **Rich Text Editor**: Visual and source editing modes for story content
|
|
- **Progress Indicators**: Visual reading progress bars and completion tracking
|
|
|
|
### 🔒 **Security & Administration**
|
|
- **JWT Authentication**: Secure token-based authentication
|
|
- **Single Password**: Simplified access control
|
|
- **HTML Sanitization**: Prevent XSS attacks with configurable sanitization
|
|
- **CORS Configuration**: Environment-specific CORS settings
|
|
- **File Upload Security**: Secure image upload with validation
|
|
|
|
### 🚀 **Technical Features**
|
|
- **Full-Text Search**: Powered by Typesense search engine
|
|
- **RESTful API**: Comprehensive REST API for all operations
|
|
- **Database Optimization**: PostgreSQL with proper indexing
|
|
- **Image Processing**: Automatic image optimization and storage
|
|
- **Environment Configuration**: Multi-environment deployment support
|
|
- **Docker Deployment**: Complete containerized deployment
|
|
|
|
### 📊 **Analytics & Statistics**
|
|
- **Usage Statistics**: Track story counts, tag usage, and more
|
|
- **Rating Analytics**: View average ratings and distributions
|
|
- **Search Analytics**: Monitor search performance and suggestions
|
|
- **Storage Metrics**: Track image storage and database usage
|
|
|
|
## 📖 Documentation
|
|
|
|
- **[Technical Specification](storycove-spec.md)**: Complete technical specification with API documentation, data models, and all feature specifications
|
|
- **[Web Scraper Specification](storycove-scraper-spec.md)**: URL content grabbing functionality
|
|
- **Environment Configuration**: Multi-environment deployment setup (see above)
|
|
- **Development Setup**: Local development environment setup (see below)
|
|
|
|
> **Note**: All feature specifications (Collections, Tag Enhancements, EPUB Import/Export) have been consolidated into the main technical specification for easier maintenance and reference.
|
|
|
|
## 🗄️ Data Model
|
|
|
|
StoryCove uses a PostgreSQL database with the following core entities:
|
|
|
|
### **Stories**
|
|
- **Primary Key**: UUID
|
|
- **Fields**: title, summary, description, content_html, content_plain, source_url, word_count, rating, volume, cover_path, is_read, reading_position, last_read_at, created_at, updated_at
|
|
- **Relationships**: Many-to-One with Author, Many-to-One with Series, Many-to-Many with Tags, One-to-Many with ReadingPositions
|
|
- **Features**: Automatic word count calculation, HTML sanitization, plain text extraction, reading progress tracking, duplicate detection
|
|
|
|
### **Authors**
|
|
- **Primary Key**: UUID
|
|
- **Fields**: name, notes, author_rating, avatar_image_path, created_at, updated_at
|
|
- **Relationships**: One-to-Many with Stories, One-to-Many with Author URLs (via @ElementCollection)
|
|
- **Features**: URL collection storage, rating system, statistics calculation, average story rating calculation
|
|
|
|
### **Collections**
|
|
- **Primary Key**: UUID
|
|
- **Fields**: name, description, rating, cover_image_path, is_archived, created_at, updated_at
|
|
- **Relationships**: Many-to-Many with Tags, One-to-Many with CollectionStories
|
|
- **Features**: Story ordering with gap-based positioning, statistics calculation, EPUB export, Typesense search
|
|
|
|
### **CollectionStories** (Junction Table)
|
|
- **Composite Key**: collection_id, story_id
|
|
- **Fields**: position, added_at
|
|
- **Relationships**: Links Collections to Stories with ordering
|
|
- **Features**: Gap-based positioning for efficient reordering
|
|
|
|
### **Series**
|
|
- **Primary Key**: UUID
|
|
- **Fields**: name, description, created_at
|
|
- **Relationships**: One-to-Many with Stories (ordered by volume)
|
|
- **Features**: Volume-based story ordering, navigation methods (next/previous story)
|
|
|
|
### **Tags**
|
|
- **Primary Key**: UUID
|
|
- **Fields**: name (unique), color (hex), description, created_at
|
|
- **Relationships**: Many-to-Many with Stories, Many-to-Many with Collections, One-to-Many with TagAliases
|
|
- **Features**: Color coding, alias system, autocomplete support, usage statistics, AI-powered suggestions
|
|
|
|
### **TagAliases**
|
|
- **Primary Key**: UUID
|
|
- **Fields**: alias_name (unique), canonical_tag_id, created_from_merge, created_at
|
|
- **Relationships**: Many-to-One with Tag (canonical)
|
|
- **Features**: Transparent alias resolution, merge tracking, autocomplete integration
|
|
|
|
### **ReadingPositions**
|
|
- **Primary Key**: UUID
|
|
- **Fields**: story_id, chapter_index, chapter_title, word_position, character_position, percentage_complete, epub_cfi, context_before, context_after, created_at, updated_at
|
|
- **Relationships**: Many-to-One with Story
|
|
- **Features**: Advanced reading position tracking, EPUB CFI support, context preservation, percentage calculation
|
|
|
|
### **Libraries**
|
|
- **Primary Key**: UUID
|
|
- **Fields**: name, description, is_default, created_at, updated_at
|
|
- **Features**: Multi-library support, library switching functionality
|
|
|
|
### **Core Join Tables**
|
|
- **story_tags**: Links stories to tags (Many-to-Many)
|
|
- **collection_tags**: Links collections to tags (Many-to-Many)
|
|
- **collection_stories**: Links collections to stories with ordering
|
|
- **author_urls**: Stores multiple URLs per author (@ElementCollection)
|
|
|
|
## 🔌 REST API Reference
|
|
|
|
### **Authentication** (`/api/auth`)
|
|
- `POST /login` - Authenticate with password
|
|
- `POST /logout` - Clear authentication token
|
|
- `GET /verify` - Verify token validity
|
|
|
|
### **Stories** (`/api/stories`)
|
|
- `GET /` - List stories (paginated)
|
|
- `GET /{id}` - Get specific story
|
|
- `GET /{id}/read` - Get story for reading interface
|
|
- `POST /` - Create new story
|
|
- `PUT /{id}` - Update story
|
|
- `DELETE /{id}` - Delete story
|
|
- `POST /{id}/cover` - Upload cover image
|
|
- `DELETE /{id}/cover` - Remove cover image
|
|
- `POST /{id}/rating` - Set story rating
|
|
- `POST /{id}/tags/{tagId}` - Add tag to story
|
|
- `DELETE /{id}/tags/{tagId}` - Remove tag from story
|
|
- `POST /{id}/reading-progress` - Update reading position
|
|
- `POST /{id}/reading-status` - Mark story as read/unread
|
|
- `GET /{id}/collections` - Get collections containing story
|
|
- `GET /random` - Get random story with optional filters
|
|
- `GET /check-duplicate` - Check for duplicate stories
|
|
- `GET /search` - Search stories (Typesense with faceting)
|
|
- `GET /search/suggestions` - Get search suggestions
|
|
- `GET /author/{authorId}` - Stories by author
|
|
- `GET /series/{seriesId}` - Stories in series
|
|
- `GET /tags/{tagName}` - Stories with tag
|
|
- `GET /recent` - Recent stories
|
|
- `GET /top-rated` - Top-rated stories
|
|
- `POST /batch/add-to-collection` - Add multiple stories to collection
|
|
- `POST /reindex` - Manual Typesense reindex
|
|
- `POST /reindex-typesense` - Reindex stories in Typesense
|
|
- `POST /recreate-typesense-collection` - Recreate Typesense collection
|
|
|
|
#### **EPUB Import/Export** (`/api/stories/epub`)
|
|
- `POST /import` - Import story from EPUB file
|
|
- `POST /export` - Export story as EPUB with options
|
|
- `GET /{id}/epub` - Export story as EPUB (simple)
|
|
- `POST /validate` - Validate EPUB file structure
|
|
|
|
### **Authors** (`/api/authors`)
|
|
- `GET /` - List authors (paginated)
|
|
- `GET /{id}` - Get specific author
|
|
- `POST /` - Create new author
|
|
- `PUT /{id}` - Update author (JSON or multipart)
|
|
- `DELETE /{id}` - Delete author
|
|
- `POST /{id}/avatar` - Upload avatar image
|
|
- `DELETE /{id}/avatar` - Remove avatar image
|
|
- `POST /{id}/rating` - Set author rating
|
|
- `POST /{id}/urls` - Add URL to author
|
|
- `DELETE /{id}/urls` - Remove URL from author
|
|
- `GET /search` - Search authors
|
|
- `GET /search-typesense` - Advanced author search
|
|
- `GET /top-rated` - Top-rated authors
|
|
|
|
### **Tags** (`/api/tags`)
|
|
- `GET /` - List tags (paginated)
|
|
- `GET /{id}` - Get specific tag
|
|
- `POST /` - Create new tag (with color and description)
|
|
- `PUT /{id}` - Update tag (name, color, description)
|
|
- `DELETE /{id}` - Delete tag
|
|
- `GET /search` - Search tags
|
|
- `GET /autocomplete` - Tag autocomplete with alias resolution
|
|
- `GET /popular` - Most used tags
|
|
- `GET /unused` - Unused tags
|
|
- `GET /stats` - Tag statistics
|
|
- `GET /collections` - Tags used by collections
|
|
- `GET /resolve/{name}` - Resolve tag name (handles aliases)
|
|
|
|
#### **Tag Aliases** (`/api/tags/{tagId}/aliases`)
|
|
- `POST /` - Add alias to tag
|
|
- `DELETE /{aliasId}` - Remove alias from tag
|
|
|
|
#### **Tag Management**
|
|
- `POST /merge` - Merge multiple tags into one
|
|
- `POST /merge/preview` - Preview tag merge operation
|
|
- `POST /suggest` - AI-powered tag suggestions for content
|
|
|
|
### **Collections** (`/api/collections`)
|
|
- `GET /` - Search and list collections (Typesense)
|
|
- `GET /{id}` - Get collection details
|
|
- `POST /` - Create new collection (JSON or multipart)
|
|
- `PUT /{id}` - Update collection metadata
|
|
- `DELETE /{id}` - Delete collection
|
|
- `PUT /{id}/archive` - Archive/unarchive collection
|
|
- `POST /{id}/cover` - Upload collection cover image
|
|
- `DELETE /{id}/cover` - Remove collection cover image
|
|
- `GET /{id}/stats` - Get collection statistics
|
|
|
|
#### **Collection Story Management**
|
|
- `POST /{id}/stories` - Add stories to collection
|
|
- `DELETE /{id}/stories/{storyId}` - Remove story from collection
|
|
- `PUT /{id}/stories/order` - Reorder stories in collection
|
|
- `GET /{id}/read/{storyId}` - Get story with collection context
|
|
|
|
#### **Collection EPUB Export**
|
|
- `GET /{id}/epub` - Export collection as EPUB
|
|
- `POST /{id}/epub` - Export collection as EPUB with options
|
|
|
|
#### **Collection Management**
|
|
- `POST /reindex-typesense` - Reindex collections in Typesense
|
|
|
|
### **Series** (`/api/series`)
|
|
- `GET /` - List series (paginated)
|
|
- `GET /{id}` - Get specific series
|
|
- `POST /` - Create new series
|
|
- `PUT /{id}` - Update series
|
|
- `DELETE /{id}` - Delete series
|
|
- `GET /search` - Search series
|
|
- `GET /with-stories` - Series with stories
|
|
- `GET /popular` - Popular series
|
|
- `GET /empty` - Empty series
|
|
- `GET /stats` - Series statistics
|
|
|
|
### **Files** (`/api/files`)
|
|
- `POST /upload/cover` - Upload cover image
|
|
- `POST /upload/avatar` - Upload avatar image
|
|
- `GET /images/**` - Serve image files
|
|
- `DELETE /images` - Delete image file
|
|
|
|
### **Search** (`/api/search`)
|
|
- `POST /reindex` - Reindex all content
|
|
- `GET /health` - Search service health
|
|
|
|
### **Configuration** (`/api/config`)
|
|
- `GET /html-sanitization` - Get HTML sanitization rules
|
|
|
|
### **Request/Response Format**
|
|
All API endpoints use JSON format with proper HTTP status codes:
|
|
- **200**: Success
|
|
- **201**: Created
|
|
- **400**: Bad Request (validation errors)
|
|
- **401**: Unauthorized
|
|
- **404**: Not Found
|
|
- **500**: Internal Server Error
|
|
|
|
### **Authentication**
|
|
- JWT tokens provided via httpOnly cookies
|
|
- All endpoints (except `/api/auth/login`) require authentication
|
|
- Tokens expire after 24 hours
|
|
|
|
## 🔧 Development
|
|
|
|
### **Technology Stack**
|
|
- **Frontend**: Next.js 14, TypeScript, Tailwind CSS, React
|
|
- **Backend**: Spring Boot 3, Java 21, PostgreSQL, Typesense
|
|
- **Infrastructure**: Docker, Docker Compose, Nginx
|
|
- **Security**: JWT authentication, HTML sanitization, CORS
|
|
- **Search**: Typesense with faceting and full-text search capabilities
|
|
|
|
### **Local Development Setup**
|
|
|
|
1. **Prerequisites**:
|
|
```bash
|
|
# Required
|
|
- Docker & Docker Compose
|
|
- Node.js 18+ (for frontend development)
|
|
- Java 21+ (for backend development)
|
|
```
|
|
|
|
2. **Environment Setup**:
|
|
```bash
|
|
# Copy environment template
|
|
cp .env.example .env
|
|
|
|
# Edit environment variables
|
|
vim .env
|
|
```
|
|
|
|
3. **Database Setup**:
|
|
```bash
|
|
# Start database only
|
|
docker-compose up -d postgres
|
|
```
|
|
|
|
4. **Backend Development**:
|
|
```bash
|
|
cd backend
|
|
./mvnw spring-boot:run
|
|
```
|
|
|
|
5. **Frontend Development**:
|
|
```bash
|
|
cd frontend
|
|
npm install
|
|
npm run dev
|
|
```
|
|
|
|
6. **Full Stack Development**:
|
|
```bash
|
|
# Start all services
|
|
docker-compose up -d
|
|
|
|
# View logs
|
|
docker-compose logs -f
|
|
```
|
|
|
|
### **Testing**
|
|
```bash
|
|
# Backend tests
|
|
cd backend && ./mvnw test
|
|
|
|
# Frontend build
|
|
cd frontend && npm run build
|
|
|
|
# Frontend linting
|
|
cd frontend && npm run lint
|
|
```
|
|
|
|
### **Database Migrations**
|
|
The application uses Hibernate with `ddl-auto: update` for schema management. For production deployments, consider using Flyway or Liquibase for controlled migrations.
|
|
|
|
For detailed technical specifications, see `storycove-spec.md`. |