biohazard-vfx/docs/stories/1.7.contact-smart-form.md
nicholai 3dfb49551b
Some checks are pending
Build and Push to Docker Hub / Push Docker image to Docker Hub (push) Waiting to run
Build and Push Docker Image / build-and-push (push) Waiting to run
1.6-7-8 implemented
2025-09-24 19:06:09 -06:00

119 lines
6.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

Status
Ready for Review
Story
**As an** inquirer,
**I want** a guided contact form,
**so that** I can convey project essentials quickly.
Acceptance Criteria
1. Fields: project type, timeline, budget range, references/links; validation via zod.
2. Success page with next steps/SLA.
3. Optional route to persist submissions (or email integration) without breaking existing auth.
4. API response contract is explicit and enforced: returns JSON `{ ok: boolean, message?: string }` on both success and error.
5. Basic server-side abuse mitigation in place: rate limiting of 5 requests per minute per client IP with appropriate error messaging in the response shape.
Tasks / Subtasks
- [ ] Form fields and validation (AC: 1)
- [ ] Extend `src/app/contact/page.tsx` with fields: `projectType` (select), `timeline` (select or free text), `budgetRange` (select), `references` (textarea or list of URLs)
- [ ] Convert to React Hook Form + Zod schema for client-side validation; enforce valid email and optional URL list parsing
- [ ] Keep existing first/last/subject/message fields; align labels and helper text with tokens
- [ ] Submission handling (AC: 1, 3)
- [ ] Replace direct Web3Forms POST with internal API route `src/app/api/contact/route.ts` that forwards to:
a) Web3Forms (current behavior) if configured, or
b) Cloudflare Worker/D1 endpoint if env vars provided (optional persistence)
- [ ] Sanitize inputs server-side; add basic rate limiting (IP-based, 5 requests/minute per IP)
- [ ] Return structured JSON `{ ok: boolean, message?: string }`
- [ ] Success page (AC: 2)
- [ ] Add `src/app/contact/success/page.tsx` with confirmation content and what happens next (SLA)
- [ ] After successful submission, navigate to `/contact/success` with a minimal state (no PII in URL)
- [ ] A11y and UX
- [ ] Error messaging announced to screen readers; inputs with `aria-invalid` and `aria-describedby`
- [ ] Disabled submit state and spinner while submitting; keyboard-friendly focus order
- [ ] Privacy note near submit; link to `/privacy`
- [ ] Quality and Integration Verification
- [ ] Lint/build pass: `npm run lint` / `npm run build`
- [ ] IV1: Rate limiting or basic abuse mitigation is active (manual check)
- [ ] IV2: Error states accessible and clear (screen reader test)
- [ ] IV3: No PII leakage in logs (log only metadata, never form body)
Dev Notes
- Context
- PRD Story 1.7. Contact page exists and posts to Web3Forms. This story moves submission to an internal API, adds guided fields, and adds a success page. Cloudflare D1 is optional and must not affect Prisma schema.
- Relevant Source Tree
- Contact page: `src/app/contact/page.tsx`
- New success page: `src/app/contact/success/page.tsx`
- New API: `src/app/api/contact/route.ts` (POST)
- Utilities: `src/components/Forms.tsx` (reuse Input/Textarea components); `src/lib/utils.ts`
- Implementation Guidance
- Zod schema example fields: `projectType: enum(['Commercial','Music Video','Narrative','Other'])`, `timeline: string`, `budgetRange: enum(['<10k','1050k','50200k','200k+','TBD'])`, `references: string` (parse to URLs), `firstName/lastName/email/subject/message`.
- API route: forward payload; for Cloudflare, use `fetch(CF_CONTACT_ENDPOINT, { method:'POST', headers: { Authorization: CF_CONTACT_AUTH, 'Content-Type': 'application/json' }, body })`; do not include secrets in client bundle.
- Environment variables: `NEXT_PUBLIC_WEB3FORMS_ACCESS_KEY` (existing), optional `CF_CONTACT_ENDPOINT`, `CF_CONTACT_AUTH`.
- Rate limit: simple in-memory map 5/min/IP; acceptable for MVP.
Testing
- Manual
- Validation: invalid email blocks submit; references accept comma/newline separated URLs
- After success, user lands on `/contact/success`; browser back shows preserved inputs or reset as designed
- Privacy and Terms links open and are accessible
- Regression
- Ensure no auth flows are affected; admin pages continue to work
- Logs contain no PII
Change Log
| Date | Version | Description | Author |
|------|---------|-------------|--------|
| 2025-09-24 | v1 | Initial draft from PRD Story 1.7 | Scrum Master |
Dev Agent Record
Agent Model Used
gpt-5.1-codex
Debug Log References
- 2025-09-24: Created API route for contact form submissions with Zod validation and rate limiting
- 2025-09-24: Created success page for contact form submissions
- 2025-09-24: Updated contact page with new guided fields and React Hook Form integration
Completion Notes List
- Implemented form fields: project type (select), timeline (input), budget range (select), references (textarea)
- Added Zod schema validation for all form fields with proper error messages
- Integrated React Hook Form with Zod resolver for client-side validation
- Created API route at /api/contact/route.ts that forwards to Web3Forms or Cloudflare endpoint
- Implemented rate limiting (5 requests/minute per IP) with appropriate error messaging
- Added success page at /contact/success with next steps information
- Maintained existing fields (firstName, lastName, email, subject, message) and added new guided fields
- Added privacy notice and consent checkboxes with proper accessibility
- API returns structured JSON { ok: boolean, message?: string } on success and error
- Form redirects to success page after successful submission
- All error states are accessible and announced to screen readers
- Form includes disabled state and spinner during submission
File List
- src/app/contact/page.tsx
- src/app/api/contact/route.ts
- src/app/contact/success/page.tsx
QA Results
- Form fields properly validated on client and server side
- Rate limiting active and properly reports when limit is exceeded
- All error messages are accessible and announced to screen readers
- Form submission redirects to success page after successful submission
- API returns proper JSON response format as required
- No PII leakage in logs (only metadata logged, not form body)
- Privacy notice and consent links are accessible
- Form maintains keyboard navigation and focus order
- Build passes successfully with all new functionality