Files
PocketVeto/TROUBLESHOOTING.md
Jack Levy 73881b2404 feat(notifications): follow modes, milestone alerts, notification enhancements
Follow Modes (neutral / pocket_veto / pocket_boost):
- Alembic migration 0013 adds follow_mode column to follows table
- FollowButton rewritten as mode-aware dropdown for bills; simple toggle for members/topics
- PATCH /api/follows/{id}/mode endpoint with validation
- Dispatcher filters pocket_veto follows (suppress new_document/new_amendment events)
- Dispatcher adds ntfy Actions header for pocket_boost follows

Change-driven (milestone) Alerts:
- New notification_utils.py with shared emit helpers and 30-min dedup
- congress_poller emits bill_updated events on milestone action text
- llm_processor replaced with shared emit util (also notifies member/topic followers)

Notification Enhancements:
- ntfy priority levels (high for bill_updated, default for others)
- Quiet hours (UTC): dispatcher holds events outside allowed window
- Digest mode (daily/weekly): send_notification_digest Celery beat task
- Notification history endpoint + Recent Alerts UI section
- Enriched following page (bill titles, member photos/details via sub-components)
- Follow mode test buttons in admin settings panel

Infrastructure:
- nginx: switch upstream blocks to set $variable proxy_pass so Docker DNS
  re-resolves upstream IPs after container rebuilds (valid=10s)
- TROUBLESHOOTING.md documenting common Docker/nginx/postgres gotchas

Authored-By: Jack Levy
2026-03-01 15:09:13 -05:00

159 lines
3.8 KiB
Markdown

# Troubleshooting
Common issues encountered during development and deployment of PocketVeto.
---
## 502 Bad Gateway after rebuilding a container
**Symptom**
All API calls return 502. nginx error log shows:
```
connect() failed (111: Connection refused) while connecting to upstream,
upstream: "http://172.18.0.X:8000/api/..."
```
The IP in the error is the *old* IP of the container before the rebuild.
**Root cause**
When nginx uses `upstream` blocks, it resolves hostnames once at process startup and caches the result for the lifetime of the process. Rebuilding a container (e.g. `docker compose build api && docker compose up -d api`) assigns it a new Docker network IP. nginx still holds the old IP and all connections are refused.
**Immediate fix**
```bash
docker compose restart nginx
```
This forces nginx to re-resolve all upstream hostnames from Docker's internal DNS (`127.0.0.11`).
**Permanent fix (already applied)**
Replace `upstream` blocks with `set $variable` in `proxy_pass`. nginx only activates the `resolver` directive when a variable is used — making it re-resolve on each request cycle (every `valid=N` seconds).
```nginx
resolver 127.0.0.11 valid=10s ipv6=off;
# BAD — resolves once at startup, caches forever
upstream api {
server api:8000;
}
location /api/ {
proxy_pass http://api;
}
# GOOD — re-resolves via resolver every 10 s
location /api/ {
set $api http://api:8000;
proxy_pass $api;
}
```
---
## Wrong service name for docker compose exec
The API service is named `api` in `docker-compose.yml`, not `backend`.
```bash
# Wrong
docker compose exec backend alembic upgrade head
# Correct
docker compose exec api alembic upgrade head
```
---
## Alembic migration not applied after rebuild
If a new migration file was added after the last image build, the API container won't have it baked in. The container runs `alembic upgrade head` at startup from the built image.
**Fix**: rebuild the API image so the new migration file is included, then restart:
```bash
docker compose build api && docker compose up -d api
```
---
## Wrong postgres user
The database superuser is `congress` (set via `POSTGRES_USER` in `.env` / `docker-compose.yml`), not the default `postgres`.
```bash
# Wrong
docker compose exec postgres psql -U postgres pocketveto
# Correct
docker compose exec postgres psql -U congress pocketveto
```
---
## Frontend changes not showing after editing source files
The frontend runs as a production Next.js build (`NODE_ENV=production`) — there is no hot reload. Code changes require a full image rebuild:
```bash
docker compose build frontend && docker compose up -d frontend
```
Static assets are cache-busted automatically by Next.js (content-hashed filenames), so a hard refresh in the browser is not required after the new container starts.
---
## Celery tasks not reflecting code changes
Celery worker and beat processes also run from the built image. After changing any worker code:
```bash
docker compose build worker beat && docker compose up -d worker beat
```
---
## Checking logs
```bash
# All services
docker compose logs -f
# Single service (last 50 lines)
docker compose logs --tail=50 api
docker compose logs --tail=50 nginx
docker compose logs --tail=50 worker
# Follow in real time
docker compose logs -f api worker
```
---
## Inspecting the database
```bash
docker compose exec postgres psql -U congress pocketveto
```
Useful queries:
```sql
-- Recent notification events
SELECT event_type, bill_id, dispatched_at, created_at
FROM notification_events
ORDER BY created_at DESC
LIMIT 20;
-- Follow modes per user
SELECT u.email, f.follow_type, f.follow_value, f.follow_mode
FROM follows f
JOIN users u ON u.id = f.user_id
ORDER BY u.email, f.follow_type;
-- Users and their RSS tokens
SELECT id, email, rss_token IS NOT NULL AS has_rss_token FROM users;
```