- docker-compose.yml: replace named volumes with ./postgres/data and ./redis/data bind mounts - .gitignore: exclude postgres/ and redis/ data directories - DEPLOYING.md: update clone URL to public PocketVeto repo - UPDATING.md: fix paths (~/pocketveto), clone URL, webhook IDs Authored by: Jack Levy
240 lines
6.0 KiB
Markdown
240 lines
6.0 KiB
Markdown
# 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.).
|