220 lines
9.7 KiB
Markdown
220 lines
9.7 KiB
Markdown
# CoopCredits Infrastructure Documentation
|
|
|
|
## Network Architecture
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────────────────────┐
|
|
│ External Access │
|
|
│ coop.hobokenchicken.com │
|
|
└─────────────────────────────────┬───────────────────────────────────────┘
|
|
│ HTTPS (443)
|
|
▼
|
|
┌─────────────────────────────────────────────────────────────────────────┐
|
|
│ CoopCredits Server (172.20.1.238) │
|
|
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
|
|
│ │ Caddy │ │ Frontend │ │ Backend │ │ PostgreSQL │ │
|
|
│ │ (reverse) │──│ (Next.js) │ │ (Express) │──│ (5432) │ │
|
|
│ │ Proxy │ │ :3000 │ │ :3002 │ │ │ │
|
|
│ └──────────────┘ └──────────────┘ └──────┬───────┘ └──────────────┘ │
|
|
│ │ │
|
|
│ ┌──────────────┐ │ ┌──────────────┐ │
|
|
│ │ Redis │◀────────┘ │ (Ko-fi) │ │
|
|
│ │ (6379) │ │ (Webhooks) │ │
|
|
│ └──────────────┘ └──────────────┘ │
|
|
└──────────────────────────────────┬──────────────────────────────────────┘
|
|
│
|
|
│ Local Network (172.20.1.0/24)
|
|
┌──────────────────────────┼──────────────────────────┐
|
|
│ │ │
|
|
▼ ▼ ▼
|
|
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
|
|
│ Plex │ │ Tautulli │ │ Overseer │
|
|
│172.20.1.220 │ │172.20.1.255 │ │172.20.1.225 │
|
|
│ :32400 │ │ :8181 │ │ :5055 │
|
|
└──────────────┘ └──────────────┘ └──────────────┘
|
|
```
|
|
|
|
> **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 2.0 login for website
|
|
|
|
### Tautulli (172.20.1.255:8181)
|
|
- **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 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 → 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 → Caddy → Backend → PostgreSQL
|
|
↓
|
|
WatchEvent + Transaction created
|
|
Socket.io → User notified
|
|
```
|
|
|
|
### 3. Content Request
|
|
```
|
|
User → Caddy → Frontend → Backend → Overseer API (172.20.1.225:5055)
|
|
↓
|
|
Request created, $COOP deducted immediately
|
|
ContentRequest stored as PENDING
|
|
↓
|
|
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. **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** — 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. **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 (Caddy handles SSL)
|
|
sudo ufw allow 80/tcp
|
|
sudo ufw allow 443/tcp
|
|
|
|
# Internal service access (from Docker containers)
|
|
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 (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
|
|
|
|
### Bridge Network (coop-network)
|
|
- Frontend container uses this
|
|
- Isolated from external network
|
|
- Connects: frontend ↔ Caddy proxy
|
|
|
|
### 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
|
|
- Backend: `docker logs coop-backend`
|
|
- Frontend: `docker logs coop-frontend`
|
|
- Database: Inside container (`/var/log/postgresql/`)
|
|
|
|
### Health Checks
|
|
```bash
|
|
# Backend health
|
|
curl http://localhost:3002/health
|
|
|
|
# Database connection
|
|
docker exec coop-postgres pg_isready -U coop
|
|
|
|
# Service status
|
|
docker ps
|
|
```
|
|
|
|
## Backup and Recovery
|
|
|
|
### Database Backup
|
|
```bash
|
|
# Automated backup
|
|
docker exec -T coop-postgres pg_dump -U coop coop_credits > backup_$(date +%Y%m%d).sql
|
|
```
|
|
|
|
### Configuration Backup
|
|
- `.env` file (contains all secrets)
|
|
- `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
|