Repository navigation
[Ops · F4] Contact after fee · guarded self-serve carousel #255
Description
Issue F4 — Contact after the fee · Guarded Self-Serve Carousel (phased)
V2 on-platform chat implementation is #476; Phase 0 WA rules unchanged.
Payer-agnostic gate: Contact unlock remains
admin fee marked paid(fee_paid/ settled) regardless of who the payer is after #444 (tutor-pays lock #464). Do not rebuild the gate around parent-pays-first.
Status / timing lock (CEO + Jarvis · 2026-10-25 HKT)
Do NOT push guarded self-serve chat as the default now.
| Stage | When | What ships |
|---|---|---|
| V1 (now) — Phase 0 | Immediate urgents | Keep this issue’s original rule: human WhatsApp match; phones after fee_paid; no product inbox / no message table. Staff-only contact before fee. Bypass = staff flag (#254), not a WA scanner. |
| V1.5 gate — Phase A | After #459 ledger + #461A lesson log + desk packs #449/#451/#454 in daily use and fee collection is boringly reliable | Contact-filter hardening on any text surfaces that will feed chat; unlock-ladder plumbing against fee_paid + verified lessons; still no public carousel chat. |
| V2 self-serve — Phases B–C | After V1.5 gate + #441 Double-Lock is routine | Tutor carousel (“Request intro”) + case-scoped intro thread + contact scanner + /phones only after lessons (ladder below). |
| V2.5 — Phase D | After volume | Auto-penalties, leak honeypot / weekly CS metrics, soft density hooks from #450. |
Unpark trigger: CEO confirms fee leakage risk and lesson logging are stable for ≥2 weeks. Until then this issue stays the V1 contact gate + a parked design for later.
Labels: keep open; not urgent. Later phases are On Hold in spirit even if the issue itself stays the live F4 home.
Phase 0 / V1 — original F4 (SHIP / KEEP)
Summary
No inbox. After the admin fee is paid, each side can see the other’s phone on that case. Before that, only staff can.
Rule (V1 — LOCKED for now)
- Status before
fee_paid: neither side sees a phone, email, or WhatsApp. - Status
fee_paidoractive: the parent or centre contact and the tutor can open the phone on that case. - A waive or a refund hides it again.
- The page says the later lessons are between them. MatchMax does not host the messages.
- Copying the number out is not blocked. The fee was for the introduction.
- No message table is created in V1.
Penalty (V1)
- If the intro happened and the fee is unpaid, staff can invoice it, close the case, and ban new requests.
- The ban covers the parent, the centre contact, and the tutor on that case.
- No fine above the unpaid fee. No scanner on WhatsApp. (Bypass = staff flag — #254.)
Acceptance (V1)
- A case at
lesson_2_donebeforefee_paidshows no phone. - A case at
fee_paidshows the phone to both parties on that case. - No message table is created in V1.
Fee alignment
- Admin fee = tutor-pays 1.5 lessons (short-case ≤5 → 20% package) — #464 · #443.
- Double-Lock Lock 2: phones stay locked until Operator marks fee paid — #441.
Phases A–D — Guarded Self-Serve Carousel (PARKED · V1.5 → V2.5)
CEO direction (2026-10-25): browse tutors like a carousel, connect/chat on-platform, detect phone / WA / contact pushes, release raw contact only after they have had lessons, heavy penalty if they try to space / bypass the filter. This extends Phase 0; it does not replace human matching V1.
Why later (not early)
- Desk speed ([Ops] Failed-trial pivot + soft tutor inactive #449 / [Ops] Matching speed & reliability pack #451 / [Ops] Matching cockpit + website conversion polish #454) is the bottleneck, not missing DMs.
- Chat without a rock-solid fee + lesson gate leaks (IG / WeChat swap → skip admin fee).
- Cap.57 + dispute surface gets heavier once MatchMax hosts intro tooling — need counsel-ready copy + report/ban rails.
- Hours ledger ([Urgent · V1] Unified account + roles + child sub-profiles + hours ledger #459) + lesson log (#461A) are required for “after lessons” unlock and Trophy/rebate flywheel — build those first.
Does not replace desk V1
- Parallel lane only. High-risk / P1 / Cap.57-sensitive / unclear cases stay human waves ≤3.
- Carousel “Request intro” creates a normal
TuitionCase(or light case) that can still fall into desk macros. - Staff can always take over / shadow the intro thread ([Ops / Security] Double-Lock Risk Flags on Cases & Tutors (V1 Manual) #441).
1. Carousel UX (Phase B)
Surfaces
- Homepage “Match tutors” row (swipe cards).
- Search / filter results (card grid that can swipe on mobile).
- Later: #472 For you shortlist.
- Public case board: tutor apply-from-card (tutor-side density; parent still goes through case + fee ladder).
Card chrome (minimum)
- Subject(s) · curriculum · rate band · verified hours (when [Urgent · V1] Unified account + roles + child sub-profiles + hours ledger #459 live) · rating / lesson count (fee-gated reviews only).
- Capacity chip if tutor not accepting ([Ops] Failed-trial pivot + soft tutor inactive #449 soft Inactive).
- CTA: “Request intro” — not “Chat now” until a case exists.
Empty / edge
- No tutors match filters → clear empty state + “Open a full case / talk to desk” CTA.
- Tutor at capacity → card disabled or “Notify when free” (wait-list later via [Parked] Autonomous Matching Density Layer — Full Idea Capture (A–H) #450); cannot start intro thread.
- Filter false-positive on profile text → existing staff override path (Issue C2 — (community feature, stage 1) Contact filter #220).
┌─────────────────────────────────────────────┐
│ Match tutors See all → │
│ ┌────────┐ ┌────────┐ ┌────────┐ │
│ │ Photo │ │ Photo │ │ Photo │ → swipe │
│ │ DSE M2 │ │ IB Econ│ │ IGCSE │ │
│ │ $350/h │ │ $400/h │ │ $280/h │ │
│ │ 42h ✓ │ │ 18h ✓ │ │ 9h ✓ │ │
│ │[Request│ │[Request│ │[Notify │ │
│ │ intro] │ │ intro] │ │ when▲] │ │
│ └────────┘ └────────┘ └────────┘ │
└─────────────────────────────────────────────┘
2. Case-scoped intro thread (Phase C) — not a social inbox
| Lock | Rule |
|---|---|
| Scope | One thread per TuitionCase (parent/centre ↔ assigned tutor). No global DM inbox, no tutor↔tutor chat here (#332 stays parked). |
| Create | Only after “Request intro” (or desk assign) creates / binds a case. |
| Staff | Desk can shadow / read for Double-Lock (#441) and dispute; audited views. |
| Exit | After /phones unlock (ladder below), copy still says ongoing lessons are between the parties; MatchMax may archive the intro thread. |
| Cap.57 | MatchMax = intro tooling host only, not employer, not party to the lesson contract. Solicitor review before launch. Cross-link live TOS + #473 protective pack where promos appear; core matching language stays in TOS. |
Wireframe (thread)
┌─ Case #1042 · DSE Maths · Intro ─────────────┐
│ 🔒 Contacts unlock after fee + 1 verified L1 │
│ │
│ Parent: Hi, looking for 2×/week after school │
│ Tutor: I can do Tue/Thu 7pm — rate $350/h │
│ ⚠ System: Phone / WA / IG links are blocked │
│ until unlock. │
│ │
│ [ Type a message… ] [Send] │
└──────────────────────────────────────────────┘
3. Contact filter stack (Phase A → C)
Reuse #215 (closed) / #220 community contact filter. Extend for intro chat:
| Detect | Notes |
|---|---|
| HK phone patterns | +852 / spaced / dashed; bare 8-digit only when adjacent to phone/tel/mobile/call (same #220 rule) |
wa.me, whatsapp, word-spaced digits |
|
| Social | Instagram / IG / Telegram / Signal / Line / WeChat / Weixin / t.me / ig.me |
| standard shapes | |
| Handles | @name when clearly contact-seeking (tune false positives) |
| Images | OCR if/when scanner configured (#220); QR codes; until OCR live → warn + report path |
| Evasion | zero-width chars, spaced digits (9 1 2 3…), homoglyphs, mixed full-width digits |
Progressive enforcement (chat)
- Redact matching spans (message may still send with
•••/[contact hidden]). - Warn toast to sender (“Contacts unlock after fee + first verified lesson”).
- Strike (see matrix) on repeated / clear intent.
- Freeze thread (read-only) pending staff.
- Ban matching requests (both sides if both leaked).
Staff override for false positives = audited (#220). Appeal: in-thread “This wasn’t a contact” → staff queue.
4. Unlock ladder — LOCKED (CEO “after lessons”)
| Stage | What parties see | Filter |
|---|---|---|
Before fee_paid |
In-app intro thread only; no raw phone / email / WA | ON |
fee_paid (tutor-pays 1.5 / short 20% settled) |
Still no raw /phones by default |
Prefer ON until L1 verified |
fee_paid AND ≥1 VERIFIED_COMPLETED lesson on that case |
/phones released to both parties on that case |
May relax for that case; optional soft warn remains |
| Waive / refund | Hide phones again | — |
Waive path (staff): Operator may unlock /phones early with audited reason (e.g. centre Cap.57 overflow, proven offline intro, goodwill) — same spirit as fee waive. Default product path = ladder above.
Payment lock: Unlock never before the admin-fee path for that case type is clear (standard 1.5 or short-case 20%). Hybrid short-case still requires the applicable fee settled before counting toward unlock.
Contrast with V1 Phase 0: V1 releases phones at fee_paid with no chat. V2 ladder is stricter on raw contact (needs lesson) because MatchMax now hosts a channel that can leak earlier.
5. Bypass penalty matrix (Phase C → D)
Keep #255 spirit: no fine above the unpaid admin fee. Ban / freeze is the heavy stick.
| Strike | Trigger (examples) | Action |
|---|---|---|
| 1 | First clear filter hit / spaced-digit attempt | Warn both sides in-thread; log hit |
| 2 | Repeat within same case or across cases | 7-day new-request ban for offender; thread freeze optional |
| 3 | Persistent bypass / successful off-platform intro with fee unpaid | Permanent matching ban (parent and/or tutor as applicable) + invoice unpaid admin if intro happened; close case |
| Staff escalate | Fraud / multi-account / safety | #441 REVIEW → BLOCKED; CS-005 playbook |
- Ban covers new cases / new requests (and posts if community live) — aligns # Issue F3 — Bypass is a staff flag, not a scanner #254.
- Both sides can be banned if both pushed contacts.
- No WhatsApp private-message scanner (still # Issue F3 — Bypass is a staff flag, not a scanner #254) — scanner applies to MatchMax-hosted intro thread (+ existing public text filters).
6. Leak honeypot / metrics (Phase D)
- Log every filter hit:
case_id, actor role, rule id, redaction vs block, strike level (no raw PII in analytics exports). - Weekly CS digest: near-misses, top evasion patterns, false-positive rate.
- Optional honeypot: invisible tokens / canary strings that only appear if user copy-pastes system UI — flag as high-intent scrape (staff review, not auto-ban alone).
7. Cap.57 / legal
- Intro tooling host only; tutors remain independent; MatchMax not employer / not party to lesson contract.
- Solicitor review before V2 launch (in-app messaging + automated penalties).
- TOS cross-link; promotional “保留最終決定權” pack is #473 (N/A to matching chat itself).
- PDPO: chat content used for safety / fee enforcement / dispute only — Privacy Policy update if needed.
8. Phasing checklist
Phase A — V1.5 gate (filter + ladder plumbing)
- Shared contact-filter module callable from future chat (reuse Issue C2 — (community feature, stage 1) Contact filter #220 rules + evasion list)
-
fee_paid+VERIFIED_COMPLETEDlesson counters readable per case ([Urgent · V1] Unified account + roles + child sub-profiles + hours ledger #459 / #461A) - Feature flag
intro_chat_enabled=falseby default - Staff waive-unlock audited action
Phase B — Carousel “Request intro”
- Homepage + search carousel cards
- CTA creates/binds case; no thread until case exists
- Capacity / empty / notify-when-free edges
- P1 / high-risk cases still route to desk wave ≤3
Phase C — Intro chat + scanner + post-lesson phones
- Case-scoped thread table (only when flag on)
- Filter on send (text); image path per Issue C2 — (community feature, stage 1) Contact filter #220
- Unlock ladder UI +
/phonesgate - Strike 1–2 automated; Strike 3 staff-confirm or careful auto
- Staff shadow read for [Ops / Security] Double-Lock Risk Flags on Cases & Tutors (V1 Manual) #441
Phase D — Auto-penalties + metrics
- Strike 3 automation where safe
- Weekly CS leak report
- Soft hooks to [Parked] Autonomous Matching Density Layer — Full Idea Capture (A–H) #450 density (wait-list from carousel, etc.)
9. Acceptance criteria (V2 — when unparked)
- Parent can browse carousel and tap Request intro without seeing tutor phone.
- Intro thread exists only for that case; no global inbox.
- Message containing
9123 4567/wa.me/ spaced digits is redacted or blocked; sender warned. -
/phoneshidden untilfee_paidand ≥1 verified completed lesson (unless staff waive). - Strike 2 imposes 7-day request ban; Strike 3 bans + invoices unpaid admin when intro happened.
- No fine amount above unpaid admin fee.
- Desk can still run human WA matching in parallel; V1 Phase 0 behaviour unchanged when
intro_chat_enabled=false. - Cap.57 / independence copy visible near chat; solicitor sign-off recorded before prod flag on.
- Filter false-positive has staff override + appeal path.
- Tutor at capacity cannot open a new intro thread from carousel.
10. Out of scope
- Global social inbox / tutor squads chat ([PARKED] Tutor connect / squads — do not build (chat conflict) #332).
- Scanning private WhatsApp (# Issue F3 — Bypass is a staff flag, not a scanner #254).
- Replacing human matching for V1 urgents.
- Parent-pays-first unlock (fee track stays tutor-pays — [Track] Fee Model — Tutor-Pays 1.5 / Short-Case 20% / ToS Align #464).
- Official past-paper libraries / Vehicles chat ([Parked · Epic] Creator-Monetized Study Vehicles — Gated Vaults · AI Mock Builder · Hybrid Tuition Bridge #474 separate).
Cross-links
| Issue | Role |
|---|---|
| #254 | Bypass = staff flag (V1); no WA scanner |
| #215 / #220 | Contact filter reuse |
| #441 | Double-Lock; staff shadow / BLOCKED |
| #450 §G | Website later — this issue is home for guarded self-serve |
| #459 / #461 | Ledger + lesson log (unlock prerequisite) |
| #449 / #451 / #454 | Desk packs before unpark |
| #464 / #443 | Tutor-pays 1.5 / short 20% |
| #472 | For you carousel surface later |
| #473 | Protective clauses (promos); TOS for matching |
| #332 | No squad / global chat |
Activity
owlstonbusiness-svg commentedon Oct 24, 2026
Cross-link: Double-Lock Lock 2 (phones stay locked until Operator fee paid) lives in #441 + CS-005.
owlstonbusiness-svg commentedon Oct 24, 2026
Broker Overflow #442: B2B cases never store end-parent phone; Lesson-2 tutor confirm gates the 1.5-lesson invoice / waive before fee collection.
owlstonbusiness-svg commentedon Oct 24, 2026
Cross-link: #442 — Referral lane still uses phones-after-fee; Overflow never stores end-parent.
owlstonbusiness-svg commentedon Oct 24, 2026
Cross-link: #443 Short-Case (≤5 → 20%) still respects Paid/Settled before contact-release promises; short invoice after L1 (or booking if 1 session).
owlstonbusiness-svg commentedon Oct 25, 2026
Packed under Fee Model Track #464 (2026-10-25).
CEO locks: tutor pays 1.5-lesson admin · short ≤5 = 20% package · pro-bono 0% · parents/centres do not pay MatchMax matching fees.
Legacy F1 parent-pays text in #252 closed as superseded. Calendar calculator UI stays parked in #461.
[-]# Issue F4 — Contact after the fee, not a chat[/-][+]Issue F4 — Contact after the fee · Guarded Self-Serve Carousel (phased)[/+]owlstonbusiness-svg commentedon Oct 25, 2026
Expanded 2026-10-25 (CEO + Jarvis) — no new epic.
fee_paid; bypass = staff flag (# Issue F3 — Bypass is a staff flag, not a scanner #254); no WA scanner.fee_paidAND ≥1 VERIFIED_COMPLETED lesson · strike matrix (warn → 7d ban → permanent + invoice unpaid admin) · leak metrics.owlstonbusiness-svg commentedon Oct 25, 2026
V1 re-audit note (2026-10-25) — not marking whole issue
urgentfee_paid· no product inbox — keep as baseline (already the gate).owlstonbusiness-svg commentedon Oct 25, 2026
V2 chat home locked → #476 (2026-10-26)
CEO design for AI-Supervised On-Platform Chat (intake bot + 3-way concierge + dual-layer anti-leak + Admin Sentinel) lives in #476.
fee_paidcontact gate + Phase 0 V1 (human WA · phones after fee · no inbox).owlstonbusiness-svg commentedon Oct 25, 2026
Follow-up: #476 unlock language now matches this issue’s ladder (
fee_paid∧ ≥1 verified lesson; filter stays on at fee alone). Strike matrix +contact-filter.tsreuse locked in #476 §4.5–4.6 / §10.owlstonbusiness-svg commentedon Oct 27, 2026
CEO 2026-10-27: marked urgent — V1 must-build for the closed loop (lead → fast match → fee → hours). Not a scope expand beyond this issue’s existing V1 slice; parked V2/community/marketplace work stays On Hold.
[-]Issue F4 — Contact after the fee · Guarded Self-Serve Carousel (phased)[/-][+][Ops · F4] Contact after fee · guarded self-serve carousel[/+]keyframesfound commentedon Nov 1, 2026
Closing — the V1 Phase 0 rule this issue locks is shipped and verified; every later phase is explicitly gated on a CEO unpark decision that lives in #476, so there is no agent-buildable scope left here.
Phase 0 (V1) verified on main @ 1a2a400:
canRevealParentContactinsrc/features/trust/trust.ts:155:NOT_MATCHED→CASE_CLOSED→RISK_HOLD(open blocking risk flags [#529] trust_blacklist + progressive reveal #535/[Trust · #511 · Urgent] WA+site AI flags, pre-match gates, drop matrix #529) → reveal only whenintroFeeSettled(or verified-hours path) — i.e. no phone/email/WA beforefee_paid, revealed after, hidden again on waive/refund.parentContactView()masks name/phone unless the gate clears — tutor-facing APIs return the masked shape.case_messages/inbox schema anywhere insupabase/migrations).Later phases (A–D) stay parked by design — the body's own timing lock ("Do NOT push guarded self-serve chat as the default now", unpark = CEO confirms fee leakage + lesson logging stable ≥2 weeks) supersedes the
urgentlabel for those phases; V2 chat implementation tracks #476. Closing per the urgent-queue sweep; reopen if the CEO unpark trigger fires.