docs: update all documentation to reflect current project state

This commit is contained in:
2026-04-23 14:35:08 -04:00
parent 8b31045dcf
commit 3029ce7053
9 changed files with 566 additions and 639 deletions
+116 -112
View File
@@ -10,15 +10,16 @@
│ HTTPS (443)
┌─────────────────────────────────────────────────────────────────────────┐
│ CoopCredits Server
│ CoopCredits Server (172.20.1.238)
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Nginx │ │ Frontend │ │ Backend │ │ PostgreSQL │ │
│ │ (80) │──│ (Next.js) │──│ (Express) │──│ (5432) │ │
│ │ Caddy │ │ Frontend │ │ Backend │ │ PostgreSQL │ │
│ │ (reverse) │──│ (Next.js) │ │ (Express) │──│ (5432) │ │
│ │ Proxy │ │ :3000 │ │ :3002 │ │ │ │
│ └──────────────┘ └──────────────┘ └──────┬───────┘ └──────────────┘ │
│ │ │
│ ┌──────────────┐ │ ┌──────────────┐ │
│ │ Redis │◀────────┘ │ Anchor CLI │ │
│ │ (6379) │ │ (Optional) │ │
│ │ Redis │◀────────┘ │ (Ko-fi) │ │
│ │ (6379) │ │ (Webhooks) │ │
│ └──────────────┘ └──────────────┘ │
└──────────────────────────────────┬──────────────────────────────────────┘
@@ -33,80 +34,115 @@
└──────────────┘ └──────────────┘ └──────────────┘
```
> **Important:** Backend runs in `network_mode: host` to reach Tautulli/Overseer on `172.20.1.0/24`. Docker bridge networking cannot route to this subnet.
## Service Details
### Caddy Reverse Proxy (Separate Machine)
- **Handles:** SSL termination (Let's Encrypt), routing
- **Routes:**
- `/*` → Frontend `:3000`
- `/api/*` → Backend `:3002` (preserves `/api/` prefix — use `handle`, not `handle_path`)
- `/webhooks/*` → Backend `:3002`
### Frontend (coop-frontend, port 3000)
- **Next.js 16** with standalone output
- **Bridge network** — exposed on `0.0.0.0:3000`
- **Static files** served from `.next/standalone`
### Backend (coop-backend, port 3002)
- **Express.js** API
- **Host network mode** — required to reach `172.20.1.x` services
- **Connects to:** PostgreSQL on `localhost:5432`, Redis on `localhost:6379`
- **Health check:** `GET /health` on `localhost:3002`
### PostgreSQL (coop-postgres, port 5432)
- **User:** `coop`
- **Database:** `coop_credits`
- **Password:** `coop_password` (change in production)
- **Health check:** `pg_isready`
### Redis (coop-redis, port 6379)
- **Used for:** Session store, Socket.io adapter
- **No auth** in current config (trusted local network)
### Plex Server (172.20.1.220:32400)
- **Purpose**: Content streaming and user authentication
- **Integration**: OAuth authentication for website login
- **Access**: HTTP on local network, may have remote access enabled
- **Purpose:** Content streaming and user authentication
- **Integration:** OAuth 2.0 login for website
### Tautulli (172.20.1.255:8181)
- **Purpose**: Plex analytics and watch event tracking
- **Integration**: Webhook notifications to CoopCredits backend
- **Access**: HTTP on local network
- **API Key**: Required for backend queries
- **Purpose:** Plex analytics and watch event tracking
- **Integration:** Webhook notifications to CoopCredits on watch events
- **API Key:** Required for backfill queries
### Overseer (172.20.1.225:5055)
- **Purpose**: Content request management
- **Integration**: API for requesting content, webhooks for status updates
- **Access**: HTTP on local network
- **API Key**: Required for backend integration
### CoopCredits Server
- **Public Access**: coop.hobokenchicken.com (HTTPS)
- **Internal Services**: Only accessible via Nginx reverse proxy
- **Database**: PostgreSQL on localhost only
- **Cache**: Redis on localhost only
- **Purpose:** Content request management
- **Integration:** API for creating requests, webhooks for status updates
- **API Key:** Required for search and request creation
- **Disk Space:** Used for dynamic pricing scarcity calculation
## Communication Flow
### 1. User Authentication
```
User → Nginx → Frontend → Backend → Plex OAuth (172.20.1.220:32400)
User authenticated, JWT issued
User → Caddy → Frontend → Backend → Plex OAuth (172.20.1.220:32400)
User authenticated, JWT issued
Session stored in PostgreSQL
```
### 2. Watch Event Processing
```
Plex → Tautulli → Webhook → Nginx → Backend → Solana Devnet
Database updated
WebSocket → User notified
Plex → Tautulli → Webhook → Caddy → Backend → PostgreSQL
WatchEvent + Transaction created
Socket.io → User notified
```
### 3. Content Request
```
User → Nginx → Frontend → Backend → Overseer API (172.20.1.225:5055)
User → Caddy → Frontend → Backend → Overseer API (172.20.1.225:5055)
Request created, $COOP reserved
Request created, $COOP deducted immediately
ContentRequest stored as PENDING
Webhook on approval → Burn $COOP
Overseer webhook → Backend → Status updated
```
### 4. Ko-fi Purchase
```
User → Ko-fi Store → Payment → Ko-fi Webhook → Caddy → Backend
KofiPayment record created
If email matches user →
Transaction (PURCHASE) + credits added
Socket.io → User notified
```
## Security Considerations
### Network Security
1. **Local Network**: All services communicate over HTTP (trusted network)
2. **External Access**: Only Nginx exposed (ports 80/443)
3. **Internal Services**: Not accessible from external network
1. **Backend host mode** — Required for local network access, but exposes host network
2. **Caddy handles SSL** Only HTTPS externally
3. **Internal services** — PostgreSQL/Redis not exposed externally (except through Docker ports)
### API Security
1. **Tautulli Webhook**: Secret verification recommended
2. **Overseer API**: API key authentication
3. **Plex OAuth**: Standard OAuth 2.0 flow
4. **JWT**: Secure tokens for session management
1. **Tautulli Webhook** — Optional secret verification (`TAUTULLI_WEBHOOK_SECRET`)
2. **Overseer Webhook** — No secret currently configured
3. **Plex OAuth** Standard OAuth 2.0 flow
4. **JWT** Secure tokens with nonce for session deduplication
5. **Rate Limiting** — 1000 requests per 15 minutes per IP
### Data Security
1. **Wallet Keys**: Encrypted with AES-256-GCM in database
2. **Database**: Not exposed externally
3. **Redis**: Password protected, localhost only
1. **No wallet keys** — Solana removed, no private keys stored
2. **Database** — Localhost only, password protected
3. **Redis** — Localhost only
4. **Ko-fi verification** — Token check on webhook endpoint
## Firewall Configuration
```bash
# Web traffic
# Web traffic (Caddy handles SSL)
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
@@ -114,102 +150,70 @@ sudo ufw allow 443/tcp
sudo ufw allow from 172.20.0.0/16 to 172.20.1.0/24
# Block external access to internal services
sudo ufw deny 3000/tcp # Frontend
sudo ufw deny 3001/tcp # Backend
sudo ufw deny 3000/tcp # Frontend (should be localhost only)
sudo ufw deny 3002/tcp # Backend (should be localhost only)
sudo ufw deny 5432/tcp # PostgreSQL
sudo ufw deny 6379/tcp # Redis
```
## Docker Network Configuration
### Internal Network (coop-internal)
- Containers can communicate with each other
### Bridge Network (coop-network)
- Frontend container uses this
- Isolated from external network
- Used for: frontend ↔ backend ↔ database
- Connects: frontend ↔ Caddy proxy
### External Network (coop-external)
- Allows containers to reach local services
- Subnet: 172.20.2.0/24
- Used for: backend → Tautulli/Overseer/Plex
## SSL/TLS
SSL/TLS is handled by an external reverse proxy (e.g., Caddy). The application stack runs HTTP only on port 80 internally.
### Host Network (backend only)
- Backend container uses `network_mode: host`
- Shares host's network stack
- Required to reach `172.20.1.x` services (Tautulli, Overseer)
- Connects directly to PostgreSQL/Redis on `localhost`
## Monitoring and Logging
### Log Locations
- Nginx: `docker/nginx/logs/`
- Backend: Docker logs (`docker-compose logs backend`)
- Frontend: Docker logs (`docker-compose logs frontend`)
- Backend: `docker logs coop-backend`
- Frontend: `docker logs coop-frontend`
- Database: Inside container (`/var/log/postgresql/`)
### Health Checks
```bash
# Backend health
curl https://coop.hobokenchicken.com/health
curl http://localhost:3002/health
# Database connection
docker-compose exec postgres pg_isready -U coop
docker exec coop-postgres pg_isready -U coop
# Service status
docker-compose ps
docker ps
```
## Troubleshooting
### Cannot reach local services
1. Check Docker network: `docker network inspect coop-credits_coop-external`
2. Verify IP connectivity: `docker exec coop-backend ping 172.20.1.255`
3. Check firewall rules: `sudo ufw status`
### Webhook not received
1. Verify Tautulli can reach CoopCredits:
```bash
curl -X POST https://coop.hobokenchicken.com/webhooks/tautulli \
-H "Content-Type: application/json" \
-d '{"test": true}'
```
2. Check Nginx logs: `tail -f docker/nginx/logs/access.log`
3. Check backend logs: `docker-compose logs -f backend`
### CORS errors
1. Verify CORS_ORIGINS in .env includes your domain
2. Check backend is sending correct headers
3. Nginx should pass through CORS headers
## Performance Optimization
### Nginx Tuning
- `worker_processes auto` - Use all CPU cores
- `worker_connections 1024` - High connection limit
- `gzip on` - Compress responses
- `proxy_cache` - Cache static assets
### Database Tuning
- Connection pooling via Prisma
- Redis for session caching
- Indexed queries on user_id, created_at
### Frontend Optimization
- Next.js static generation where possible
- Image optimization
- Code splitting
## Backup and Recovery
### Database Backup
```bash
# Automated backup script
docker-compose exec -T postgres pg_dump -U coop coop_credits > backup_$(date +%Y%m%d).sql
# Automated backup
docker exec -T coop-postgres pg_dump -U coop coop_credits > backup_$(date +%Y%m%d).sql
```
### Wallet Recovery
- Private keys are encrypted in database
- Backup keys stored securely (encrypted)
- Recovery requires encryption key from .env
### Configuration Backup
- `.env` file (contains all secrets)
- `docker/nginx/ssl/` certificates
- `docker-compose.prod.yml` service config
- `docker-compose.yml` service config
- Caddy config (on separate machine)
## Troubleshooting
### Cannot reach local services
1. Check backend is in host network mode: `docker inspect coop-backend | grep NetworkMode`
2. Verify IP connectivity from host: `ping 172.20.1.255`
3. Check backend logs: `docker logs --tail 50 coop-backend`
### Webhook not received
1. Verify Caddy routes `/webhooks/*` to backend
2. Check backend logs for webhook handler output
3. Test manually: `curl -X POST https://coop.hobokenchicken.com/webhooks/tautulli -d '{"test":true}'`
### CORS errors
1. Verify `FRONTEND_URL` and `API_URL` in `.env`
2. Check backend CORS origins include your domain
3. Caddy should pass through headers without modification