docs: update all documentation to reflect current project state
This commit is contained in:
+9
-17
@@ -8,9 +8,9 @@ DATABASE_URL="postgresql://coop:CHANGE_PASSWORD@localhost:5432/coop_credits?sche
|
|||||||
POSTGRES_PASSWORD="CHANGE_THIS_PASSWORD"
|
POSTGRES_PASSWORD="CHANGE_THIS_PASSWORD"
|
||||||
|
|
||||||
# Server
|
# Server
|
||||||
PORT=3001
|
PORT=3002
|
||||||
NODE_ENV=development
|
NODE_ENV=development
|
||||||
API_URL=http://localhost:3001
|
API_URL=http://localhost:3002
|
||||||
FRONTEND_URL=http://localhost:3000
|
FRONTEND_URL=http://localhost:3000
|
||||||
|
|
||||||
# JWT Secret (generate with: openssl rand -hex 32)
|
# JWT Secret (generate with: openssl rand -hex 32)
|
||||||
@@ -26,30 +26,24 @@ PLEX_REDIRECT_URI=http://localhost:3000/auth/callback
|
|||||||
|
|
||||||
# ==========================================
|
# ==========================================
|
||||||
# Tautulli (Watch Analytics)
|
# Tautulli (Watch Analytics)
|
||||||
|
# Backend uses host network mode to reach this
|
||||||
# ==========================================
|
# ==========================================
|
||||||
# Your Tautulli instance URL
|
|
||||||
TAUTULLI_URL=http://172.20.1.255:8181
|
TAUTULLI_URL=http://172.20.1.255:8181
|
||||||
# Get API key from: Tautulli Settings > Web Interface > API
|
|
||||||
TAUTULLI_API_KEY=""
|
TAUTULLI_API_KEY=""
|
||||||
# Optional: Secret for webhook signature verification
|
|
||||||
TAUTULLI_WEBHOOK_SECRET=""
|
TAUTULLI_WEBHOOK_SECRET=""
|
||||||
|
|
||||||
# ==========================================
|
# ==========================================
|
||||||
# Overseer (Content Requests)
|
# Overseer (Content Requests)
|
||||||
|
# Backend uses host network mode to reach this
|
||||||
# ==========================================
|
# ==========================================
|
||||||
# Your Overseer instance URL
|
|
||||||
OVERSEER_URL=http://172.20.1.225:5055
|
OVERSEER_URL=http://172.20.1.225:5055
|
||||||
# Get API key from: Overseer Settings > General
|
|
||||||
OVERSEER_API_KEY=""
|
OVERSEER_API_KEY=""
|
||||||
|
|
||||||
# ==========================================
|
# ==========================================
|
||||||
# Solana (Devnet for testing)
|
# Ko-fi (Optional Credit Purchases)
|
||||||
|
# Get verification token from Ko-fi Settings > Webhooks
|
||||||
# ==========================================
|
# ==========================================
|
||||||
SOLANA_RPC_URL=https://api.devnet.solana.com
|
KOFI_VERIFICATION_TOKEN=""
|
||||||
SOLANA_PROGRAM_ID=CoopCredits111111111111111111111111111111111
|
|
||||||
# Generate keypair with: npm run setup:solana
|
|
||||||
SOLANA_MINT_AUTHORITY_KEYPAIR=""
|
|
||||||
SOLANA_TOKEN_DECIMALS=6
|
|
||||||
|
|
||||||
# ==========================================
|
# ==========================================
|
||||||
# Redis (optional caching)
|
# Redis (optional caching)
|
||||||
@@ -59,15 +53,13 @@ REDIS_PASSWORD=""
|
|||||||
|
|
||||||
# ==========================================
|
# ==========================================
|
||||||
# Encryption (generate with: openssl rand -base64 32)
|
# Encryption (generate with: openssl rand -base64 32)
|
||||||
# Used for encrypting wallet private keys
|
# Used for session cookie encryption
|
||||||
# ==========================================
|
# ==========================================
|
||||||
ENCRYPTION_KEY=""
|
ENCRYPTION_KEY=""
|
||||||
|
|
||||||
# ==========================================
|
# ==========================================
|
||||||
# Frontend Public Variables
|
# Frontend Public Variables
|
||||||
# ==========================================
|
# ==========================================
|
||||||
NEXT_PUBLIC_API_URL=http://localhost:3001
|
NEXT_PUBLIC_API_URL=http://localhost:3002
|
||||||
NEXT_PUBLIC_SOLANA_NETWORK=devnet
|
|
||||||
NEXT_PUBLIC_SOLANA_RPC_URL=https://api.devnet.solana.com
|
|
||||||
NEXT_PUBLIC_APP_NAME=CoopCredits
|
NEXT_PUBLIC_APP_NAME=CoopCredits
|
||||||
NEXT_PUBLIC_APP_URL=http://localhost:3000
|
NEXT_PUBLIC_APP_URL=http://localhost:3000
|
||||||
|
|||||||
+21
-18
@@ -1,21 +1,24 @@
|
|||||||
# Frontend Todo List
|
# Frontend Todo List
|
||||||
|
|
||||||
## Phase 1: Accessibility & Onboarding (Priority: 1)
|
## Completed
|
||||||
- [x] **Landing Page**: Marketing page at `/` with "How it Works".
|
- [x] **Landing Page** — Barnyard-themed "Enter the Coop" page
|
||||||
- [x] **Onboarding Flow**: Better guided steps for new users to set up their wallet.
|
- [x] **Login Flow** — Plex OAuth with auto-redirect
|
||||||
- [x] **Mobile Responsiveness**: Audit and fix layout shifts on small screens.
|
- [x] **Dashboard** — Nest Egg balance, Eggs Ordered, Market Price cards
|
||||||
|
- [x] **Watch History** — Personal watch events with credits earned
|
||||||
|
- [x] **Request History** — Content requests with status filtering
|
||||||
|
- [x] **Search Request Modal** — Overseer search with posters, episode counts, dynamic pricing
|
||||||
|
- [x] **Buy Credits Modal** — Ko-fi store links for $5/500 and $10/1000
|
||||||
|
- [x] **Activity Feed** — Recent transactions sidebar
|
||||||
|
- [x] **Leaderboard** — Rich Birds (top earners) and Lazy Birds (top watchers)
|
||||||
|
- [x] **Socket.io Integration** — Live balance updates, credit earned toasts
|
||||||
|
- [x] **Disk Space Bar** — The Silo: used/total GB with scarcity warning
|
||||||
|
- [x] **Admin Dashboard** — The Flock, Barn Rules, Donations, Egg Stats, The Feed Queue
|
||||||
|
- [x] **Mobile Responsiveness** — Barnyard cards stack on small screens
|
||||||
|
- [x] **Barnyard Theme** — Comic Sans, thick borders, earthy palette, jokey copy
|
||||||
|
|
||||||
## Phase 2: Engagement & Real-time (Priority: 2)
|
## Future Ideas
|
||||||
- [x] **Socket.io Integration**: Connect to backend for live watch events.
|
- [ ] **Referral System** — Earn bonus $COOP for inviting Plex users
|
||||||
- [x] **Live Reward Toasts**: Show "You earned 10 $COOP" alerts in real-time.
|
- [ ] **Seasonal Events** — Double credits weekends, holiday multipliers
|
||||||
- [x] **Activity Feed**: A small sidebar or section for "Global Recent Earners".
|
- [ ] **Achievements** — Badges for watch milestones (100 movies, 1000 hours, etc.)
|
||||||
|
- [ ] **Notifications** — Browser push for request approvals
|
||||||
## Phase 3: Core Spend Loop (Priority: 3)
|
- [ ] **Dark Mode** — Night coop theme
|
||||||
- [x] **Overseer Request UI**: Create `SearchRequestModal` component.
|
|
||||||
- [x] **Request History**: Show status of Overseer requests (Pending/Processing/Available).
|
|
||||||
- [x] **Balance Refresh**: Ensure balance updates immediately after a request.
|
|
||||||
|
|
||||||
## Phase 4: Advanced Features (Priority: 4)
|
|
||||||
- [x] **Browser Wallets**: Connect Phantom/Solflare/Backpack.
|
|
||||||
- [ ] **Referral System**: Earn bonus $COOP for inviting other Plex users. (Requires DB Migration)
|
|
||||||
- [x] **Leaderboard**: Weekly/Monthly top watchers.
|
|
||||||
|
|||||||
+47
-56
@@ -5,25 +5,22 @@
|
|||||||
| Service | IP Address | Port | Integration Role |
|
| Service | IP Address | Port | Integration Role |
|
||||||
|----------|----------------|------|--------------------------------|
|
|----------|----------------|------|--------------------------------|
|
||||||
| Plex | 172.20.1.220 | 32400| User authentication, content |
|
| Plex | 172.20.1.220 | 32400| User authentication, content |
|
||||||
| Overseer | 172.20.1.225 | 5055 | Content requests, $COOP spend |
|
| Overseer | 172.20.1.225 | 5055 | Content requests, disk space |
|
||||||
| Tautulli | 172.20.1.255 | 8181 | Watch tracking, $COOP earn |
|
| Tautulli | 172.20.1.255 | 8181 | Watch tracking, $COOP earn |
|
||||||
| Website | coop.hobokenchicken.com | 443 | User dashboard, admin panel |
|
| Website | coop.hobokenchicken.com | 443 | User dashboard, admin panel |
|
||||||
|
|
||||||
## Files Created/Updated
|
## Files Created/Updated
|
||||||
|
|
||||||
### Configuration Files
|
### Configuration Files
|
||||||
- `.env.production` - Production environment template
|
- `.env` - Production environment
|
||||||
|
- `docker-compose.yml` - Docker orchestration
|
||||||
- `docker-compose.prod.yml` - Production Docker orchestration
|
- `docker-compose.prod.yml` - Production Docker orchestration
|
||||||
- `docker/nginx/nginx.prod.conf` - Nginx reverse proxy config
|
|
||||||
|
|
||||||
### Deployment Scripts
|
|
||||||
- `deployment/setup-infrastructure.sh` - Initial infrastructure setup
|
|
||||||
- `deployment/deploy-production.sh` - Production deployment
|
|
||||||
- `deployment/health-check.sh` - Service health monitoring
|
|
||||||
|
|
||||||
### Documentation
|
### Documentation
|
||||||
- `docs/SETUP-INFRASTRUCTURE.md` - Step-by-step setup guide
|
- `docs/SETUP-INFRASTRUCTURE.md` - Step-by-step setup guide
|
||||||
- `docs/INFRASTRUCTURE.md` - Architecture and network documentation
|
- `docs/INFRASTRUCTURE.md` - Architecture and network documentation
|
||||||
|
- `docs/CADDY-CONFIG.md` - Reverse proxy configuration
|
||||||
|
- `docs/TROUBLESHOOTING.md` - Common issues and fixes
|
||||||
|
|
||||||
## Network Architecture
|
## Network Architecture
|
||||||
|
|
||||||
@@ -32,14 +29,15 @@ Internet
|
|||||||
│ HTTPS
|
│ HTTPS
|
||||||
▼
|
▼
|
||||||
┌─────────────┐
|
┌─────────────┐
|
||||||
│ Nginx │ (80/443) - SSL termination, rate limiting
|
│ Caddy │ (443) - SSL termination
|
||||||
└──────┬──────┘
|
└──────┬──────┘
|
||||||
│
|
│
|
||||||
┌───┴───┐
|
┌───┴───┐
|
||||||
▼ ▼
|
▼ ▼
|
||||||
┌──────┐ ┌──────┐
|
┌──────┐ ┌──────┐
|
||||||
│Frontend│ │Backend│
|
│Front-│ │Back- │
|
||||||
│:3000 │ │:3001 │
|
│end │ │end │
|
||||||
|
│:3000 │ │:3002 │
|
||||||
└──────┘ └───┬───┘
|
└──────┘ └───┬───┘
|
||||||
│
|
│
|
||||||
┌──────┼──────┐
|
┌──────┼──────┐
|
||||||
@@ -61,23 +59,18 @@ Internet
|
|||||||
## Quick Deployment Commands
|
## Quick Deployment Commands
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# 1. Setup infrastructure
|
# 1. Setup
|
||||||
npm run setup:infra
|
cp .env.example .env
|
||||||
|
# Edit .env with your API keys
|
||||||
|
|
||||||
# 2. Edit .env with your API keys
|
# 2. Deploy
|
||||||
nano .env
|
docker-compose up -d --build
|
||||||
|
|
||||||
# 3. Setup Solana
|
# 3. Initialize database (first time only)
|
||||||
npm run setup:solana
|
docker exec coop-backend npx prisma db push --accept-data-loss
|
||||||
|
|
||||||
# 4. Deploy
|
# 4. Check health
|
||||||
npm run deploy:prod
|
curl https://coop.hobokenchicken.com/health
|
||||||
|
|
||||||
# 5. Check health
|
|
||||||
npm run health
|
|
||||||
|
|
||||||
# 6. Watch mode monitoring
|
|
||||||
npm run health -- --watch
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Integration Points
|
## Integration Points
|
||||||
@@ -85,84 +78,82 @@ npm run health -- --watch
|
|||||||
### Tautulli → CoopCredits
|
### Tautulli → CoopCredits
|
||||||
- **Trigger**: Watch events
|
- **Trigger**: Watch events
|
||||||
- **Webhook URL**: `https://coop.hobokenchicken.com/webhooks/tautulli`
|
- **Webhook URL**: `https://coop.hobokenchicken.com/webhooks/tautulli`
|
||||||
- **Action**: Mint $COOP tokens
|
- **Action**: Create WatchEvent + Transaction (EARN), update user balance
|
||||||
|
|
||||||
### Overseer → CoopCredits
|
### Overseer → CoopCredits
|
||||||
- **Trigger**: Request approval/decline
|
- **Trigger**: Request approval/decline
|
||||||
- **Webhook URL**: `https://coop.hobokenchicken.com/webhooks/overseer`
|
- **Webhook URL**: `https://coop.hobokenchicken.com/webhooks/overseer`
|
||||||
- **Action**: Burn/spend $COOP tokens
|
- **Action**: Update ContentRequest status (refund if declined)
|
||||||
|
|
||||||
### Plex → CoopCredits
|
### Plex → CoopCredits
|
||||||
- **Trigger**: User login
|
- **Trigger**: User login
|
||||||
- **Method**: OAuth via plex.tv
|
- **Method**: OAuth via plex.tv
|
||||||
- **Action**: Authenticate users
|
- **Action**: Authenticate users, create session
|
||||||
|
|
||||||
|
### Ko-fi → CoopCredits
|
||||||
|
- **Trigger**: Store purchase
|
||||||
|
- **Webhook URL**: `https://coop.hobokenchicken.com/webhooks/kofi`
|
||||||
|
- **Action**: Create KofiPayment, credit user if email matches
|
||||||
|
|
||||||
## Security Features
|
## Security Features
|
||||||
|
|
||||||
1. **SSL/TLS**: Let's Encrypt or custom certificates
|
1. **SSL/TLS**: Caddy with Let's Encrypt
|
||||||
2. **Rate Limiting**: Nginx level protection
|
2. **Rate Limiting**: 1000 req/15min per IP
|
||||||
3. **Firewall**: UFW rules for local network
|
3. **Firewall**: UFW rules for local network
|
||||||
4. **Secrets**: Encrypted in `.env` file
|
4. **Secrets**: In `.env` file (gitignored)
|
||||||
5. **Wallet Keys**: AES-256-GCM encrypted in database
|
5. **CORS**: Configured for your domain
|
||||||
6. **CORS**: Configured for your domain
|
6. **JWT**: Secure session tokens
|
||||||
7. **JWT**: Secure session tokens
|
7. **Ko-fi Verification**: Token check on webhook
|
||||||
|
|
||||||
## Monitoring
|
## Monitoring
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Health check
|
# Health check
|
||||||
./deployment/health-check.sh
|
curl https://coop.hobokenchicken.com/health
|
||||||
|
|
||||||
# Watch mode (continuous)
|
|
||||||
./deployment/health-check.sh --watch
|
|
||||||
|
|
||||||
# Docker logs
|
# Docker logs
|
||||||
docker-compose -f docker-compose.prod.yml logs -f
|
docker-compose logs -f
|
||||||
|
|
||||||
# Specific service
|
# Specific service
|
||||||
docker-compose -f docker-compose.prod.yml logs -f backend
|
docker-compose logs -f backend
|
||||||
```
|
```
|
||||||
|
|
||||||
## Backup Strategy
|
## Backup Strategy
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Database backup
|
# Database backup
|
||||||
docker-compose -f docker-compose.prod.yml exec -T postgres pg_dump -U coop coop_credits > backup_$(date +%Y%m%d).sql
|
docker exec -T coop-postgres pg_dump -U coop coop_credits > backup_$(date +%Y%m%d).sql
|
||||||
|
|
||||||
# Environment backup
|
# Environment backup
|
||||||
cp .env .env.backup.$(date +%Y%m%d)
|
cp .env .env.backup.$(date +%Y%m%d)
|
||||||
|
|
||||||
# Wallet keys (secure offsite storage)
|
|
||||||
# - Solana mint authority keypair
|
|
||||||
# - Encryption key from .env
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Next Steps
|
## Next Steps
|
||||||
|
|
||||||
1. **Run setup**: `npm run setup:infra`
|
1. **Run setup**: `cp .env.example .env` and edit
|
||||||
2. **Get API keys**:
|
2. **Get API keys**:
|
||||||
- Tautulli: http://172.20.1.255:8181 → Settings → API
|
- Tautulli: http://172.20.1.255:8181 → Settings → API
|
||||||
- Overseer: http://172.20.1.225:5055 → Settings → General
|
- Overseer: http://172.20.1.225:5055 → Settings → General
|
||||||
- Plex: https://plex.tv/claim
|
- Plex: https://plex.tv/claim
|
||||||
3. **Edit .env** with your keys
|
3. **Deploy**: `docker-compose up -d --build`
|
||||||
4. **Setup Solana**: `npm run setup:solana`
|
4. **Configure webhooks** in Tautulli, Overseer, and Ko-fi
|
||||||
5. **Deploy**: `npm run deploy:prod`
|
5. **Set admin**: `UPDATE users SET is_admin = true WHERE ...`
|
||||||
6. **Configure webhooks** in Tautulli and Overseer
|
6. **Test**: `curl https://coop.hobokenchicken.com/health`
|
||||||
7. **Test**: `npm run health`
|
|
||||||
|
|
||||||
## Troubleshooting
|
## Troubleshooting
|
||||||
|
|
||||||
| Issue | Solution |
|
| Issue | Solution |
|
||||||
|-------|----------|
|
|-------|----------|
|
||||||
| Cannot reach local services | Check Docker network: `docker network ls` |
|
| Cannot reach local services | Check backend `network_mode: host` |
|
||||||
| Webhook not received | Check Nginx logs: `docker/nginx/logs/access.log` |
|
| Webhook not received | Check Caddy routes to port 3002 |
|
||||||
| Database connection failed | Verify `.env` DATABASE_URL |
|
| Database connection failed | Verify `.env` DATABASE_URL |
|
||||||
| SSL error | Check certificate paths in nginx config |
|
| SSL error | Check Caddy certificate status |
|
||||||
| CORS errors | Verify CORS_ORIGINS in `.env` |
|
| CORS errors | Verify CORS_ORIGINS in `.env` |
|
||||||
|
| Request stuck PENDING | Use admin **SYNC** button or check Overseer webhook |
|
||||||
|
|
||||||
## Support Resources
|
## Support Resources
|
||||||
|
|
||||||
- **Setup Guide**: `docs/SETUP-INFRASTRUCTURE.md`
|
- **Setup Guide**: `docs/SETUP-INFRASTRUCTURE.md`
|
||||||
- **Architecture**: `docs/INFRASTRUCTURE.md`
|
- **Architecture**: `docs/INFRASTRUCTURE.md`
|
||||||
- **Health Check**: `npm run health`
|
- **Troubleshooting**: `docs/TROUBLESHOOTING.md`
|
||||||
- **Logs**: `npm run docker:prod:logs`
|
- **Caddy Config**: `docs/CADDY-CONFIG.md`
|
||||||
|
|||||||
@@ -1,89 +1,192 @@
|
|||||||
# CoopCoins: Our Family Media Rewards
|
# CoopCredits ($COOP) — Hoboken Chicken Media Rewards
|
||||||
|
|
||||||
Welcome to our private media rewards system for the Hoboken Chicken family and friends! It's powered by Solana and integrates with our Plex, Tautulli, and Overseer setup. Earn CoopCoins ($COOP) for enjoying media, and use them to request new content!
|
A jokey barnyard-themed rewards system for the Hoboken Chicken family and friends. Watch stuff on Plex, earn $COOP credits, request new media through Overseer. Buy extra credits via Ko-fi when the silo runs low.
|
||||||
|
|
||||||
## System Architecture
|
> **Theme:** Everything is chickens, eggs, coops, and corn. Comic Sans / Chalkboard font, thick borders, earthy palette.
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
```
|
```
|
||||||
┌─────────────────────────────────────────────────────────────────────────────┐
|
┌─────────────────────────────────────────────────────────────────────────────┐
|
||||||
│ coop.hobokenchicken.com │
|
│ coop.hobokenchicken.com │
|
||||||
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌─────────────────┐ │
|
|
||||||
│ │ Next.js │ │ Express │ │ PostgreSQL │ │ Solana Devnet │ │
|
|
||||||
│ │ Frontend │◄─┤ API │◄─┤ Database │◄─┤ $COOP SPL │ │
|
|
||||||
│ │ │ │ │ │ │ │ Token │ │
|
|
||||||
│ └──────────────┘ └──────────────┘ └──────────────┘ └─────────────────┘ │
|
|
||||||
│ ▲ ▲ │
|
|
||||||
│ │ │ │
|
|
||||||
│ Plex OAuth Tautulli Webhooks │
|
|
||||||
│ │ │ │
|
|
||||||
│ ▼ ▼ │
|
|
||||||
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
|
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
|
||||||
│ │ Plex Server │ │ Tautulli │ │ Overseer │ │
|
│ │ Next.js │ │ Express │ │ PostgreSQL │ │
|
||||||
│ │ (Content) │ │ (Analytics) │ │ (Requests) │ │
|
│ │ Frontend │◄─┤ API │◄─┤ Database │ │
|
||||||
|
│ │ (3000) │ │ (3002) │ │ (5432) │ │
|
||||||
│ └──────────────┘ └──────────────┘ └──────────────┘ │
|
│ └──────────────┘ └──────────────┘ └──────────────┘ │
|
||||||
|
│ ▲ ▲ ▲ │
|
||||||
|
│ │ │ │ │
|
||||||
|
│ Plex OAuth Tautulli Webhooks Ko-fi Webhooks │
|
||||||
|
│ │ │ │ │
|
||||||
|
│ ▼ ▼ ▼ │
|
||||||
|
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
|
||||||
|
│ │ Plex Server │ │ Tautulli │ │ Ko-fi │ │
|
||||||
|
│ │172.20.1.220 │ │172.20.1.255 │ │ (Payments) │ │
|
||||||
|
│ └──────────────┘ └──────────────┘ └──────────────┘ │
|
||||||
|
│ │
|
||||||
|
│ ┌──────────────┐ │
|
||||||
|
│ │ Overseer │ (Requests & disk space for dynamic pricing) │
|
||||||
|
│ │172.20.1.225 │ │
|
||||||
|
│ └──────────────┘ │
|
||||||
└─────────────────────────────────────────────────────────────────────────────┘
|
└─────────────────────────────────────────────────────────────────────────────┘
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Key Features
|
||||||
|
|
||||||
|
- **Plex OAuth Login** — No passwords, just Plex auth
|
||||||
|
- **Watch-to-Earn** — Tautulli webhooks credit $COOP for watched content (30-day backfill on signup)
|
||||||
|
- **Request-to-Spend** — Request movies/shows through Overseer, pay $COOP
|
||||||
|
- **Dynamic Pricing** — Request costs rise as disk space fills (scarcity multiplier)
|
||||||
|
- **TV Episode Tiers** — Long-running shows cost more per episode count
|
||||||
|
- **Ko-fi Purchases** — Buy $COOP with real money via Ko-fi store items
|
||||||
|
- **Admin Dashboard** — Manage users, view donations, sync request statuses, adjust barn rules
|
||||||
|
- **Barnyard Theme** — "Peck for Feed", "Join the Flock", thick borders, earthy palette
|
||||||
|
|
||||||
## Quick Start
|
## Quick Start
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# 1. Clone and install dependencies
|
# 1. Clone
|
||||||
git clone <repository> coop-credits
|
git clone <repository> coop-credits
|
||||||
cd coop-credits
|
cd coop-credits
|
||||||
npm install
|
|
||||||
|
|
||||||
# 2. Set up environment
|
# 2. Install dependencies
|
||||||
|
npm run install:all
|
||||||
|
|
||||||
|
# 3. Configure environment
|
||||||
cp .env.example .env
|
cp .env.example .env
|
||||||
# Edit .env with your values
|
# Edit .env with your API keys (Plex, Tautulli, Overseer, Ko-fi)
|
||||||
|
|
||||||
# 3. Create public directory
|
|
||||||
mkdir -p frontend/public
|
|
||||||
|
|
||||||
# 4. Start services
|
# 4. Start services
|
||||||
docker-compose up -d --build
|
docker-compose up -d --build
|
||||||
|
|
||||||
# 5. Initialize database (first time only)
|
# 5. Initialize database (first time only)
|
||||||
docker-compose exec backend npx prisma db push
|
docker exec coop-backend npx prisma db push --accept-data-loss
|
||||||
|
|
||||||
# 6. Configure Caddy (see docs/CADDY-CONFIG.md)
|
# 6. Configure Caddy (see docs/CADDY-CONFIG.md)
|
||||||
# Services expose ports 3000 (frontend) and 3001 (backend) on localhost
|
|
||||||
```
|
```
|
||||||
|
|
||||||
See `docs/CADDY-CONFIG.md` for reverse proxy setup.
|
|
||||||
|
|
||||||
## Project Structure
|
## Project Structure
|
||||||
|
|
||||||
```
|
```
|
||||||
coop-credits/
|
coop-credits/
|
||||||
├── anchor-program/ # Solana Anchor program for $COOP token
|
├── backend/ # Express API server (port 3002)
|
||||||
├── backend/ # Express API server
|
│ ├── src/
|
||||||
├── frontend/ # Next.js dashboard
|
│ │ ├── routes/ # API routes (auth, users, wallet, overseer, admin, webhooks)
|
||||||
├── shared/ # Shared types and utilities
|
│ │ ├── services/ # Tautulli backfill, socket handlers
|
||||||
|
│ │ ├── middleware/ # Auth, rate limiting, error handling
|
||||||
|
│ │ └── utils/ # Prisma client
|
||||||
|
│ └── prisma/
|
||||||
|
│ └── schema.prisma # DB schema (User, Transaction, WatchEvent, ContentRequest, KofiPayment, etc.)
|
||||||
|
├── frontend/ # Next.js 16 dashboard (port 3000)
|
||||||
|
│ └── src/
|
||||||
|
│ ├── app/
|
||||||
|
│ │ ├── page.tsx # Landing page ("Enter the Coop")
|
||||||
|
│ │ ├── login/page.tsx # Plex OAuth login
|
||||||
|
│ │ ├── dashboard/page.tsx # User dashboard
|
||||||
|
│ │ ├── admin/page.tsx # Admin panel
|
||||||
|
│ │ └── dashboard/components/ # WatchHistory, RequestHistory, SearchRequestModal, BuyCreditsModal, etc.
|
||||||
|
│ └── lib/
|
||||||
|
│ ├── api.ts # API client
|
||||||
|
│ ├── store.ts # Zustand auth store
|
||||||
|
│ └── socket.ts # Socket.io connection
|
||||||
├── docs/ # Documentation
|
├── docs/ # Documentation
|
||||||
│ └── CADDY-CONFIG.md # Reverse proxy setup
|
│ ├── CADDY-CONFIG.md # Reverse proxy setup
|
||||||
├── docker-compose.yml # Docker orchestration (no nginx)
|
│ ├── INFRASTRUCTURE.md # Network architecture
|
||||||
|
│ ├── SETUP-INFRASTRUCTURE.md
|
||||||
|
│ └── TROUBLESHOOTING.md
|
||||||
|
├── docker-compose.yml # Docker orchestration
|
||||||
└── .env.example # Environment template
|
└── .env.example # Environment template
|
||||||
```
|
```
|
||||||
|
|
||||||
**Note:** No internal reverse proxy. Use Caddy/Nginx/Traefik externally.
|
|
||||||
|
|
||||||
## User Flow
|
## User Flow
|
||||||
|
|
||||||
1. **Login** → User visits coop.hobokenchicken.com, authenticates with Plex
|
1. **Login** → Visit coop.hobokenchicken.com, click "Join the Flock", authenticate with Plex
|
||||||
2. **Wallet** → Auto-created Solana wallet or connect existing
|
2. **Auto-Backfill** → First login triggers 30-day Tautulli history import (DB-only credits)
|
||||||
3. **Watch** → Viewing on Plex → Tautulli triggers → $COOP minted
|
3. **Watch** → Viewing on Plex → Tautulli webhook → $COOP credited to DB balance
|
||||||
4. **Earn** → Real-time balance updates on dashboard
|
4. **Earn** → Real-time balance updates via Socket.io on dashboard
|
||||||
5. **Spend** → Request content on Overseer → $COOP deducted
|
5. **Spend** → "Peck for Feed" → Search → Request content → $COOP deducted immediately
|
||||||
6. **History** → Full transaction history visible on dashboard
|
6. **Buy More** → "Buy Feed" → Ko-fi store → Credits auto-delivered via webhook
|
||||||
|
|
||||||
## Admin Features
|
## Admin Features
|
||||||
|
|
||||||
- System overview and analytics
|
Access `/admin` with an admin account:
|
||||||
- User management and balance adjustments
|
- **The Flock** — User list with search, reward bonuses, manual backfill, promote/demote admins
|
||||||
- Minting rate controls
|
- **Barn Rules** — Edit credits per minute, min watch %/minutes, movie/TV costs
|
||||||
- Spending controls and promotions
|
- **Donations** — View all incoming Ko-fi payments with status (CREDITED / UNCLAIMED)
|
||||||
- Emergency pause and recovery
|
- **The Feed Queue** — All content requests across users, manual Overseer sync button
|
||||||
|
- **Egg Stats** — Analytics cards: flock size, total $COOP, total requests, pending count
|
||||||
|
|
||||||
## Environment Variables
|
## Environment Variables
|
||||||
|
|
||||||
See `backend/.env.example` and `frontend/.env.local.example` for full configuration.
|
See `.env.example` for full configuration. Key vars:
|
||||||
|
|
||||||
|
```env
|
||||||
|
# Database
|
||||||
|
DATABASE_URL="postgresql://coop:password@localhost:5432/coop_credits?schema=public"
|
||||||
|
|
||||||
|
# Server
|
||||||
|
PORT=3002
|
||||||
|
API_URL=https://coop.hobokenchicken.com
|
||||||
|
|
||||||
|
# JWT (generate: openssl rand -hex 32)
|
||||||
|
JWT_SECRET="..."
|
||||||
|
|
||||||
|
# Plex OAuth
|
||||||
|
PLEX_CLIENT_ID="..."
|
||||||
|
PLEX_CLIENT_SECRET="..."
|
||||||
|
PLEX_REDIRECT_URI=https://coop.hobokenchicken.com/auth/callback
|
||||||
|
|
||||||
|
# Tautulli (host network mode required)
|
||||||
|
TAUTULLI_URL=http://172.20.1.255:8181
|
||||||
|
TAUTULLI_API_KEY="..."
|
||||||
|
|
||||||
|
# Overseer (host network mode required)
|
||||||
|
OVERSEER_URL=http://172.20.1.225:5055
|
||||||
|
OVERSEER_API_KEY="..."
|
||||||
|
|
||||||
|
# Ko-fi
|
||||||
|
KOFI_VERIFICATION_TOKEN="..."
|
||||||
|
|
||||||
|
# Security
|
||||||
|
ENCRYPTION_KEY="..." # openssl rand -base64 32
|
||||||
|
```
|
||||||
|
|
||||||
|
## Dynamic Pricing
|
||||||
|
|
||||||
|
Request costs are adjusted by disk scarcity:
|
||||||
|
- **Multiplier** = `1 + (usedPercent × 2)`
|
||||||
|
- At 0% disk used → 1× base cost
|
||||||
|
- At 50% disk used → 2× base cost
|
||||||
|
- At 90% disk used → 2.8× base cost
|
||||||
|
|
||||||
|
TV shows also have episode tier multipliers on top of scarcity:
|
||||||
|
- ≤50 episodes → base
|
||||||
|
- 51-100 → 1.3×
|
||||||
|
- 101-200 → 1.6×
|
||||||
|
- 201-400 → 2.0×
|
||||||
|
- 400+ → 2.5×
|
||||||
|
|
||||||
|
## Theme
|
||||||
|
|
||||||
|
- **Primary:** Terracotta (`#C06F4A`)
|
||||||
|
- **Secondary:** Duck Egg Blue (`#D4E4E0`)
|
||||||
|
- **Accent:** Wheat (`#E8D5B5`)
|
||||||
|
- **Muted:** Feather Grey (`#C4B5AA`)
|
||||||
|
- **Font:** Comic Sans MS / Chalkboard SE (fallback system-ui)
|
||||||
|
- **Style:** Thick 4px borders, hard black box shadows, rounded-3xl corners
|
||||||
|
|
||||||
|
## Tech Stack
|
||||||
|
|
||||||
|
| Layer | Technology |
|
||||||
|
|-------|-----------|
|
||||||
|
| Frontend | Next.js 16, React 19, TypeScript, Tailwind CSS, shadcn/ui, Zustand |
|
||||||
|
| Backend | Express.js, TypeScript, Prisma ORM, Socket.io |
|
||||||
|
| Database | PostgreSQL 16 |
|
||||||
|
| Cache | Redis 7 (sessions, Socket.io adapter) |
|
||||||
|
| Auth | Plex OAuth 2.0 + JWT |
|
||||||
|
| Payments | Ko-fi webhooks |
|
||||||
|
| Deployment | Docker Compose, Caddy reverse proxy |
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
Private — Hoboken Chicken family use only.
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
# CoopCredits Setup Guide
|
# CoopCredits Setup Guide
|
||||||
|
|
||||||
This guide will walk you through setting up the complete CoopCredits ecosystem.
|
This guide walks you through setting up the complete CoopCredits ecosystem.
|
||||||
|
|
||||||
## Prerequisites
|
## Prerequisites
|
||||||
|
|
||||||
- Node.js 20+
|
- Node.js 20+
|
||||||
- Docker & Docker Compose
|
- Docker & Docker Compose
|
||||||
- Solana CLI (for blockchain development)
|
- Access to Plex, Tautulli, and Overseer instances
|
||||||
- Anchor Framework (for Solana program deployment)
|
- Domain name (for production)
|
||||||
|
|
||||||
## Quick Start
|
## Quick Start
|
||||||
|
|
||||||
@@ -31,48 +31,20 @@ nano .env
|
|||||||
|
|
||||||
Required environment variables:
|
Required environment variables:
|
||||||
- `DATABASE_URL` - PostgreSQL connection string
|
- `DATABASE_URL` - PostgreSQL connection string
|
||||||
- `JWT_SECRET` - Random string for JWT signing
|
- `JWT_SECRET` - Random string for JWT signing (openssl rand -hex 32)
|
||||||
- `PLEX_CLIENT_ID` & `PLEX_CLIENT_SECRET` - From Plex.tv
|
- `PLEX_CLIENT_ID` & `PLEX_CLIENT_SECRET` - From Plex.tv
|
||||||
- `TAUTULLI_API_KEY` - From Tautulli settings
|
- `TAUTULLI_API_KEY` - From Tautulli settings
|
||||||
- `OVERSEER_API_KEY` - From Overseer settings
|
- `OVERSEER_API_KEY` - From Overseer settings
|
||||||
- `SOLANA_MINT_AUTHORITY_KEYPAIR` - Will be generated in step 3
|
- `ENCRYPTION_KEY` - For encrypting session data (openssl rand -base64 32)
|
||||||
|
- `KOFI_VERIFICATION_TOKEN` - From Ko-fi settings (optional)
|
||||||
|
|
||||||
### 3. Solana Setup
|
### 3. Database Setup
|
||||||
|
|
||||||
```bash
|
|
||||||
# Run the Solana setup script
|
|
||||||
npm run setup:solana
|
|
||||||
|
|
||||||
# This will:
|
|
||||||
# - Install Solana CLI if needed
|
|
||||||
# - Create a devnet keypair
|
|
||||||
# - Request airdrop (2 SOL)
|
|
||||||
# - Output the private key for your .env file
|
|
||||||
```
|
|
||||||
|
|
||||||
Copy the `SOLANA_MINT_AUTHORITY_KEYPAIR` value into your `.env` file.
|
|
||||||
|
|
||||||
### 4. Deploy Solana Program
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd anchor-program
|
|
||||||
|
|
||||||
# Build the program
|
|
||||||
anchor build
|
|
||||||
|
|
||||||
# Deploy to devnet
|
|
||||||
anchor deploy
|
|
||||||
|
|
||||||
# Note the Program ID and update .env SOLANA_PROGRAM_ID
|
|
||||||
```
|
|
||||||
|
|
||||||
### 5. Database Setup
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Start PostgreSQL and Redis
|
# Start PostgreSQL and Redis
|
||||||
docker-compose up -d postgres redis
|
docker-compose up -d postgres redis
|
||||||
|
|
||||||
# Push schema to database (no migrations needed for fresh setup)
|
# Push schema to database
|
||||||
cd backend
|
cd backend
|
||||||
npx prisma db push
|
npx prisma db push
|
||||||
|
|
||||||
@@ -80,44 +52,34 @@ npx prisma db push
|
|||||||
npx prisma generate
|
npx prisma generate
|
||||||
```
|
```
|
||||||
|
|
||||||
### 6. Start Development
|
### 4. Start Development
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Start all services
|
# Start all services
|
||||||
npm run dev
|
npm run dev
|
||||||
|
|
||||||
# Or individually:
|
# Or individually:
|
||||||
npm run dev:backend # API on port 3001
|
npm run dev:backend # API on port 3002
|
||||||
npm run dev:frontend # Next.js on port 3000
|
npm run dev:frontend # Next.js on port 3000
|
||||||
```
|
```
|
||||||
|
|
||||||
### 7. Configure Tautulli Webhook
|
### 5. Production Deployment
|
||||||
|
|
||||||
1. Open Tautulli Settings
|
|
||||||
2. Go to Notification Agents → Add Agent → Webhook
|
|
||||||
3. Configure:
|
|
||||||
- Webhook URL: `http://your-server:3001/webhooks/tautulli`
|
|
||||||
- Webhook Method: POST
|
|
||||||
- JSON Payload: See webhook template in Admin Dashboard
|
|
||||||
4. Enable "Notify on Watched"
|
|
||||||
|
|
||||||
### 8. Production Deployment
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Create public directory (required for build)
|
# Create public directory (required for build)
|
||||||
mkdir -p frontend/public
|
mkdir -p frontend/public
|
||||||
|
|
||||||
# Deploy (Caddy handles SSL termination)
|
# Deploy
|
||||||
docker-compose up -d --build
|
docker-compose up -d --build
|
||||||
```
|
```
|
||||||
|
|
||||||
**Note:** This setup runs HTTP only on port 80. Place behind Caddy or another reverse proxy for SSL termination.
|
**Note:** This runs HTTP internally. Place behind Caddy or another reverse proxy for SSL termination. Backend runs on port 3002.
|
||||||
|
|
||||||
## Architecture Overview
|
## Architecture Overview
|
||||||
|
|
||||||
```
|
```
|
||||||
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
|
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
|
||||||
│ User Browser │────▶│ Next.js (3000) │────▶│ Express (3001) │
|
│ User Browser │────▶│ Next.js (3000) │────▶│ Express (3002) │
|
||||||
└─────────────────┘ └─────────────────┘ └─────────────────┘
|
└─────────────────┘ └─────────────────┘ └─────────────────┘
|
||||||
│
|
│
|
||||||
┌─────────────────┐ │
|
┌─────────────────┐ │
|
||||||
@@ -126,8 +88,8 @@ docker-compose up -d --build
|
|||||||
└─────────────────┘
|
└─────────────────┘
|
||||||
▲
|
▲
|
||||||
┌─────────────────┐
|
┌─────────────────┐
|
||||||
│ Solana Devnet │
|
│ Ko-fi │
|
||||||
│ ($COOP Token) │
|
│ (Purchases) │
|
||||||
└─────────────────┘
|
└─────────────────┘
|
||||||
▲
|
▲
|
||||||
┌───────────────────────┴───────────────────────┐
|
┌───────────────────────┴───────────────────────┐
|
||||||
@@ -141,19 +103,20 @@ docker-compose up -d --build
|
|||||||
## User Flow
|
## User Flow
|
||||||
|
|
||||||
1. **Login**: User authenticates with Plex OAuth
|
1. **Login**: User authenticates with Plex OAuth
|
||||||
2. **Wallet**: Auto-created Solana wallet (or connect existing)
|
2. **Backfill**: First login triggers 30-day Tautulli history import
|
||||||
3. **Watch**: Viewing on Plex → Tautulli triggers webhook
|
3. **Watch**: Viewing on Plex → Tautulli triggers webhook → $COOP credited to DB
|
||||||
4. **Earn**: Backend validates → Mints $COOP tokens
|
4. **Earn**: Real-time balance updates on dashboard via Socket.io
|
||||||
5. **Spend**: Request content on Overseer → Deducts $COOP
|
5. **Spend**: Request content on Overseer → $COOP deducted from DB balance
|
||||||
|
6. **Buy**: Ko-fi purchase → Webhook → $COOP added to DB balance
|
||||||
|
|
||||||
## Admin Features
|
## Admin Features
|
||||||
|
|
||||||
Access `/admin` with an admin account to:
|
Access `/admin` with an admin account to:
|
||||||
- View system analytics
|
- **The Flock** — User list with search, bonuses, backfill, promote/demote
|
||||||
- Manage users and grant bonuses
|
- **Barn Rules** — Edit credits per minute, watch thresholds, request costs
|
||||||
- Configure minting rates
|
- **Donations** — View Ko-fi payment history
|
||||||
- Pause/resume minting
|
- **The Feed Queue** — All content requests with Overseer sync button
|
||||||
- Monitor transactions
|
- **Egg Stats** — Analytics cards (users, total credits, requests, pending)
|
||||||
|
|
||||||
## Troubleshooting
|
## Troubleshooting
|
||||||
|
|
||||||
@@ -162,30 +125,26 @@ Access `/admin` with an admin account to:
|
|||||||
# Reset database
|
# Reset database
|
||||||
docker-compose down -v
|
docker-compose down -v
|
||||||
docker-compose up -d postgres
|
docker-compose up -d postgres
|
||||||
npx prisma migrate dev
|
cd backend && npx prisma db push
|
||||||
```
|
|
||||||
|
|
||||||
### Solana Transaction Failures
|
|
||||||
```bash
|
|
||||||
# Check balance
|
|
||||||
solana balance <pubkey>
|
|
||||||
|
|
||||||
# Request airdrop
|
|
||||||
solana airdrop 2 <pubkey>
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Tautulli Webhook Not Working
|
### Tautulli Webhook Not Working
|
||||||
1. Check webhook URL is accessible
|
1. Check webhook URL is accessible
|
||||||
2. Verify `TAUTULLI_WEBHOOK_SECRET` matches
|
2. Verify `TAUTULLI_WEBHOOK_SECRET` matches (optional)
|
||||||
3. Check backend logs: `docker-compose logs backend`
|
3. Check backend logs: `docker-compose logs backend`
|
||||||
|
|
||||||
|
### Request Stuck on PENDING
|
||||||
|
1. Check Overseer webhook is configured
|
||||||
|
2. Use admin dashboard **The Feed Queue** → **SYNC** button
|
||||||
|
3. Or use dashboard **Requests** tab → refresh button
|
||||||
|
|
||||||
## Security Considerations
|
## Security Considerations
|
||||||
|
|
||||||
1. **Private Keys**: Never commit `.env` files
|
1. **Never commit `.env` files**
|
||||||
2. **JWT Secret**: Use a strong random string (32+ chars)
|
2. **JWT Secret**: Use a strong random string (32+ chars)
|
||||||
3. **Encryption Key**: Use `openssl rand -base64 32`
|
3. **Encryption Key**: Use `openssl rand -base64 32`
|
||||||
4. **SSL**: Always use HTTPS in production
|
4. **SSL**: Always use HTTPS in production (Caddy handles this)
|
||||||
5. **Rate Limiting**: Nginx config includes rate limits
|
5. **Rate Limiting**: 1000 req/15min per IP
|
||||||
|
|
||||||
## Support
|
## Support
|
||||||
|
|
||||||
@@ -193,3 +152,4 @@ For issues or questions:
|
|||||||
1. Check logs: `docker-compose logs -f`
|
1. Check logs: `docker-compose logs -f`
|
||||||
2. Review environment variables
|
2. Review environment variables
|
||||||
3. Verify all services are running: `docker-compose ps`
|
3. Verify all services are running: `docker-compose ps`
|
||||||
|
4. Check `docs/TROUBLESHOOTING.md`
|
||||||
|
|||||||
+26
-17
@@ -1,41 +1,47 @@
|
|||||||
# Caddy Configuration
|
# Caddy Configuration
|
||||||
|
|
||||||
Caddy handles SSL termination and routes to the application services.
|
Caddy handles SSL termination and routes to the application services running on `172.20.1.238`.
|
||||||
|
|
||||||
## Caddyfile Example
|
## Caddyfile Example
|
||||||
|
|
||||||
```caddy
|
```caddy
|
||||||
coop.hobokenchicken.com {
|
coop.hobokenchicken.com {
|
||||||
# Frontend (Next.js)
|
# Frontend (Next.js)
|
||||||
handle_path /* {
|
handle /* {
|
||||||
reverse_proxy localhost:3000
|
reverse_proxy 172.20.1.238:3000
|
||||||
}
|
}
|
||||||
|
|
||||||
# API routes
|
# API routes — use handle (NOT handle_path) to preserve /api/ prefix
|
||||||
handle_path /api/* {
|
handle /api/* {
|
||||||
reverse_proxy localhost:3001
|
reverse_proxy 172.20.1.238:3002
|
||||||
}
|
}
|
||||||
|
|
||||||
# Webhooks
|
# Webhooks
|
||||||
handle_path /webhooks/* {
|
handle /webhooks/* {
|
||||||
reverse_proxy localhost:3001
|
reverse_proxy 172.20.1.238:3002
|
||||||
}
|
}
|
||||||
|
|
||||||
# WebSocket support
|
# WebSocket support
|
||||||
handle_path /socket.io/* {
|
handle /socket.io/* {
|
||||||
reverse_proxy localhost:3001
|
reverse_proxy 172.20.1.238:3002
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
> **Critical:** Use `handle` (not `handle_path`) for `/api/*` and `/webhooks/*`. `handle_path` strips the path prefix, which breaks Express routing.
|
||||||
|
|
||||||
## Docker Compose (no nginx)
|
## Docker Compose (no nginx)
|
||||||
|
|
||||||
Services bind to localhost only (`127.0.0.1`):
|
Services bind as follows:
|
||||||
|
|
||||||
- **Frontend**: `127.0.0.1:3000`
|
- **Frontend**: `0.0.0.0:3000` (bridge network, accessible from Caddy)
|
||||||
- **Backend**: `127.0.0.1:3001`
|
- **Backend**: `localhost:3002` (host network, accessible from Caddy via host IP)
|
||||||
- **Postgres**: `5432` (internal only)
|
- **Postgres**: `127.0.0.1:5432` (localhost only)
|
||||||
- **Redis**: `6379` (internal only)
|
- **Redis**: `127.0.0.1:6379` (localhost only)
|
||||||
|
|
||||||
|
## Backend Port
|
||||||
|
|
||||||
|
Backend runs on **port 3002** (not 3001). Caddy must proxy to `172.20.1.238:3002`.
|
||||||
|
|
||||||
## Start Stack
|
## Start Stack
|
||||||
|
|
||||||
@@ -43,8 +49,11 @@ Services bind to localhost only (`127.0.0.1`):
|
|||||||
# Start services
|
# Start services
|
||||||
docker-compose up -d
|
docker-compose up -d
|
||||||
|
|
||||||
# Verify
|
# Verify backend
|
||||||
curl http://localhost:3001/health
|
curl http://172.20.1.238:3002/health
|
||||||
|
|
||||||
|
# Verify frontend
|
||||||
|
curl http://172.20.1.238:3000
|
||||||
```
|
```
|
||||||
|
|
||||||
Caddy automatically provisions SSL and routes traffic.
|
Caddy automatically provisions SSL and routes traffic.
|
||||||
|
|||||||
+113
-109
@@ -10,15 +10,16 @@
|
|||||||
│ HTTPS (443)
|
│ HTTPS (443)
|
||||||
▼
|
▼
|
||||||
┌─────────────────────────────────────────────────────────────────────────┐
|
┌─────────────────────────────────────────────────────────────────────────┐
|
||||||
│ CoopCredits Server │
|
│ CoopCredits Server (172.20.1.238) │
|
||||||
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
|
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
|
||||||
│ │ Nginx │ │ Frontend │ │ Backend │ │ PostgreSQL │ │
|
│ │ Caddy │ │ Frontend │ │ Backend │ │ PostgreSQL │ │
|
||||||
│ │ (80) │──│ (Next.js) │──│ (Express) │──│ (5432) │ │
|
│ │ (reverse) │──│ (Next.js) │ │ (Express) │──│ (5432) │ │
|
||||||
|
│ │ Proxy │ │ :3000 │ │ :3002 │ │ │ │
|
||||||
│ └──────────────┘ └──────────────┘ └──────┬───────┘ └──────────────┘ │
|
│ └──────────────┘ └──────────────┘ └──────┬───────┘ └──────────────┘ │
|
||||||
│ │ │
|
│ │ │
|
||||||
│ ┌──────────────┐ │ ┌──────────────┐ │
|
│ ┌──────────────┐ │ ┌──────────────┐ │
|
||||||
│ │ Redis │◀────────┘ │ Anchor CLI │ │
|
│ │ Redis │◀────────┘ │ (Ko-fi) │ │
|
||||||
│ │ (6379) │ │ (Optional) │ │
|
│ │ (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
|
## 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)
|
### Plex Server (172.20.1.220:32400)
|
||||||
- **Purpose**: Content streaming and user authentication
|
- **Purpose:** Content streaming and user authentication
|
||||||
- **Integration**: OAuth authentication for website login
|
- **Integration:** OAuth 2.0 login for website
|
||||||
- **Access**: HTTP on local network, may have remote access enabled
|
|
||||||
|
|
||||||
### Tautulli (172.20.1.255:8181)
|
### Tautulli (172.20.1.255:8181)
|
||||||
- **Purpose**: Plex analytics and watch event tracking
|
- **Purpose:** Plex analytics and watch event tracking
|
||||||
- **Integration**: Webhook notifications to CoopCredits backend
|
- **Integration:** Webhook notifications to CoopCredits on watch events
|
||||||
- **Access**: HTTP on local network
|
- **API Key:** Required for backfill queries
|
||||||
- **API Key**: Required for backend queries
|
|
||||||
|
|
||||||
### Overseer (172.20.1.225:5055)
|
### Overseer (172.20.1.225:5055)
|
||||||
- **Purpose**: Content request management
|
- **Purpose:** Content request management
|
||||||
- **Integration**: API for requesting content, webhooks for status updates
|
- **Integration:** API for creating requests, webhooks for status updates
|
||||||
- **Access**: HTTP on local network
|
- **API Key:** Required for search and request creation
|
||||||
- **API Key**: Required for backend integration
|
- **Disk Space:** Used for dynamic pricing scarcity calculation
|
||||||
|
|
||||||
### 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
|
|
||||||
|
|
||||||
## Communication Flow
|
## Communication Flow
|
||||||
|
|
||||||
### 1. User Authentication
|
### 1. User Authentication
|
||||||
```
|
```
|
||||||
User → Nginx → Frontend → Backend → Plex OAuth (172.20.1.220:32400)
|
User → Caddy → Frontend → Backend → Plex OAuth (172.20.1.220:32400)
|
||||||
↓
|
↓
|
||||||
User authenticated, JWT issued
|
User authenticated, JWT issued
|
||||||
|
Session stored in PostgreSQL
|
||||||
```
|
```
|
||||||
|
|
||||||
### 2. Watch Event Processing
|
### 2. Watch Event Processing
|
||||||
```
|
```
|
||||||
Plex → Tautulli → Webhook → Nginx → Backend → Solana Devnet
|
Plex → Tautulli → Webhook → Caddy → Backend → PostgreSQL
|
||||||
↓
|
↓
|
||||||
Database updated
|
WatchEvent + Transaction created
|
||||||
↓
|
Socket.io → User notified
|
||||||
WebSocket → User notified
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### 3. Content Request
|
### 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
|
## Security Considerations
|
||||||
|
|
||||||
### Network Security
|
### Network Security
|
||||||
1. **Local Network**: All services communicate over HTTP (trusted network)
|
1. **Backend host mode** — Required for local network access, but exposes host network
|
||||||
2. **External Access**: Only Nginx exposed (ports 80/443)
|
2. **Caddy handles SSL** — Only HTTPS externally
|
||||||
3. **Internal Services**: Not accessible from external network
|
3. **Internal services** — PostgreSQL/Redis not exposed externally (except through Docker ports)
|
||||||
|
|
||||||
### API Security
|
### API Security
|
||||||
1. **Tautulli Webhook**: Secret verification recommended
|
1. **Tautulli Webhook** — Optional secret verification (`TAUTULLI_WEBHOOK_SECRET`)
|
||||||
2. **Overseer API**: API key authentication
|
2. **Overseer Webhook** — No secret currently configured
|
||||||
3. **Plex OAuth**: Standard OAuth 2.0 flow
|
3. **Plex OAuth** — Standard OAuth 2.0 flow
|
||||||
4. **JWT**: Secure tokens for session management
|
4. **JWT** — Secure tokens with nonce for session deduplication
|
||||||
|
5. **Rate Limiting** — 1000 requests per 15 minutes per IP
|
||||||
|
|
||||||
### Data Security
|
### Data Security
|
||||||
1. **Wallet Keys**: Encrypted with AES-256-GCM in database
|
1. **No wallet keys** — Solana removed, no private keys stored
|
||||||
2. **Database**: Not exposed externally
|
2. **Database** — Localhost only, password protected
|
||||||
3. **Redis**: Password protected, localhost only
|
3. **Redis** — Localhost only
|
||||||
|
4. **Ko-fi verification** — Token check on webhook endpoint
|
||||||
|
|
||||||
## Firewall Configuration
|
## Firewall Configuration
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Web traffic
|
# Web traffic (Caddy handles SSL)
|
||||||
sudo ufw allow 80/tcp
|
sudo ufw allow 80/tcp
|
||||||
sudo ufw allow 443/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
|
sudo ufw allow from 172.20.0.0/16 to 172.20.1.0/24
|
||||||
|
|
||||||
# Block external access to internal services
|
# Block external access to internal services
|
||||||
sudo ufw deny 3000/tcp # Frontend
|
sudo ufw deny 3000/tcp # Frontend (should be localhost only)
|
||||||
sudo ufw deny 3001/tcp # Backend
|
sudo ufw deny 3002/tcp # Backend (should be localhost only)
|
||||||
sudo ufw deny 5432/tcp # PostgreSQL
|
sudo ufw deny 5432/tcp # PostgreSQL
|
||||||
sudo ufw deny 6379/tcp # Redis
|
sudo ufw deny 6379/tcp # Redis
|
||||||
```
|
```
|
||||||
|
|
||||||
## Docker Network Configuration
|
## Docker Network Configuration
|
||||||
|
|
||||||
### Internal Network (coop-internal)
|
### Bridge Network (coop-network)
|
||||||
- Containers can communicate with each other
|
- Frontend container uses this
|
||||||
- Isolated from external network
|
- Isolated from external network
|
||||||
- Used for: frontend ↔ backend ↔ database
|
- Connects: frontend ↔ Caddy proxy
|
||||||
|
|
||||||
### External Network (coop-external)
|
### Host Network (backend only)
|
||||||
- Allows containers to reach local services
|
- Backend container uses `network_mode: host`
|
||||||
- Subnet: 172.20.2.0/24
|
- Shares host's network stack
|
||||||
- Used for: backend → Tautulli/Overseer/Plex
|
- Required to reach `172.20.1.x` services (Tautulli, Overseer)
|
||||||
|
- Connects directly to PostgreSQL/Redis on `localhost`
|
||||||
## SSL/TLS
|
|
||||||
|
|
||||||
SSL/TLS is handled by an external reverse proxy (e.g., Caddy). The application stack runs HTTP only on port 80 internally.
|
|
||||||
|
|
||||||
## Monitoring and Logging
|
## Monitoring and Logging
|
||||||
|
|
||||||
### Log Locations
|
### Log Locations
|
||||||
- Nginx: `docker/nginx/logs/`
|
- Backend: `docker logs coop-backend`
|
||||||
- Backend: Docker logs (`docker-compose logs backend`)
|
- Frontend: `docker logs coop-frontend`
|
||||||
- Frontend: Docker logs (`docker-compose logs frontend`)
|
|
||||||
- Database: Inside container (`/var/log/postgresql/`)
|
- Database: Inside container (`/var/log/postgresql/`)
|
||||||
|
|
||||||
### Health Checks
|
### Health Checks
|
||||||
```bash
|
```bash
|
||||||
# Backend health
|
# Backend health
|
||||||
curl https://coop.hobokenchicken.com/health
|
curl http://localhost:3002/health
|
||||||
|
|
||||||
# Database connection
|
# Database connection
|
||||||
docker-compose exec postgres pg_isready -U coop
|
docker exec coop-postgres pg_isready -U coop
|
||||||
|
|
||||||
# Service status
|
# 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
|
## Backup and Recovery
|
||||||
|
|
||||||
### Database Backup
|
### Database Backup
|
||||||
```bash
|
```bash
|
||||||
# Automated backup script
|
# Automated backup
|
||||||
docker-compose exec -T postgres pg_dump -U coop coop_credits > backup_$(date +%Y%m%d).sql
|
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
|
### Configuration Backup
|
||||||
- `.env` file (contains all secrets)
|
- `.env` file (contains all secrets)
|
||||||
- `docker/nginx/ssl/` certificates
|
- `docker-compose.yml` service config
|
||||||
- `docker-compose.prod.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
|
||||||
|
|||||||
+76
-159
@@ -5,9 +5,10 @@ This guide covers setting up CoopCredits with your existing Plex/Tautulli/Overse
|
|||||||
## Prerequisites
|
## Prerequisites
|
||||||
|
|
||||||
- Server running Docker and Docker Compose
|
- Server running Docker and Docker Compose
|
||||||
- Access to 172.20.1.0/24 network
|
- Access to `172.20.1.0/24` network
|
||||||
- API keys from Tautulli and Overseer
|
- API keys from Tautulli and Overseer
|
||||||
- Domain name (coop.hobokenchicken.com) pointing to your server
|
- Domain name (`coop.hobokenchicken.com`) pointing to your server
|
||||||
|
- Ko-fi account with store items set up (optional, for credit purchases)
|
||||||
|
|
||||||
## Network Overview
|
## Network Overview
|
||||||
|
|
||||||
@@ -38,72 +39,64 @@ git clone <repository> coop-credits
|
|||||||
cd coop-credits
|
cd coop-credits
|
||||||
```
|
```
|
||||||
|
|
||||||
### 2. Run Infrastructure Setup
|
### 2. Configure Environment
|
||||||
|
|
||||||
```bash
|
|
||||||
./deployment/setup-infrastructure.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
This script will:
|
|
||||||
- Test connectivity to your services (Plex, Tautulli, Overseer)
|
|
||||||
- Generate a secure `.env` file
|
|
||||||
- Output configuration instructions
|
|
||||||
|
|
||||||
**Note:** SSL/TLS is handled by your external reverse proxy (Caddy). The application runs HTTP on port 80 internally.
|
|
||||||
|
|
||||||
### 3. Configure Environment
|
|
||||||
|
|
||||||
Edit the generated `.env` file:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
cp .env.example .env
|
||||||
nano .env
|
nano .env
|
||||||
```
|
```
|
||||||
|
|
||||||
Add your API keys:
|
Required environment variables:
|
||||||
|
|
||||||
```env
|
```env
|
||||||
# Get from Tautulli: Settings > Web Interface > API
|
# Database
|
||||||
TAUTULLI_API_KEY=your-tautulli-api-key
|
DATABASE_URL="postgresql://coop:coop_password@localhost:5432/coop_credits?schema=public"
|
||||||
|
|
||||||
# Get from Overseer: Settings > General > API Key
|
# Server
|
||||||
OVERSEER_API_KEY=your-overseer-api-key
|
PORT=3002
|
||||||
|
API_URL=https://coop.hobokenchicken.com
|
||||||
|
FRONTEND_URL=https://coop.hobokenchicken.com
|
||||||
|
|
||||||
# Get from https://plex.tv/claim or Plex settings
|
# JWT Secret (generate: openssl rand -hex 32)
|
||||||
|
JWT_SECRET=your-random-secret
|
||||||
|
|
||||||
|
# Plex OAuth
|
||||||
PLEX_CLIENT_ID=your-plex-client-id
|
PLEX_CLIENT_ID=your-plex-client-id
|
||||||
PLEX_CLIENT_SECRET=your-plex-client-secret
|
PLEX_CLIENT_SECRET=your-plex-client-secret
|
||||||
|
PLEX_REDIRECT_URI=https://coop.hobokenchicken.com/auth/callback
|
||||||
|
|
||||||
|
# Tautulli
|
||||||
|
TAUTULLI_URL=http://172.20.1.255:8181
|
||||||
|
TAUTULLI_API_KEY=your-tautulli-api-key
|
||||||
|
|
||||||
|
# Overseer
|
||||||
|
OVERSEER_URL=http://172.20.1.225:5055
|
||||||
|
OVERSEER_API_KEY=your-overseer-api-key
|
||||||
|
|
||||||
|
# Ko-fi (optional — for credit purchases)
|
||||||
|
KOFI_VERIFICATION_TOKEN=your-kofi-verification-token
|
||||||
|
|
||||||
|
# Security
|
||||||
|
ENCRYPTION_KEY=$(openssl rand -base64 32)
|
||||||
```
|
```
|
||||||
|
|
||||||
### 4. Setup Solana
|
### 3. Deploy
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npm run setup:solana
|
docker-compose up -d --build
|
||||||
|
|
||||||
|
# Initialize database (first time only)
|
||||||
|
docker exec coop-backend npx prisma db push --accept-data-loss
|
||||||
```
|
```
|
||||||
|
|
||||||
This will:
|
### 4. Configure Caddy
|
||||||
- Install Solana CLI
|
|
||||||
- Create a devnet wallet
|
|
||||||
- Request airdrop
|
|
||||||
- Output the private key for your `.env` file
|
|
||||||
|
|
||||||
Copy the `SOLANA_MINT_AUTHORITY_KEYPAIR` into your `.env` file.
|
See `docs/CADDY-CONFIG.md`. Key points:
|
||||||
|
- Backend runs on **port 3002**
|
||||||
|
- Use `handle` (not `handle_path`) for `/api/*`
|
||||||
|
- Proxy `/webhooks/*` to backend
|
||||||
|
|
||||||
### 5. Deploy Solana Program
|
### 5. Configure Tautulli Webhook
|
||||||
|
|
||||||
```bash
|
|
||||||
cd anchor-program
|
|
||||||
anchor build
|
|
||||||
anchor deploy
|
|
||||||
```
|
|
||||||
|
|
||||||
Update `SOLANA_PROGRAM_ID` in `.env` with the deployed program ID.
|
|
||||||
|
|
||||||
### 6. Deploy
|
|
||||||
|
|
||||||
```bash
|
|
||||||
./deployment/deploy-production.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
### 8. Configure Tautulli Webhook
|
|
||||||
|
|
||||||
1. Open Tautulli: http://172.20.1.255:8181
|
1. Open Tautulli: http://172.20.1.255:8181
|
||||||
2. Go to **Settings > Notification Agents**
|
2. Go to **Settings > Notification Agents**
|
||||||
@@ -134,7 +127,7 @@ Update `SOLANA_PROGRAM_ID` in `.env` with the deployed program ID.
|
|||||||
|
|
||||||
**Triggers:** Enable **Watched**
|
**Triggers:** Enable **Watched**
|
||||||
|
|
||||||
### 9. Configure Overseer Webhook
|
### 6. Configure Overseer Webhook
|
||||||
|
|
||||||
1. Open Overseer: http://172.20.1.225:5055
|
1. Open Overseer: http://172.20.1.225:5055
|
||||||
2. Go to **Settings > Notifications**
|
2. Go to **Settings > Notifications**
|
||||||
@@ -142,7 +135,7 @@ Update `SOLANA_PROGRAM_ID` in `.env` with the deployed program ID.
|
|||||||
|
|
||||||
**Configuration:**
|
**Configuration:**
|
||||||
- Webhook URL: `https://coop.hobokenchicken.com/webhooks/overseer`
|
- Webhook URL: `https://coop.hobokenchicken.com/webhooks/overseer`
|
||||||
- Authorization Header: `Bearer your-webhook-secret-from-env`
|
- Content Type: `application/json`
|
||||||
|
|
||||||
**JSON Payload:**
|
**JSON Payload:**
|
||||||
```json
|
```json
|
||||||
@@ -156,24 +149,33 @@ Update `SOLANA_PROGRAM_ID` in `.env` with the deployed program ID.
|
|||||||
|
|
||||||
**Events:** Enable **Request Approved** and **Request Declined**
|
**Events:** Enable **Request Approved** and **Request Declined**
|
||||||
|
|
||||||
|
### 7. Configure Ko-fi Webhook (Optional)
|
||||||
|
|
||||||
|
1. Go to ko-fi.com → **Settings > Webhooks**
|
||||||
|
2. Set **Webhook URL** to: `https://coop.hobokenchicken.com/webhooks/kofi`
|
||||||
|
3. Save
|
||||||
|
|
||||||
|
Create store items:
|
||||||
|
- $5 item → link: `https://ko-fi.com/s/YOUR_ITEM_ID`
|
||||||
|
- $10 item → link: `https://ko-fi.com/s/YOUR_ITEM_ID`
|
||||||
|
|
||||||
|
Update frontend preset links in `frontend/src/app/dashboard/components/BuyCreditsModal.tsx`
|
||||||
|
|
||||||
|
### 8. Set Admin User
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker exec coop-postgres psql -U coop -d coop_credits -c "UPDATE users SET is_admin = true WHERE plex_username = 'YOUR_USERNAME';"
|
||||||
|
```
|
||||||
|
|
||||||
## Verification
|
## Verification
|
||||||
|
|
||||||
### Test Connectivity
|
### Test Connectivity
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
./deployment/health-check.sh
|
# Backend health
|
||||||
```
|
curl https://coop.hobokenchicken.com/health
|
||||||
|
|
||||||
### Watch Mode
|
# Test Tautulli webhook manually
|
||||||
|
|
||||||
```bash
|
|
||||||
./deployment/health-check.sh --watch
|
|
||||||
```
|
|
||||||
|
|
||||||
### Manual Tests
|
|
||||||
|
|
||||||
**Test Tautulli webhook:**
|
|
||||||
```bash
|
|
||||||
curl -X POST https://coop.hobokenchicken.com/webhooks/tautulli \
|
curl -X POST https://coop.hobokenchicken.com/webhooks/tautulli \
|
||||||
-H "Content-Type: application/json" \
|
-H "Content-Type: application/json" \
|
||||||
-d '{
|
-d '{
|
||||||
@@ -190,88 +192,6 @@ curl -X POST https://coop.hobokenchicken.com/webhooks/tautulli \
|
|||||||
}'
|
}'
|
||||||
```
|
```
|
||||||
|
|
||||||
**Test API:**
|
|
||||||
```bash
|
|
||||||
curl https://coop.hobokenchicken.com/api/health
|
|
||||||
```
|
|
||||||
|
|
||||||
## Firewall Configuration
|
|
||||||
|
|
||||||
If using UFW:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Allow web traffic
|
|
||||||
sudo ufw allow 80/tcp
|
|
||||||
sudo ufw allow 443/tcp
|
|
||||||
|
|
||||||
# Allow backend to reach local network
|
|
||||||
sudo ufw allow from 172.20.2.0/16 to 172.20.1.0/24
|
|
||||||
|
|
||||||
# Deny direct access to internal services
|
|
||||||
sudo ufw deny 3000/tcp
|
|
||||||
sudo ufw deny 3001/tcp
|
|
||||||
sudo ufw deny 5432/tcp
|
|
||||||
sudo ufw deny 6379/tcp
|
|
||||||
|
|
||||||
# Enable firewall
|
|
||||||
sudo ufw enable
|
|
||||||
```
|
|
||||||
|
|
||||||
## Troubleshooting
|
|
||||||
|
|
||||||
### Cannot reach local services
|
|
||||||
|
|
||||||
1. Check Docker network:
|
|
||||||
```bash
|
|
||||||
docker network inspect coop-credits_coop-external
|
|
||||||
```
|
|
||||||
|
|
||||||
2. Test connectivity from container:
|
|
||||||
```bash
|
|
||||||
docker exec coop-backend ping 172.20.1.255
|
|
||||||
```
|
|
||||||
|
|
||||||
3. Verify firewall rules:
|
|
||||||
```bash
|
|
||||||
sudo ufw status verbose
|
|
||||||
```
|
|
||||||
|
|
||||||
### Webhooks not working
|
|
||||||
|
|
||||||
1. Check Nginx logs:
|
|
||||||
```bash
|
|
||||||
tail -f docker/nginx/logs/access.log
|
|
||||||
```
|
|
||||||
|
|
||||||
2. Check backend logs:
|
|
||||||
```bash
|
|
||||||
docker-compose -f docker-compose.prod.yml logs -f backend
|
|
||||||
```
|
|
||||||
|
|
||||||
3. Test webhook manually:
|
|
||||||
```bash
|
|
||||||
curl -X POST https://coop.hobokenchicken.com/webhooks/tautulli \
|
|
||||||
-H "Content-Type: application/json" \
|
|
||||||
-d '{"test": true}'
|
|
||||||
```
|
|
||||||
|
|
||||||
### Database connection issues
|
|
||||||
|
|
||||||
1. Check database status:
|
|
||||||
```bash
|
|
||||||
docker-compose -f docker-compose.prod.yml ps postgres
|
|
||||||
```
|
|
||||||
|
|
||||||
2. View database logs:
|
|
||||||
```bash
|
|
||||||
docker-compose -f docker-compose.prod.yml logs postgres
|
|
||||||
```
|
|
||||||
|
|
||||||
3. Test connection:
|
|
||||||
```bash
|
|
||||||
docker-compose -f docker-compose.prod.yml exec postgres pg_isready -U coop
|
|
||||||
```
|
|
||||||
|
|
||||||
## Maintenance
|
## Maintenance
|
||||||
|
|
||||||
### Update Application
|
### Update Application
|
||||||
@@ -279,48 +199,45 @@ sudo ufw enable
|
|||||||
```bash
|
```bash
|
||||||
cd /opt/coop-credits
|
cd /opt/coop-credits
|
||||||
git pull
|
git pull
|
||||||
./deployment/deploy-production.sh
|
docker-compose up -d --build
|
||||||
```
|
```
|
||||||
|
|
||||||
### Backup Database
|
### Backup Database
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Automated backup
|
docker exec -T coop-postgres pg_dump -U coop coop_credits > backup_$(date +%Y%m%d).sql
|
||||||
docker-compose -f docker-compose.prod.yml exec -T postgres pg_dump -U coop coop_credits > backup_$(date +%Y%m%d).sql
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### View Logs
|
### View Logs
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# All services
|
# All services
|
||||||
docker-compose -f docker-compose.prod.yml logs -f
|
docker-compose logs -f
|
||||||
|
|
||||||
# Specific service
|
# Specific service
|
||||||
docker-compose -f docker-compose.prod.yml logs -f backend
|
docker-compose logs -f backend
|
||||||
```
|
```
|
||||||
|
|
||||||
### Restart Services
|
### Restart Services
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker-compose -f docker-compose.prod.yml restart backend
|
docker-compose restart backend
|
||||||
|
docker-compose restart frontend
|
||||||
```
|
```
|
||||||
|
|
||||||
## Security Checklist
|
## Security Checklist
|
||||||
|
|
||||||
- [ ] Changed all default passwords in `.env`
|
- [ ] Changed default PostgreSQL password
|
||||||
- [ ] External reverse proxy (Caddy) configured for SSL
|
- [ ] External reverse proxy (Caddy) configured for SSL
|
||||||
- [ ] Firewall rules configured
|
- [ ] Firewall rules configured
|
||||||
- [ ] Tautulli webhook secret set
|
|
||||||
- [ ] Overseer webhook secret set
|
|
||||||
- [ ] JWT secret is random and secure
|
- [ ] JWT secret is random and secure
|
||||||
- [ ] Database not exposed externally
|
- [ ] Database not exposed externally
|
||||||
- [ ] Redis password set
|
|
||||||
- [ ] Encryption key is random and backed up
|
- [ ] Encryption key is random and backed up
|
||||||
- [ ] Solana mint authority key backed up securely
|
- [ ] Ko-fi verification token set (if using purchases)
|
||||||
|
|
||||||
## Support
|
## Support
|
||||||
|
|
||||||
For issues:
|
For issues:
|
||||||
1. Check health: `./deployment/health-check.sh`
|
1. Check logs: `docker-compose logs -f`
|
||||||
2. Review logs: `docker-compose -f docker-compose.prod.yml logs`
|
2. Review environment variables
|
||||||
3. Check documentation in `docs/INFRASTRUCTURE.md`
|
3. Verify all services are running: `docker ps`
|
||||||
|
|||||||
+82
-134
@@ -1,35 +1,5 @@
|
|||||||
# CoopCredits Troubleshooting Guide
|
# CoopCredits Troubleshooting Guide
|
||||||
|
|
||||||
## Installation Warnings
|
|
||||||
|
|
||||||
### NPM Deprecation Warnings
|
|
||||||
|
|
||||||
When running `npm install`, you may see warnings like:
|
|
||||||
|
|
||||||
```
|
|
||||||
npm WARN deprecated inflight@1.0.6: This module is not supported...
|
|
||||||
npm WARN deprecated glob@7.2.0: Old versions of glob are not supported...
|
|
||||||
npm WARN deprecated @walletconnect/sign-client@2.19.0: ...
|
|
||||||
```
|
|
||||||
|
|
||||||
**These are safe to ignore.** These warnings come from:
|
|
||||||
- Transitive dependencies (dependencies of dependencies)
|
|
||||||
- Solana wallet adapter packages that haven't updated yet
|
|
||||||
- Legacy packages still used by the Anchor framework
|
|
||||||
|
|
||||||
**Critical fix applied:**
|
|
||||||
- ✅ Next.js updated from 14.0.4 to 14.2.15 (security vulnerability patched)
|
|
||||||
|
|
||||||
**What you can do:**
|
|
||||||
```bash
|
|
||||||
# The warnings don't affect functionality
|
|
||||||
# To suppress them during install:
|
|
||||||
npm install --silent
|
|
||||||
|
|
||||||
# Or use --legacy-peer-deps if needed:
|
|
||||||
npm install --legacy-peer-deps
|
|
||||||
```
|
|
||||||
|
|
||||||
## Common Issues
|
## Common Issues
|
||||||
|
|
||||||
### Database Connection Failed
|
### Database Connection Failed
|
||||||
@@ -48,21 +18,6 @@ sleep 5
|
|||||||
docker-compose exec postgres pg_isready -U coop
|
docker-compose exec postgres pg_isready -U coop
|
||||||
```
|
```
|
||||||
|
|
||||||
### Solana Program Build Fails
|
|
||||||
|
|
||||||
**Error:** `anchor build` fails with Rust errors
|
|
||||||
|
|
||||||
**Solution:**
|
|
||||||
```bash
|
|
||||||
# Update Rust
|
|
||||||
cd anchor-program
|
|
||||||
rustup update
|
|
||||||
|
|
||||||
# Rebuild
|
|
||||||
anchor clean
|
|
||||||
anchor build
|
|
||||||
```
|
|
||||||
|
|
||||||
### Webhooks Not Receiving
|
### Webhooks Not Receiving
|
||||||
|
|
||||||
**Error:** Tautulli/Overseer webhooks not triggering
|
**Error:** Tautulli/Overseer webhooks not triggering
|
||||||
@@ -75,16 +30,18 @@ anchor build
|
|||||||
|
|
||||||
2. Check webhook URL in Tautulli/Overseer settings
|
2. Check webhook URL in Tautulli/Overseer settings
|
||||||
|
|
||||||
3. Check Nginx logs:
|
3. Check Caddy routes `/webhooks/*` to backend port 3002
|
||||||
|
|
||||||
|
4. Check backend logs:
|
||||||
```bash
|
```bash
|
||||||
tail -f docker/nginx/logs/access.log
|
docker logs --tail 50 coop-backend
|
||||||
```
|
```
|
||||||
|
|
||||||
4. Test webhook manually:
|
5. Test webhook manually:
|
||||||
```bash
|
```bash
|
||||||
curl -X POST https://coop.hobokenchicken.com/webhooks/tautulli \
|
curl -X POST https://coop.hobokenchicken.com/webhooks/tautulli \
|
||||||
-H "Content-Type: application/json" \
|
-H "Content-Type: application/json" \
|
||||||
-d '{"test": true}'
|
-d '{"action":"watched","user_id":"1","rating_key":"1","session_key":"1","media_type":"movie","title":"Test","started":1,"stopped":3601,"percent_complete":90}'
|
||||||
```
|
```
|
||||||
|
|
||||||
### Cannot Reach Local Services (172.20.1.x)
|
### Cannot Reach Local Services (172.20.1.x)
|
||||||
@@ -93,85 +50,72 @@ anchor build
|
|||||||
|
|
||||||
**Solution:**
|
**Solution:**
|
||||||
```bash
|
```bash
|
||||||
# Test connectivity from backend container
|
# Verify backend is in host network mode
|
||||||
docker exec coop-backend ping 172.20.1.255
|
docker inspect coop-backend | grep NetworkMode
|
||||||
|
# Should show: "host"
|
||||||
|
|
||||||
# Check Docker network
|
# Test connectivity from host
|
||||||
docker network ls
|
ping 172.20.1.255
|
||||||
docker network inspect coop-credits_coop-external
|
|
||||||
|
|
||||||
# Verify firewall rules
|
# Check backend logs
|
||||||
sudo ufw status
|
docker logs --tail 50 coop-backend
|
||||||
|
|
||||||
|
# Verify env vars
|
||||||
|
docker exec coop-backend env | grep TAUTULLI
|
||||||
|
docker exec coop-backend env | grep OVERSEER
|
||||||
```
|
```
|
||||||
|
|
||||||
### Wallet Creation Fails
|
> Backend must use `network_mode: host` to reach `172.20.1.x` subnet. Docker bridge networking cannot route to this subnet.
|
||||||
|
|
||||||
**Error:** `Failed to create wallet` or Solana errors
|
### Ko-fi Webhook Not Working
|
||||||
|
|
||||||
|
**Error:** Payments not crediting users
|
||||||
|
|
||||||
**Solution:**
|
**Solution:**
|
||||||
|
1. Verify `KOFI_VERIFICATION_TOKEN` env var is set in backend container:
|
||||||
```bash
|
```bash
|
||||||
# Check Solana configuration
|
docker exec coop-backend env | grep KOFI
|
||||||
solana config get
|
|
||||||
|
|
||||||
# Ensure you're on devnet
|
|
||||||
solana config set --url devnet
|
|
||||||
|
|
||||||
# Check balance
|
|
||||||
solana balance
|
|
||||||
|
|
||||||
# Request airdrop if needed
|
|
||||||
solana airdrop 2
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
2. Check Ko-fi webhook settings — URL should be:
|
||||||
|
```
|
||||||
|
https://coop.hobokenchicken.com/webhooks/kofi
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Check backend logs for verification token mismatch
|
||||||
|
|
||||||
|
4. Check admin **Donations** tab to see if payments arrive as UNCLAIMED (email mismatch)
|
||||||
|
|
||||||
|
### BigInt JSON Serialization Error
|
||||||
|
|
||||||
|
**Error:** `Do not know how to serialize a BigInt`
|
||||||
|
|
||||||
|
**Solution:** This is fixed in `backend/src/index.ts` with:
|
||||||
|
```typescript
|
||||||
|
(BigInt.prototype as any).toJSON = function () {
|
||||||
|
return this.toString();
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
If you still see it, ensure the patch is loaded before any route handlers.
|
||||||
|
|
||||||
### CORS Errors in Browser
|
### CORS Errors in Browser
|
||||||
|
|
||||||
**Error:** `Access-Control-Allow-Origin` errors
|
**Error:** `Access-Control-Allow-Origin` errors
|
||||||
|
|
||||||
**Solution:**
|
**Solution:**
|
||||||
1. Check `FRONTEND_URL` in backend `.env` matches your actual URL
|
1. Check `FRONTEND_URL` in backend `.env` matches your actual URL
|
||||||
2. Verify CORS_ORIGINS includes your domain
|
2. Verify CORS origins include your domain in `backend/src/index.ts`
|
||||||
3. Restart backend after changes
|
3. Restart backend after changes
|
||||||
|
|
||||||
### High Memory Usage
|
### Rate Limiting (429 Too Many Requests)
|
||||||
|
|
||||||
**Symptom:** Server slows down or OOM errors
|
**Error:** Dashboard shows "Slow down, chicken!" or fails to load
|
||||||
|
|
||||||
**Solution:**
|
**Solution:**
|
||||||
```bash
|
- Rate limit is 1000 requests per 15 minutes per IP
|
||||||
# Check what's using memory
|
- If you hit it, wait a few minutes
|
||||||
docker stats
|
- The dashboard makes several parallel calls on load — this is normal
|
||||||
|
|
||||||
# Restart services
|
|
||||||
docker-compose -f docker-compose.prod.yml restart
|
|
||||||
|
|
||||||
# Increase swap if needed
|
|
||||||
sudo fallocate -l 2G /swapfile
|
|
||||||
sudo chmod 600 /swapfile
|
|
||||||
sudo mkswap /swapfile
|
|
||||||
sudo swapon /swapfile
|
|
||||||
```
|
|
||||||
|
|
||||||
## Docker Build Issues
|
|
||||||
|
|
||||||
### Backend Build Fails: Cannot redeclare block-scoped variable
|
|
||||||
|
|
||||||
**Error:** `error TS2451: Cannot redeclare block-scoped variable 'signature'`
|
|
||||||
|
|
||||||
**Solution:** Fixed in source. If you see this, pull the latest code.
|
|
||||||
|
|
||||||
### Backend: Prisma Client could not locate Query Engine
|
|
||||||
|
|
||||||
**Error:** `PrismaClientInitializationError: Prisma Client could not locate the Query Engine`
|
|
||||||
|
|
||||||
**Solution:**
|
|
||||||
```bash
|
|
||||||
# Regenerate Prisma client with correct binary target
|
|
||||||
cd backend
|
|
||||||
npx prisma generate
|
|
||||||
|
|
||||||
# Rebuild backend container
|
|
||||||
docker-compose up -d --build backend
|
|
||||||
```
|
|
||||||
|
|
||||||
### Frontend Build Fails: Module not found
|
### Frontend Build Fails: Module not found
|
||||||
|
|
||||||
@@ -184,23 +128,7 @@ docker-compose up -d --build backend
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Frontend: Prerender Error on /login
|
### Docker Build: Public Directory Not Found
|
||||||
|
|
||||||
**Error:** `Error occurred prerendering page "/login"`
|
|
||||||
|
|
||||||
**Solution:** This was caused by zustand persist middleware accessing localStorage during SSR. Fixed by wrapping providers with dynamic import `ssr: false`.
|
|
||||||
|
|
||||||
### Frontend: Cannot find module 'next-themes'
|
|
||||||
|
|
||||||
**Error:** `Module not found: Can't resolve 'next-themes'`
|
|
||||||
|
|
||||||
**Solution:**
|
|
||||||
```bash
|
|
||||||
cd frontend
|
|
||||||
npm install next-themes
|
|
||||||
```
|
|
||||||
|
|
||||||
### Docker Compose: Public Directory Not Found
|
|
||||||
|
|
||||||
**Error:** `failed to calculate checksum: "/app/frontend/public": not found`
|
**Error:** `failed to calculate checksum: "/app/frontend/public": not found`
|
||||||
|
|
||||||
@@ -210,25 +138,45 @@ mkdir -p frontend/public
|
|||||||
touch frontend/public/.gitkeep
|
touch frontend/public/.gitkeep
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Request Stuck on PENDING
|
||||||
|
|
||||||
|
**Error:** Request never updates from PENDING status
|
||||||
|
|
||||||
|
**Solution:**
|
||||||
|
1. Check Overseer webhook is configured correctly
|
||||||
|
2. In admin dashboard, go to **The Feed Queue** tab and click **SYNC**
|
||||||
|
3. Or manually sync from dashboard's Requests tab
|
||||||
|
4. Check backend logs for Overseer API errors
|
||||||
|
|
||||||
|
### Disk Space Not Updating
|
||||||
|
|
||||||
|
**Error:** Silo bar shows old values after downloading large files
|
||||||
|
|
||||||
|
**Solution:**
|
||||||
|
- Disk space is cached for 30 seconds
|
||||||
|
- Wait 30 seconds and refresh
|
||||||
|
- The bar updates automatically on dashboard load
|
||||||
|
|
||||||
## Getting Help
|
## Getting Help
|
||||||
|
|
||||||
1. Check health status:
|
1. View all logs:
|
||||||
```bash
|
```bash
|
||||||
./deployment/health-check.sh
|
docker-compose logs -f
|
||||||
```
|
```
|
||||||
|
|
||||||
2. View all logs:
|
2. Check specific service:
|
||||||
```bash
|
```bash
|
||||||
docker-compose -f docker-compose.prod.yml logs -f
|
docker-compose logs -f backend
|
||||||
|
docker-compose logs -f frontend
|
||||||
```
|
```
|
||||||
|
|
||||||
3. Check specific service:
|
3. Verify environment:
|
||||||
```bash
|
|
||||||
docker-compose -f docker-compose.prod.yml logs -f backend
|
|
||||||
```
|
|
||||||
|
|
||||||
4. Verify environment:
|
|
||||||
```bash
|
```bash
|
||||||
# Check all required env vars are set
|
# Check all required env vars are set
|
||||||
grep -E '^\w+=' .env | wc -l
|
grep -E '^\w+=' .env | wc -l
|
||||||
```
|
```
|
||||||
|
|
||||||
|
4. Check database:
|
||||||
|
```bash
|
||||||
|
docker exec coop-postgres psql -U coop -d coop_credits -c "SELECT COUNT(*) FROM users;"
|
||||||
|
```
|
||||||
|
|||||||
Reference in New Issue
Block a user