# Proposal: add-rsvp-v1

## Why

Managing 300–1,500 wedding guests across three events (Mehedi, Marriage Ceremony, Walima) by phone calls and paper cards produces guessed headcounts, wasted catering spend, and no record of who was invited to what. This change builds the v1 (MVP) of the Wedding Invitation & RSVP Automation App defined in `rsvp-prd.pdf`: tokenized animated invitation links, gated RSVP forms, automated T-15/T-7/T-2 reminders with self-service cancellation, and an admin dashboard with live per-event counts and CSV export.

## What Changes

- New split application scaffolded in this repo: a Next.js 15 (App Router) frontend for rendering and a FastAPI (Python) backend owning all business logic, data access, and authorization, with PostgreSQL 16 + SQLAlchemy/Alembic and an APScheduler worker that uses Postgres itself as the job queue (no Redis or message broker) — deployed as a single VPS Docker Compose stack behind Caddy.
- Guest-facing animated invitation pages at `/i/{token}` (personalised) and `/e/{eventSlug}` (open/QR), mobile-first, English default with Bangla toggle.
- Accept-gated RSVP form flow with decline path, open-link self-registration with duplicate merging, and idempotent submission.
- POST-only self-service cancellation flow that updates headcount immediately and skips future reminders.
- Admin area: Google OAuth sign-in only (allowlisted Google accounts, no passwords or TOTP in v1), role-based permissions (Super Admin / Co-host / Viewer), dashboard counts, guest CRUD + bulk CSV import, audit log.
- Filtered CSV export (UTF-8 BOM) including one-click "Caterer list".
- Outbound messaging over **Email only in v1** behind a single channel-shaped `MessageProvider` interface (WhatsApp and SMS deferred to v2 — the interface, templates, and message-job pipeline are built so adding them later is a provider file, not a rewrite), with throttling, delivery/bounce webhooks, message log, and dry-run mode.
- Automated reminder engine: hourly idempotent planner + queue sender, quiet hours 22:00–08:00, cancellation-aware skipping. Reminder waves send via email.
- QR code generation (per-event open link and optional per-guest) as SVG/PNG for printed cards.

Decisions resolved from the PRD's open questions and owner direction: default locale = **English** (Bangla via toggle); hosting = **single VPS with Docker Compose**; plus-ones are a count only (no named sub-guests, per PRD scope); **all v1 messaging is email-only** — WhatsApp/SMS (PRD FR-6.1's other channels, §8.1–8.2) move to v2, which removes the Meta template-approval and BTRC sender-ID schedule risks entirely; **admin auth is Google OAuth only** — the PRD's email+password with argon2id and optional TOTP (FR-4.1) is replaced by allowlisted Google account sign-in, so no passwords are stored and 2FA is inherited from the admins' Google accounts. Consequence: guests without an email address receive no automated messages in v1 — they are reached via printed QR cards or shared links, and the admin can record their RSVP manually.

## Capabilities

### New Capabilities

- `invitation-page`: Guest-facing animated invitation landing pages — token and open routes, hero/countdown/venue sections, personalisation, locale toggle, deadline and already-responded states, accessibility and performance budgets. (FR-1.x, §9)
- `rsvp-flow`: Accept-gated RSVP form, decline path, validation and phone normalisation, pre-fill, open-link registration with event selection and duplicate merging, rate limiting and bot protection, confirmation messaging. (FR-2.x)
- `cancellation`: Cancel links in messages, POST-only confirmed cancellation, immediate headcount decrement, reminder skipping, re-accept, post-start blocking. (FR-3.x)
- `admin-auth`: Google OAuth admin sign-in with an email allowlist, sessions, role-based permissions matrix, audit log of admin actions. (FR-4.1 adapted, §2.2, §7.6)
- `admin-dashboard`: Overview counts per event and aggregate, trend/channel charts, guest table with search/filters, guest detail timeline, live refresh, content editor with phone-frame preview, settings screens, capacity warnings. (FR-4.2–4.7, 4.12, 4.14–4.17)
- `guest-management`: Manual add/edit/delete of guests, bulk CSV import with column mapping, preview, duplicate detection and per-row errors, event tagging, manual RSVP marking. (FR-4.6, FR-4.8, §14.2)
- `csv-export`: Filtered CSV export with fixed column set, UTF-8 BOM, streamed large exports, caterer list, export audit logging. (FR-5.x)
- `messaging`: Email channel behind a channel-shaped provider interface (v2-ready for WhatsApp/SMS), template placeholders, send screen with preview and recipient count, broadcasts, message log with retry, bounce/delivery webhooks, unsubscribe opt-out, dry-run. (FR-6.1–6.4 scoped to email, 6.11, 6.13–6.15, FR-4.9–4.10, §8.3–8.4)
- `reminders`: T-15/T-7/T-2 planner and email sender, configurable per-event schedules, idempotency, quiet hours, throttled retries, skip-late rule, reminder settings UI, date-change re-planning. (FR-6.5–6.10, FR-4.11)
- `qr-codes`: Per-event and per-guest QR generation at error-correction level H, SVG/PNG outputs, short URLs, human-readable fallback code, print_qr source tagging. (FR-7.x, FR-4.13)

### Modified Capabilities

None — greenfield project, no existing specs.

## Impact

- New codebase: monorepo with a Next.js frontend and a FastAPI backend, SQLAlchemy schema (11+ tables per PRD §4.2), APScheduler worker process, Docker Compose stack (web, api, worker, Postgres, Caddy). This deviates from the PRD's single-app §7.1 stack by owner decision — the trade is roughly two weeks of extra integration work for an enforced trust boundary where the browser can never reach the database and the API authorizes every request on its own authority.
- External dependencies (v1): transactional email provider with SPF/DKIM/DMARC on a verified domain, Cloudflare Turnstile, S3-compatible object storage. (WhatsApp Cloud API and BD SMS gateway are v2 — no Meta verification or BTRC paperwork needed for launch.)
- Handles guest PII (name, phone, email) — retention purge 90 days after last event, export auditing, 128-bit bearer tokens.
- P2 items (share button, no-JS fallback, thank-you messages, XLSX export, capacity banner, cancel reason) are specced but may be deferred at implementation time; P0 items are launch-blocking.
