Skip to content

[Feature · V1] Extracurriculars — hybrid tags, portfolio, ecosystem #415

Open

Description

@owlstonbusiness-svg

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


Non-goals


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_exams via existing subjects / 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/tutors TutorEditor already edits the URL array — add 1-click Hide / Unhide that toggles membership in portfolio_hidden_urls without deleting the R2 object (polish on top of edit-URLs).
  • Publish RPC (publish_tutor / card JSON) must continue to pass portfolio_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 if portfolio_hidden_urls ships.

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/tutors TutorEditor: per-image Hide control → add URL to portfolio_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_categories non-empty and does not include academics_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, and
  • offered_categories label 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_exams for 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_exams is 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)

3.C Partner / centre case form (#412)


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 Impact instead 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 $0 community / 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.

Discovery (so schools can find speakers)

  • Default /tutors stays 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)

  • $0 Pro-Bono checkout & validation

    • Update Zod schemas on tutor profile rate and gig price to allow 0 (Pro-Bono) OR the existing minimum paid rate (reject accidental $1–$9 typos; do not allow tiny paid junk rates).
    • For digital_materials gigs with price === 0, change CTA from Buy Now to Request Pro-Bono Session (or Request Pro-Bono Talk for talk gigs) and bypass the manual FPS payment-proof upload on /orders/$orderId — go straight to confirmed / WhatsApp coordination.
    • When sorting /tutors by rate ascending (Low → High), sort rate = 0 after paid rates (ORDER BY (rate = 0) ASC, rate ASC) unless the user is filtering specifically for Pro-Bono / talks_camps_community / community talks.
  • 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_tags is non-empty OR any non-academic offered_categories is selected → heading 🏆 Extracurriculars, Skills & Certifications (tags + gallery + self-reported disclaimer).
    • If Academic-only (extracurricular_tags empty and only academics_exams) AND visible portfolio_images exist → still render the gallery under fallback heading 🏆 Portfolio & Certificates with 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.

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 /tutors with mode + category preselected). Optional: a short banner line e.g. “Beyond exams — skills coaching, guest talks & community workshops.”
  • /guide hub — 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.
  • /tutors empty / 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.xml when 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:

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_tags or any non-academic offered_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_urls on tutors with backfill default ['academics_exams'].
  • broad_category + skills_tags on tutoring_cases and digital_materials with Academics default so legacy rows work.
  • portfolio_images remains text[], max 6; public read filters portfolio_hidden_urls.
  • Publish RPC / public queries updated; TypeScript integrations/supabase/types.ts regenerated or patched consistently.
  • No new custom_headline column; Feature: Dual-Language Custom Headline + Core Academic Breakdown Restructure #411 owns bilingual headlines.

Discovery

Forms

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


Talks / schools / pro-bono

Checkout, sorting, legacy gallery, promotion

  • Zod allows rate/price 0 OR min paid rate; rejects accidental tiny paid amounts.
  • $0 gig CTA = Request Pro-Bono Session/Talk; FPS proof step bypassed on /orders/$orderId.
  • Rate sort Low→High places rate = 0 after paid rates unless Pro-Bono / talks filter is on.
  • Academic-only tutors with legacy portfolio_images still see Portfolio & Certificates (one gallery).
  • Homepage + /guide promote 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


