v1.21 — Goal Template Library — Curated Seed
Eliminate the blank-slate problem by shipping 12 curated goal templates with pre-built milestones, letting new users tap "Start from a template" to prefill the goal form and get moving immediately.
Summary
Goal Template Library is a four-phase implementation of a read-only, curator-authored feature that reduces friction at goal creation. New users navigating to /goals/create can now tap "Start from a template" in quickMode to browse 12 hand-built templates grouped by theme (fitness, learning, financial, habit/wellness). Selecting a template prefills the goal form with name, category, estimated duration, and milestone suggestions — all editable — and the goal + milestones create atomically in a single addGoal mutation round-trip. Goal detail shows a small "From template: [name]" badge for opted-in users.
The milestone shipped in four sequential phases (82–85), with all code landing on master via direct phase PRs. Phases 82–83 (backend data layer + apply-template plumbing) and Phase 84 (frontend picker UI) shipped in parallel tracks, converging on Phase 85 (telemetry + canonical content drop). Total delivery time: 1 day from plan lock to v3.9.150 tag, driven by pre-mature PRD specification (Phase 4 had locked the contract since November 2025).
This milestone advances the north-star metric (cumulative goals completed) by shortening time-to-first-goal for new users. The Phase 4 PRD activation target — 30%+ of new goals created within the first 7 days via template — is now measurable via PostHog telemetry and feeds a cohort-analysis signal for DAU/MAU lift.
Goal
Eliminate the blank-slate problem in goal creation by shipping a curated library of 12 hand-built GoalTemplates selectable from /goals/create. Selecting a template prefills form state and lets users customize freely before submit. The objective is activation, not breadth: the target is 30%+ of new goals created within the first 7 days via template, which maps to the north-star (goals completed).
Scope — What Shipped
Backend:
GoalTemplatemodel (PublicRecord + acts_as_paranoid); migration creatinggoal_templatestable;goalTemplatesGraphQL query;GoalTemplateType+MilestoneInputinput typesgoals.from_template_idnullable string column;Goal#from_templateassociation;GoalType.fromTemplateGraphQL fieldMutations::AddGoalextended with optionalfromTemplateId+milestonesargs (backward compatible)GoalTracking::AddGoalinteraction with atomic transaction;valid_templateexistence guardGamification::GoalCreatedFromTemplateJob+UserAction.goal_created_from_templateenum- 12 curated placeholder seeds (Phase 82) → Penny's canonical content drop (Phase 85)
- ≥80% line / 75% branch coverage on all new backend files
Frontend:
TemplatePickerModal.vue,TemplateCard.vuecomponents with theme grouping and detail expansionuseGoalForm.tsextended withprefillFromTemplate()method; auto-expands quickModeGoalCreate.vueintegration with "Start from a template" CTA bannerGoal.vue"From template: [name]" badge (glass chip styling)GOAL_TEMPLATES_QUERY+ADD_GOAL_MUTATIONwith new args insrc/constants/graphql/- Storybook stories for all new components (light + dark + addon-a11y)
- ≥80% statement coverage Vitest on all new files
Telemetry:
- Three PostHog events:
template_browsed(TemplatePickerModal.vue:348),template_selected(TemplatePickerModal.vue:381),goal_created_from_template(useGoalForm.ts:231) has_created_from_templateuser property (set at boot + on mutation success)- Cypress E2E golden-path spec covering full flow (OBJ-379)
Documentation:
docs/features/goal-templates.md— feature overview, GraphQL surface, telemetry event table, v1 scope boundarydocs/product/competitive/feature-matrix.md— Templates column flipped from--to current capabilitydocs/architecture/data-models.md— GoalTemplate + goals.from_template_id appendedCHANGELOG.mdv3.9.150 entry- Milestone narrative at
docs/milestones/v1.21-goal-template-library.md
Phases
| Phase | Name | Status | Key Deliverable |
|---|---|---|---|
| 82 | Backend foundation: GoalTemplate data layer | Shipped | Model, migration, GraphQL surface, 12 placeholder seeds (PR #671) |
| 83 | Apply-template plumbing on AddGoal | Shipped | from_template_id column, atomic transaction, UserAction (PR #674) |
| 84 | Frontend template picker UI | Shipped | Modal, cards, GoalCreate integration, badge (PR #682 + PR #697) |
| 85 | Telemetry + canonical content drop | Shipped | Three PostHog events, has_created_from_template property, 12 curated templates (PR #698) |
| 85.2 | Docs + milestone close | Shipped | Feature docs, feature matrix flip, PRD status, milestone narrative, audit |
Key Decisions
- Model vs. static YAML — GoalTemplate as ActiveRecord (not static YAML) for future extensibility (ratings, usage metrics). Supports
acts_as_paranoidsoft deletion andpublic_idauto-gen. - JSONB milestones, not separate table — Template milestones as JSONB array (not separate table) because v1 is read-only curated content. Matches v1.18
EnneagramAssessment.scorespattern. - Extended AddGoal, not separate mutation — Optional
fromTemplateId+milestonesargs on existingMutations::AddGoalfor backward compatibility and single round-trip create. - Atomic transaction for goal + milestones — Goal + all template milestones create in one
ActiveRecord::Base.transaction. Rollback if any milestone validation fails. Verified by regression test. - Content-gated frontend with eng-stubs + content-author drop — Phase 82 ships placeholder seeds; Phase 85 holds merge until Penny delivers canonical copy. Proven v1.18 pattern avoids production "TODO" regressions.
- Public-ID-based linkage —
from_template_idstores template'spublic_idstring (not integer PK), matchinggoal.parent_goal_idconvention. - Opt-in, no paywall, no dark patterns — Templates are free-tier core feature. Picker is opt-in CTA parallel to name field. Zero impact on non-template goal creation.
Requirements Coverage
All 14 Phase 4 PRD Feature 5 acceptance criteria satisfied.
| Category | Count | Status |
|---|---|---|
| Data model + GraphQL | 3 | Satisfied (Phase 82–83) |
| Frontend discovery + picker | 4 | Satisfied (Phase 84) |
| Atomic create + badge | 3 | Satisfied (Phase 83–84) |
| Telemetry + activation signals | 2 | Satisfied (Phase 85) |
| Documentation + scope boundary | 2 | Satisfied (Phase 85.2) |
Outcomes
For users: New goal creators have a friction-reducing starting point. "Run Your First 5K" with pre-built milestones is more actionable than a blank form. All fields remain editable.
For the product: Activation funnel is now measurable via PostHog. The Phase 4 PRD target of 30%+ of new goals created within 7 days via template is now owned by Penny post-ship via cohort analysis.
For the platform: Competitive table-stakes gap is closed. Feature matrix Templates column flips from -- to baseline parity with direct competitors.
Tech Debt
Closed:
- ✅ N+1 on
goalTemplatesresolver (Phase 83) - ✅ Seed re-run guard for canonical content (Phase 85)
- ✅
fromTemplateIdonaddGoalmutation call (Phase 84-C) - ✅
fromTemplateNamefield onGOAL_QUERY(Phase 84-C) - ✅
valid_templateexistence guard (Phase 84-C)
Closed:
- ✅ Cypress E2E golden-path spec (OBJ-379) — Shipped PR #707
Related Artifacts
- Roadmap: v1.21-goal-template-library-ROADMAP.md
- Milestone Audit: v1.21-goal-template-library-MILESTONE-AUDIT.md
- PRD: Phase 4 Engagement & Retention — Feature 5
- Feature docs: docs/features/goal-templates.md
- Git tag: v3.9.150
Related Commits
126ff6d3— Phase 82: GoalTemplate data layer (PR #671)e5f44dd4— Phase 83: Apply-template plumbing (PR #674)ab318454— Phase 84-C: Frontend wiring (PR #697)901c3714— Phase 85: Telemetry + content drop (PR #698)
Last updated: 2026-06-22