Repository navigation
[Feature · V1] Extracurriculars — hybrid tags, portfolio, ecosystem #415
Description
Summary
Expand MatchMax beyond standard exam tutoring into a full CV-Building Ecosystem (Music, Sports, STEM, Debate, Talks, Camps & Community) without diluting the academic moat that parents trust on /tutors and /.
This ships a Hybrid Tag System (fixed broad-category buckets + user-generated autocomplete tags), extends the existing Trophy Cabinet (portfolio_images) into tutor-uploadable Portfolio & Proof with light admin hide, and extends the Digital Shop / Gigs taxonomy (digital_materials) so notes and freestyle gigs can live under the same verticals.
Architecture principle: one unified stack — tutors, tutoring_cases, digital_materials. A tutor may be Academic-only, Skill-only, or Multi-skilled. The UI dynamically shows/hides Core Academic Breakdown vs Extracurriculars / Skills sections. Discovery stays Academic-First by default.
This is an additive extension of live schema and shipped UX — not a parallel product and not a greenfield rebuild.
Goals
- Let tutors declare non-academic verticals (Music coaching, Sports, STEM clubs, Debate, Talks / Community, Camps) alongside or instead of exam tutoring — including guest speakers & awareness educators.
- Hybrid taxonomy: strict broad category enum + freeform skills / extracurricular tags with autocomplete.
- Portfolio gallery of self-declared proof (certificates, trophies, performance shots) on the detail page only, with admin 1-click hide.
- Protect
/tutors+ homepage from brand dilution: pure-skills tutors do not flood the default academic grid. - Extend case posting (parent + [Compliance / B2B] Extend centre partnership (#251/#256–258): 3-step EA-safe triage, BR org fields, COMPLIANCE_HOLD, How-it-works Partners tab #412 partner/B2B) and shop listings with the same taxonomy.
- Actively promote Skills / Music and Talks & Community on homepage +
/guideso the category is discoverable (not filter-only). - Preserve Cap.57 contractor-only B2B path ([Compliance / B2B] Extend centre partnership (#251/#256–258): 3-step EA-safe triage, BR org fields, COMPLIANCE_HOLD, How-it-works Partners tab #412): Camps / centres never look like employment or a jobs board ([PARKED · Cap.57] Partner storefront SaaS + vacancy ad board — blocked pending solicitor/EAA; storefront-only slice under D1/D3 #413 stays parked).
Non-goals
- Do not invent parallel columns that replace live ones (
headline,academic_headline,subjects,profile_tags,portfolio_images text[],academic_tier,gig_category, shop freestyle taxonomy from Epic: Freestyle micro-services / gig marketplace (extends notes shop) #325–329). - Do not invent
custom_headlineas a new column. Headline bilingual work is Feature: Dual-Language Custom Headline + Core Academic Breakdown Restructure #411 (custom_headline_en/custom_headline_zh). This issue depends on / sequences after Feature: Dual-Language Custom Headline + Core Academic Breakdown Restructure #411 for headline + Core Academic Breakdown layout; until Feature: Dual-Language Custom Headline + Core Academic Breakdown Restructure #411 lands, wireframes and code continue to use liveacademic_headline(and legacyheadlinewhere still referenced). - Do not replace or remove the live Kindergarten | Primary & Secondary | University tabs from Expand Platform to Support Kindergarten & University Tutoring Verticals #190. The new Academic vs Activities mode merges above / beside those tabs.
- Do not shrink
portfolio_imagesbelow max 6 (Add Optional "Trophy Cabinet" Photo Uploads to Tutor Form and Profiles #97). Do not migrate to JSONB objects as the only storage without a careful backfill + publish-RPC update — prefer additive hide list (below). - Do not build a separate Speaker Portal, NGO app, or school-only product surface — reuse Skill-only tutors +
workshop_package+ [Compliance / B2B] Extend centre partnership (#251/#256–258): 3-step EA-safe triage, BR org fields, COMPLIANCE_HOLD, How-it-works Partners tab #412 Partner Orgs. - Do not turn Talks / Camps / Community into a vacancy / “Apply to centre” board ([PARKED · Cap.57] Partner storefront SaaS + vacancy ad board — blocked pending solicitor/EAA; storefront-only slice under D1/D3 #413 On Hold). Do not change Cap.57 triage questions in [Compliance / B2B] Extend centre partnership (#251/#256–258): 3-step EA-safe triage, BR org fields, COMPLIANCE_HOLD, How-it-works Partners tab #412.
- Do not redefine the whole shop UI (Shop UI (Big Cover + Expandable Card), Topic Folder Bundles, Video Courses & General Courses #392) — only add category/tag fields + card pills that reuse existing listing rails.
- Do not show portfolio gallery, self-reported disclaimer, or long ToS copy on explore cards — detail page + legal/guide only.
- Do not create a second onboarding flow — extend
ApplicationForm.tsx(Expand Platform to Support Kindergarten & University Tutoring Verticals #190 vertical routing) with conditional sections.
Related issues (reconcile — do not clash)
| Issue | State | Relationship |
|---|---|---|
| #411 Dual-language headlines + Core Academic Breakdown | OPEN | Depends on / sequence after. Headline row + Core Academic layout owned by #411. This issue only adds the Skills line + Extracurriculars section + conditional hide of Core Academic for pure-skills. Wireframes below say academic_headline / “active #411 headline” — never a new custom_headline column. |
#190 K | P&S | Uni tabs on /tutors |
CLOSED (LIVE) | Merge, don’t replace. Mode filter (Academic Tutoring vs Activities, Music & Skills vs All) sits above or beside the tier tabs. Default remains Academic Tutoring → Primary & Secondary. |
#97 Trophy Cabinet / portfolio_images |
CLOSED | Extend. Keep portfolio_images text[] (R2 URLs, max 6). Add additive admin-hide storage. Policy change (explicit): move from admin-curated-only toward tutor self-upload → immediately visible on profile, with admin hide + contact-info warning (see §3). |
#217 / profile_tags |
CLOSED | Keep unchanged. Card chips stay profile_tags (max 5). Skills taxonomy uses new extracurricular_tags / skills_tags — do not overload profile_tags as the skills system. |
| #392 Shop UI / courses | OPEN | Cross-link. Add broad_category + skills_tags to listings; do not rebuild shop chrome. |
| #412 Cap.57 B2B triage / partner cases | OPEN | Compose. Partner case form gets top-level broad_category above Parts 1–4; Cap.57 unchanged. Also owns org type (Tutorial / Day School / NGO) + optional BR/EDB/Charity id (§4b). Talks must not look like employment. |
| #413 Vacancy / storefront SaaS | On Hold | Out of scope. This is not a jobs board. |
| #325–329 Freestyle gigs taxonomy | CLOSED | Reuse. Keep gig_category (document_review | speaking_mock | workshop_package | other) and existing note tags; layer broad category + skills tags on top. |
1. Database, backfills & moderation (ADDITIVE)
1.1 Global taxonomy (broad categories)
Define a strict enum / canonical code list (store codes in DB; render EN/ZH labels in UI):
| Code | EN label | ZH label (suggested) |
|---|---|---|
academics_exams |
Academics & Exams | 學術與考試 |
music_arts |
Music & Arts | 音樂與藝術 |
sports_fitness |
Sports & Fitness | 運動與體適能 |
stem_coding_robotics |
STEM, Coding & Robotics | STEM、編程與機械人 |
debate_languages |
Debate & Languages | 辯論與語文技能 |
talks_camps_community |
Talks, Camps & Community | 講座、營隊與社區教育 |
Music / Languages collision (critical):
- Academic subject pills that already exist (e.g. IB Music, DSE music papers, language exam subjects) stay under
academics_examsvia existingsubjects/ grade labels /approved_grade_labels. - Performance coaching, ABRSM-as-skill, ensemble coaching, debate coaching, spoken-language coaching for CV (not exam papers) use
music_arts/debate_languages+extracurricular_tags/skills_tags. - UI copy on forms must say: “Exam Music / Language subjects → Academics. Performance, certificates, coaching, clubs → the matching Activities bucket + tags.”
UI short label: filters/chips may show Talks & Community (full: Talks, Camps & Community) so the mode toggle does not overflow.
Talk-provider seed tags (autocomplete static list — add to extracurriculars.ts):
School Assembly Talk, Anti-Drug Education, Animal Welfare, Sustainability & ESG, Mental Health, Career & Life Planning, Community Service Learning.
Shared constant module (suggested): src/features/tutors/extracurriculars.ts (codes, labels, autocomplete seed list, pure-skills helpers).
1.2 tutors table — ADD only
Live today (do not replace): headline, academic_headline, subjects[], target_students[], profile_tags[] (max 5), portfolio_images text[] (max 6, R2), approved_grade_labels, uni/kindergarten vertical columns from #190.
Add:
| Column | Type | Default / constraints | Notes |
|---|---|---|---|
offered_categories |
text[] NOT NULL |
'{academics_exams}' |
Subset of broad-category codes. Backfill all existing rows to ['academics_exams']. Check: non-empty; every element ∈ enum. |
extracurricular_tags |
text[] NOT NULL |
'{}' |
Freeform skill tags, e.g. ABRSM Grade 8 Piano, FIDE Chess 1800, VEX Robotics. App-layer: trim, length cap (~40), contact-info reject (reuse existing public-text guards), reasonable max count (suggest 12; card displays 1 line with +N). Distinct from profile_tags. |
portfolio_hidden_urls |
text[] NOT NULL |
'{}' |
Additive admin-hide list. Public gallery = portfolio_images minus any URL present in portfolio_hidden_urls. Prefer this over JSONB rewrite of portfolio_images. |
Do not add: custom_headline, offered_categories as a replacement for subjects, per-image JSONB as the sole portfolio store, or shrinking max images to 5.
Portfolio policy (#97 → Phase 1.5):
- Keep
portfolio_images text[], max 6, JPG/PNG/WebP via existing R2 upload path (src/features/tutors/r2.functions.ts+ Trophy Cabinet). - Accept policy change: tutors may upload portfolio images that become immediately visible on
/tutors/$tutorCode(no pre-publish approval queue). Show a clear warning: no phone / WhatsApp / email / social handles / QR in images (contact guard already exists for text; extend upload UX with the same rule + admin hide for offenders). - Admin
/admin/tutorsTutorEditor already edits the URL array — add 1-click Hide / Unhide that toggles membership inportfolio_hidden_urlswithout deleting the R2 object (polish on top of edit-URLs). - Publish RPC (
publish_tutor/ card JSON) must continue to passportfolio_images; filter hidden URLs in the public read path (queries / mapper), not by deleting from the array on hide. - If a future migration to
{ url, hidden_by_admin }[]is desired, it must include backfill + publish RPC update in the same PR — not required for Phase 1.5 ifportfolio_hidden_urlsships.
Backfill:
-- illustrative
UPDATE public.tutors
SET offered_categories = ARRAY['academics_exams']::text[]
WHERE offered_categories IS NULL
OR cardinality(offered_categories) = 0;1.3 tutoring_cases table — ADD only
Live today: academic_tier (kindergarten | primary_secondary | university), subjects, tags, kindergarten_focus, uni funnel fields (#190 / #412 surfaces).
Add:
| Column | Type | Default | Notes |
|---|---|---|---|
broad_category |
text |
'academics_exams' |
Enum check; legacy cases default Academics. |
skills_tags |
text[] NOT NULL |
'{}' |
Freeform tags for non-academic / hybrid requests. |
academic_tier remains the academic vertical. For Activities-mode cases, academic_tier may be null or kept only when the request also needs a school tier — product rule: if broad_category = academics_exams, require tier as today; if non-academic, tier optional / hidden in UI.
1.4 digital_materials table — ADD only
Live today: school_tag, curriculum_tag, subject_tag, document_type, material_type (notes | mock | exemplar | flashcards | gig), gig_category (document_review | speaking_mock | workshop_package | other).
Add:
| Column | Type | Default | Notes |
|---|---|---|---|
broad_category |
text NOT NULL |
'academics_exams' |
Must default so legacy notes/gigs never break. |
skills_tags |
text[] NOT NULL |
'{}' |
Hybrid tags for shop cards (1-line max in UI). |
Do not remove or redefine freestyle gig_category / note tag columns (#325–329, #392).
1.5 Light photo moderation (admin)
- Portfolio images are self-uploaded and immediately publicly visible (minus hidden URLs).
- In
/admin/tutorsTutorEditor: per-image Hide control → add URL toportfolio_hidden_urls; Unhide removes it. - Hidden images must not render in
TrophyCabinet/ Extracurriculars gallery on the public detail page. - Optional: small admin badge “N hidden” on the tutor row — nice-to-have, not blocking.
2. Search, filter & discovery (/tutors & /)
2.1 Academic-First default (moat protection)
- Default explore grid (
/tutors) and homepage tutor rails remain Academic-First on initial load. - Pure-skills tutors =
offered_categoriesnon-empty and does not includeacademics_exams(or includes only non-academic codes) and no usable academic grade payload for Core Academic. - Pure-skills profiles must not appear in the default Academic Tutoring → Primary & Secondary grid unless the user:
- switches mode to Activities, Music & Skills or All, or
- types a keyword that matches
extracurricular_tags/ skills (unified search — see below).
2.2 Mode filter merged with #190 tier tabs
Live today (#190): tabs Kindergarten | Primary & Secondary (default) | University.
Ship this merge (document in PR):
┌─ Mode (new) ─────────────────────────────────────────────────────────┐
│ (•) Academic Tutoring ( ) Activities, Music & Skills ( ) All │
└──────────────────────────────────────────────────────────────────────┘
┌─ Tier tabs (#190 — visible when Mode = Academic Tutoring or All) ────┐
│ [ Kindergarten ] [ Primary & Secondary ✓ ] [ University ] │
└──────────────────────────────────────────────────────────────────────┘
Behaviour:
| Mode | Tier tabs (#190) | Who appears |
|---|---|---|
| Academic Tutoring (default) | Shown; default Primary & Secondary | Tutors with academics_exams in offered_categories (or legacy rows backfilled). Apply existing K / P&S / Uni filters via target_students exactly as #190. |
| Activities, Music & Skills | Hidden or demoted to optional secondary chips | Tutors with any non-academics_exams category. Facet by broad category + tag. Pure-academic-only tutors may be excluded unless they also offer a skills category. |
| All | Shown | Union; still apply tier filter when a tier tab is selected. |
Homepage search should respect the same Academic-First default (no silent pure-skills flood on /).
2.3 Unified keyword & tag search
Typing into the global /tutors search (and home search, if shared) must query across:
- existing academic fields (
subjects,approved_grade_labels, uni/school text,profile_tags, etc.), and extracurricular_tags, andoffered_categorieslabel match (EN/ZH),
so “ABRSM”, “robotics”, “debate” surface the right tutors even from the Academic mode when the keyword clearly matches — without putting pure-skills tutors into the unfiltered default grid.
Case board / shop search should likewise include skills_tags / broad_category where those list UIs already search tags.
3. Form integrations (onboarding & case posting)
3.A Unified tutor application & profile (/join & /account)
Extend src/features/tutor-application/ApplicationForm.tsx (#190 vertical routing) — conditional sections, not a second wizard.
- Offered categories multi-select (broad-category codes). Default tick
academics_examsfor new applicants who look academic; allow unticking for Skill-only. - Extracurricular tags input: autocomplete from a seeded suggestion list (ABRSM grades, common sports, STEM programmes, debate formats, camp types) + freeform add. Store in
extracurricular_tags. - Conditional academic block: if
academics_examsis not offered and applicant is Skill-only, hide/skip exam-results heavy UI where Expand Platform to Support Kindergarten & University Tutoring Verticals #190 already skips for uni/kind-only — mirror that pattern for pure skills (still collect identity, rates, availability, ToS). - Conditional skills block: if any non-academic category is selected, show Skills tags + Portfolio upload (max 6) with self-report warning.
- Portfolio upload: tutor can add images to
portfolio_images(R2). Visible on profile immediately after publish/save path used today; show contact-info / guideline warning at upload time. - Account / profile edit mirrors the same fields for published tutors.
- Multi-skilled tutors keep both academic sections (Expand Platform to Support Kindergarten & University Tutoring Verticals #190 / Feature: Dual-Language Custom Headline + Core Academic Breakdown Restructure #411) and skills/portfolio sections.
3.B Parent case post (/tutor-requests?post=true / case request flow)
- Top dropdown: Broad category (default
academics_exams). - When non-academic: show
skills_tagsinput; soften/hide exam-system fields that don’t apply; keep district/mode/budget UX. - When academic: existing subject / tier / vertical behaviour unchanged (Expand Platform to Support Kindergarten & University Tutoring Verticals #190).
3.C Partner / centre case form (#412)
- Same broad category dropdown on top of Cap.57 Parts 1–4.
- Cap.57 engagement-category radios, financial questions, non-integration gates, childcare / household-duty holds — unchanged.
- If category is
talks_camps_community, copy must still read as independent educator / course module / project, never “hire camp staff” / vacancy language ([Compliance / B2B] Extend centre partnership (#251/#256–258): 3-step EA-safe triage, BR org fields, COMPLIANCE_HOLD, How-it-works Partners tab #412 vocab + [PARKED · Cap.57] Partner storefront SaaS + vacancy ad board — blocked pending solicitor/EAA; storefront-only slice under D1/D3 #413 non-goal).
4. Legal, ToS, safeguarding & disclaimers
4.1 Self-reported disclaimer (placement rules)
Show once on tutor detail page inside / immediately above the Extracurriculars, Skills & Certifications block (and optionally once in /guide + /tos community section):
ⓘ Self-Reported: Portfolio images and non-academic certificates are self-declared; please verify prior to lesson 1.
NEVER on explore / home tutor cards.
NEVER as a second sticky banner if Core Academic already has a transcript self-report note nearby — merge visually into one quiet info line if both apply.
4.2 ToS / childcare / safeguarding
- Update
/tos(and matching locale strings) to state that MatchMax listings for Activities / Camps are educational / coaching / enrichment engagements, not employment placement, and not a general childcare / babysitting marketplace. - Explicit ban / decline path for requests that are primarily household childcare, babysitting, or non-teaching domestic duties (align with [Compliance / B2B] Extend centre partnership (#251/#256–258): 3-step EA-safe triage, BR org fields, COMPLIANCE_HOLD, How-it-works Partners tab #412 triage hold when “non-tutoring household / childcare duties” = Yes).
-
/guide/parents+/guide/tutors: short note on verifying extracurricular credentials; link to ToS. - Upload warning copy (EN + zh-HK): no personal contact details in portfolio images; violations → admin hide / account action under existing community rules.
4.3 Cap.57
No change to contractor-only B2B legal stance. This feature must not introduce “Apply for a job at camp/centre” CTAs.
4b. Talk providers, schools & social impact (reuse — no new product)
Verdict: Guest speakers (drug / animal / environment / arts / career / awareness), NGOs, and day schools do not need new tables, onboarding flows, or surfaces. Map onto assets already in this issue + #412 + freestyle gigs (#325–329).
| Existing asset | How talk providers / schools use it |
|---|---|
| Tutor profile + Skill-only path (this issue) | Speaker unchecks Academics; Core Academic hides; #411 headline e.g. Registered Social Worker — Animal Welfare Educator; offered_categories includes talks_camps_community; tags + portfolio (certs, talk photos). |
Freestyle gig workshop_package (digital_materials) |
Packaged assembly / workshop listing via /account/services/new (paid honorarium or $0 pro-bono). |
| Partner Org + case board (#412) | School OLE / Values / Careers coordinator or NGO registers as Partner Organisation and posts: “Environmental speaker for Form 4 assembly…”. Cap.57 triage unchanged — one-off Contract for Services. |
Pro-bono / Community Impact pricing
- Tutor rate and gig price must accept exactly
0. - When value is strictly
0, render badge🌱 Pro-Bono / Community Impactinstead of$0 up/hr/$0. - Do not auto-apply the badge to low-priced paid talks.
- Policy note (product, not schema): platform may take 0% commission on confirmed
$0community / underprivileged cases — document in fee terms when ops confirms; out of scope to invent a new fee engine here.
Partner Organisation onboarding (#412 — compose, don’t duplicate)
Track implementation primarily on #412; this issue only requires the taxonomy + $0 badge so speakers are discoverable.
- Org type dropdown:
Tutorial Centre|Day School|NGO or Charity. - Identifier field label:
BR Number / EDB School Reg. No. / Charity IRD No.— field optional so schools/NGOs without commercial BR are not blocked (.edu.hkemail still valid for trust later). - Live constraint:
/business,/business/join,/pricingare 404 whileCENTRE_MARKET_ENABLED=false. School self-serve onboarding ships only when [Compliance / B2B] Extend centre partnership (#251/#256–258): 3-step EA-safe triage, BR org fields, COMPLIANCE_HOLD, How-it-works Partners tab #412 lands and the flag (or a scoped school/NGO path) is enabled. Until then, ops can still seed speaker tutor profiles + gigs; school demand can use authenticated case posts / desk handoff.
Discovery (so schools can find speakers)
- Default
/tutorsstays Academic-First — pure talk providers appear under mode Activities / Talks & Community (or All) + keyword/tag search, not the default P&S academic grid. - Partner-posted cases are the B2B pull; public speaker browse is the supply side of the same taxonomy.
Additional guardrails (edge cases locked)
-
$0Pro-Bono checkout & validation- Update Zod schemas on tutor profile
rateand gigpriceto allow0(Pro-Bono) OR the existing minimum paid rate (reject accidental$1–$9typos; do not allow tiny paid junk rates). - For
digital_materialsgigs withprice === 0, change CTA fromBuy NowtoRequest Pro-Bono Session(orRequest Pro-Bono Talkfor talk gigs) and bypass the manual FPS payment-proof upload on/orders/$orderId— go straight to confirmed / WhatsApp coordination. - When sorting
/tutorsby rate ascending (Low → High), sortrate = 0after paid rates (ORDER BY (rate = 0) ASC, rate ASC) unless the user is filtering specifically for Pro-Bono /talks_camps_community/ community talks.
- Update Zod schemas on tutor profile
-
Legacy Add Optional "Trophy Cabinet" Photo Uploads to Tutor Form and Profiles #97 Trophy Cabinet fallback (no disappearing galleries)
- Never render two galleries on
/tutors/$tutorCode. - If
extracurricular_tagsis non-empty OR any non-academicoffered_categoriesis selected → heading🏆 Extracurriculars, Skills & Certifications(tags + gallery + self-reported disclaimer). - If Academic-only (
extracurricular_tagsempty and onlyacademics_exams) AND visibleportfolio_imagesexist → still render the gallery under fallback heading🏆 Portfolio & Certificateswith the same self-reported disclaimer, so legacy Add Optional "Trophy Cabinet" Photo Uploads to Tutor Form and Profiles #97 Trophy Cabinet photos do not vanish.
- Never render two galleries on
Cap.57
School assembly / workshop talks are one-off independent engagements — safest EA posture. Do not frame as jobs/vacancies (#413 stays parked). Camps must not look like employment.
Site promotion & discoverability (people must know these exist)
Do not bury Talks / Music / Skills as silent filters only. Actively surface them on marketing + guide surfaces so parents, schools, speakers, and NGOs learn MatchMax offers this ecosystem.
Required promo surfaces (copy EN + zh-HK):
- Homepage — a discover row / chip rail under search (or next to featured tutors) for at least:
Music & Arts,STEM & Coding,Talks & Community,Sports & Fitness(link into/tutorswith mode + category preselected). Optional: a short banner line e.g. “Beyond exams — skills coaching, guest talks & community workshops.” -
/guidehub — new card(s) or section linking to dedicated guide pages below; update hub blurb so it is not “tutoring-only.” -
/guide/talks-community(new) — what guest speakers / NGOs / school OLE talks are; how schools request; how speakers list Skill-only +workshop_package; pro-bono badge explanation; Cap.57-safe one-off framing (no jobs board language). -
/guide/skills-music(new) or expand/guide/tutors— Music & Arts, Sports, STEM, Debate paths; Academic vs Activities mode; Skill-only vs Multi-skilled; portfolio self-reported disclaimer once. -
/tutorsempty / intro copy — when Mode = Activities & Skills, show a one-line explainer (“Browse skills coaches, music educators, and community talk providers”) so the grid does not look like a broken academic list. - Footer / nav (optional light touch) — Guide submenu links to Talks & Community + Skills & Music; do not add a permanent top-nav tab that dilutes Tutors/Guide/Cases.
- SEO / sitemap — add the new guide URLs to
sitemap.xmlwhen published.
Non-goals for promo: do not invent a separate Speakers marketplace URL; deep-link into existing /tutors mode + category + /notes gigs.
Launch note (ops — not engineering ACs)
Seed supply first (existing tutors with societies/volunteer work + NGO DMs), then pitch OLE / Values Education / Careers coordinators with free OLE / pro-bono community framing. Full GTM copy lives outside this issue.
5. UI target states (visual reference — keep card & profile looks)
Field-name rules for implementers:
- Top bold line = live
academic_headline, or after Feature: Dual-Language Custom Headline + Core Academic Breakdown Restructure #411 ships = active localizedcustom_headline_en/custom_headline_zh(fallback EN). Do not inventcustom_headline. - Skills line =
extracurricular_tags(hybrid tags), 1 line with ellipsis /+N. - Portfolio = detail only; public set =
portfolio_images−portfolio_hidden_urls; max 6. - Core Academic Breakdown = Feature: Dual-Language Custom Headline + Core Academic Breakdown Restructure #411 layout; hide entirely for pure-skills tutors with no academic scores / grades.
profile_tagschips may remain elsewhere on the card as today (Profile tags, not a feed #217) — do not confuse them with the Skills line.
A. Tutor Card (Explore / List — /tutors, home rails)
Height guardrails: keep existing card styling/spacing; Skills one line; no portfolio thumbnails; no disclaimer text on the card.
┌────────────────────────────────────────────────────────────────────┐
│ [Avatar] IBDP 45/45 | ABRSM Grade 8 Piano | Debate Cap [8 Male] │ <-- Active academic_headline / #411 headline
│ MM-T105 🎓 HKU - Medicine (Year 1) │
│ [Blue Tick] 🏫 Diocesan Boys' School │
│ │
│ ────────────────────────────────────────────────────────────────── │
│ 📊 Core Expertise │
│ IBDP: 45/45 [Bio HL: 7] [Chem HL: 7] [Math AA HL: 7] │ <-- Academics (hidden if pure-skills)
│ Skills: [🎹 ABRSM Grade 8 Piano] [🗣️ Public Speaking] +2 │ <-- extracurricular_tags; 1 line + ellipsis/+N
│ │
│ ────────────────────────────────────────────────────────────────── │
│ 🎖️ Achievements and Experiences │
│ • HKU Medicine Dean's List (Year 1) │
│ • 5+ Years competitive piano performance and coaching │
│ │
│ ────────────────────────────────────────────────────────────────── │
│ $500 up/hr [📋] [🔗] [🔖] ( Request tutor )│
└────────────────────────────────────────────────────────────────────┘
Pure-skills card: omit the Core Expertise academic row entirely; Skills line may move up under the education rows; headline still from academic_headline / #411 (tutors should set a skills-forward headline).
Multi-curriculum stretch: continue using the existing expand / “View all grades” system from #411 — Skills line stays capped to one line even when academics expand.
B. Tutor Profile (Detail — /tutors/$tutorCode)
Conditional rendering: if no academic scores/grades → hide Core Academic Breakdown completely. If extracurricular_tags or visible portfolio images exist → render Extracurriculars, Skills & Certifications.
← Back
[Avatar] MM-T105 • Male [ 8 Blue Tick ] $500 up/hr [🔖] [🏳️] [🔗]
IBDP 45/45 | ABRSM Grade 8 Piano | Debate Captain ( 💬 Request tutor )
🎓 Undergraduate: HKU - Medicine (Year 1)
🏫 Secondary School: Diocesan Boys' School
──────────────────────────────────────────────────────────────────────────────────────────────────────────
📈 Core Academic Breakdown (Hides completely if purely a Music/Chess/STEM tutor)
IBDP: 45/45
│ Bio HL - Grade 7
│ Chem HL - Grade 7
│ Math AA HL - Grade 7
──────────────────────────────────────────────────────────────────────────────────────────────────────────
🏆 Extracurriculars, Skills & Certifications (Renders if extracurricular_tags or visible portfolio_images exist)
( ⓘ Self-Reported: Portfolio images and non-academic certificates are self-declared; please verify prior to lesson 1. )
[ 🎹 ABRSM Grade 8 Piano ] [ 🗣️ Varsity Public Speaking ] [ ♟️ FIDE Rating 1800 ]
Portfolio & Proof (Detail Page Only — Admin can hide flagged images; max 6):
┌─────────┐ ┌─────────┐ ┌─────────┐
│ [Image] │ │ [Image] │ │ [Image] │ <-- Horizontal scrollable / responsive gallery (R2)
│ Cert. │ │ Trophy │ │ Action │ Click to expand in lightbox (existing TrophyCabinet)
└─────────┘ └─────────┘ └─────────┘
──────────────────────────────────────────────────────────────────────────────────────────────────────────
🎖️ Achievement & Experience (Existing section unchanged)
• HKU Medicine Dean's List
• 5+ Years competitive piano performance and coaching
Reuse / evolve src/features/tutors/trophy-cabinet.tsx for the gallery (already lightbox). One gallery only — never duplicate.
Heading rules:
- Non-empty
extracurricular_tagsor any non-academicoffered_categories→🏆 Extracurriculars, Skills & Certifications(tags + gallery + disclaimer). - Academic-only with empty tags but visible
portfolio_images(legacy Add Optional "Trophy Cabinet" Photo Uploads to Tutor Form and Profiles #97) →🏆 Portfolio & Certificates(gallery + same self-reported disclaimer) so Trophy Cabinet does not disappear. - No tags and no visible portfolio → omit the section entirely.
C. Digital Shop / Notes & Gigs card (/notes/$slug, home rows)
Legacy items with null/empty broad_category fall back to Academics & Exams via DB default.
┌──────────────────────────────────────────┐
│ [ Cover Image / Watermarked Preview ] │
│ ⭐ 4.9 (12 reviews) │
├──────────────────────────────────────────┤
│ [Music & Arts] │ <-- Broad Category Pill (Fallback: Academics & Exams)
│ ABRSM Grade 8 Sight Reading Mastery │ <-- Title
│ │
│ Tags: [Piano] [Sight Reading] [Exam] │ <-- skills_tags / hybrid tags (1 line max)
│ │
│ By: MM-T105 • HKU Med │
│ │
│ HK$ 150 [ Buy Now ]│
└──────────────────────────────────────────┘
6. Acceptance criteria
Schema & data
-
offered_categories,extracurricular_tags,portfolio_hidden_urlsontutorswith backfill default['academics_exams']. -
broad_category+skills_tagsontutoring_casesanddigital_materialswith Academics default so legacy rows work. -
portfolio_imagesremainstext[], max 6; public read filtersportfolio_hidden_urls. - Publish RPC / public queries updated; TypeScript
integrations/supabase/types.tsregenerated or patched consistently. - No new
custom_headlinecolumn; Feature: Dual-Language Custom Headline + Core Academic Breakdown Restructure #411 owns bilingual headlines.
Discovery
- Default
/tutors= Academic Tutoring + Primary & Secondary (Expand Platform to Support Kindergarten & University Tutoring Verticals #190) — no pure-skills dilution. - Mode toggle works and is documented relative to K/P&S/Uni tabs.
- Keyword search hits extracurricular / skills tags and category labels.
- Homepage tutor rails respect Academic-First.
Forms
-
ApplicationForm.tsxconditional Academic / Skills / Portfolio sections; Skill-only and Multi-skilled paths work. - Parent case + [Compliance / B2B] Extend centre partnership (#251/#256–258): 3-step EA-safe triage, BR org fields, COMPLIANCE_HOLD, How-it-works Partners tab #412 partner case collect
broad_category(+skills_tagswhen needed) without changing Cap.57 gates. - Shop create/edit (Shop UI (Big Cover + Expandable Card), Topic Folder Bundles, Video Courses & General Courses #392 surfaces) can set category + skills tags without breaking
gig_category.
UI
- Card matches §5.A: headline + optional Core Expertise + 1-line Skills; no portfolio; no disclaimer.
- Detail matches §5.B: conditional Core Academic; Extracurriculars + disclaimer + gallery; Achievements unchanged.
- Shop card shows category pill + 1-line tags (§5.C).
- Admin 1-click hide/unhide portfolio image reflected on public detail immediately.
Legal
- Self-reported disclaimer only on detail (+ guide/tos), never on cards.
- ToS/guide childcare / non-employment language updated EN + zh-HK.
- No vacancy / Apply-for-job CTAs; [PARKED · Cap.57] Partner storefront SaaS + vacancy ad board — blocked pending solicitor/EAA; storefront-only slice under D1/D3 #413 remains parked.
Talks / schools / pro-bono
- Broad category code is
talks_camps_community(EN full: Talks, Camps & Community; short UI: Talks & Community; ZH: 講座、營隊與社區教育) — notcamps_experiences. - Seed autocomplete includes School Assembly Talk, Anti-Drug Education, Animal Welfare, Sustainability & ESG, Mental Health, Career & Life Planning, Community Service Learning.
- Profile rate + gig price accept
0; strict-0shows Pro-Bono / Community Impact badge (not$0 up/hr). - [Compliance / B2B] Extend centre partnership (#251/#256–258): 3-step EA-safe triage, BR org fields, COMPLIANCE_HOLD, How-it-works Partners tab #412 tracks org type dropdown + optional BR/EDB/Charity identifier; this issue does not block on that shipping first for tutor/gig speaker listings.
Checkout, sorting, legacy gallery, promotion
- Zod allows rate/price
0OR min paid rate; rejects accidental tiny paid amounts. -
$0gig CTA = Request Pro-Bono Session/Talk; FPS proof step bypassed on/orders/$orderId. - Rate sort Low→High places
rate = 0after paid rates unless Pro-Bono / talks filter is on. - Academic-only tutors with legacy
portfolio_imagesstill see Portfolio & Certificates (one gallery). - Homepage +
/guidepromote Music/Skills and Talks & Community; new guide page(s) shipped; Activities mode has intro copy; new guides in sitemap.
7. File / route map (where to change)
| Area | Primary files |
|---|---|
| Taxonomy constants | src/features/tutors/extracurriculars.ts (new), labels in src/features/i18n/locales/en.json + zh |
| Migrations | supabase/migrations/<ts>_phase15_extracurriculars.sql — columns, checks, backfill, comments |
| Publish / public read | Latest publish_tutor migration pattern; src/features/tutors/queries.ts; src/lib/tutor-card-mapping.ts |
| Join / apply | src/features/tutor-application/ApplicationForm.tsx, src/lib/tutor-application.schema.ts (if present) |
| Explore | src/routes/tutors.index.tsx, src/features/tutors/public-tutor-card.tsx, src/routes/index.tsx (home rails) |
| Detail | src/routes/tutors.$tutorCode.tsx, src/features/tutors/trophy-cabinet.tsx |
| Cases | Parent post flow under src/routes/_authenticated.tutor-requests*.tsx / cases functions; partner form paths from #412 |
| Shop | src/routes/notes.$slug.tsx, account notes/services editors, digital_materials RPCs (get_public_notes / get_public_gigs) |
| Admin | src/routes/_authenticated.admin.tutors.tsx (+ TutorEditor portfolio controls) |
| Legal / guide | src/routes/tos.tsx, src/features/legal/*, src/routes/guide.parents.tsx, src/routes/guide.tutors.tsx |
| Verticals coexistence | src/features/tutors/verticals.ts, verticals-form.ts — do not break #190 markers |
Also touch (promo + $0 checkout):
| src/routes/guide.talks-community.tsx (new) + i18n | Talks / community / school OLE guide |
| src/routes/guide.skills-music.tsx (new) or expand guide.tutors | Skills / Music / Activities guide |
| Homepage discover chips / row | Promo deep-links into /tutors mode+category |
| Order / checkout path for $0 gigs | Bypass FPS proof when price === 0 |
| Tutor + gig Zod schemas | Allow 0 OR min paid rate |
8. Out of scope
- Vacancy ads, centre storefront billing, “Apply Directly” jobs ([PARKED · Cap.57] Partner storefront SaaS + vacancy ad board — blocked pending solicitor/EAA; storefront-only slice under D1/D3 #413).
- Replacing Cap.57 triage or Fee Agreement / 1.5-lesson model ([Compliance / B2B] Extend centre partnership (#251/#256–258): 3-step EA-safe triage, BR org fields, COMPLIANCE_HOLD, How-it-works Partners tab #412 / Fee terms).
- Full redesign of shop chrome or course marketplace (Shop UI (Big Cover + Expandable Card), Topic Folder Bundles, Video Courses & General Courses #392 /
CENTRE_MARKET_ENABLED). - Forcing every legacy tutor to fill skills tags (defaults keep them academic-only).
- Pre-publish human approval queue for every portfolio image (admin hide is enough for Phase 1.5).
- Implementing Feature: Dual-Language Custom Headline + Core Academic Breakdown Restructure #411 headline bilingual fields inside this issue (depend / sequence only).
9. Implementation sequence (suggested)
- Land or rebase on Feature: Dual-Language Custom Headline + Core Academic Breakdown Restructure #411 (headline + Core Academic layout) so card/detail ASCII don’t thrash twice.
- Migration + types + query/mapper filters for hidden portfolio URLs.
ApplicationForm+ account edit conditional sections + R2 upload warning./tutorsmode filter merged with Expand Platform to Support Kindergarten & University Tutoring Verticals #190 tabs + Academic-First gating + search.- Detail Extracurriculars section + disclaimer + TrophyCabinet placement.
- Cases (parent + [Compliance / B2B] Extend centre partnership (#251/#256–258): 3-step EA-safe triage, BR org fields, COMPLIANCE_HOLD, How-it-works Partners tab #412 top category) + shop category/tags.
- Admin hide control + ToS/guide copy EN/zh-HK.
- QA matrix: Academic-only / Skill-only / Multi-skilled × K/P&S/Uni × card/detail/shop/admin.
10. Product decisions (RESOLVED — lock in PR description)
Do not re-ask Ryan / implementers. Lock these in the PR description as well:
- Hide the Expand Platform to Support Kindergarten & University Tutoring Verticals #190 tier tabs (
Kindergarten | Primary & Secondary | University) completely when Mode = Activities, Music & Skills (or short UI: Activities & Skills). When Mode = Academic Tutoring or All, tier tabs behave as live today (default Academic → P&S). - Hard-cap
extracurricular_tagsat max 12 stored tags per tutor (max 40 chars each); cards always render 1 line with+N. - Ship autocomplete seeds as a static TS constant in
src/features/tutors/extracurriculars.tsfor Phase 1.5 (no DB-backed tag thesaurus yet).
Mode filter mobile label (optional): full label Activities, Music & Skills is fine; if cramped on mobile, short form Activities & Skills — same filter logic.
Final Pre-Build Lock (2026-10-21) — CEO SAFE / Gemini
Do not re-open naming or fee-copy debates in the PR. Lock:
- Section header: use
Core Academic Breakdowneverywhere this issue touches layout (cards/detail/forms). Do not rename to “Core Expertise”. Headline bilingual fields remain owned by Feature: Dual-Language Custom Headline + Core Academic Breakdown Restructure #411; this ticket only adds Skills / Extracurriculars and conditional hide of Core Academic for pure-skills tutors. $0notes / materials: when price is0(Pro-Bono / free community notes), checkout CTA is Download Free (or equivalent) and bypasses FPS payment proof — same spirit as$0gig bypass already called out in §7 promo table.$0pro-bono case apply modal — fee line copy (locked):- EN:
This is a $0 community / pro-bono case. Platform admin fee: HK$0. - 繁中 (zh-HK):
此為 $0 社區/義教個案。平台行政費:HK$0。 - 简中 (zh-CN):
此为 $0 社区/义教个案。平台行政费:HK$0。
- EN:
- Contact strip: run
stripContactDetailsonextracurricular_tagsandskills_tags(and any free-text tag path that reaches public UI) before persist — coordinate with Public case board: contact-filter parent free text outside the uni columns (description, target_school) #410 parent free-text strip; strip never reject.
Activity
owlstonbusiness-svg commentedon Oct 21, 2026
Related brand colour: #416 — CV-builder / pro-bono talk pitch on tutor guide ties to portfolio + talks_camps_community; keep optional and secondary.
owlstonbusiness-svg commentedon Oct 22, 2026
CEO lock — 2026-10-22 · Cooler pills (Pro-Bono + taxonomy colour)
Ship system colour-coded pills (no user-uploaded card banners):
Keep discovery card backgrounds white. Colour lives in chips + Blue Tick only.
owlstonbusiness-svg commentedon Oct 27, 2026
Materials Marketplace Pack (Parked) will compose with this issue’s
broad_category+ skills tags for shop listings — reuse these codes; no parallelSTORE_VERTICALS.Pack: #487 · #488 · #489
owlstonbusiness-svg commentedon Oct 28, 2026
CEO placement lock (2026-10-28) — where Music / other areas must appear
Status check: Extracurriculars / Music / Skills expansion is NOT shipped yet. Live home only has:
That work lives on this issue (#415), still OPEN (Phase 1.5). Do not replace the K | P&S | Uni pills — merge above or beside them per issue body.
CEO photo (live home — gap)
Placement locks (CEO)
Search / home discoverability (required)
Add an Academic vs Activities / Music & Skills (or equivalent) control on the same home search surface as the screenshot — visible without opening deep filters. Default stays Academic → Primary & Secondary.
Tutor browse
Skill / Music / other non-exam tutors are findable when that mode (or All) is selected; pure-skills tutors must not flood the default academic grid (issue non-goal preserved).
Study Materials
Same taxonomy applies when parents switch to Study Materials — music/skills/notes verticals searchable under the materials rail (reuse shop/gig tags; don’t rebuild shop chrome — see Shop UI (Big Cover + Expandable Card), Topic Folder Bundles, Video Courses & General Courses #392 cross-link).
Search bar
Keyword / subject search must resolve Music & other extracurricular tags once taxonomy ships (not academic subjects only).
Guide / homepage promo
Keep issue goal: actively surface Skills / Music & Talks on homepage +
/guideso the category isn’t filter-only.Out of this amendment
Asset branch:
docs/ceo-415-search-placementowlstonbusiness-svg commentedon Oct 28, 2026
CEO priority (2026-10-28)
Bumped to urgent for next eng sprint.
Ship discovery first (home search Academic vs Activities / Music & Skills + materials taxonomy + keyword), per placement lock. Full portfolio gallery / hybrid tags can follow in the same issue without blocking the visible search option.
owlstonbusiness-svg commentedon Oct 28, 2026
Sprint note: #415 stays P1 urgent (Academic vs Activities/Music). Study Materials toggle is already live — do not rebuild. Full CORRECTED: #498 (comment)
owlstonbusiness-svg commentedon Oct 28, 2026
CEO integrate (2026-10-28) — Grok Expert FIX
Grok Expert bundled “Study Materials toggle missing” into the #415 gap. REJECT that part.
Tutors | Study Materialstoggle (Implement "Digital Study Materials" Marketplace MVP (Trust, Retention, and Search Mechanics) #131)Do not rebuild the materials tab. Ship discovery mode first.
owlstonbusiness-svg commentedon Oct 28, 2026
CEO re-check ADOPT (2026-10-28 ~14:27 HKT) — Grok Expert
Delta vs prior: Tutors | Study Materials toggle + K|P&S|Uni chips are visible (PARTIAL). Music/Activities mode still missing.
ADOPT:
Prior FIX stands: do not rebuild a materials tab from scratch — fix the live switch / empty state.
owlstonbusiness-svg commentedon Oct 28, 2026
CEO re-check ~14:33 — sprint order confirm
P1 after P0 (#502/#498/#499): wire or hide Study Materials toggle (still dead on live) + Academic vs Activities/Music above K|P&S|Uni. No flood of academic grid.
[-][Feature / Phase 1.5] Extracurriculars Expansion: Hybrid Tags, Portfolio Gallery & Unified Ecosystem[/-][+][Feature · V1] Extracurriculars — hybrid tags, portfolio, ecosystem[/+]owlstonbusiness-svg commentedon Oct 31, 2026
Align with #553 hybrid lock (CEO 2026-10-31)
#typeahead on global search — additive, not a fork of this taxonomy.