Files
resolutionflow/docs/plans/2026-03-04-survey-invite-tracking-design.md
2026-03-05 01:33:17 -05:00

77 lines
3.1 KiB
Markdown

# Survey Invite Tracking — Design
> **Date:** 2026-03-04
> **Status:** Approved
## Goal
Add invite tracking to the FlowPilot survey so Michael can create personalized links, optionally email them, and see who has/hasn't responded. Each invite token is single-use — one submission per token.
## Data Model
### New table: `survey_invites`
| Column | Type | Notes |
|--------|------|-------|
| `id` | UUID PK | |
| `token` | VARCHAR(32) UNIQUE | Random URL-safe token |
| `recipient_name` | VARCHAR(255) NOT NULL | Who it's for |
| `recipient_email` | VARCHAR(255) NULL | Only if emailing |
| `status` | VARCHAR(20) DEFAULT 'pending' | `pending` or `completed` |
| `email_sent` | BOOLEAN DEFAULT false | Whether Resend email was sent |
| `created_at` | TIMESTAMPTZ NOT NULL | |
| `completed_at` | TIMESTAMPTZ NULL | Set on submission |
### Modified table: `survey_responses`
Add `invite_id` UUID FK nullable → `survey_invites.id`. Responses from tokenless `/survey` have `invite_id = NULL`.
## API Endpoints
### Public (no auth)
- `GET /api/v1/survey/invite/{token}` — Returns invite status (`{ name, status }`). If `completed`, frontend shows "already submitted" screen. Returns 404 for invalid tokens.
- `POST /api/v1/survey/submit` — Modified: accepts optional `token` field. If token provided, validates it's `pending`, links the response, and marks invite as `completed`. Returns 409 if token already used.
### Admin (super_admin auth)
- `POST /api/v1/admin/survey-invites` — Create invite. Body: `{ recipient_name, recipient_email?, send_email? }`. Generates token, optionally sends email. Returns the invite with the full survey URL.
- `GET /api/v1/admin/survey-invites` — List all invites with status.
## Frontend
### Survey page changes (`/survey`)
- On load, reads `?t=<token>` from URL params
- If token present: calls `GET /survey/invite/{token}`
- If `completed` → show "already submitted" screen
- If `pending` → show survey, include token in submission payload
- If 404 → show survey without token (treat as open link)
- If no token: show survey as-is (open access)
### Admin page (`/admin/survey-invites`)
**Top section: Create Invite**
- Name input (required) + Email input (optional)
- "Generate Link" button → creates invite, shows URL with copy button
- "Send Email" button → creates invite with `send_email: true`, shows confirmation toast
- "Send Email" only enabled when email field is filled
**Bottom section: Invite Table**
- Columns: Name, Email, Status badge (pending amber / completed green), Sent (email icon or dash), Created date, Completed date
- Sorted by created_at descending
## Email Template
Uses existing `EmailService` + Resend pattern. Dark-themed email matching Slate & Ice aesthetic:
- Subject: "FlowPilot Survey — Your expertise matters"
- Body: Brief intro, CTA button linking to `/survey?t=<token>`, ~5 minutes note
- From: existing `FROM_EMAIL` config
## Constraints
- No token expiration
- No reminder/resend (keep it simple)
- Tokenless survey still works for open sharing
- One submission per invite token (enforced backend + frontend)