@funnelsgrove/cli 0.1.14 → 0.1.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/contracts/step-contract-v2.json +733 -0
- package/dist/analyticsOutput.d.ts +30 -15
- package/dist/analyticsOutput.js +45 -28
- package/dist/apiClient.d.ts +85 -0
- package/dist/apiClient.js +225 -8
- package/dist/cli.d.ts +149 -1
- package/dist/cli.js +1232 -71
- package/dist/diagnosticOutput.d.ts +42 -0
- package/dist/diagnosticOutput.js +83 -0
- package/dist/docsOutput.d.ts +19 -0
- package/dist/docsOutput.js +73 -0
- package/dist/docsTransaction.d.ts +81 -0
- package/dist/docsTransaction.js +1755 -0
- package/dist/funnelValidation.d.ts +14 -0
- package/dist/funnelValidation.js +297 -0
- package/dist/localSync.d.ts +79 -0
- package/dist/localSync.js +428 -53
- package/dist/projectValidator.d.ts +27 -0
- package/dist/projectValidator.js +208 -0
- package/dist/reskin.js +27 -1
- package/dist/stepContractMigration.d.ts +71 -0
- package/dist/stepContractMigration.js +1323 -0
- package/dist/templateDocs.js +8 -25
- package/docs-release-history.json +66 -0
- package/legacy-docs-catalog.json +1012 -0
- package/package.json +13 -4
- package/template_docs/.funnelsgrove-docs.json +144 -0
- package/template_docs/AGENTS.md +30 -58
- package/template_docs/CLAUDE.md +0 -2
- package/template_docs/docs/funnelsgrove/START-HERE.md +73 -0
- package/template_docs/docs/funnelsgrove/contracts/analytics-events.md +59 -0
- package/template_docs/docs/funnelsgrove/contracts/content-answers.md +44 -0
- package/template_docs/docs/funnelsgrove/contracts/flow-routing.md +41 -0
- package/template_docs/docs/funnelsgrove/contracts/payments.md +42 -0
- package/template_docs/docs/funnelsgrove/contracts/step-metadata.md +57 -0
- package/template_docs/docs/funnelsgrove/migrations/step-contract-v3.md +39 -0
- package/template_docs/docs/funnelsgrove/qa/analytics.md +43 -0
- package/template_docs/docs/funnelsgrove/qa/local.md +42 -0
- package/template_docs/docs/funnelsgrove/qa/paywall-checkout.md +55 -0
- package/template_docs/docs/funnelsgrove/qa/publish.md +32 -0
- package/template_docs/docs/funnelsgrove/recipes/add-experiment.md +34 -0
- package/template_docs/docs/funnelsgrove/recipes/add-step.md +33 -0
- package/template_docs/docs/funnelsgrove/recipes/edit-step.md +31 -0
- package/template_docs/docs/funnelsgrove/steps/INDEX.md +26 -0
- package/template_docs/docs/funnelsgrove/steps/cancellation_offer.md +112 -0
- package/template_docs/docs/funnelsgrove/steps/checkout.md +120 -0
- package/template_docs/docs/funnelsgrove/steps/form_input.md +115 -0
- package/template_docs/docs/funnelsgrove/steps/intro_hero.md +110 -0
- package/template_docs/docs/funnelsgrove/steps/multi_select_choice.md +123 -0
- package/template_docs/docs/funnelsgrove/steps/paywall_offer.md +115 -0
- package/template_docs/docs/funnelsgrove/steps/progress_interstitial.md +111 -0
- package/template_docs/docs/funnelsgrove/steps/purchase_completed.md +117 -0
- package/template_docs/docs/funnelsgrove/steps/single_step_choice.md +122 -0
- package/template_docs/docs/funnelsgrove/steps/single_step_choice_emoji.md +122 -0
- package/template_docs/docs/funnelsgrove/steps/social_proof.md +110 -0
- package/template_docs/docs/funnelsgrove/steps/subscription_handoff.md +113 -0
- package/template_docs/docs/funnelsgrove/steps/subscription_management.md +112 -0
- package/template_docs/docs/funnelsgrove/steps/summary_confirmation.md +110 -0
- package/template_docs/docs/funnelsgrove/steps/upsell_offer.md +112 -0
- package/template_docs/docs/funnelsgrove/steps/value_prop_story.md +110 -0
- package/template_docs/funnel-docs.config.json +43 -0
- package/template_scaffold/.env.example +41 -0
- package/template_scaffold/.funnelsgrove-contract-tools.json +19 -0
- package/template_scaffold/.funnelsgrove-docs.json +144 -0
- package/template_scaffold/.funnelsgrove-scaffold.json +1078 -0
- package/template_scaffold/AGENTS.md +42 -0
- package/template_scaffold/CLAUDE.md +1 -0
- package/template_scaffold/PLAN.md +81 -0
- package/template_scaffold/PRODUCT_SENSE.md +28 -0
- package/template_scaffold/context/build-context.md +34 -0
- package/template_scaffold/docs/AGENT_FUNNEL_IMPLEMENTATION_SPEC.md +5 -0
- package/template_scaffold/docs/ARCHITECTURE.md +5 -0
- package/template_scaffold/docs/FLOW_CONFIG_AND_ROUTING.md +5 -0
- package/template_scaffold/docs/PAYWALL_AND_PAYMENTS.md +5 -0
- package/template_scaffold/docs/README.md +5 -0
- package/template_scaffold/docs/funnelsgrove/START-HERE.md +73 -0
- package/template_scaffold/docs/funnelsgrove/contracts/analytics-events.md +59 -0
- package/template_scaffold/docs/funnelsgrove/contracts/content-answers.md +44 -0
- package/template_scaffold/docs/funnelsgrove/contracts/flow-routing.md +41 -0
- package/template_scaffold/docs/funnelsgrove/contracts/payments.md +42 -0
- package/template_scaffold/docs/funnelsgrove/contracts/step-metadata.md +57 -0
- package/template_scaffold/docs/funnelsgrove/migrations/step-contract-v3.md +39 -0
- package/template_scaffold/docs/funnelsgrove/qa/analytics.md +43 -0
- package/template_scaffold/docs/funnelsgrove/qa/local.md +42 -0
- package/template_scaffold/docs/funnelsgrove/qa/paywall-checkout.md +55 -0
- package/template_scaffold/docs/funnelsgrove/qa/publish.md +32 -0
- package/template_scaffold/docs/funnelsgrove/recipes/add-experiment.md +34 -0
- package/template_scaffold/docs/funnelsgrove/recipes/add-step.md +33 -0
- package/template_scaffold/docs/funnelsgrove/recipes/edit-step.md +31 -0
- package/template_scaffold/docs/funnelsgrove/steps/INDEX.md +26 -0
- package/template_scaffold/docs/funnelsgrove/steps/cancellation_offer.md +112 -0
- package/template_scaffold/docs/funnelsgrove/steps/checkout.md +120 -0
- package/template_scaffold/docs/funnelsgrove/steps/form_input.md +115 -0
- package/template_scaffold/docs/funnelsgrove/steps/intro_hero.md +110 -0
- package/template_scaffold/docs/funnelsgrove/steps/multi_select_choice.md +123 -0
- package/template_scaffold/docs/funnelsgrove/steps/paywall_offer.md +115 -0
- package/template_scaffold/docs/funnelsgrove/steps/progress_interstitial.md +111 -0
- package/template_scaffold/docs/funnelsgrove/steps/purchase_completed.md +117 -0
- package/template_scaffold/docs/funnelsgrove/steps/single_step_choice.md +122 -0
- package/template_scaffold/docs/funnelsgrove/steps/single_step_choice_emoji.md +122 -0
- package/template_scaffold/docs/funnelsgrove/steps/social_proof.md +110 -0
- package/template_scaffold/docs/funnelsgrove/steps/subscription_handoff.md +113 -0
- package/template_scaffold/docs/funnelsgrove/steps/subscription_management.md +112 -0
- package/template_scaffold/docs/funnelsgrove/steps/summary_confirmation.md +110 -0
- package/template_scaffold/docs/funnelsgrove/steps/upsell_offer.md +112 -0
- package/template_scaffold/docs/funnelsgrove/steps/value_prop_story.md +110 -0
- package/template_scaffold/docs/references/funnel-sdk-user-answers.md +5 -0
- package/template_scaffold/eslint.config.mjs +16 -0
- package/template_scaffold/funnel-agent-docs.test.ts +699 -0
- package/template_scaffold/funnel-docs.config.json +43 -0
- package/template_scaffold/funnel.config.json +5 -0
- package/template_scaffold/gitignore.template +5 -0
- package/template_scaffold/next-env.d.ts +6 -0
- package/template_scaffold/next.config.ts +53 -0
- package/template_scaffold/package-lock.json +7737 -0
- package/template_scaffold/package.json +37 -0
- package/template_scaffold/package.test.ts +23 -0
- package/template_scaffold/public/claimbee/bee.png +0 -0
- package/template_scaffold/public/claimbee/device-iphone.png +0 -0
- package/template_scaffold/public/claimbee/device-macbook.png +0 -0
- package/template_scaffold/public/claimbee/device-none.png +0 -0
- package/template_scaffold/public/claimbee/device-watch.png +0 -0
- package/template_scaffold/public/claimbee/glow.svg +3 -0
- package/template_scaffold/public/claimbee/steps-sprite-alt.png +0 -0
- package/template_scaffold/public/claimbee/steps-sprite-default.png +0 -0
- package/template_scaffold/public/claimbee/testimonial-avatar.png +0 -0
- package/template_scaffold/public/claimbee/testimonial-star.svg +3 -0
- package/template_scaffold/public/paywall/ai-claim-assistant.png +0 -0
- package/template_scaffold/public/paywall/claim-history.png +0 -0
- package/template_scaffold/public/paywall/clear-progress.png +0 -0
- package/template_scaffold/public/paywall/hero.png +0 -0
- package/template_scaffold/public/paywall/money-alerts.png +0 -0
- package/template_scaffold/public/paywall/money-back-badge.png +0 -0
- package/template_scaffold/public/paywall/paywall-image.png +0 -0
- package/template_scaffold/public/paywall/r1.png +0 -0
- package/template_scaffold/public/paywall/r2.png +0 -0
- package/template_scaffold/public/paywall/r3.png +0 -0
- package/template_scaffold/public/paywall/r4.png +0 -0
- package/template_scaffold/public/paywall/r5.png +0 -0
- package/template_scaffold/public/paywall/r6.png +0 -0
- package/template_scaffold/public/paywall/special-offer-gift.png +0 -0
- package/template_scaffold/public/please/bee.png +0 -0
- package/template_scaffold/public/please/device-iphone.png +0 -0
- package/template_scaffold/public/please/device-macbook.png +0 -0
- package/template_scaffold/public/please/device-none.png +0 -0
- package/template_scaffold/public/please/device-watch.png +0 -0
- package/template_scaffold/public/please/glow.svg +3 -0
- package/template_scaffold/public/please/steps-sprite-alt.png +0 -0
- package/template_scaffold/public/please/steps-sprite-default.png +0 -0
- package/template_scaffold/public/please/testimonial-avatar.png +0 -0
- package/template_scaffold/public/please/testimonial-star.svg +3 -0
- package/template_scaffold/public/upsell/upgrade-hero.png +0 -0
- package/template_scaffold/src/app/[stepId]/page.test.tsx +59 -0
- package/template_scaffold/src/app/[stepId]/page.tsx +62 -0
- package/template_scaffold/src/app/globals.css +49 -0
- package/template_scaffold/src/app/layout.test.ts +26 -0
- package/template_scaffold/src/app/layout.tsx +61 -0
- package/template_scaffold/src/app/page.tsx +8 -0
- package/template_scaffold/src/app/sdk/page.tsx +673 -0
- package/template_scaffold/src/app/subscription-dashboard/page.tsx +274 -0
- package/template_scaffold/src/assets/claimbee/bee.png +0 -0
- package/template_scaffold/src/assets/claimbee/device-iphone.png +0 -0
- package/template_scaffold/src/assets/claimbee/device-macbook.png +0 -0
- package/template_scaffold/src/assets/claimbee/device-none.png +0 -0
- package/template_scaffold/src/assets/claimbee/device-watch.png +0 -0
- package/template_scaffold/src/assets/claimbee/glow.svg +3 -0
- package/template_scaffold/src/assets/claimbee/steps-sprite-alt.png +0 -0
- package/template_scaffold/src/assets/claimbee/steps-sprite-default.png +0 -0
- package/template_scaffold/src/assets/claimbee/testimonial-avatar.png +0 -0
- package/template_scaffold/src/assets/claimbee/testimonial-star.svg +3 -0
- package/template_scaffold/src/components/FunnelEditorPanel.tsx +194 -0
- package/template_scaffold/src/components/FunnelFlow.test.tsx +17 -0
- package/template_scaffold/src/components/FunnelFlow.tsx +114 -0
- package/template_scaffold/src/components/FunnelStepImage.test.ts +15 -0
- package/template_scaffold/src/components/FunnelStepImage.tsx +28 -0
- package/template_scaffold/src/components/step/FunnelStepHeader.tsx +35 -0
- package/template_scaffold/src/config/billing.plans.test.ts +143 -0
- package/template_scaffold/src/config/billing.plans.ts +69 -0
- package/template_scaffold/src/config/billing.test.plans.ts +32 -0
- package/template_scaffold/src/config/experiments.generated.ts +4 -0
- package/template_scaffold/src/config/experiments.test.ts +12 -0
- package/template_scaffold/src/config/experiments.ts +9 -0
- package/template_scaffold/src/config/funnel.config.ts +12 -0
- package/template_scaffold/src/config/funnel.manifest.test.ts +166 -0
- package/template_scaffold/src/config/funnel.manifest.ts +139 -0
- package/template_scaffold/src/config/offer-sets.generated.ts +4 -0
- package/template_scaffold/src/contract/funnel-project.validation.test.ts +80 -0
- package/template_scaffold/src/contract/funnel-project.validation.ts +44 -0
- package/template_scaffold/src/contract/funnel-validator.vite.config.ts +11 -0
- package/template_scaffold/src/contract/golden/cancellation_offer.fixture.ts +29 -0
- package/template_scaffold/src/contract/golden/checkout.fixture.ts +37 -0
- package/template_scaffold/src/contract/golden/form_input.fixture.ts +28 -0
- package/template_scaffold/src/contract/golden/golden-fixtures.test.ts +190 -0
- package/template_scaffold/src/contract/golden/intro_hero.fixture.ts +27 -0
- package/template_scaffold/src/contract/golden/multi_select_choice.fixture.ts +37 -0
- package/template_scaffold/src/contract/golden/paywall_offer.fixture.ts +30 -0
- package/template_scaffold/src/contract/golden/progress_interstitial.fixture.ts +28 -0
- package/template_scaffold/src/contract/golden/purchase_completed.fixture.ts +33 -0
- package/template_scaffold/src/contract/golden/single_step_choice.fixture.ts +36 -0
- package/template_scaffold/src/contract/golden/single_step_choice_emoji.fixture.ts +36 -0
- package/template_scaffold/src/contract/golden/social_proof.fixture.ts +27 -0
- package/template_scaffold/src/contract/golden/subscription_handoff.fixture.ts +30 -0
- package/template_scaffold/src/contract/golden/subscription_management.fixture.ts +29 -0
- package/template_scaffold/src/contract/golden/summary_confirmation.fixture.ts +27 -0
- package/template_scaffold/src/contract/golden/upsell_offer.fixture.ts +29 -0
- package/template_scaffold/src/contract/golden/value_prop_story.fixture.ts +27 -0
- package/template_scaffold/src/contract/validate-funnel.cli.test.ts +180 -0
- package/template_scaffold/src/contract/validate-funnel.cli.ts +199 -0
- package/template_scaffold/src/runtime/checkout-runtime-config.test.ts +60 -0
- package/template_scaffold/src/runtime/checkout-runtime-config.ts +26 -0
- package/template_scaffold/src/runtime/funnel-runtime.test.ts +25 -0
- package/template_scaffold/src/runtime/funnel-runtime.ts +118 -0
- package/template_scaffold/src/runtime/step-content-context.test.ts +38 -0
- package/template_scaffold/src/runtime/step-content-context.ts +65 -0
- package/template_scaffold/src/runtime/step-registry.ts +66 -0
- package/template_scaffold/src/runtime/step-variable-values.ts +31 -0
- package/template_scaffold/src/runtime/use-funnel-flow-controller.integration.test.ts +203 -0
- package/template_scaffold/src/runtime/use-funnel-flow-controller.test.ts +76 -0
- package/template_scaffold/src/runtime/use-funnel-flow-controller.ts +53 -0
- package/template_scaffold/src/steps/content/email-capture.content.ts +29 -0
- package/template_scaffold/src/steps/content/manage-subscription.content.ts +62 -0
- package/template_scaffold/src/steps/content/paywall.content.ts +191 -0
- package/template_scaffold/src/steps/content/step-01.content.ts +23 -0
- package/template_scaffold/src/steps/content/step-02.content.ts +77 -0
- package/template_scaffold/src/steps/content/step-03.content.ts +40 -0
- package/template_scaffold/src/steps/content/step-04.content.ts +49 -0
- package/template_scaffold/src/steps/content/step-32-paywall.content.ts +352 -0
- package/template_scaffold/src/steps/content/subscription-started.content.ts +68 -0
- package/template_scaffold/src/steps/editor/email-capture.editor.ts +58 -0
- package/template_scaffold/src/steps/editor/manage-subscription.editor.ts +179 -0
- package/template_scaffold/src/steps/editor/paywall.editor.ts +232 -0
- package/template_scaffold/src/steps/editor/step-01.editor.ts +22 -0
- package/template_scaffold/src/steps/editor/step-02.editor.ts +41 -0
- package/template_scaffold/src/steps/editor/step-03.editor.ts +58 -0
- package/template_scaffold/src/steps/editor/step-04.editor.ts +98 -0
- package/template_scaffold/src/steps/editor/step-32-paywall.editor.ts +478 -0
- package/template_scaffold/src/steps/editor/subscription-started.editor.ts +131 -0
- package/template_scaffold/src/steps/index.ts +25 -0
- package/template_scaffold/src/steps/paywall-checkout-options.test.ts +104 -0
- package/template_scaffold/src/steps/paywall-checkout-options.ts +130 -0
- package/template_scaffold/src/steps/pricing/paywall-b.pricing.ts +12 -0
- package/template_scaffold/src/steps/pricing/paywall.pricing.ts +12 -0
- package/template_scaffold/src/steps/pricing/shared-plan-order.ts +17 -0
- package/template_scaffold/src/steps/pricing/upsell-form.pricing.ts +16 -0
- package/template_scaffold/src/steps/shared-header-contract.test.ts +27 -0
- package/template_scaffold/src/steps/step-01.test.ts +38 -0
- package/template_scaffold/src/steps/step-01.tsx +108 -0
- package/template_scaffold/src/steps/step-02.test.ts +43 -0
- package/template_scaffold/src/steps/step-02.tsx +140 -0
- package/template_scaffold/src/steps/step-03.test.ts +15 -0
- package/template_scaffold/src/steps/step-03.tsx +262 -0
- package/template_scaffold/src/steps/step-04.test.ts +32 -0
- package/template_scaffold/src/steps/step-04.tsx +673 -0
- package/template_scaffold/src/steps/step-31-email-capture.test.ts +22 -0
- package/template_scaffold/src/steps/step-31-email-capture.tsx +195 -0
- package/template_scaffold/src/steps/step-32-paywall.test.ts +770 -0
- package/template_scaffold/src/steps/step-32-paywall.tsx +2253 -0
- package/template_scaffold/src/steps/step-32b-paywall-b.tsx +35 -0
- package/template_scaffold/src/steps/step-33-subscription-started.test.ts +26 -0
- package/template_scaffold/src/steps/step-33-subscription-started.tsx +86 -0
- package/template_scaffold/src/steps/step-34-upsell-form.test.ts +27 -0
- package/template_scaffold/src/steps/step-35-manage-subscription.tsx +46 -0
- package/template_scaffold/src/steps/step-content.registry.ts +45 -0
- package/template_scaffold/src/steps/step-image-migration.test.ts +20 -0
- package/template_scaffold/src/steps/styles/index.css +2 -0
- package/template_scaffold/src/steps/styles/shared/final-flow-shared.css +55 -0
- package/template_scaffold/src/steps/styles/shared/funnel-base.css +543 -0
- package/template_scaffold/src/steps/styles/shared/info-shared.css +139 -0
- package/template_scaffold/src/steps/styles/shared/progress-shared.css +117 -0
- package/template_scaffold/src/steps/styles/shared/question-shared.css +76 -0
- package/template_scaffold/src/steps/styles/shared/responsive-container.css +176 -0
- package/template_scaffold/src/steps/types.ts +7 -0
- package/template_scaffold/src/steps/use-claimbee-step-content.ts +15 -0
- package/template_scaffold/src/theme/theme.ts +81 -0
- package/template_scaffold/tsconfig.json +38 -0
- package/template_scaffold/vitest.config.ts +32 -0
- package/template_validation/.funnelsgrove-contract-tools.json +19 -0
- package/template_validation/src/contract/funnel-project.validation.ts +44 -0
- package/template_validation/src/contract/funnel-validator.vite.config.ts +11 -0
- package/template_validation/src/contract/validate-funnel.cli.ts +199 -0
- package/template_docs/docs/ab-experiments.md +0 -55
- package/template_docs/docs/analytics.md +0 -65
- package/template_docs/docs/editing-flow.md +0 -125
- package/template_docs/docs/editing-step.md +0 -125
- package/template_docs/docs/editor-and-content.md +0 -58
- package/template_docs/docs/funnel-runtime-architecture.md +0 -125
- package/template_docs/docs/meta-pixel-conversions-api.md +0 -50
- package/template_docs/docs/payment-plans-and-discounts.md +0 -106
- package/template_docs/docs/publishing-and-versioning.md +0 -117
- package/template_docs/docs/qa-checklist.md +0 -80
- package/template_docs/docs/sdk-api-endpoints.md +0 -78
- package/template_docs/docs/step-ui-guidelines.md +0 -110
- package/template_docs/docs/theme.md +0 -35
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# `form_input`
|
|
2
|
+
|
|
3
|
+
## Use when / do not use when
|
|
4
|
+
|
|
5
|
+
Use for non-choice structured input. The reserved email-capture screen also uses this type. Do not use for option lists or payment-entry forms.
|
|
6
|
+
|
|
7
|
+
## Exact metadata contract
|
|
8
|
+
|
|
9
|
+
<!-- funnelsgrove:generated:start contract-v3/step/form_input -->
|
|
10
|
+
### Generated contract facts — do not edit
|
|
11
|
+
|
|
12
|
+
- Step contract version: `3`
|
|
13
|
+
- Contract hash: `d761e91d5ac6ff9e72c6d49c5bcd014270912473a66f99c49d726c65998085cf`
|
|
14
|
+
- Type: `form_input`
|
|
15
|
+
- Family: `form`
|
|
16
|
+
- Description: Non-choice structured input, including reserved email capture.
|
|
17
|
+
- Action owner: `either`
|
|
18
|
+
- Analytics role: _none_
|
|
19
|
+
- Terminal: `false`
|
|
20
|
+
- Required kind: _none_
|
|
21
|
+
- Allowed kinds: _None_
|
|
22
|
+
- Allowed semantic events: `email_captured`
|
|
23
|
+
- Forbidden capabilities: `choice-write`, `checkout`, `subscription-management`, `subscription-handoff`, `hardcoded-navigation`, `provider-direct-analytics`, `browser-registration-completed`
|
|
24
|
+
|
|
25
|
+
#### Choice contract
|
|
26
|
+
|
|
27
|
+
_Not a choice type._
|
|
28
|
+
|
|
29
|
+
#### Automatic lifecycle events
|
|
30
|
+
|
|
31
|
+
`first_step_clicked`, `first_step_viewed`, `funnel_started`, `step_completed`, `step_exited`, `step_started`
|
|
32
|
+
|
|
33
|
+
#### Approved capability owners
|
|
34
|
+
|
|
35
|
+
- `email-capture` must be owned by `submitEmailCapture`.
|
|
36
|
+
|
|
37
|
+
#### Reserved identities
|
|
38
|
+
|
|
39
|
+
- `email-capture`: id=`email-capture`, name=`email-capture`; type=`form_input`; unique=`true`
|
|
40
|
+
|
|
41
|
+
#### Golden fixture source
|
|
42
|
+
|
|
43
|
+
```ts
|
|
44
|
+
import type { FunnelManifestStep, FunnelStepMeta } from '@funnelsgrove/runtime';
|
|
45
|
+
|
|
46
|
+
const manifestStep = {
|
|
47
|
+
id: 'email-capture',
|
|
48
|
+
name: 'email-capture',
|
|
49
|
+
path: '/email-capture',
|
|
50
|
+
filePath: 'src/steps/step-email-capture.tsx',
|
|
51
|
+
componentKey: 'stepEmailCapture',
|
|
52
|
+
type: 'form_input',
|
|
53
|
+
title: 'Your email',
|
|
54
|
+
} as const satisfies FunnelManifestStep;
|
|
55
|
+
|
|
56
|
+
const componentMeta = {
|
|
57
|
+
id: 'email-capture',
|
|
58
|
+
name: 'email-capture',
|
|
59
|
+
type: 'form_input',
|
|
60
|
+
figmaNodeId: 'golden:form-input',
|
|
61
|
+
title: 'Your email',
|
|
62
|
+
description: 'Capture an email through the transactional helper.',
|
|
63
|
+
} as const satisfies FunnelStepMeta;
|
|
64
|
+
|
|
65
|
+
export const goldenFixture = {
|
|
66
|
+
stepType: 'form_input',
|
|
67
|
+
manifestStep,
|
|
68
|
+
componentMeta,
|
|
69
|
+
helper: 'submitEmailCapture',
|
|
70
|
+
forbiddenCalls: ['trackLead', 'provider APIs', 'hard-coded paywall navigation'],
|
|
71
|
+
} as const;
|
|
72
|
+
```
|
|
73
|
+
<!-- funnelsgrove:generated:end contract-v3/step/form_input -->
|
|
74
|
+
|
|
75
|
+
## Interaction and persisted answer shape
|
|
76
|
+
|
|
77
|
+
Validate local input before submission. For the reserved email screen, pass the email to `submitEmailCapture`; the helper owns persistence, event creation, lifecycle completion, and routing.
|
|
78
|
+
|
|
79
|
+
## Automatic lifecycle events
|
|
80
|
+
|
|
81
|
+
The controller owns lifecycle events. A failed email request leaves state, lifecycle, and navigation unchanged. Preview makes no API or provider call.
|
|
82
|
+
|
|
83
|
+
## Required semantic conversions
|
|
84
|
+
|
|
85
|
+
The reserved email screen produces `email_captured` transactionally on the server. Only a newly created conversion may fan out browser Pixel/Google events with the returned event ID.
|
|
86
|
+
|
|
87
|
+
## Approved shared helpers
|
|
88
|
+
|
|
89
|
+
Use `submitEmailCapture`. Use the manifest flow controller for the next route.
|
|
90
|
+
|
|
91
|
+
## MUST rules
|
|
92
|
+
|
|
93
|
+
- Keep the reserved email identity exact.
|
|
94
|
+
- Disable duplicate submits while one request is in flight.
|
|
95
|
+
- Complete only after the API succeeds.
|
|
96
|
+
|
|
97
|
+
## NEVER rules
|
|
98
|
+
|
|
99
|
+
- Never call `trackLead`, PostHog, Meta CAPI, Pixel, Google, or any provider directly.
|
|
100
|
+
- Never generate a browser event ID or hard-code paywall navigation.
|
|
101
|
+
- Never put raw email or other PII in analytics event metadata or logs.
|
|
102
|
+
- Only the server delivery boundary may use raw email as Meta hashing input.
|
|
103
|
+
- PostHog properties must remain non-PII.
|
|
104
|
+
|
|
105
|
+
## Golden template or fixture
|
|
106
|
+
|
|
107
|
+
See the [embedded canonical fixture](#golden-fixture-source) generated from `form_input.fixture.ts`.
|
|
108
|
+
|
|
109
|
+
## Validation command
|
|
110
|
+
|
|
111
|
+
Run `fgrove validate`.
|
|
112
|
+
|
|
113
|
+
## Manual QA and completion criteria
|
|
114
|
+
|
|
115
|
+
Test success, duplicate, API failure, double-submit, preview, and stale-visit cases; verify only a newly created conversion triggers browser fanout.
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# `intro_hero`
|
|
2
|
+
|
|
3
|
+
## Use when / do not use when
|
|
4
|
+
|
|
5
|
+
Use for the opening promise or a low-friction entry screen. Do not use for a questionnaire, reveal, offer, or checkout.
|
|
6
|
+
|
|
7
|
+
## Exact metadata contract
|
|
8
|
+
|
|
9
|
+
<!-- funnelsgrove:generated:start contract-v3/step/intro_hero -->
|
|
10
|
+
### Generated contract facts — do not edit
|
|
11
|
+
|
|
12
|
+
- Step contract version: `3`
|
|
13
|
+
- Contract hash: `d761e91d5ac6ff9e72c6d49c5bcd014270912473a66f99c49d726c65998085cf`
|
|
14
|
+
- Type: `intro_hero`
|
|
15
|
+
- Family: `content`
|
|
16
|
+
- Description: Opening promise or low-friction entry screen.
|
|
17
|
+
- Action owner: `shared-shell`
|
|
18
|
+
- Analytics role: _none_
|
|
19
|
+
- Terminal: `false`
|
|
20
|
+
- Required kind: _none_
|
|
21
|
+
- Allowed kinds: _None_
|
|
22
|
+
- Allowed semantic events: _None_
|
|
23
|
+
- Forbidden capabilities: `choice-write`, `email-capture`, `checkout`, `subscription-management`, `subscription-handoff`, `hardcoded-navigation`, `provider-direct-analytics`, `browser-registration-completed`
|
|
24
|
+
|
|
25
|
+
#### Choice contract
|
|
26
|
+
|
|
27
|
+
_Not a choice type._
|
|
28
|
+
|
|
29
|
+
#### Automatic lifecycle events
|
|
30
|
+
|
|
31
|
+
`first_step_clicked`, `first_step_viewed`, `funnel_started`, `step_completed`, `step_exited`, `step_started`
|
|
32
|
+
|
|
33
|
+
#### Approved capability owners
|
|
34
|
+
|
|
35
|
+
_No special capability is allowed._
|
|
36
|
+
|
|
37
|
+
#### Reserved identities
|
|
38
|
+
|
|
39
|
+
_No reserved identity for this type._
|
|
40
|
+
|
|
41
|
+
#### Golden fixture source
|
|
42
|
+
|
|
43
|
+
```ts
|
|
44
|
+
import type { FunnelManifestStep, FunnelStepMeta } from '@funnelsgrove/runtime';
|
|
45
|
+
|
|
46
|
+
const manifestStep = {
|
|
47
|
+
id: 'welcome',
|
|
48
|
+
name: 'welcome',
|
|
49
|
+
path: '/welcome',
|
|
50
|
+
filePath: 'src/steps/step-welcome.tsx',
|
|
51
|
+
componentKey: 'stepWelcome',
|
|
52
|
+
type: 'intro_hero',
|
|
53
|
+
title: 'Welcome',
|
|
54
|
+
} as const satisfies FunnelManifestStep;
|
|
55
|
+
|
|
56
|
+
const componentMeta = {
|
|
57
|
+
id: 'welcome',
|
|
58
|
+
name: 'welcome',
|
|
59
|
+
type: 'intro_hero',
|
|
60
|
+
figmaNodeId: 'golden:intro-hero',
|
|
61
|
+
title: 'Welcome',
|
|
62
|
+
description: 'Opening promise and low-friction entry.',
|
|
63
|
+
} as const satisfies FunnelStepMeta;
|
|
64
|
+
|
|
65
|
+
export const goldenFixture = {
|
|
66
|
+
stepType: 'intro_hero',
|
|
67
|
+
manifestStep,
|
|
68
|
+
componentMeta,
|
|
69
|
+
actionOwner: 'shared-shell',
|
|
70
|
+
} as const;
|
|
71
|
+
```
|
|
72
|
+
<!-- funnelsgrove:generated:end contract-v3/step/intro_hero -->
|
|
73
|
+
|
|
74
|
+
## Interaction and persisted answer shape
|
|
75
|
+
|
|
76
|
+
This content screen does not persist an answer. Put its primary progression action in the shared shell.
|
|
77
|
+
|
|
78
|
+
## Automatic lifecycle events
|
|
79
|
+
|
|
80
|
+
The flow controller owns the applicable automatic view, start, completion, and exit events. `step_engaged` is registered as non-automatic and is not emitted by default. Only an explicit, centralized, tested engagement policy may emit it through the approved controller/helper boundary; step components never emit it manually. Preview suppresses lifecycle delivery.
|
|
81
|
+
|
|
82
|
+
## Required semantic conversions
|
|
83
|
+
|
|
84
|
+
None. A hero CTA is navigation, not a conversion event.
|
|
85
|
+
|
|
86
|
+
## Approved shared helpers
|
|
87
|
+
|
|
88
|
+
Use `useFunnel()` only when the view needs controller state; use the shared action bar for normal Continue behavior.
|
|
89
|
+
|
|
90
|
+
## MUST rules
|
|
91
|
+
|
|
92
|
+
- Keep the component and manifest metadata identical.
|
|
93
|
+
- Keep the opening action low-friction and let the manifest choose the next step.
|
|
94
|
+
|
|
95
|
+
## NEVER rules
|
|
96
|
+
|
|
97
|
+
- Never write answers or call an analytics provider.
|
|
98
|
+
- Never hard-code the next route.
|
|
99
|
+
|
|
100
|
+
## Golden template or fixture
|
|
101
|
+
|
|
102
|
+
See the [embedded canonical fixture](#golden-fixture-source) generated from `intro_hero.fixture.ts`.
|
|
103
|
+
|
|
104
|
+
## Validation command
|
|
105
|
+
|
|
106
|
+
Run `fgrove validate`.
|
|
107
|
+
|
|
108
|
+
## Manual QA and completion criteria
|
|
109
|
+
|
|
110
|
+
Confirm the screen starts the funnel once, the CTA advances through manifest routing, and back/exit behavior records the correct lifecycle outcome.
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# `multi_select_choice`
|
|
2
|
+
|
|
3
|
+
## Use when / do not use when
|
|
4
|
+
|
|
5
|
+
Use when zero or more options can be selected before an explicit Continue action. Do not use for single-selection or implicit selection-to-advance behavior.
|
|
6
|
+
|
|
7
|
+
## Exact metadata contract
|
|
8
|
+
|
|
9
|
+
<!-- funnelsgrove:generated:start contract-v3/step/multi_select_choice -->
|
|
10
|
+
### Generated contract facts — do not edit
|
|
11
|
+
|
|
12
|
+
- Step contract version: `3`
|
|
13
|
+
- Contract hash: `d761e91d5ac6ff9e72c6d49c5bcd014270912473a66f99c49d726c65998085cf`
|
|
14
|
+
- Type: `multi_select_choice`
|
|
15
|
+
- Family: `choice`
|
|
16
|
+
- Description: Multiple options are selected before explicit completion.
|
|
17
|
+
- Action owner: `either`
|
|
18
|
+
- Analytics role: _none_
|
|
19
|
+
- Terminal: `false`
|
|
20
|
+
- Required kind: _none_
|
|
21
|
+
- Allowed kinds: _None_
|
|
22
|
+
- Allowed semantic events: _None_
|
|
23
|
+
- Forbidden capabilities: `email-capture`, `checkout`, `subscription-management`, `subscription-handoff`, `hardcoded-navigation`, `provider-direct-analytics`, `browser-registration-completed`
|
|
24
|
+
|
|
25
|
+
#### Choice contract
|
|
26
|
+
|
|
27
|
+
- Cardinality: `many`
|
|
28
|
+
- Presentation: `standard`
|
|
29
|
+
- Completion: `explicit`
|
|
30
|
+
- Allow empty config: `true`
|
|
31
|
+
|
|
32
|
+
#### Automatic lifecycle events
|
|
33
|
+
|
|
34
|
+
`first_step_clicked`, `first_step_viewed`, `funnel_started`, `step_completed`, `step_exited`, `step_started`
|
|
35
|
+
|
|
36
|
+
#### Approved capability owners
|
|
37
|
+
|
|
38
|
+
- `choice-write` must be owned by `useStepChoices`.
|
|
39
|
+
|
|
40
|
+
#### Reserved identities
|
|
41
|
+
|
|
42
|
+
_No reserved identity for this type._
|
|
43
|
+
|
|
44
|
+
#### Golden fixture source
|
|
45
|
+
|
|
46
|
+
```ts
|
|
47
|
+
import type { FunnelManifestStep, FunnelStepMeta } from '@funnelsgrove/runtime';
|
|
48
|
+
|
|
49
|
+
const choice = { answerKey: 'priorities', allowEmpty: true } as const;
|
|
50
|
+
|
|
51
|
+
const manifestStep = {
|
|
52
|
+
id: 'priorities',
|
|
53
|
+
name: 'priorities',
|
|
54
|
+
path: '/priorities',
|
|
55
|
+
filePath: 'src/steps/step-priorities.tsx',
|
|
56
|
+
componentKey: 'stepPriorities',
|
|
57
|
+
type: 'multi_select_choice',
|
|
58
|
+
choice,
|
|
59
|
+
title: 'Choose your priorities',
|
|
60
|
+
} as const satisfies FunnelManifestStep;
|
|
61
|
+
|
|
62
|
+
const componentMeta = {
|
|
63
|
+
id: 'priorities',
|
|
64
|
+
name: 'priorities',
|
|
65
|
+
type: 'multi_select_choice',
|
|
66
|
+
choice,
|
|
67
|
+
figmaNodeId: 'golden:multi-select-choice',
|
|
68
|
+
title: 'Choose your priorities',
|
|
69
|
+
description: 'Select any priorities that apply.',
|
|
70
|
+
} as const satisfies FunnelStepMeta;
|
|
71
|
+
|
|
72
|
+
export const goldenFixture = {
|
|
73
|
+
stepType: 'multi_select_choice',
|
|
74
|
+
manifestStep,
|
|
75
|
+
componentMeta,
|
|
76
|
+
options: [
|
|
77
|
+
{ id: 'sleep', label: 'Better sleep' },
|
|
78
|
+
{ id: 'focus', label: 'More focus' },
|
|
79
|
+
],
|
|
80
|
+
persistedAnswer: ['sleep', 'focus'],
|
|
81
|
+
emptyAnswer: [],
|
|
82
|
+
helper: 'useStepChoices',
|
|
83
|
+
} as const;
|
|
84
|
+
```
|
|
85
|
+
<!-- funnelsgrove:generated:end contract-v3/step/multi_select_choice -->
|
|
86
|
+
|
|
87
|
+
## Interaction and persisted answer shape
|
|
88
|
+
|
|
89
|
+
Declare `choice.answerKey` and the intended `allowEmpty` value. Persist an array of stable option IDs; an allowed empty selection is `[]`.
|
|
90
|
+
|
|
91
|
+
## Automatic lifecycle events
|
|
92
|
+
|
|
93
|
+
`useStepChoices` coordinates array persistence and explicit completion. Preview suppresses provider delivery.
|
|
94
|
+
|
|
95
|
+
## Required semantic conversions
|
|
96
|
+
|
|
97
|
+
None.
|
|
98
|
+
|
|
99
|
+
## Approved shared helpers
|
|
100
|
+
|
|
101
|
+
Use `useStepChoices` for toggles, saving, completion, and routing.
|
|
102
|
+
|
|
103
|
+
## MUST rules
|
|
104
|
+
|
|
105
|
+
- Preserve stable IDs and exact array shape.
|
|
106
|
+
- Make Continue state match `allowEmpty`.
|
|
107
|
+
|
|
108
|
+
## NEVER rules
|
|
109
|
+
|
|
110
|
+
- Never store comma-separated text, labels, or option objects.
|
|
111
|
+
- Never auto-advance on the first selection.
|
|
112
|
+
|
|
113
|
+
## Golden template or fixture
|
|
114
|
+
|
|
115
|
+
See the [embedded canonical fixture](#golden-fixture-source) generated from `multi_select_choice.fixture.ts`.
|
|
116
|
+
|
|
117
|
+
## Validation command
|
|
118
|
+
|
|
119
|
+
Run `fgrove validate`.
|
|
120
|
+
|
|
121
|
+
## Manual QA and completion criteria
|
|
122
|
+
|
|
123
|
+
Test select, deselect, reload, and empty-state behavior; confirm one ID array persists and explicit Continue completes once.
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# `paywall_offer`
|
|
2
|
+
|
|
3
|
+
## Use when / do not use when
|
|
4
|
+
|
|
5
|
+
Use only for a monetization screen that presents purchasable plans. Do not use for a loading, calculation, reveal, or pre-offer bridge.
|
|
6
|
+
|
|
7
|
+
## Exact metadata contract
|
|
8
|
+
|
|
9
|
+
<!-- funnelsgrove:generated:start contract-v3/step/paywall_offer -->
|
|
10
|
+
### Generated contract facts — do not edit
|
|
11
|
+
|
|
12
|
+
- Step contract version: `3`
|
|
13
|
+
- Contract hash: `d761e91d5ac6ff9e72c6d49c5bcd014270912473a66f99c49d726c65998085cf`
|
|
14
|
+
- Type: `paywall_offer`
|
|
15
|
+
- Family: `commerce`
|
|
16
|
+
- Description: A monetization offer that presents purchasable plans.
|
|
17
|
+
- Action owner: `step`
|
|
18
|
+
- Analytics role: `paywall`
|
|
19
|
+
- Terminal: `false`
|
|
20
|
+
- Required kind: `paywall`
|
|
21
|
+
- Allowed kinds: `paywall`
|
|
22
|
+
- Allowed semantic events: `checkout_started`, `add_payment_info`, `checkout_completed`
|
|
23
|
+
- Forbidden capabilities: `choice-write`, `email-capture`, `subscription-management`, `subscription-handoff`, `hardcoded-navigation`, `provider-direct-analytics`, `browser-registration-completed`
|
|
24
|
+
|
|
25
|
+
#### Choice contract
|
|
26
|
+
|
|
27
|
+
_Not a choice type._
|
|
28
|
+
|
|
29
|
+
#### Automatic lifecycle events
|
|
30
|
+
|
|
31
|
+
`first_step_clicked`, `first_step_viewed`, `funnel_started`, `step_completed`, `step_exited`, `step_started`
|
|
32
|
+
|
|
33
|
+
#### Approved capability owners
|
|
34
|
+
|
|
35
|
+
- `checkout` must be owned by `named-payment-helpers`.
|
|
36
|
+
|
|
37
|
+
#### Reserved identities
|
|
38
|
+
|
|
39
|
+
- `paywall`: id=`paywall`, name=`paywall`; type=`paywall_offer`; kind=`paywall`; primary=`true`; unique=`true`
|
|
40
|
+
- `paywall-variant`: idPattern=`^paywall-[a-z0-9-]+$`, namePattern=`^paywall-[a-z0-9-]+$`; type=`paywall_offer`; kind=`paywall`; primary=`false`; unique=`false`
|
|
41
|
+
|
|
42
|
+
#### Golden fixture source
|
|
43
|
+
|
|
44
|
+
```ts
|
|
45
|
+
import type { FunnelManifestStep, FunnelStepMeta } from '@funnelsgrove/runtime';
|
|
46
|
+
|
|
47
|
+
const manifestStep = {
|
|
48
|
+
id: 'paywall',
|
|
49
|
+
name: 'paywall',
|
|
50
|
+
path: '/paywall',
|
|
51
|
+
filePath: 'src/steps/step-paywall.tsx',
|
|
52
|
+
componentKey: 'stepPaywall',
|
|
53
|
+
type: 'paywall_offer',
|
|
54
|
+
kind: 'paywall',
|
|
55
|
+
title: 'Choose your plan',
|
|
56
|
+
} as const satisfies FunnelManifestStep;
|
|
57
|
+
|
|
58
|
+
const componentMeta = {
|
|
59
|
+
id: 'paywall',
|
|
60
|
+
name: 'paywall',
|
|
61
|
+
type: 'paywall_offer',
|
|
62
|
+
kind: 'paywall',
|
|
63
|
+
figmaNodeId: 'golden:paywall-offer',
|
|
64
|
+
title: 'Choose your plan',
|
|
65
|
+
description: 'Present purchasable plans.',
|
|
66
|
+
} as const satisfies FunnelStepMeta;
|
|
67
|
+
|
|
68
|
+
export const goldenFixture = {
|
|
69
|
+
stepType: 'paywall_offer',
|
|
70
|
+
manifestStep,
|
|
71
|
+
componentMeta,
|
|
72
|
+
presentsPurchasablePlans: true,
|
|
73
|
+
semanticHelpers: ['trackCheckoutStarted', 'trackPaymentInfoSubmitted', 'trackCheckoutCompleted'],
|
|
74
|
+
} as const;
|
|
75
|
+
```
|
|
76
|
+
<!-- funnelsgrove:generated:end contract-v3/step/paywall_offer -->
|
|
77
|
+
|
|
78
|
+
## Interaction and persisted answer shape
|
|
79
|
+
|
|
80
|
+
Resolve offers and plans through shared payments configuration. Do not persist plan data as a choice answer.
|
|
81
|
+
|
|
82
|
+
## Automatic lifecycle events
|
|
83
|
+
|
|
84
|
+
The controller owns view/start/completion/exit lifecycle. Closing or leaving without purchase is an exit, not a completion.
|
|
85
|
+
|
|
86
|
+
## Required semantic conversions
|
|
87
|
+
|
|
88
|
+
Use named helpers for checkout started, payment info, and checkout completed at their real boundaries with one stable event ID.
|
|
89
|
+
|
|
90
|
+
## Approved shared helpers
|
|
91
|
+
|
|
92
|
+
Use shared plan resolution, checkout, wallet, and `trackCheckoutStarted`, `trackPaymentInfoSubmitted`, and `trackCheckoutCompleted` helpers.
|
|
93
|
+
|
|
94
|
+
## MUST rules
|
|
95
|
+
|
|
96
|
+
- Keep the primary paywall identity exact; variants use contract-compliant distinct identities.
|
|
97
|
+
- Present at least one purchasable plan.
|
|
98
|
+
- Read prices, discounts, provider IDs, and payment mode from shared configuration.
|
|
99
|
+
|
|
100
|
+
## NEVER rules
|
|
101
|
+
|
|
102
|
+
- Never classify a reveal/interstitial as a paywall.
|
|
103
|
+
- Never put secrets, provider IDs, amount math, or provider analytics in JSX.
|
|
104
|
+
|
|
105
|
+
## Golden template or fixture
|
|
106
|
+
|
|
107
|
+
See the [embedded canonical fixture](#golden-fixture-source) generated from `paywall_offer.fixture.ts`.
|
|
108
|
+
|
|
109
|
+
## Validation command
|
|
110
|
+
|
|
111
|
+
Run `fgrove validate`.
|
|
112
|
+
|
|
113
|
+
## Manual QA and completion criteria
|
|
114
|
+
|
|
115
|
+
Verify plans and discounts, every payment method, decline/retry, checkout event metadata/deduplication, cancel/exit, and manifest routing after success.
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# `progress_interstitial`
|
|
2
|
+
|
|
3
|
+
## Use when / do not use when
|
|
4
|
+
|
|
5
|
+
Use for progress, calculation, loading, reveal, or transition. Do not use for a screen that presents purchasable plans: that is a paywall offer.
|
|
6
|
+
|
|
7
|
+
## Exact metadata contract
|
|
8
|
+
|
|
9
|
+
<!-- funnelsgrove:generated:start contract-v3/step/progress_interstitial -->
|
|
10
|
+
### Generated contract facts — do not edit
|
|
11
|
+
|
|
12
|
+
- Step contract version: `3`
|
|
13
|
+
- Contract hash: `d761e91d5ac6ff9e72c6d49c5bcd014270912473a66f99c49d726c65998085cf`
|
|
14
|
+
- Type: `progress_interstitial`
|
|
15
|
+
- Family: `transition`
|
|
16
|
+
- Description: Progress, calculation, loading, reveal, or transition screen.
|
|
17
|
+
- Action owner: `either`
|
|
18
|
+
- Analytics role: _none_
|
|
19
|
+
- Terminal: `false`
|
|
20
|
+
- Required kind: _none_
|
|
21
|
+
- Allowed kinds: _None_
|
|
22
|
+
- Allowed semantic events: _None_
|
|
23
|
+
- Forbidden capabilities: `choice-write`, `email-capture`, `checkout`, `subscription-management`, `subscription-handoff`, `hardcoded-navigation`, `provider-direct-analytics`, `browser-registration-completed`
|
|
24
|
+
|
|
25
|
+
#### Choice contract
|
|
26
|
+
|
|
27
|
+
_Not a choice type._
|
|
28
|
+
|
|
29
|
+
#### Automatic lifecycle events
|
|
30
|
+
|
|
31
|
+
`first_step_clicked`, `first_step_viewed`, `funnel_started`, `step_completed`, `step_exited`, `step_started`
|
|
32
|
+
|
|
33
|
+
#### Approved capability owners
|
|
34
|
+
|
|
35
|
+
_No special capability is allowed._
|
|
36
|
+
|
|
37
|
+
#### Reserved identities
|
|
38
|
+
|
|
39
|
+
_No reserved identity for this type._
|
|
40
|
+
|
|
41
|
+
#### Golden fixture source
|
|
42
|
+
|
|
43
|
+
```ts
|
|
44
|
+
import type { FunnelManifestStep, FunnelStepMeta } from '@funnelsgrove/runtime';
|
|
45
|
+
|
|
46
|
+
const manifestStep = {
|
|
47
|
+
id: 'building-plan',
|
|
48
|
+
name: 'building-plan',
|
|
49
|
+
path: '/building-plan',
|
|
50
|
+
filePath: 'src/steps/step-building-plan.tsx',
|
|
51
|
+
componentKey: 'stepBuildingPlan',
|
|
52
|
+
type: 'progress_interstitial',
|
|
53
|
+
title: 'Building your plan',
|
|
54
|
+
} as const satisfies FunnelManifestStep;
|
|
55
|
+
|
|
56
|
+
const componentMeta = {
|
|
57
|
+
id: 'building-plan',
|
|
58
|
+
name: 'building-plan',
|
|
59
|
+
type: 'progress_interstitial',
|
|
60
|
+
figmaNodeId: 'golden:progress-interstitial',
|
|
61
|
+
title: 'Building your plan',
|
|
62
|
+
description: 'Show progress while preparing the next screen.',
|
|
63
|
+
} as const satisfies FunnelStepMeta;
|
|
64
|
+
|
|
65
|
+
export const goldenFixture = {
|
|
66
|
+
stepType: 'progress_interstitial',
|
|
67
|
+
manifestStep,
|
|
68
|
+
componentMeta,
|
|
69
|
+
semanticHelpers: [],
|
|
70
|
+
isPaywall: false,
|
|
71
|
+
} as const;
|
|
72
|
+
```
|
|
73
|
+
<!-- funnelsgrove:generated:end contract-v3/step/progress_interstitial -->
|
|
74
|
+
|
|
75
|
+
## Interaction and persisted answer shape
|
|
76
|
+
|
|
77
|
+
This transition does not persist a choice answer. An automatic delay or explicit Continue may complete it through the controller.
|
|
78
|
+
|
|
79
|
+
## Automatic lifecycle events
|
|
80
|
+
|
|
81
|
+
The controller distinguishes completion from abandonment and suppresses provider delivery in preview.
|
|
82
|
+
|
|
83
|
+
## Required semantic conversions
|
|
84
|
+
|
|
85
|
+
None. A reveal or “your plan is ready” transition is not a paywall or checkout conversion.
|
|
86
|
+
|
|
87
|
+
## Approved shared helpers
|
|
88
|
+
|
|
89
|
+
Use shared progress/action primitives and manifest routing.
|
|
90
|
+
|
|
91
|
+
## MUST rules
|
|
92
|
+
|
|
93
|
+
- Keep automatic completion cancellable when the visit becomes stale.
|
|
94
|
+
- Classify by actual interaction, not by funnel position.
|
|
95
|
+
|
|
96
|
+
## NEVER rules
|
|
97
|
+
|
|
98
|
+
- Never set paywall identity or emit checkout semantics.
|
|
99
|
+
- Never hard-code a paywall destination.
|
|
100
|
+
|
|
101
|
+
## Golden template or fixture
|
|
102
|
+
|
|
103
|
+
See the [embedded canonical fixture](#golden-fixture-source) generated from `progress_interstitial.fixture.ts`.
|
|
104
|
+
|
|
105
|
+
## Validation command
|
|
106
|
+
|
|
107
|
+
Run `fgrove validate`.
|
|
108
|
+
|
|
109
|
+
## Manual QA and completion criteria
|
|
110
|
+
|
|
111
|
+
Confirm timer/manual completion fires once, leaving early records an exit, and no paywall or checkout event appears.
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
# `purchase_completed`
|
|
2
|
+
|
|
3
|
+
## Use when / do not use when
|
|
4
|
+
|
|
5
|
+
Use for the canonical terminal after an initial subscription or one-time purchase flow. Do not use for a generic handoff, receipt, renewal, or pre-purchase summary. Entering this screen does not prove that the backend verified payment.
|
|
6
|
+
|
|
7
|
+
## Exact metadata contract
|
|
8
|
+
|
|
9
|
+
<!-- funnelsgrove:generated:start contract-v3/step/purchase_completed -->
|
|
10
|
+
### Generated contract facts — do not edit
|
|
11
|
+
|
|
12
|
+
- Step contract version: `3`
|
|
13
|
+
- Contract hash: `d761e91d5ac6ff9e72c6d49c5bcd014270912473a66f99c49d726c65998085cf`
|
|
14
|
+
- Type: `purchase_completed`
|
|
15
|
+
- Family: `terminal`
|
|
16
|
+
- Description: The canonical terminal shown after a verified initial purchase.
|
|
17
|
+
- Action owner: `step`
|
|
18
|
+
- Analytics role: `purchase-completed`
|
|
19
|
+
- Terminal: `true`
|
|
20
|
+
- Required kind: `subscription-handoff`
|
|
21
|
+
- Allowed kinds: `subscription-handoff`
|
|
22
|
+
- Allowed semantic events: `funnel_completed`
|
|
23
|
+
- Forbidden capabilities: `choice-write`, `email-capture`, `checkout`, `subscription-management`, `hardcoded-navigation`, `provider-direct-analytics`, `browser-registration-completed`
|
|
24
|
+
|
|
25
|
+
#### Choice contract
|
|
26
|
+
|
|
27
|
+
_Not a choice type._
|
|
28
|
+
|
|
29
|
+
#### Automatic lifecycle events
|
|
30
|
+
|
|
31
|
+
`first_step_clicked`, `first_step_viewed`, `funnel_started`, `step_completed`, `step_exited`, `step_started`
|
|
32
|
+
|
|
33
|
+
#### Approved capability owners
|
|
34
|
+
|
|
35
|
+
- `subscription-handoff` must be owned by `runtime-handoff-helper`.
|
|
36
|
+
|
|
37
|
+
#### Reserved identities
|
|
38
|
+
|
|
39
|
+
- `subscription-started`: id=`subscription-started`, name=`subscription-started`; type=`purchase_completed`; kind=`subscription-handoff`; unique=`true`
|
|
40
|
+
|
|
41
|
+
#### Golden fixture source
|
|
42
|
+
|
|
43
|
+
```ts
|
|
44
|
+
import type { FunnelContextValue, FunnelManifestStep, FunnelStepMeta } from '@funnelsgrove/runtime';
|
|
45
|
+
|
|
46
|
+
const terminalCompletionHelper = 'completeFunnel' as const satisfies keyof FunnelContextValue;
|
|
47
|
+
|
|
48
|
+
const manifestStep = {
|
|
49
|
+
id: 'subscription-started',
|
|
50
|
+
name: 'subscription-started',
|
|
51
|
+
path: '/subscription-started',
|
|
52
|
+
filePath: 'src/steps/step-subscription-started.tsx',
|
|
53
|
+
componentKey: 'stepSubscriptionStarted',
|
|
54
|
+
type: 'purchase_completed',
|
|
55
|
+
kind: 'subscription-handoff',
|
|
56
|
+
title: 'Purchase completed',
|
|
57
|
+
} as const satisfies FunnelManifestStep;
|
|
58
|
+
|
|
59
|
+
const componentMeta = {
|
|
60
|
+
id: 'subscription-started',
|
|
61
|
+
name: 'subscription-started',
|
|
62
|
+
type: 'purchase_completed',
|
|
63
|
+
kind: 'subscription-handoff',
|
|
64
|
+
figmaNodeId: 'golden:purchase-completed',
|
|
65
|
+
title: 'Purchase completed',
|
|
66
|
+
description: 'Complete the funnel after purchase and continue into the app.',
|
|
67
|
+
} as const satisfies FunnelStepMeta;
|
|
68
|
+
|
|
69
|
+
export const goldenFixture = {
|
|
70
|
+
stepType: 'purchase_completed',
|
|
71
|
+
manifestStep,
|
|
72
|
+
componentMeta,
|
|
73
|
+
helper: 'runtime handoff helper',
|
|
74
|
+
semanticHelpers: [terminalCompletionHelper],
|
|
75
|
+
forbiddenBrowserEvents: ['purchase_completed', 'registration_completed'],
|
|
76
|
+
} as const;
|
|
77
|
+
```
|
|
78
|
+
<!-- funnelsgrove:generated:end contract-v3/step/purchase_completed -->
|
|
79
|
+
|
|
80
|
+
## Interaction and persisted answer shape
|
|
81
|
+
|
|
82
|
+
The runtime terminal/handoff helper owns completion and destination construction. No choice answer is persisted.
|
|
83
|
+
|
|
84
|
+
## Automatic lifecycle events
|
|
85
|
+
|
|
86
|
+
`completeFunnel(stepId)` atomically claims the active terminal visit, emits the normal step completion and one deduplicated `funnel_completed`, then flushes before outbound handoff. Preview/editor still claims the local completion outcome while suppressing persistence and provider delivery.
|
|
87
|
+
|
|
88
|
+
## Required semantic conversions
|
|
89
|
+
|
|
90
|
+
The browser may request lifecycle-only funnel completion. The business conversion `purchase_completed` is trusted-server-only after the backend verifies a successful initial subscription or one-time payment. `registration_completed` remains a separate later app-link claim.
|
|
91
|
+
|
|
92
|
+
## Approved shared helpers
|
|
93
|
+
|
|
94
|
+
Use `completeFunnel` through the runtime handoff surface. The reserved terminal passes `completionMode="funnel"` to `SubscriptionHandoffScreen`; the shared component defaults to `completionMode="step"` for non-terminal handoffs.
|
|
95
|
+
|
|
96
|
+
## MUST rules
|
|
97
|
+
|
|
98
|
+
- Preserve the reserved `subscription-started` identity.
|
|
99
|
+
- Complete the funnel once before the app handoff.
|
|
100
|
+
- Keep terminal completion mode explicit; only the current `purchase_completed` terminal may call `completeFunnel`.
|
|
101
|
+
|
|
102
|
+
## NEVER rules
|
|
103
|
+
|
|
104
|
+
- Never emit `purchase_completed` in browser code.
|
|
105
|
+
- Never treat terminal reach, `funnel_completed`, a pending payment, or a renewal as purchase verification.
|
|
106
|
+
|
|
107
|
+
## Golden template or fixture
|
|
108
|
+
|
|
109
|
+
See the [embedded canonical fixture](#golden-fixture-source) generated from `purchase_completed.fixture.ts`.
|
|
110
|
+
|
|
111
|
+
## Validation command
|
|
112
|
+
|
|
113
|
+
Run `fgrove validate`.
|
|
114
|
+
|
|
115
|
+
## Manual QA and completion criteria
|
|
116
|
+
|
|
117
|
+
Confirm funnel completion is deduplicated, the trusted purchase event requires backend verification, preview is silent, and the app destination works.
|