VictoryStays/review.md
## Snapshot
- Public-records/property microsite generator for LA rentals, parcels, claims, maps, and enrichment dashboards.
- Stack: Node.js/Express, static HTML/CSS/JS, Python build scripts, SQLite via `better-sqlite3`; docs mention PostgreSQL but code uses SQLite.
- How it's run: PM2 via `ecosystem.config.js`; also `npm start`.
- Status: live/active - April 2026 changes, PM2 config.
## Top Risks (P0 — fix this week)
- [server.js](/Users/stevestudio2/Projects/VictoryStays/server.js:51): `express.static(__dirname)` publishes the whole repo, including `data/victorystays.db`, source, lockfiles, generated datasets, and future `data/claims.jsonl`. Fix: serve a dedicated `public/` dir and explicitly block `/data`, scripts, DB/WAL/SHM, logs.
- [api-claim.js](/Users/stevestudio2/Projects/VictoryStays/api-claim.js:81): `GET /api/claim?admin=1` returns every claim, PII, and verification codes with no auth. Fix: require operator auth/session or remove public route.
- [api-claim.js](/Users/stevestudio2/Projects/VictoryStays/api-claim.js:103): unauthenticated `PATCH /api/claim` can mark any claim verified/rejected; code check is optional. Fix: authenticate operator actions and require code for verification.
- [api-claim.js](/Users/stevestudio2/Projects/VictoryStays/api-claim.js:72), [home.html](/Users/stevestudio2/Projects/VictoryStays/home.html:434): claim submission returns the postcard verification code to the claimant, defeating the mail-based proof. Fix: never return the code; only store/print/mail it.
- [api-claim.js](/Users/stevestudio2/Projects/VictoryStays/api-claim.js:27): unbounded JSON body plus sync append lets anyone fill disk with claims. Fix: `express.json({limit})`, rate-limit/IP throttle, validate field lengths.
## Notable Issues (P1 — fix this month)
- [api-claim.js](/Users/stevestudio2/Projects/VictoryStays/api-claim.js:17): each admin/list lookup reads and parses the whole JSONL file synchronously. Failure mode: admin page slows or blocks the Node event loop as claims grow. Fix: move claims to SQLite with indexes.
- [api-claim.js](/Users/stevestudio2/Projects/VictoryStays/api-claim.js:120): `PATCH` rewrites the entire claims file without locking/atomic rename. Failure mode: concurrent patches lose updates or corrupt the file. Fix: SQLite transaction or write temp + atomic rename with lock.
- [api-property.js](/Users/stevestudio2/Projects/VictoryStays/api-property.js:75): address is interpolated into an ArcGIS SQL-like `LIKE` clause after only quote escaping. Failure mode: wildcard-heavy input causes expensive broad queries. Fix: cap input length, strip `%/_`, require house-number-ish patterns.
- [api-build-status.js](/Users/stevestudio2/Projects/VictoryStays/api-build-status.js:15): status API opens the production SQLite DB read/write and changes WAL mode. Failure mode: dashboard can contend with the worker. Fix: open readonly where possible; set pragmas in DB init/worker only.
- [scripts/enrich-listings-worker.js](/Users/stevestudio2/Projects/VictoryStays/scripts/enrich-listings-worker.js:95): transient API failures permanently mark listings `failed`; no retry/backoff count. Fix: store retry count/error, retry transient 5xx/timeouts before final failure.
- [templates/city.html](/Users/stevestudio2/Projects/VictoryStays/templates/city.html:464), [search.html](/Users/stevestudio2/Projects/VictoryStays/search.html:131): user input is inserted into `innerHTML`. Failure mode: client-side XSS. Fix: use `textContent` or escape before interpolation.
## Polish (P2 — when convenient)
- [INFRASTRUCTURE.md](/Users/stevestudio2/Projects/VictoryStays/INFRASTRUCTURE.md:24): docs describe PostgreSQL/Redis architecture, but runtime uses SQLite. Update docs to match deployed reality.
- [admin/claims.html](/Users/stevestudio2/Projects/VictoryStays/admin/claims.html:111): footer documents known missing auth. Promote this from note to blocking launch checklist.
- Tests: none observed for claim auth, static exposure, or enrichment retry behavior.
## Strengths
- Clear PM2 process split for web and long-running enrichment in [ecosystem.config.js](/Users/stevestudio2/Projects/VictoryStays/ecosystem.config.js:1).
- External API calls mostly use caching/timeouts and degrade gracefully.
- Admin/status dashboards expose operational state, which is useful once gated.
## Open questions for the owner
- Is this ever exposed through nginx/Tailscale/cloudflared, or strictly loopback-only?
- Are `data/*.json` parcel/address datasets intended to be public downloads?
- Should homeowner claims be production-facing, or is this still an operator-only prototype?