4.4 KiB
4.4 KiB
📱 PERSON A — Web App (Customer-Facing)
Functional Requirements
- WEB-FR-1: User registration (email + password) with email verification
- WEB-FR-2: Login / logout
- WEB-FR-3: Password reset flow
- WEB-FR-4: Display the event's card offering — name, description, price, expiration date
- WEB-FR-5: Checkout flow via Stripe (EUR)
- Open item: single card per order, or multiple?
- WEB-FR-6: On confirmed payment (via Stripe webhook), trigger card/QR generation (calls shared backend)
- WEB-FR-7: Send confirmation email with QR code attached/embedded (via transactional email service)
- WEB-FR-8: "My Cards" account page — shows purchase history, card status (unused/used/expired), QR re-download button
- WEB-FR-9: Basic account settings page (update email/password)
Non-Functional Requirements
- WEB-NFR-1: HTTPS only
- WEB-NFR-2: GDPR-compliant — privacy policy, consent checkbox at registration, data retention/erasure process
- WEB-NFR-3: No raw card/payment data stored — Stripe handles PCI compliance, you only store payment references
- WEB-NFR-4: Responsive design (mobile browser support, since users will pull up emails on phones too, though the QR itself is scanned by the admin's phone, not theirs)
Open Items for This Side
- Multi-card orders — yes/no, and if yes, does each card need a separate recipient email field?
- Refund/cancellation flow — in scope for v1 or not?
- Any requirement to resend the QR email if a user loses it (vs. just downloading from account page)?
📷 PERSON B — Android Scanner App (Admin-Facing)
Functional Requirements
- APP-FR-1: Single admin login (one hardcoded/managed admin role — no multi-account complexity)
- APP-FR-2: Camera-based QR scanning (use a standard library — e.g., ML Kit or ZXing)
- APP-FR-3: On scan, send token to backend validation endpoint
- APP-FR-4: Display result clearly and immediately:
- ✅ Valid → show card owner name + card type, mark as used
- ❌ Already Used → show when it was originally used
- ❌ Expired → show expiration date
- ❌ Not Found → invalid/forged code
- APP-FR-5: Local on-device scan log (timestamp + result) for admin's own reference during the event
- APP-FR-6: Manual entry fallback (in case camera/QR fails to scan — type in code manually)
Non-Functional Requirements
- APP-NFR-1: Requires internet connectivity to validate (confirm: acceptable, or do you need offline fallback?)
- APP-NFR-2: Fast response time — scan-to-result should feel instant (sub-1s ideally) since there may be a line of people
- APP-NFR-3: Simple, high-contrast UI readable in bright outdoor daylight or dark event lighting
- APP-NFR-4: Since it's single-admin/single-device, no need to handle concurrent scan conflicts — backend validation is still atomic, but app itself doesn't need sync logic
Open Items for This Side
- Offline fallback — if there's no signal at the venue, what happens? Worth deciding now since it affects architecture (native online-only call vs. local cache + sync).
- Does the admin need to undo an accidental valid scan (e.g., mis-scan, wrong card)?
- Any requirement to see a running count (e.g., "142 checked in") during the event?
🔗 SHARED — Backend Contract (Both of you depend on this)
This is the glue between your two apps — worth agreeing on before you start building independently, since a mismatch here is the most likely source of integration pain later.
- API-1:
POST /api/orders— creates order, integrates Stripe checkout - API-2: Stripe webhook handler — on payment success, generates Card record + signed QR token, triggers email
- API-3:
POST /api/cards/validate— takes scanned token, returns{status: valid|used|expired|not_found, owner_name, card_type, used_at?}, atomically updates status if valid - API-4:
GET /api/users/me/cards— for the web app's "My Cards" page - API-5: Shared Card data model:
id, unique_token (signed), user_id, card_type, status, purchased_at, expires_at, used_at - API-6: Auth — separate token/role for admin scanner vs. customer web sessions
Recommendation: whoever owns the backend (or whoever's building it jointly) should nail down the exact JSON shape of API-3's response first, since that's the contract Person B's UI directly renders.