How everything connects
This is the map. Detail for every button lives in 02–06. Marketing CTAs that start these flows are in 01-marketing-pages.md.
Access words used below:
- public — no login
- logged-in — Supabase Auth session
- onboarded —
profiles.onboarding_completed_atset, or name + AUB/LAU already filled (major and campus are optional) - subscribed — at least one
user_accessrow withpayment_statusinpaid/confirmedandexpires_atnull or in the future (admins skip this for/my-courses)
proxy.ts gates:
/— if a Supabase Auth cookie is present anduserHasActiveSubscriptionis true (user_accesspaid/confirmed,expires_atnull or in the future) →/dashboard. Anonymous visitors and logged-in users with no active access still get the marketing homepage. Other public routes (/pricing,/courses, legal) are not redirected./login,/signup— if already logged in →/auth/home(with safenextwhen present)/dashboard,/welcome,/admin,/my-courses— if anonymous →/login?next=…/my-courses/{slug}and/dashboard/course/{slug}— also require subscribed (else/pricing);/dashboardand the/my-courseshome alias do not/checkout— session refresh; the page itself sends anonymous users to/login?next=/checkout?…and incomplete profiles to/welcome?next=…
Active access is not “logged in” and not a historical order. Authoritative read: user_access where user_id matches, payment_status in paid/confirmed, and expires_at is null or > now(). Expired or revoked rows do not count. Canonical student home is /dashboard.
1. Registration and first login
Tables
| Step | Writes | Reads |
|---|---|---|
| Google / email signup | auth.users; trigger inserts profiles (id, email, full_name, avatar_url, nickname; role defaults to student) | — |
| Email login | Auth session cookies only | auth.users |
/auth/callback | Session cookies; optional Resend welcome email if profiles.created_at ≤ 5s | profiles.created_at |
/auth/home | — | profiles.full_name, university, onboarding_completed_at |
/welcome submit | profiles.full_name, university, optional campus/major/programs, nickname, onboarding_completed_at, updated_at | same fields as prefill |
Where login is forced
- Any
/dashboard,/welcome,/admin,/my-courseshit while logged out →/login?next=… /checkoutwithout a session →/login?next=/checkout?plan=…- Workspace layout and checkout bounce incomplete name/university to
/welcome?next=…
After login, where you land
- Default
nextis/auth/home /auth/home→/welcome?next=…or the preserved course/checkout path; default home is/dashboardonly whenuserHasActiveSubscriptionis true, otherwise/- Course-preview signup uses
/signup?next=/checkout?plan=focus&course={uuid}
Phone signup is not offered. Phone sign-in was removed from /login (zero hosted identities).
Full page inventory: 02-auth-onboarding.md Product rules: ../onboarding.md
2. Checkout and access grant
Plan slugs on the URL vs database ids
URL ?plan= | Display name | PLANS / orders.plan / user_access.plan_type |
|---|---|---|
focus | Focus | single_course (also accepted as focus) |
balance | Balance | two_courses |
fullload | Full Load | semester_access |
crunch | Crunch | exam_crunch |
Catalog: lib/payments/catalog.ts. Full Load is up to 6 courses; Crunch is up to 4. New grants do not write schedule_verifications.
Live writes
| Moment | Table |
|---|---|
| Continue to secure payment | orders (status=pending, payment_provider=whish, course_ids, registered_credits, whatsapp, email = uni email, amount, external_id, collect_url) |
| Whish paid (status poll or callback) | orders.payment_status=paid; grantAccess → user_access (payment_status=paid, course_ids, expires_at, payment_reference). New grants do not insert schedule_verifications. |
payment_events | Server audit around create/reconcile (no UI) |
Entitlement reads use user_access.course_ids. Junction tables may be dual-written and are not the read source of truth.
Not the live CTA path (removed)
- Legacy reservation modal /
POST /api/reservations - Legacy
POST /api/orders - Placeholder payment sessions
profiles is not updated at checkout. University on the form is stored on orders, not on the profile.
Paid course lists still read user_access.course_ids / orders.course_ids. Junction tables (access_grant_courses, order_courses) are dual-written when present and are not the read source of truth yet.
Full page inventory: 03-checkout.md
3. After pay: dashboard vs my-courses
/dashboard/course/{slug}/… redirects to /my-courses/{slug}.
/my-courses/library|progress|semester-plan redirect to the /dashboard/… twins.
Someone who is logged in but has not paid can still open /dashboard (empty onboarding banner). /my-courses without a slug redirects to /dashboard. Course URLs /my-courses/{slug} still require a paid grant.
Full page inventory: 04-dashboard-and-workspace.md
4. Settings (every tab)
Opened over the workspace (not a standalone /settings page). Gear, account flyout Settings, or /dashboard?settings={tab}. Query is stripped after open. Legacy /settings/* redirects into these tabs.
| Tab id | Label | What it does |
|---|---|---|
profile | Profile | Edit name, nickname, photo, university/campus/major; badge display |
notifications | Notifications | Four email/reminder toggles on profiles.notification_preferences |
billing | Plan & billing | Active user_access + Whish orders history; Upgrade or change plan → /pricing |
security | Security | Password, Google link/unlink, phone display, backup password, this-device time |
danger | Danger zone | Sign out → /; delete account (type DELETE) |
help | Help & contact | WhatsApp, request a course, policy links |
Dark mode and extra languages are not shipped. Appearance and Language panes and server actions were removed. /settings/appearance and /settings/language still redirect to profile.
Full inventory: 05-settings.md
5. Study: how a workspace is used
Course settings (/my-courses/{slug}/settings) writes flashcard_deck_settings and can upload syllabuses. Exam dates are read from course_events.
Full inventory: 06-study-views.md
6. End-to-end student path (one sitting)
- Land on
/or/pricing→ Get Focus (or another plan CTA). /checkout?plan=focus→ if logged out, Sign in / Create account withnextback to checkout.- New account: verify email if needed →
/auth/home→/welcome(name, AUB/LAU, major) →/dashboard(still no courses). - Return to checkout (
next) → pick course(s) → details → Continue to secure payment → Whish OTP. /checkout/payment/successpolls until Payment confirmed → Go to my courses.- Dashboard shows the course card → open
/my-courses/{slug}→ Notes / Flashcards / Quiz. - Gear → Settings: nickname, photo, notification toggles, billing (active access), security.
- Sidebar Progress / Library / Semester Plan read the same study writes (
content_progress,study_sessions,library_items,exam_schedules,course_events). Syllabus upload is optional and private.
7. Connection cheat sheet
| From | To | How |
|---|---|---|
| Header Get access / Add more courses | /checkout | navCheckoutHref |
| Header Sign in | /login | — |
| Header Dashboard (mobile logged-in) | /dashboard | — |
| Account flyout Upgrade plan | /pricing | then back into checkout |
| Account flyout Settings / Get help | Settings modal or /dashboard?settings= | workspace vs marketing header |
| Checkout success Go to my courses | /dashboard | after user_access grant |
| Dashboard course card | /my-courses/{slug} | buildCourseOverviewHref |
| Course Get access (public catalog) | /checkout?plan=focus&course={id} | preselects that course |
Non-subscriber /my-courses | /dashboard (free-state home) | alias redirect; course slugs still gated |
Non-subscriber /my-courses/{slug} | /pricing | proxy |
| Incomplete profile any workspace page | /welcome | layout |
| Logout | / | Auth sign-out |
| Delete account | / (or /login if unauthorized) | auth.admin.deleteUser |
8. Tables the student product actually uses
| Table | Written by | Read by |
|---|---|---|
auth.users | signup, password change, delete | login, settings security |
profiles | signup trigger, welcome, profile/avatar/notifications, nickname | header, dashboard greeting, settings, /auth/home |
orders | Whish checkout create + reconcile | payment return status, settings billing |
user_access | grantAccess after paid Whish | dashboard courses, billing, proxy /my-courses, nav CTA |
courses / course_packs / universities / course_modules / module_pack_items | admin | catalog, checkout picker, study |
content_progress | notes, quiz complete, flashcard scheduled review | overview, resume, progress |
flashcard_sessions, flashcard_card_states, flashcard_review_logs, flashcard_deck_settings | flashcard UI / course settings | flashcards + progress |
quiz_attempts | quiz complete | progress quiz notes |
study_sessions | study heartbeat | streak, study hours, progress |
library_items | save note / upload | library |
syllabuses | syllabus modal | semester plan, course settings |
course_events | admin / syllabus parse | exam banner, semester plan, course settings |
notifications | server triggers | dashboard bell |
user_badges | streak/badge jobs | settings Profile “Showing up” |
user_streaks | streak compute | sidebar streak card |