- Add Express.js backend with REST API - Implement comprehensive security measures (helmet, rate limiting, input validation) - Add Docker volume support for persistent JSON storage - Update container security (non-root user, minimal Alpine) - Add deployment and security documentation - Configure production-ready Docker setup with Coolify compatibility 🤖 Generated with Claude Code (https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
4.2 KiB
4.2 KiB
Docker Volume JSON Storage Deployment Guide
The Reading Tracker app now supports persistent JSON storage using Docker volumes, enabling multi-device access and data persistence across container restarts.
Architecture Overview
The application now consists of:
- Frontend: React SPA (served by Express in production)
- Backend: Express.js server with API endpoints
- Storage: JSON files in Docker volume (
/app/data) - Fallback: localStorage for offline/server unavailable scenarios
Docker Deployment
Quick Start with Docker Compose
# Build and start the application
docker-compose up -d
# The app will be available at http://localhost:8080
Manual Docker Commands
# Build the image
docker build -t reading-tracker:latest .
# Run with persistent storage
docker run -d \
--name reading-tracker \
-p 8080:80 \
-v reading-data:/app/data \
--restart unless-stopped \
reading-tracker:latest
For Coolify or Similar Platforms
Use these settings:
- Port: 80 (internal), map to your desired external port
- Volume Mount:
/app/data(for JSON storage) - Health Check:
GET /api/health - Environment Variables:
NODE_ENV=productionDATA_DIR=/app/data(optional, defaults to/app/data)ALLOWED_ORIGINS=https://your-domain.com(comma-separated for production CORS)
API Endpoints
GET /api/books- Load all books from JSON storagePOST /api/books- Save books array to JSON storageGET /api/health- Health check endpoint
Data Storage Details
File Location
- Production:
/app/data/books.json(Docker volume) - Development:
./data/books.json(local directory)
JSON Format
{
"books": [
{
"id": 1,
"title": "Book Title",
"author": "Author Name",
"totalPages": 300,
"currentPage": 150,
"startDate": "2025-01-01",
"targetDate": "2025-02-01",
"readingHistory": {
"2025-01-01": 10,
"2025-01-02": 25
},
"createdAt": "2025-01-01T00:00:00.000Z"
}
],
"lastModified": "2025-08-17T21:46:52.274Z",
"version": "1.0"
}
Security Features
- Security Headers: Helmet.js with CSP, anti-clickjacking, MIME protection
- Rate Limiting: 100 req/15min general, 20 req/15min for saves
- Input Validation: String limits, numeric bounds, date format validation
- CORS Protection: Configurable origins for production
- Error Disclosure Prevention: Generic error messages, sanitized logs
- Container Security: Non-root user, minimal Alpine base image
📋 See SECURITY.md for complete security documentation
Fallback Behavior
The app gracefully handles server unavailability:
- Load Priority: Server JSON → localStorage fallback
- Save Priority: Server JSON → localStorage backup
- Offline Mode: Continues working with localStorage
- Auto-Recovery: Syncs with server when available
Development
Local Development
# Install dependencies
npm install
# Start both frontend and backend
npm run dev
# Frontend: http://localhost:5173
# Backend: http://localhost:3001
Backend Only
npm run server
Volume Management
Backup Data
# Create backup
docker cp reading-tracker:/app/data/books.json ./backup-books.json
# Restore backup
docker cp ./backup-books.json reading-tracker:/app/data/books.json
View Volume Contents
# List volume contents
docker exec reading-tracker ls -la /app/data
# View current data
docker exec reading-tracker cat /app/data/books.json
Troubleshooting
Health Check
curl http://localhost:8080/api/health
Check Logs
docker logs reading-tracker
Volume Issues
# Verify volume mount
docker inspect reading-tracker | grep -A 10 "Mounts"
# Recreate volume if needed
docker volume rm reading-data
docker-compose up -d
Migration from localStorage
When first deploying, the app will:
- Try to load from server (empty initially)
- Fall back to localStorage if available
- Save localStorage data to server on first interaction
- Continue using server storage for all subsequent operations
No manual migration needed - the fallback system handles it automatically!