94 lines
4.2 KiB
Markdown
94 lines
4.2 KiB
Markdown
Status
|
||
|
||
Approved
|
||
|
||
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
|
||
|
||
{{agent_model_name_version}}
|
||
|
||
Debug Log References
|
||
|
||
|
||
|
||
Completion Notes List
|
||
|
||
|
||
|
||
File List
|
||
|
||
|
||
|
||
QA Results
|