# 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