9. Implementation sequence (suggested)

  1. 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.
  2. Migration + types + query/mapper filters for hidden portfolio URLs.
  3. ApplicationForm + account edit conditional sections + R2 upload warning.
  4. /tutors mode filter merged with Expand Platform to Support Kindergarten & University Tutoring Verticals #190 tabs + Academic-First gating + search.
  5. Detail Extracurriculars section + disclaimer + TrophyCabinet placement.
  6. 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.
  7. Admin hide control + ToS/guide copy EN/zh-HK.
  8. 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:

  1. 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).
  2. Hard-cap extracurricular_tags at max 12 stored tags per tutor (max 40 chars each); cards always render 1 line with +N.
  3. Ship autocomplete seeds as a static TS constant in src/features/tutors/extracurriculars.ts for 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:

  1. Section header: use Core Academic Breakdown everywhere 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.
  2. $0 notes / materials: when price is 0 (Pro-Bono / free community notes), checkout CTA is Download Free (or equivalent) and bypasses FPS payment proof — same spirit as $0 gig bypass already called out in §7 promo table.
  3. $0 pro-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。
  4. Contact strip: run stripContactDetails on extracurricular_tags and skills_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

  1. owlstonbusiness-svg commented on Oct 21, 2026

    @owlstonbusiness-svg
    CollaboratorAuthor

    Related brand colour: #416 — CV-builder / pro-bono talk pitch on tutor guide ties to portfolio + talks_camps_community; keep optional and secondary.

  2. owlstonbusiness-svg commented on Oct 22, 2026

    @owlstonbusiness-svg
    CollaboratorAuthor

    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.

  3. owlstonbusiness-svg commented on Oct 27, 2026

    @owlstonbusiness-svg
    CollaboratorAuthor

    Materials Marketplace Pack (Parked) will compose with this issue’s broad_category + skills tags for shop listings — reuse these codes; no parallel STORE_VERTICALS.

    Pack: #487 · #488 · #489

  4. owlstonbusiness-svg commented on Oct 28, 2026

    @owlstonbusiness-svg
    CollaboratorAuthor

    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)

    Live home search — academic tiers only; no Music/Skills option yet

    Placement locks (CEO)

    1. 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.

    2. 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).

    3. 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).

    4. Search bar
      Keyword / subject search must resolve Music & other extracurricular tags once taxonomy ships (not academic subjects only).

    5. Guide / homepage promo
      Keep issue goal: actively surface Skills / Music & Talks on homepage + /guide so the category isn’t filter-only.

    Out of this amendment

    Asset branch: docs/ceo-415-search-placement

  5. owlstonbusiness-svg commented on Oct 28, 2026

    @owlstonbusiness-svg
    CollaboratorAuthor

    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.

  6. owlstonbusiness-svg commented on Oct 28, 2026

    @owlstonbusiness-svg
    CollaboratorAuthor

    Sprint note: #415 stays P1 urgent (Academic vs Activities/Music). Study Materials toggle is already live — do not rebuild. Full CORRECTED: #498 (comment)

  7. owlstonbusiness-svg commented on Oct 28, 2026

    @owlstonbusiness-svg
    CollaboratorAuthor

    CEO integrate (2026-10-28) — Grok Expert FIX

    Grok Expert bundled “Study Materials toggle missing” into the #415 gap. REJECT that part.

    Do not rebuild the materials tab. Ship discovery mode first.

  8. owlstonbusiness-svg commented on Oct 28, 2026

    @owlstonbusiness-svg
    CollaboratorAuthor

    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:

    1. Materials control: toggle must actually switch to a materials surface, or hide until ready — do not leave a dead control that still shows the tutor list.
    2. Music/Skills (unchanged P1 urgent): Academic vs Activities mode above the existing K|P&S|Uni chips; don’t flood the academic grid.

    Prior FIX stands: do not rebuild a materials tab from scratch — fix the live switch / empty state.

  9. owlstonbusiness-svg commented on Oct 28, 2026

    @owlstonbusiness-svg
    CollaboratorAuthor

    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.

  10. changed the title [-][Feature / Phase 1.5] Extracurriculars Expansion: Hybrid Tags, Portfolio Gallery & Unified Ecosystem[/-] [+][Feature · V1] Extracurriculars — hybrid tags, portfolio, ecosystem[/+] on Oct 29, 2026
  11. owlstonbusiness-svg commented on Oct 31, 2026

    @owlstonbusiness-svg
    CollaboratorAuthor

    Align with #553 hybrid lock (CEO 2026-10-31)

    • Extracurriculars broad_category pills / admin taxonomy = structured layer (keep).
    • Free-form user tags (notes/profiles/posts) = long-tail discovery via # typeahead on global search — additive, not a fork of this taxonomy.
    • No conflict; eng should reuse the same normalize rules (lowercase, hyphenate) where tags overlap extracurricular labels.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    ClaudeRoute to Claude Code: complex or UI-heavy workenhancementNew feature or requesturgentGood for newcomers

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions