3.1 KiB
3.1 KiB
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 }). Ifcompleted, frontend shows "already submitted" screen. Returns 404 for invalid tokens.POST /api/v1/survey/submit— Modified: accepts optionaltokenfield. If token provided, validates it'spending, links the response, and marks invite ascompleted. 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
- 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_EMAILconfig
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)