16 KiB
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)
- Deploy for your environment:
# For development
./deploy.sh development
# For staging
./deploy.sh staging
# For production (edit .env.production first with your values)
./deploy.sh production
- Edit the environment file (
.env.development,.env.staging, or.env.production) with your specific configuration
Option 2: Manual Configuration
- Copy environment variables:
cp .env.example .env
-
Edit
.envwith secure values for all variables -
Start the application:
docker-compose up -d
- 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 accessibleSTORYCOVE_CORS_ALLOWED_ORIGINS- Comma-separated list of allowed CORS originsDB_PASSWORD- PostgreSQL database passwordJWT_SECRET- Secret key for JWT token signing (minimum 32 characters)APP_PASSWORD- Application login passwordTYPESENSE_API_KEY- API key for Typesense search serviceNEXT_PUBLIC_API_URL- Frontend API URL (for development only)
Deployment Examples
For a production deployment at https://stories.example.com:
# 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:
./deploy.sh development
Development
Frontend Development
cd frontend
npm install
npm run dev
Backend Development
cd backend
./mvnw spring-boot:run
Commands
docker-compose up -d- Start all servicesdocker-compose down- Stop all servicesdocker-compose logs -f [service]- View logsdocker-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: Complete technical specification with API documentation, data models, and all feature specifications
- Web Scraper Specification: 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 passwordPOST /logout- Clear authentication tokenGET /verify- Verify token validity
Stories (/api/stories)
GET /- List stories (paginated)GET /{id}- Get specific storyGET /{id}/read- Get story for reading interfacePOST /- Create new storyPUT /{id}- Update storyDELETE /{id}- Delete storyPOST /{id}/cover- Upload cover imageDELETE /{id}/cover- Remove cover imagePOST /{id}/rating- Set story ratingPOST /{id}/tags/{tagId}- Add tag to storyDELETE /{id}/tags/{tagId}- Remove tag from storyPOST /{id}/reading-progress- Update reading positionPOST /{id}/reading-status- Mark story as read/unreadGET /{id}/collections- Get collections containing storyGET /random- Get random story with optional filtersGET /check-duplicate- Check for duplicate storiesGET /search- Search stories (Typesense with faceting)GET /search/suggestions- Get search suggestionsGET /author/{authorId}- Stories by authorGET /series/{seriesId}- Stories in seriesGET /tags/{tagName}- Stories with tagGET /recent- Recent storiesGET /top-rated- Top-rated storiesPOST /batch/add-to-collection- Add multiple stories to collectionPOST /reindex- Manual Typesense reindexPOST /reindex-typesense- Reindex stories in TypesensePOST /recreate-typesense-collection- Recreate Typesense collection
EPUB Import/Export (/api/stories/epub)
POST /import- Import story from EPUB filePOST /export- Export story as EPUB with optionsGET /{id}/epub- Export story as EPUB (simple)POST /validate- Validate EPUB file structure
Authors (/api/authors)
GET /- List authors (paginated)GET /{id}- Get specific authorPOST /- Create new authorPUT /{id}- Update author (JSON or multipart)DELETE /{id}- Delete authorPOST /{id}/avatar- Upload avatar imageDELETE /{id}/avatar- Remove avatar imagePOST /{id}/rating- Set author ratingPOST /{id}/urls- Add URL to authorDELETE /{id}/urls- Remove URL from authorGET /search- Search authorsGET /search-typesense- Advanced author searchGET /top-rated- Top-rated authors
Tags (/api/tags)
GET /- List tags (paginated)GET /{id}- Get specific tagPOST /- Create new tag (with color and description)PUT /{id}- Update tag (name, color, description)DELETE /{id}- Delete tagGET /search- Search tagsGET /autocomplete- Tag autocomplete with alias resolutionGET /popular- Most used tagsGET /unused- Unused tagsGET /stats- Tag statisticsGET /collections- Tags used by collectionsGET /resolve/{name}- Resolve tag name (handles aliases)
Tag Aliases (/api/tags/{tagId}/aliases)
POST /- Add alias to tagDELETE /{aliasId}- Remove alias from tag
Tag Management
POST /merge- Merge multiple tags into onePOST /merge/preview- Preview tag merge operationPOST /suggest- AI-powered tag suggestions for content
Collections (/api/collections)
GET /- Search and list collections (Typesense)GET /{id}- Get collection detailsPOST /- Create new collection (JSON or multipart)PUT /{id}- Update collection metadataDELETE /{id}- Delete collectionPUT /{id}/archive- Archive/unarchive collectionPOST /{id}/cover- Upload collection cover imageDELETE /{id}/cover- Remove collection cover imageGET /{id}/stats- Get collection statistics
Collection Story Management
POST /{id}/stories- Add stories to collectionDELETE /{id}/stories/{storyId}- Remove story from collectionPUT /{id}/stories/order- Reorder stories in collectionGET /{id}/read/{storyId}- Get story with collection context
Collection EPUB Export
GET /{id}/epub- Export collection as EPUBPOST /{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 seriesPOST /- Create new seriesPUT /{id}- Update seriesDELETE /{id}- Delete seriesGET /search- Search seriesGET /with-stories- Series with storiesGET /popular- Popular seriesGET /empty- Empty seriesGET /stats- Series statistics
Files (/api/files)
POST /upload/cover- Upload cover imagePOST /upload/avatar- Upload avatar imageGET /images/**- Serve image filesDELETE /images- Delete image file
Search (/api/search)
POST /reindex- Reindex all contentGET /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
-
Prerequisites:
# Required - Docker & Docker Compose - Node.js 18+ (for frontend development) - Java 21+ (for backend development) -
Environment Setup:
# Copy environment template cp .env.example .env # Edit environment variables vim .env -
Database Setup:
# Start database only docker-compose up -d postgres -
Backend Development:
cd backend ./mvnw spring-boot:run -
Frontend Development:
cd frontend npm install npm run dev -
Full Stack Development:
# Start all services docker-compose up -d # View logs docker-compose logs -f
Testing
# 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.