Therapy Pack MVP — front-page flow + Editor (7.0.0)¶
1. Summary¶
Replace the current front page — a six-tool "info dump" (WelcomeView.tsx) that presents the technology and requires an SLP to already know which tool maps to their task — with an outcome-first flow that guides a clinician from a target sound to a therapy-ready, editable, printable pack. This is the app inversion: the pack (a persistent, editable object) becomes the primary surface; the six tools are demoted to an "Advanced" section and become populators that push selections into the pack.
7.0.0 is the first end-to-end slice of the Therapy Packs wedge (PHON-158): type/pick a target → seeded pack → curate in an Editor → export a printable you keep. Billing is designed-but-deferred; the flow delivers value before requiring an account (there are no accounts in 7.0.0).
This is a major release (new primary surface, navigation re-orientation) → version 7.0.0.
2. Why (grounding)¶
- Competitive landing research (
docs/commercial/2026-07-19-landing-flow-competitive-research.md): SLP-audience pages that convert lead with a prep-time / progress outcome, not features. No SLP competitor offers a guided "what are you targeting?" flow — it is a category differentiator. Winning first-run patterns terminate in seeded, editable work, never a blank tool. A single input box that doubles as a router (Canva pattern) is the lowest-friction first action. - Demand data (
~/Repos/speech-community-analysis, 92,842-unit Reddit SLP corpus): materials/resources is the centerpiece cluster; phoneme demand is broad-but-bounded — /r/ dominates (3,489 mentions), /s/ (1,479), minimal pairs (510), stopping (486), vocalic /r/ (460); the Word Lists curation already mapped cluster reduction / cycles / apraxia / complexity. Pre-built packs are seeded from this, so breadth ≠ presumption. (Dysphagia is the #1 cluster overall but is out of PhonoLex's phonology scope.) - Pricing / positioning (
docs/commercial/market-differentiation.md, PHON-178): the psychology to beat is TPT's buy-once-own-forever; the counter is an editable export the clinician owns — which is why the export renderer is a first-class deliverable, not a nice-to-have.
3. Goals / Non-goals¶
Goals (7.0.0): 1. New outcome-first front page with a target box + pre-built pack gallery + trust line; tools demoted to Advanced. 2. A target resolver (curated, shipped JSON — no runtime embeddings/LLM) with deterministic parsing and a seeded "did you mean". 3. A short guided refine step that seeds a pack from existing APIs. 4. The Editor: a sectioned workspace where curation happens, backed by an IndexedDB "My Packs" library (many saved packs, revisitable) with start-over/new-pack. 5. Light tools→Editor integration: one "Add to Editor" per tool near its export; tools keep their own UX + export. 6. Export: picture cards + worksheet/list + CSV, images where available, word-only fallback. 7. A starter set of pre-built packs from real demand.
Non-goals (explicitly deferred): - Accounts, server-side pack persistence, sharing links. - Billing / paywall enforcement (design the free/Pro line only; §10). - The tight in-tool loop (per-item add + multi-select + pack-chip-everywhere) — data model stays forward-compatible with it. - Target inference from pack contents → suggested additions (data model stays forward-compatible with it). - Audio / Speech Analysis stays entirely outside the pack MVP.
4. Architecture¶
Front page (new WelcomeView replacement)
├─ Target box ──resolver(curated JSON)──▶ resolved target ──▶ Guided refine (position/level)
│ │
├─ Popular-packs gallery ──(pre-built target spec)────────────────────┤
│ ▼
└─ "Build your own with the tools" ─▶ Advanced tools Seed via existing APIs
│ (words/search, contrastive, sentences)
│ "Add to Editor" │
▼ ▼
┌─────────────────────────────────────┐
│ EDITOR (primary surface) │
│ Words · Contrasts · Sentences · │
│ Notes — curate (remove/replace/…) │
│ local-draft autosave │
└───────────────┬─────────────────────┘
▼
Export: cards | worksheet | CSV
All orchestration is client-side over existing endpoints (plan §4.6). No new backend service, no new D1 tables required for 7.0.0 (packs live in localStorage).
5. Component designs¶
5.1 Front page (replaces WelcomeView.tsx)¶
- Hero: outcome headline (candidate: "Therapy-ready materials for any speech sound — in minutes.") + subline stating the deliverable.
- Target box (primary action): placeholder
Enter a target — /r/, s-blends, k vs t, final /s/…; empty/focused state renders the popular-packs gallery (collapses "search bar" and "gallery" into one element). - Escape hatch: "Or build your own custom pack using the tools →" → Advanced tools.
- Trust line: evidence-based methodology · privacy · "decision support, not a diagnosis."
- Tools → Advanced: the sidebar's Build/Analyze/Explore tools move under an "Advanced" grouping; the Editor becomes the primary destination.
App_new.tsxnull-state renders the front page; a persistent pack indicator (header chip on desktop, bottom drawer on mobile) appears once a pack exists. - Returning users → My Packs: the front page surfaces the saved My Packs library (also reachable from the pack indicator) as the fast path back into prior work — this serves the "returner" half of balance-both, alongside the newcomer-facing hero.
5.2 Target resolver¶
- Controlled vocabulary shipped as JSON (client-side; no embeddings, no LLM, no round-trip):
- phonemes + aliases (reuse
normalizePhoneme/to_ipa/to_ascii; digraphsth→θ/ð,sh→ʃ,ch→tʃ); - positions (initial/medial/final + everyday synonyms);
- contrast syntax (
vs///-between two sounds → contrast mode); - clusters/blends; phonological-process presets (fronting/stopping/gliding/…) → curated target sets;
- the named pre-built packs.
- Deterministic parse → resolved target chip; Build only enabled on a resolved chip.
- "Did you mean": a hand-seeded near-miss map (e.g.
start→initial), always badged as a suggestion, never silently rewriting input. Clinical process names are excluded from fuzzy guessing (everyday-meaning collision) and stay curated.
5.3 Guided refine + seeding¶
- After a bare-phoneme resolve, a 1-step refine (position, approximate level/difficulty) — the richer target modes (sound+position, contrast, process preset) from plan §4.2.
- Seed via existing endpoints:
- target words →
/api/words/search(compileWordFilter), difficulty-ordered by norms (AoA / frequency percentiles), 15–25 candidates (plan §4.3); - contrast pairs →
/api/contrastive(minimal/maximal/multiple); - sentences →
/api/sentences. - Result assembled into a pack draft and opened in the Editor.
5.4 Pre-built packs (sourcing)¶
- Recommended model: a pack is a saved target spec (params) + optional curated overrides (hand-picked words/sentences). Opening it runs the same seeding path as the guided flow, so content stays consistent and fresh; overrides let us guarantee quality starters. (Alternative: fully static JSON — rejected as it duplicates content and drifts from the live lexicon.)
- Starter set (from demand data): Initial /r/, Vocalic /r/, S-blends, k vs t (fronting), Final /s/ (stopping), Cycles, Apraxia, Minimal pairs. Final list = advisor picks 3–6 (market-diff §7 open item).
5.5 Editor (primary surface)¶
- Sectioned workspace (single scroll): header (editable title, target chips, level, counts, autosave state, My Packs, New / Start over, Duplicate, Preview, Export) → Target words (image cards,
×remove /⟳replace) → Contrast pairs → Sentences (target-highlighted) → Clinician notes (prints on the pack). ⟳ replacesurfaces Qwensim word-suggestions (word→word similarity via/api/associations/*) — reuses existing infra; its most natural home.- Each section has "+ Add from [tool]" which opens the matching Advanced tool.
- Curate-here principle: adding is generous; pruning/replacing/reordering happens in the Editor.
5.6 Data model + persistence¶
- Local-first, IndexedDB-backed pack library. No accounts, no server persistence in 7.0.0. IndexedDB (via a light wrapper —
idb-keyvalorDexie, picked at planning) rather than localStorage, because the clinician builds and revisits a growing library of many packs — localStorage's ~5 MB string cap doesn't fit a pack library. - "My Packs" library: many saved packs, each autosaved on edit; list view to open / rename / duplicate / delete. A pack is the unit of work you return to across sessions.
- Start over / New pack: an explicit action to clear the current pack (with confirm) or begin a fresh one without losing saved packs.
- Schema per plan §4.5 (
TherapyPackRequest/TherapyPack), extended with:schemaVersion(migration guard); per-item provenance (sourceTool, why-included) — required so the tight loop and target-inference are possible later without rework; the resolved target(s) stored structurally (not just a title);createdAt/updatedAt. - Keep all content non-patient-specific (privacy posture) — copy reminds users packs live in their browser and must not carry patient identifiers.
5.7 Tools ↔ Editor (Light integration)¶
- Each of the six tools keeps its UX and its own export (the Editor is an additional destination, not a replacement).
- Each gains one "Add to Editor" control near its export that pushes the tool's current results into the active pack; a uniform contract across tools (works for word grids, contrast pairs, sentences, a single Lookup word, a Text-Analysis extraction — "add these results" maps everywhere, unlike per-card buttons).
- Confirmation toast with Undo. Pack indicator updates.
5.8 Export¶
Grounded in docs/commercial/2026-07-19-slp-worksheet-conventions-research.md, with one deliberate deviation recorded here: that research found adult materials favor real photos, but PhonoLex uses AAC symbols (Mulberry + OpenMoji) for all ages and treats them as preferable to real photos. AAC symbol sets are designed for iconicity — including abstract concepts that photographs represent poorly — which is exactly the vocabulary range therapy targets span. So imagery is unified across age bands; the pediatric/adult difference lives in format options, not image style. (A real-photo mode stays a possible future toggle if adult confrontation-naming demand appears — not in 7.0.0.)
Shared imagery — Mulberry/OpenMoji from R2 where available (~22K words post-PHON-185); word-only fallback (existing imageless policy). These are CC BY-SA — the per-image attribution key MUST flow into the exported PDF footer (ship policy in packages/data/src/phonolex_data/runtime/images.py). Never emulate Boardmaker/proprietary symbol art.
Formats (each a client-side–rendered PDF, plus CSV):
- Picture cards — cut-out grid; label above image (toggle above / below / none — the none option covers adult confrontation-naming); grid-ladder presets 2×2 (4), 2×3 (6), 3×4 (12), 4×5 (20), default 12 / 20; bordered cells = cut lines + "print on cardstock / laminate" note; contrast mode = adjacent-cell pairs supporting the 6 initial + 6 final = 24-card convention.
- Worksheet / list — header fields (Name · Date · Goal/Target · Clinician · Cue level — the difference between "printable" and "chartable"); default 10-item data block (n/10 = %) with per-item trial boxes + __/__ = __% + cue-level column (I/min/mod/max), or a whole-page "/N" score box; three stacked sections words → sentences (bold/underlined target) → optional passage; two-column contrast-pair block; caregiver home-practice footer.
- CSV — machine-readable superset: word, IPA/phonemes, position, syllable_count, CV-shape, contrast-partner, carrier sentence, has_image.
Two convenience presets (they only preset the options above — imagery is identical AAC symbols): - "Kids" — labeled cards, position-organized (initial/medial/final), carrier-phrase sentences, trial-tally data, playful copy. - "Adult / medical" — optional unlabeled cards, word lists ordered by syllable complexity (mono → bi → multi) then word → phrase → sentence, functional sentences + optional script/stress + optional CVCV / nonword drill row (phonology layer generates these), accuracy-gated (80%) + cue-level data, functional copy.
PDF generation — decided: client-side PDF renderer (@react-pdf/renderer or pdfmake; final pick at planning) for deterministic, image-embedding output.
6. Analytics (PHON-168 taxonomy, via lib/analytics.ts track())¶
landing_view, target_resolved (target, method: box|gallery|tool), pack_seeded, add_to_editor (tool), pack_edited, export (format), plus the existing funnel events. No patient-identifying content.
7. IA / routing / version¶
- New front page replaces the
activeTool === nullnull-state; Editor becomes a primary, linkable surface (introduce a route so a pack is bookmarkable/reloadable). Tools grouped under "Advanced" inAppSidebar.tsx. - Version bump to 7.0.0 —
package.json(single source of truth viaconfig/product.ts), AppHeader chip, About drawer,index.html/structured data, docs (per version-bump checklist).
8. Monetization boundary (design only; deferred)¶
- Free tier with real value (plan §5.1; "one or two complete packs" framing). Because there are no accounts in 7.0.0, nothing is enforced — 7.0.0 is effectively all-free; we only design where the line will be:
- Likely-free: build/edit/export, unlimited local drafts, export carries a subtle "Made with PhonoLex" footer (doubles as distribution).
- Likely-Pro (later): remove footer, premium/age-band formats, cloud save + share, higher volume.
- Price test already set: $149/yr, $99 founding (market-diff §5). Do not build billing until willingness-to-pay is tested after observed use (plan §4.6, Week 5).
9. Affected files (indicative)¶
- Replace
packages/web/frontend/src/components/WelcomeView.tsx; editApp_new.tsx(routing/null-state/pack indicator),AppSidebar.tsx(Advanced grouping). - New: front page, target-resolver module + vocab JSON, guided refine, Editor + pack store (localStorage), pack indicator/drawer, export renderer, pre-built pack specs, "Add to Editor" in each tool.
- Reuse:
lib/wordFilter.ts,/api/words/search,/api/contrastive,/api/sentences,/api/associations/*,lib/normalize.ts,config/product.ts,lib/analytics.ts.
10. Decisions (resolved 2026-07-19)¶
- PDF approach — ✓ client-side PDF renderer (
@react-pdf/renderer/pdfmake; final pick at planning). (§5.8) - Pre-built pack sourcing — ✓ target-spec + curated overrides, materialized via live APIs. (§5.4)
- Free/Pro line — ✓ designed boundary in §8 confirmed (free = build/edit/export + "Made with PhonoLex" footer; Pro-later = remove footer, premium formats, cloud save/share). Not built in 7.0.0.
- Imagery — ✓ AAC symbols (Mulberry/OpenMoji) for all ages, preferable to real photos (iconicity for abstract concepts); real-photo mode dropped from 7.0.0 scope. (§5.8)
- Persistence — ✓ IndexedDB-backed multi-pack "My Packs" library + start-over. (§5.6)
Minor, at planning: IndexedDB wrapper (idb-keyval vs Dexie); final PDF lib pick.
11. Decomposition → implementation phases (feeds writing-plans)¶
Ordered by dependency (the Editor + data model is the spine): 1. Pack data model + IndexedDB "My Packs" store + Editor shell (sectioned workspace, add/remove/replace/reorder, autosave, library open/rename/duplicate/delete, start-over). 2. Export renderer — two age-band presets (kids picture cards + adult word/reading) × formats (cards/worksheet/CSV) + PDF. The owned artifact. 3. Front page + resolver + guided refine + seeding (the new entry). 4. Pre-built packs (starter set). 5. Tools → "Add to Editor" (light integration across six tools) + pack indicator/drawer. 6. IA/nav (Advanced grouping) + 7.0.0 version bump + analytics wiring.
12. Research inputs (complete)¶
Both spikes are done and their findings are folded into this spec:
- Landing-flow competitive research → docs/commercial/2026-07-19-landing-flow-competitive-research.md (§2, §5.1).
- SLP worksheet-conventions research → docs/commercial/2026-07-19-slp-worksheet-conventions-research.md (§5.8 — decided the two age-band presets).
13. Testing¶
- Resolver unit tests (aliases, contrast syntax, did-you-mean gating, process-name exclusion).
- Pack store tests (schema versioning/migration, autosave, provenance).
- Seeding integration (guided target → correct API bodies via
compileWordFilter). - Export snapshot tests (card + worksheet + CSV; image vs word-only fallback).
- "Add to Editor" contract test per tool.
- Frontend type-check + lint + build; workers unchanged (no API changes expected).
14. Risks¶
- Scope: this is the full MVP flow; phases §11 must ship incrementally behind the new front page.
- Export quality is load-bearing (monetization wedge) — the PDF-approach decision matters.
- Image coverage gaps make some cards word-only; acceptable per imageless policy but set expectations in copy.
- Seeding quality: guided defaults must produce a genuinely good starter pack or the "value before account" promise fails; lean on norm-ordered difficulty + curated overrides for pre-built packs.
15. Amendment 2026-07-20 — Editor cards + word-linking + quick-add (post-Phase-3 live-review)¶
After Phases 1/1b/2/3 shipped on the branch, a live walkthrough surfaced editor gaps against §5.5 and refinements to §5.7. Decisions (approved 2026-07-20):
- §5.5 was under-built: Target words must render as picture cards, not text rows. Phase 1b's
PackItemCardis text-only; the spec always said "image cards." The editor renders each target word as an AAC picture card (image where available viawordImageUrl/WordImageThumb, word-only fallback) with×remove /⟳replace. - Words link to the lexicon (the "not linking words to word cards" gap). Added/seeded/typed words resolve to their lexicon entry at add-time and store
ipa+ image on the pack item, so the pack is self-contained (instant cards, export needs no re-fetch).PackWordgainsimageFile?/imageProvider?(additive, optional — no schema-version bump). Phase 3b'smapWordToPackWordis updated to persistimage_file/image_providerfrom the search response (it currently drops them, keeping onlyhasImage). AresolveWordForPack(word)helper (over the existing/api/words/batchor/api/words/:word) backs manual-add resolution; a word not in the lexicon stays word-only. - Quick-add on every section (interim + permanent), alongside Phase 5's "+ Add from [tool]". The Phase-1b manual add existed only on Words; make it consistent:
- Words — type a word → resolve → picture card.
- Contrasts — two small word fields (Word A / Word B) → a pair; each word resolved to a card; label defaults to the pack target or blank.
- Sentences — one free-text field → the sentence; target words auto-highlighted (surface words containing the pack's target sound; none when no target). The per-section "+ Add from [tool]" (§5.5) remains the richer Phase-5 path; quick-add is the "just say what you want" path and does not replace it.
- §5.7 refinement — "Add to Editor" is a pack-picker. Instead of always pushing to the active pack, the tool control presents a dropdown of the user's saved packs (default: active pack, plus "New pack…") so a selection can be added to any of several packs. Same word→lexicon linking applies to tool-added words.
Re-sequencing of remaining phases (§11): the editor card/linking/quick-add work is foundational (a PackWord data-model change + core editor display that pre-built packs and tool-add both ride on), so it lands before pre-built packs:
1. Editor cards + word-linking + quick-add (this amendment) — picture cards, PackWord image fields, resolveWordForPack, quick-add on all three sections, seeding stores image refs.
2. Pre-built packs (former Phase 4) — now display cards for free.
3. Tools → "Add to Editor" (former Phase 5) — with the pack-picker dropdown + linking.
4. IA/nav "Advanced" grouping + 7.0.0 bump + analytics taxonomy (former Phase 6).