70 lines
4.6 KiB
Markdown
70 lines
4.6 KiB
Markdown
# 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: `phone` → `handle`, `activities` appended to `body`, `inquiryType` → `subject`, `preferSms` → `channel`. 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-003** — `CONTACT_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-004** — `public-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) |
|