# Deploying PocketVeto Step-by-step guide for standing up the full stack on a fresh server. --- ## Prerequisites **Server:** - Linux (Ubuntu 22.04+ or Debian 12 recommended) - Docker Engine 24+ and Docker Compose v2 (`docker compose` — note: no hyphen) - At least 2 GB RAM (4 GB recommended if running an Ollama LLM locally) - Port 80 open to the internet (and 443 if you add SSL) **API keys you will need:** | Key | Where to get it | Required? | |---|---|---| | `DATA_GOV_API_KEY` | [api.data.gov/signup](https://api.data.gov/signup/) — free, instant | **Yes** | | One LLM key (OpenAI / Anthropic / Gemini) | Provider dashboard | **Yes** (or use Ollama) | | `NEWSAPI_KEY` | [newsapi.org](https://newsapi.org) — free tier (100 req/day) | Optional | Google Trends (`pytrends`) needs no key. --- ## 1. Get the code ```bash git clone https://git.jackhlevy.com/jack/PocketVeto.git pocketveto cd pocketveto ``` --- ## 2. Configure environment ```bash cp .env.example .env nano .env # or your preferred editor ``` **Minimum required values:** ```env # Network LOCAL_URL=http://YOUR_SERVER_IP # or https://yourdomain.com if behind SSL PUBLIC_URL= # leave blank unless you have a public domain # Auth — generate with: python -c "import secrets; print(secrets.token_hex(32))" JWT_SECRET_KEY=your-generated-secret # Encryption key for sensitive prefs (generate once, never change after data is written) ENCRYPTION_SECRET_KEY= # generate: python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())" # PostgreSQL POSTGRES_USER=congress POSTGRES_PASSWORD=your-strong-password POSTGRES_DB=pocketveto # Redis REDIS_URL=redis://redis:6379/0 # Congress.gov + GovInfo (shared api.data.gov key) DATA_GOV_API_KEY=your-api-key # LLM — pick one LLM_PROVIDER=openai OPENAI_API_KEY=sk-... OPENAI_MODEL=gpt-4o-mini ``` Other providers (swap in place of the OpenAI block): ```env # Anthropic LLM_PROVIDER=anthropic ANTHROPIC_API_KEY=sk-ant-... ANTHROPIC_MODEL=claude-sonnet-4-6 # Gemini LLM_PROVIDER=gemini GEMINI_API_KEY=AIza... GEMINI_MODEL=gemini-2.0-flash # Ollama (local model — server must be running on the host) LLM_PROVIDER=ollama OLLAMA_BASE_URL=http://host.docker.internal:11434 OLLAMA_MODEL=llama3.1 ``` Optional extras: ```env NEWSAPI_KEY=your-newsapi-key # enables richer news correlation PYTRENDS_ENABLED=true # Google Trends; disable if hitting rate limits CONGRESS_POLL_INTERVAL_MINUTES=30 # how often to check Congress.gov ``` ```env # Email notifications (optional — requires SMTP relay, e.g. Resend) SMTP_HOST=smtp.resend.com SMTP_PORT=465 SMTP_USER=resend SMTP_PASSWORD=re_your-api-key SMTP_FROM=alerts@yourdomain.com ``` --- ## 3. Build and start ```bash docker compose up --build -d ``` This will: 1. Pull base images (postgres, redis, nginx, node) 2. Build the API, worker, beat, and frontend images 3. Start all 7 containers 4. Run `alembic upgrade head` automatically inside the API container on startup 5. Seed the Celery Beat schedule in Redis **First build takes 3–8 minutes** depending on your server. Subsequent builds are faster (Docker layer cache). --- ## 4. Verify it's running ```bash docker compose ps ``` All services should show `Up`: ``` civicstack-api-1 Up civicstack-beat-1 Up civicstack-frontend-1 Up civicstack-nginx-1 Up 0.0.0.0:80->80/tcp civicstack-postgres-1 Up (healthy) civicstack-redis-1 Up (healthy) civicstack-worker-1 Up ``` Check the API health endpoint: ```bash curl http://localhost/api/health # → {"status":"ok","timestamp":"..."} ``` Open `http://YOUR_SERVER_IP` in a browser. --- ## 5. Create the admin account Navigate to `http://YOUR_SERVER_IP/register` and create the first account. **The first registered account automatically becomes admin.** All subsequent accounts are regular users. The admin account gets access to the Settings page with the pipeline controls, LLM switching, and user management. --- ## 6. Trigger initial data load Log in as admin and go to **Settings**: 1. **Trigger Poll** — fetches bills updated in the last 60 days from Congress.gov (~5–10 minutes to complete) 2. **Sync Members** — syncs current Congress members (~2 minutes) The Celery workers then automatically: - Fetch bill text from GovInfo - Generate AI briefs (rate-limited at 10/minute) - Fetch news articles and calculate trend scores You can watch progress in **Settings → Pipeline Status**. --- ## 7. Optional: Domain + SSL If you have a domain name pointing to the server, add an SSL terminator in front of nginx. The simplest approach is Caddy as a reverse proxy: ```bash # Install Caddy apt install -y debian-keyring debian-archive-keyring apt-transport-https curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | tee /etc/apt/sources.list.d/caddy-stable.list apt update && apt install caddy ``` `/etc/caddy/Caddyfile`: ``` yourdomain.com { reverse_proxy localhost:80 } ``` ```bash systemctl reload caddy ``` Caddy handles HTTPS certificates automatically via Let's Encrypt. After adding SSL, update `.env`: ```env PUBLIC_URL=https://yourdomain.com ``` Then rebuild the API so the new URL is used in notification payloads: ```bash docker compose up --build -d api ``` --- ## Useful commands ```bash # View logs for a service docker compose logs --tail=50 api docker compose logs --tail=50 worker docker compose logs -f worker # follow in real time # Restart a service docker compose restart worker # Run a database query docker compose exec postgres psql -U congress pocketveto # Apply any pending migrations manually docker compose exec api alembic upgrade head # Open a Python shell inside the API container docker compose exec api python ``` --- ## Troubleshooting See `TROUBLESHOOTING.md` for common issues (502 errors after rebuild, wrong postgres user, frontend changes not showing, etc.).