← back to Restaurant Directory

PLAN.md

110 lines

# LA County Eats — Project Plan

**Domain:** lacountyeats.com (registered 2026-05-02 at GoDaddy, expiry 2027-05-02, A → 45.61.58.125)
**Database:** `restaurant_professional_directory` (Postgres, Mac Studio 2 local)
**Pattern:** Mirrors `~/Projects/professional-directory/` (doctor) and `~/Projects/lawyer-directory-builder/` and `~/Projects/animals/`.

---

## Goal

Comprehensive directory of every active food-establishment permit in LA County (~49,000 facilities), with health-grade enrichment, mockup variants per record (3x via Four Horsemen + claude-codex debate), recurring "new restaurant" detection, and lead-gen rails (ads + leads + claim-your-listing upgrade + B2B data lists).

---

## Data Source (confirmed by la-research-agent 2026-05-02)

**LA County DPH Environmental Health** — three datasets on data.lacounty.gov (ArcGIS Hub, NOT Socrata):

| Dataset | ArcGIS Item ID | Rows (est) | File size |
|---|---|---|---|
| Inventory (directory source) | `4f31c9a99e444a40a3806e3bbe7b5fdd` | ~49K | 9.9 MB |
| Inspections (3-yr rolling) | `19b6607ac82c4512b10811870975dbdc` | ~123K | 24.7 MB |
| Violations | `5eaea9f89b7549ee841da7617d3a9cba` | ~416K | 41.6 MB |

**Pull URL pattern:** `https://www.arcgis.com/sharing/rest/content/items/{ITEM_ID}/data` → flat CSV
**Encoding:** **Latin-1** (NOT UTF-8 — must specify in parser)
**Refresh:** Quarterly. Last update 2026-04-06.
**License:** None stated; LA County open data; attribute "LA County Department of Public Health, Environmental Health Division".
**Coverage gap:** Pasadena, Long Beach, and Vernon run independent health depts — NOT in this dataset. Pasadena has its own ArcGIS dataset (item `24525f546e5e4346957bb55695afc448`); Long Beach is web-UI only, may need CPRA.
**No phone, no cuisine, no permit dates** in inventory. Phone needs Yelp/Google enrichment (paid) OR OSM (free, sparse). Cuisine needs LLM classification of facility name.

---

## Architecture

### Ports (9740–9747)

| Port | Service | Description |
|---|---|---|
| 9740 | rd-ingest | Quarterly ArcGIS pull + diff + INSERT new + UPDATE changed |
| 9741 | rd-crawler | Optional: crawl each restaurant's website if Yelp/Google has one |
| 9742 | rd-enrich | qwen3:14b cuisine classification + LLaVA hero-image checks |
| 9743 | rd-dedupe | Address/name fuzzy-match dedup |
| 9744 | rd-api | Public REST API (`/api/restaurants`, `/api/restaurants/:slug`) |
| 9745 | rd-preview | Mockup-engine viewer (3 variants per restaurant) |
| 9746 | rd-web | Next.js / Express public site (lacountyeats.com proxies here) |
| 9747 | reserved | (future: rd-leads or rd-admin) |

### Database schema (high-level — see db/schema.sql)

- `facility` — one row per LA County permit (FACILITY_ID = PK)
- `inspection` — many-to-one with facility (3-yr rolling)
- `violation` — many-to-one with inspection
- `facility_enrichment` — cuisine, phone, hours, website, hero_image (when sourced)
- `facility_mockup` — 3 variants per facility (HTML/JSX), via Four Horsemen
- `facility_claim` — claim-your-listing flow (upgrade rail)
- `lead` — B2B leads / pitch funnel

### Recurring jobs

- **Quarterly ArcGIS pull** (cron 1st of Jan/Apr/Jul/Oct) — diff against current `facility` set, INSERT new, UPDATE changed.
- **Weekly "new restaurant" check** (Mon 4am) — even though source is quarterly, check anyway in case of out-of-band updates; email Steve via George if any new.
- **Mockup engine** — for every newly-INSERTed `facility`, queue 3 mockup variants through Four Horsemen, run claude-codex debate to pick winner, store in `facility_mockup`.
- **Watchdog `com.steve.rd-hawk`** — every 30m, pm2 restart any down agent.

### Out of scope day-1

- Pasadena/Long Beach/Vernon (deferred to v2; need separate ingest scripts)
- Phone enrichment (deferred to v2; pick between Yelp Fusion (free tier capped) and Google Places (paid))
- Reviews / ratings (no source; deferred indefinitely)
- Mobile food trucks (separate EH dataset; deferred)

---

## Phasing

### Phase 1 — Foundation (today, 2026-05-02)
- [x] Domain registered + DNS pointed
- [x] PLAN.md (this file)
- [ ] PG database created
- [ ] schema.sql + initial migrations applied
- [ ] ingest script (TypeScript) for Inventory + Inspections
- [ ] FIRST RUN — populate `facility` + `inspection` with full LA County data

### Phase 2 — Public surface (today/tomorrow)
- [ ] rd-api (Express, port 9744) — `/api/restaurants?lat&lng&grade` + `/api/restaurants/:facility_id`
- [ ] rd-web (Next.js, port 9746) — list view (paginated/filtered) + map view (Leaflet/OSM) + detail page
- [ ] nginx vhost on Kamatera proxies lacountyeats.com → :9746 (overwrite the "coming soon" page)

### Phase 3 — Mockups + debate (next week)
- [ ] Wire Four Horsemen orchestrator to spawn 3 mockup variants per `facility`
- [ ] Claude-codex debate loop picks the winner per batch
- [ ] `facility_mockup` table stores all 3 + winner pointer

### Phase 4 — Monetization rails (later)
- [ ] Claim-your-listing flow (claimmyaddress.com SSO?)
- [ ] $499 site upgrade rail (mirror animals project)
- [ ] B2B data list export (CSV download by ZIP / cuisine)
- [ ] Stripe billing wired

---

## Standing rules to enforce

- All restaurant photos public-domain or open-license only (per `feedback_no_stock_images.md`). Source list: USC DigLib, LAPL, Wikimedia, IA, Calisphere, LoC, Street View, owner uploads. Empty state > fake.
- Every new `facility` row triggers 3 mockup variants (per `feedback_stayclaim_3_mockups_per_record.md`).
- LAPL TESSA2 photos use the canonical "Editorial use — LAPL Photo Collection" license tag (per `feedback_lapl_editorial_use_tag.md`).
- Bulk batch jobs alert on >10% failure rate via George (per `feedback_batch_failure_alerts.md`).
- pm2 actions on lacountyeats.com need explicit Steve auth per the cncp-domain rule.