119 lines
6.0 KiB
Markdown
119 lines
6.0 KiB
Markdown
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','10–50k','50–200k','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
|