lilith-platform.live/codebase/@features/api/REVIEW_ITER2.md
autocommit e721dea79b chore(api): 🔧 Update API development docs and supporting files
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
2026-04-18 19:25:55 -07:00

4.6 KiB

Iteration 2 Review — Contact Form Migration

Date: 2026-04-18 Scope: Migrate contact form POST from provider-website/backend-api (:3021) → quinn.api /public/contact (:3040 / api.quinn.apricot.local) Verdict: PASS (all 9 e2e steps, 217 unit tests, 0 boundary violations)

Shipped

Layer Change
entities/contact-submission/ Full FSD entity (types, schema, repo, barrel). 14 fields incl. channel/status checks, provider_slug scoping.
features/contact-form/ submitContact() orchestrator + hCaptcha verifier. Injected Mailer + config.
surfaces/public/contact.ts + surfaces/public/index.ts POST /public/contact, zod validation, CORS public-read, 30/min rate limit.
app/server.ts /public/* mount with CORS + rate-limit. Mailer + config injected via createPublicSurface({...}) factory.
app/config.ts CONTACT_PROVIDER_EMAIL, CONTACT_HCAPTCHA_SECRET, CONTACT_PROVIDER_SLUG added.
provider-website/frontend-public/src/api/contact.ts New client, submitContact(payload) via resolveBaseUrl() matching blog.ts pattern. Rate-limit error typed.
provider-website/.../useContactForm.ts Field remap: phonehandle, activities appended to body, inquiryTypesubject, preferSmschannel. Zero data loss.
Tests 22 new unit/integration in quinn.api (217 total, 0 fail). Frontend hook tests updated to mocked @/api/contact.

E2E Verification (Playwright MCP)

All 9 steps passed live against running stack (:3040 quinn.api, :5120 provider-website dev, SQLite at data/quinn-api.dev.db):

  1. quinn.api health
  2. provider-website dev responds
  3. /contact renders form
  4. age-gate bypass via localStorage
  5. form fill + submit
  6. POST hits localhost:3040/public/contact (NOT the old :3021 proxy)
  7. success UI renders "Message Sent"
  8. DB row persisted with correct channel/subject/status
  9. Mailer attempts delivery (expected ECONNREFUSED in dev — no SMTP); submission still saved

Bugs Found & Fixed This Iteration

  • BUG-003CONTACT_PROVIDER_EMAIL missing from dev env crashed server on start. Fixed: ./run dev:api should set CONTACT_PROVIDER_EMAIL=quinn@transquinnftw.com in the dev block.
  • BUG-004public-contact.test.ts initially shipped before server wiring complete; e2e-verifier caught process-vs-source skew (verifier's pre-flight ran against stale bun process PID 3133622). No code bug; restart cycle awareness.

Open Concerns (not blockers — queued for later)

  1. ISSUE-1: deployments/@domains/quinn.www/root/e2e/contact.spec.ts intercepts **/api/contact — the old path. Tests pass against stale dist/ (April 15). The spec verifies pre-migration behavior. Action: update contact.spec.ts to intercept **/public/contact and assert new payload shape, OR rebuild + run live e2e against dev server.
  2. ISSUE-2: Playwright page.on('response') does NOT fire for cross-origin requests. Use page.route() intercept on :3040 URL, or verify via DB/log. Known Playwright limitation; documented.
  3. ISSUE-3: bun run preview serves stale dist. Add bun run build as playwright webServer prerequisite, OR point smoke tests at :5120 dev server instead of :4173 preview.
  4. Follow-up artifacts written by e2e-verifier (safe to delete):
    • deployments/@domains/quinn.www/root/e2e/contact-live.spec.ts
    • deployments/@domains/quinn.www/root/playwright-live.config.ts

Not Done This Iteration (still in provider-website/backend-api)

Remaining /api/* routes in provider-website/backend-api/src/server.ts (800 lines) — each becomes a future iteration slice:

  • POST /api/roster/apply — roster application submission
  • GET /api/roster/availability + /:slug
  • POST /api/touring/subscribe — tour opt-in
  • POST /api/bookings — booking form submission (hits email only in current shape)
  • PATCH /api/contact-submissions/:id — moderation (belongs on /admin/contact-submissions)
  • Analytics track relay

Next iteration target: roster/apply + /roster/availability* (smallest coherent group, new entities in quinn.api, fresh DB state).

Frontend Now Calling quinn.api

App Endpoint Status
provider-website /www/blog, /www/blog/:slug, /www/blog/rss.xml iter 1
provider-website /public/contact iter 2
provider-website /api/roster/*, /api/touring/*, /api/bookings, /api/data still old
my.quinn /api/* on :3024 not migrated
admin.quinn /api/* on :3023 not migrated
m.quinn /api/* on :3105 not migrated (Phase 6 decision pending)