Repository navigation
[Feature · #459] DOB / age on Google sign-up #522
Description
[Feature · under #459] Collect DOB / age on Google sign-up — UX card flow, HK contractual capacity & PDPO, spotlight tour handoff & #514 CRM birthday automation
Parent: #459 (Unified Account & Child Sub-Profiles)
Linked: #514 (Client relationship memory) under #511 (WA desk / Ops CRM) · fee framing #508 / Drop-Protection #520
1. Why
MatchMax connects students, parents, and Independent Tutors. Collecting Date of Birth (DOB) at the right moment solves three problems:
- Role & flow routing ([Urgent · V1] Unified account + roles + child sub-profiles + hours ledger #459): Student vs Parent vs Independent Tutor, plus child sub-profiles.
- Legal self-protection (HK + PDPO): Age of majority for binding commercial contracts is 18 (Cap. 410). Primary/secondary students must be welcomed (not hard-banned like an 18+ app), but financial obligations — including the 1.5-lesson Platform Administrative Fee (100% L1 + 50% L2) — and Independent Tutor terms need age-tiered guardrails so fees cannot be voided for lack of capacity.
- High-touch memory ([Ops · CRM · #511] Client relationship memory #514): Birthday WhatsApp + CRM notes without making Day-0 onboarding feel like an interrogation. Also: if someone only exists on WA (no website account yet), Ops can capture age/DOB/Form level into #514 notes; website DOB is source of truth once they sign up.
2. UX: when, where, card, spotlight
2.1 Timing
Google OAuth (openid email profile) does not reliably return birthday unless we request sensitive user.birthday.read (scary consent screen → kills conversion). Collect natively right after OAuth:
- Google OAuth callback
- Post-OAuth onboarding card
/onboarding/welcome(before full home, or over dimmed backdrop) — target 5–8 seconds - On Continue → Spotlight tour handoff (role-aware profile/sub-profiles → matching/notes → Account & Privacy)
2.2 Card wireframe (copy lock)
Welcome to MatchMax 👋 Step 1/1
Let's personalise your experience in 5 seconds.
1. I am joining primarily as a...
[ 🎓 Student ] [ 👨👩👧 Parent ] [ Independent Tutor ]
(You can switch or add roles anytime in your profile)
2. Your Date of Birth
[ Day (DD) v ] [ Month (MMM) v ] [ Year (YYYY) v ]
🔒 Year is strictly private. Used for age-appropriate features and optional birthday wishes.
[If age < 18]
[x] My parent/guardian is aware I am using MatchMax, and will approve any paid tutor bookings or fees.
[If age < 13]
Parent / Guardian WhatsApp or Email (for account link):
[ +852 … or parent@email.com ]
[ ] Show my birthday (Month & Day only, e.g. 🎂 15 Mar) on my public profile. (Optional — off by default)
By continuing, you agree to our updated [Terms of Service] and [Privacy Policy (PICS)], including WhatsApp service updates.
[ Continue to My Profile → ]
Dropdowns DD/MMM/YYYY (not native <input type="date">) — faster to reach 2008–2012 birth years.
Parent mis-entry: If role = Parent AND calculated age < 18 → inline helper:
"Looks like you entered a student's birthday! Please enter your own birth year here — you can add your child's age on their sub-profile in the next step."
Brand: primary #1d9bf0, ink #0f1419, sky #8ecdf8, white card #ffffff.
3. Age tiers (CEO/legal: confirm Form 1 ~11–12 → Tier 4)
| Age tier | Cohort | Browse / platform | Booking & 1.5 fee | Independent Tutor |
|---|---|---|---|---|
| ≥18 | Parents, adult students, uni tutors | Full; can create child sub-profiles | Full capacity | Full (notes sell / payouts OK; score verify optional) |
| 16–17 | Senior secondary F5–6 / IB | Full student | Parental awareness checkbox; parent/guardian contact as financial guarantor on paid cases | Co-sign parent on tutor terms + payout bank verify |
| 13–15 | Junior secondary ~F1–4 | Full student browse / requests | Parent co-pilot at checkout for 1.5 fee confirm | Blocked from tutor role |
| <13 (incl. primary & early Form 1 ~11–12) | Young students | No hard ban — convert to #459 student sub-profile linked to parent email/WA | Parent-managed fees + WA | Blocked from tutor role |
Legacy users: no login lockout; non-blocking banner on next booking or profile edit until DOB collected.
4. Public birthday (Facebook-style, opt-in)
- Default
show_birthday_public = false - If on: show 🎂 15 Mar (month + day only) to logged-in users only
- Never public year or exact age
- Not in unauthenticated HTML/API (anti-scrape)
5. #514 CRM + birthday WhatsApp
- Primary: WhatsApp via [Epic · Ops/WA] Business WhatsApp AI desk #511/[Ops · CRM · #511] Client relationship memory #514 desk (not midnight email spam)
- Fallback: in-app banner in birthday week; email only if no verified WA
- V1 human-in-the-loop: daily 09:30 HKT cron → Birthday Action Card in ops queue with pre-drafted, [Ops · CRM · #511] Client relationship memory #514-enriched message (1-click send; optional auto 10:00–18:00 later)
- Feb 29 → treat as Feb 28 in non-leap years
- Templates: student / parent (own or child) / Independent Tutor — pull subject/goal/notes from [Ops · CRM · #511] Client relationship memory #514 when present
- Marketing opt-out:
allow_birthday_whatsapp(default true until they turn off)
Progressive profiling (keep Day-0 card thin)
| When | Collect | Why |
|---|---|---|
| Onboarding (Day 0) | Role + DOB only | Gates + birthday |
| First case / tutor setup | Curriculum, exam year, subject/goal | Milestone check-ins |
| WA chat tags (#514) | Language, hobbies, learning style, age/Form/DOB if no website account | Holistic memory |
6. ToS + Privacy Policy / PICS (must ship with feature)
Privacy / PICS (Cap. 486)
- DPP1: DOB collected for age eligibility & safeguards; contractual capacity for paid matches / Platform Administrative Fee; personalisation (optional public month/day badge; birthday WA/email subject to marketing consent).
- DPP3: Birth year confidential; month/day public only if user toggles show-birthday.
- Part 6A direct marketing: clear Account Settings opt-out for birthday wishes & perks via WhatsApp.
- DPP2/4: restricted Ops/CS access ([Ops · CRM · #511] Client relationship memory #514); user can see own DOB.
ToS
- Minors & parental guarantee: under-18 browse/connect with parent/guardian involvement; parent assumes financial responsibility for the 1.5-lesson Platform Administrative Fee and related settlements.
- Independent Tutor: independent operators (never employment / agency-employee language); warrant ≥18 or verified parental co-consent to tutor.
7. Risks
| Risk | Mitigation |
|---|---|
| Fake DOB | No default date; flag Form vs age mismatches in #514 |
| Edit abuse | 1 self-serve edit; further changes via CS + user_audit_logs |
| Child safety | Never public year/age; <13 via parent contact |
| Leap day | Feb 29 → Feb 28 non-leap |
8. Data sketch
-- users
date_of_birth DATE NULL,
dob_collected_at TIMESTAMPTZ NULL,
dob_edit_count INT NOT NULL DEFAULT 0,
parental_gate_status VARCHAR(32) NOT NULL DEFAULT 'none',
-- none | awareness_checked | parent_linked | verified_adult | blocked
parent_contact_reference VARCHAR(255) NULL,
show_birthday_public BOOLEAN NOT NULL DEFAULT FALSE,
allow_birthday_whatsapp BOOLEAN NOT NULL DEFAULT TRUE,
onboarding_tour_completed BOOLEAN NOT NULL DEFAULT FALSE;
-- child_sub_profiles (#459)
date_of_birth DATE NULL,
graduation_year INT NULL,
personal_notes JSONB DEFAULT '{}';
-- birthday cron index on month/day where DOB set and allow_birthday_whatsappPublic serializer: strip DOB; if opted in + authenticated requester → birthday_display: "15 Mar" only.
Middleware: if dob_collected_at null on new account → onboarding card; on complete → persist + startSpotlightTour.
9. Acceptance criteria
- Post-OAuth card: role + DD/MMM/YYYY; brand palette; <8s path
- Age gates per table (≥18 / 16–17 / 13–15 / <13 → sub-profile, no hard ban)
- Parent role + age <18 → mis-entry helper (child DOB blocked on parent primary)
- Spotlight tour after Continue
- Public birthday opt-in month/day only; never year; logged-in only
- One self-serve DOB edit; further via CS + audit
- 09:30 HKT birthday cards into [Epic · Ops/WA] Business WhatsApp AI desk #511/[Ops · CRM · #511] Client relationship memory #514 queue; Feb 29 handled; marketing opt-out
- Ops can store age/DOB/Form on [Ops · CRM · #511] Client relationship memory #514 for WA-only clients
- ToS + PICS updated (Cap. 410 parental guarantee for 1.5 fee; Independent Tutor; PDPO + marketing opt-out)
- Copy: Platform Administrative Fee / Independent Tutor only
Open for CEO / counsel
- Confirm cut-offs (esp. Form 1 ~11–12 = Tier 4).
- Tutor minimum: block <16 hard vs co-sign at 16–17 only (draft = co-sign 16–17, block <16).
- Birthday WA: Business line only vs also personal CS2.
Out of scope
Community birthday feed; selling age data; replacing #459 role model; Google user.birthday.read scope.
Activity
[-][Feature · #459] Collect DOB / age on Google sign-up — UX card, HK capacity & PDPO, spotlight + #514 birthday CRM[/-][+][Feature · #459] DOB / age on Google sign-up[/+]feat(#545,#547,#548,#550,#522): unified-account children — Education …
keyframesfound commentedon Nov 1, 2026
Closing — website-side scope shipped on main (c0e8ce4, 20261101060000 migration prod-applied):
OnboardingGate.tsx): Day/Month/Year selects, 🔒 year-private copy, optional — the 5-second target. Same save records role intent + handle (unchanged [Urgent · V1] Unified account + roles + child sub-profiles + hours ledger #459 flow).<18requires the parental-awareness checkbox (parental_awareness_confirmed_atstamped server-side);<13collects parent/guardian contact; under-16 cannot activate Teaching — enforced in the extendedcomplete_onboardingRPC (AGE_RESTRICTED) AND insubmitTutorApplication(defence in depth). 16–17 full student with co-sign checkbox; ≥18 full. Missing DOB never blocks (legacy).show_birthday_publicdefault off; when on, the Channel Profile shows 🎂 MM-DD only to logged-in users — year/age never leave the server (verified ingetChannelProfile).date_of_birtheditable there).profiles.date_of_birth/show_birthday_public/parent_guardian_contact/parental_awareness_confirmed_at+age_tier(user_id)helper; migration live on prod.