# Purchase Flow ## User Journey ``` ┌─────────────────────────────────────────────────────────────────┐ │ │ │ Home Page │ │ ┌─────────────────────────────────────┐ │ │ │ [Buy Full Pack — $5] │ │ │ │ │ │ │ │ 🔒 🔒 🔒 (blurred wallpapers) │ │ │ └─────────────────────────────────────┘ │ │ │ │ │ ▼ │ │ 1. Click "Buy" │ │ 2. Token saved to localStorage │ │ │ │ │ ▼ │ │ ┌─────────────────────────────────────┐ │ │ │ Stripe Checkout │ │ │ │ [Enter card details + Pay] │ │ │ └─────────────────────────────────────┘ │ │ │ │ │ ┌──────────┴───────────┐ │ │ ▼ ▼ │ │ Success Cancel │ │ │ │ │ │ ▼ ▼ │ │ ┌──────────────┐ ┌──────────────┐ │ │ │ Success Page │ │ Home Page │ │ │ │ │ │ (can retry) │ │ │ │ ✓ Unlocked! │ └──────────────┘ │ │ │ 🖼 🖼 🖼 │ │ │ └──────────────┘ │ │ │ └─────────────────────────────────────────────────────────────────┘ ``` ## Payment Flow ``` Client Stripe Server │ │ │ │ 1. Generate token │ │ │ Save to localStorage │ │ │ │ │ │ 2. POST /api/checkout ────────────────────────────────▶ │ │ │ │ ◀─────────────────── checkout URL ─────────────────│ │ │ │ │ 3. Redirect ─────────────▶│ │ │ │ │ │ 4. User pays │ │ │ │ │ │ 5. Webhook ──────────────▶│ │ │ (with token) │ │ │ │ 6. Create │ │ │ purchase │ │ │ │ ◀── 7. Redirect ───────│ │ │ to /success │ │ │ │ │ │ 8. Query wallpapers ──────────────────────────────────▶ │ with token │ │ │ │ │ │ ◀─────────────────── fullResUrl returned ──────────│ │ │ │ ▼ ▼ ▼ ``` ## Data Model ``` purchases wallpapers ├── token (proves ownership) ├── name ├── email ├── thumbnailUrl (public) ├── stripeSessionId ◀────▶├── fullResUrl (protected) ├── status └── order └── createdAt └────── many-to-many ──────┘ ``` ## Access Control ```ts // Permission rule for wallpapers.fullResUrl "ruleParams.token in data.ref('purchases.token')" ``` - Query includes valid token → `fullResUrl` returned → wallpaper unlocked - Query has no token or invalid token → `fullResUrl` omitted → wallpaper locked ## Recovery Flow ``` /recover │ ▼ Enter email │ ▼ Receive magic code (via InstantDB) │ ▼ Enter code → Authenticated │ ▼ Query purchases by email │ ▼ Save token to localStorage → Done ```