002_fires and 002_cameras both had down_revision=001_initial, producing two heads so 'alembic upgrade head' fails at container startup and the dashboard never boots. Tables are independent; linearize 001 -> 002_fires -> 002_cameras.
- camera_scraper: public-directory-only discovery (Insecam-style HTML + plain-text lists), hard private-range guard (fail closed), per-host rate limiting, Nominatim geocoding at <=1 req/s, TTL'd local snapshot cache, sha256 url_hash dedupe with Postgres upsert - cameras table (migration 002) + /api/cameras?bbox= + snapshot endpoint with cache passthrough in main.py - run_camera_service: long-running cycle worker following NATS->ingester pattern; publishes events.camera for shared ingester - docker-compose camera-service profile, .env.example knobs Verified E2E against TimescaleDB+PostGIS: private-range entries dropped, dedupe across cycles holds, bbox query returns expected rows.