@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,43 @@
|
|
|
1
|
+
# Analytics QA
|
|
2
|
+
|
|
3
|
+
<!-- funnelsgrove:generated:start contract-v3/qa/analytics -->
|
|
4
|
+
Step contract version: `3`
|
|
5
|
+
|
|
6
|
+
Contract hash: `d761e91d5ac6ff9e72c6d49c5bcd014270912473a66f99c49d726c65998085cf`
|
|
7
|
+
|
|
8
|
+
| Contract key | Public event | Raw event | Allowed step types | Allowed identities | Owner | Automatic | Dedupe | Required metadata |
|
|
9
|
+
| --- | --- | --- | --- | --- | --- | --- | --- | --- |
|
|
10
|
+
| `add_payment_info` | `add_payment_info` | `add_payment_info` | `paywall_offer`, `upsell_offer`, `checkout` | `any` | `named-helper` | `false` | `event-id` | `funnelId`, `funnelVersionId`, `environment`, `stepContractVersion`, `stepId`, `stepName`, `stepType`, `eventId` |
|
|
11
|
+
| `checkout_completed` | `checkout_completed` | `checkout_completed` | `paywall_offer`, `upsell_offer`, `checkout` | `any` | `named-helper` | `false` | `event-id` | `funnelId`, `funnelVersionId`, `environment`, `stepContractVersion`, `stepId`, `stepName`, `stepType`, `eventId` |
|
|
12
|
+
| `checkout_started` | `checkout_started` | `checkout_started` | `paywall_offer`, `upsell_offer`, `checkout` | `any` | `named-helper` | `false` | `event-id` | `funnelId`, `funnelVersionId`, `environment`, `stepContractVersion`, `stepId`, `stepName`, `stepType`, `eventId` |
|
|
13
|
+
| `email_captured` | `email_captured` | `email_captured` | `form_input` | `email-capture` | `transactional-server` | `false` | `logical-email-conversion` | `funnelId`, `funnelVersionId`, `environment`, `stepContractVersion`, `stepId`, `stepName`, `stepType`, `projectId`, `funnelEndUserId`, `eventId` |
|
|
14
|
+
| `first_step_clicked` | `first_step_clicked` | `first_step_clicked` | `any` | `any` | `controller` | `true` | `step-visit` | `funnelId`, `funnelVersionId`, `environment`, `stepContractVersion`, `stepId`, `stepName`, `stepType` |
|
|
15
|
+
| `first_step_viewed` | `first_step_viewed` | `first_step_viewed` | `any` | `any` | `controller` | `true` | `step-visit` | `funnelId`, `funnelVersionId`, `environment`, `stepContractVersion`, `stepId`, `stepName`, `stepType` |
|
|
16
|
+
| `funnel_completed` | `funnel_completed` | `funnel_completed` | `purchase_completed` | `any` | `terminal-helper` | `false` | `funnel-run` | `funnelId`, `funnelVersionId`, `environment`, `stepContractVersion`, `stepId`, `stepName`, `stepType`, `eventId` |
|
|
17
|
+
| `funnel_started` | `funnel_started` | `funnel_start` | `any` | `any` | `controller` | `true` | `funnel-run` | `funnelId`, `funnelVersionId`, `environment`, `stepContractVersion` |
|
|
18
|
+
| `purchase_completed` | `purchase_completed` | `purchase_completed` | _None_ | _None_ | `trusted-server` | `false` | `provider-payment` | `funnelId`, `funnelVersionId`, `environment`, `stepContractVersion`, `projectId`, `funnelEndUserId`, `eventId`, `providerPaymentId`, `purchaseKind` |
|
|
19
|
+
| `registration_completed` | `registration_completed` | `registration_completed` | _None_ | _None_ | `trusted-server` | `false` | `subscription-claim` | `funnelId`, `funnelVersionId`, `environment`, `stepContractVersion`, `projectId`, `funnelEndUserId`, `eventId`, `subscriptionClaimId` |
|
|
20
|
+
| `step_completed` | `step_completed` | `step_end` | `any` | `any` | `controller` | `true` | `step-visit` | `funnelId`, `funnelVersionId`, `environment`, `stepContractVersion`, `stepId`, `stepName`, `stepType` |
|
|
21
|
+
| `step_engaged` | `step_engaged` | `step_engaged` | `any` | `any` | `controller` | `false` | `step-visit` | `funnelId`, `funnelVersionId`, `environment`, `stepContractVersion`, `stepId`, `stepName`, `stepType`, `durationMs` |
|
|
22
|
+
| `step_exited` | `step_exited` | `step_exit` | `any` | `any` | `controller` | `true` | `step-visit` | `funnelId`, `funnelVersionId`, `environment`, `stepContractVersion`, `stepId`, `stepName`, `stepType` |
|
|
23
|
+
| `step_started` | `step_started` | `step_start` | `any` | `any` | `controller` | `true` | `step-visit` | `funnelId`, `funnelVersionId`, `environment`, `stepContractVersion`, `stepId`, `stepName`, `stepType` |
|
|
24
|
+
<!-- funnelsgrove:generated:end contract-v3/qa/analytics -->
|
|
25
|
+
|
|
26
|
+
## Journey assertions
|
|
27
|
+
|
|
28
|
+
- Funnel start occurs once per run.
|
|
29
|
+
- Each visit has one start and exactly one completion or exit.
|
|
30
|
+
- First-step view/click dedupe correctly.
|
|
31
|
+
- If an explicit qualified policy emits `step_engaged`, it includes `durationMs` and deduplicates per visit; no default engagement event is expected.
|
|
32
|
+
- Choice steps save the exact stable ID shape before completion.
|
|
33
|
+
- Email success creates one server conversion; duplicate capture skips browser fanout; failure changes no state/lifecycle/route.
|
|
34
|
+
- Checkout helpers fire only at real boundaries with complete metadata and stable event IDs.
|
|
35
|
+
- Quiz completed requires trusted-server `purchase_completed`, deduplicated by `provider-payment`; browser `funnel_completed` is lifecycle-only and never satisfies it.
|
|
36
|
+
- `registration_completed` remains the separate later app-link claim.
|
|
37
|
+
- Preview sends no API/provider analytics.
|
|
38
|
+
- No component sends PostHog or server Meta directly.
|
|
39
|
+
- Never put raw email or other PII in analytics event metadata or logs.
|
|
40
|
+
- Only the server delivery boundary may use raw email as Meta hashing input.
|
|
41
|
+
- PostHog properties must remain non-PII.
|
|
42
|
+
|
|
43
|
+
Inspect raw events and user state, not only dashboard totals. Finish by running `fgrove validate`.
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Local QA
|
|
2
|
+
|
|
3
|
+
<!-- funnelsgrove:generated:start contract-v3/qa/local -->
|
|
4
|
+
Step contract version: `3`
|
|
5
|
+
|
|
6
|
+
Contract hash: `d761e91d5ac6ff9e72c6d49c5bcd014270912473a66f99c49d726c65998085cf`
|
|
7
|
+
|
|
8
|
+
| Capability | Allowed types | Allowed identities | Required owner |
|
|
9
|
+
| --- | --- | --- | --- |
|
|
10
|
+
| `browser-registration-completed` | _None_ | _None_ | `trusted-subscription-claim-server` |
|
|
11
|
+
| `checkout` | `paywall_offer`, `upsell_offer`, `checkout` | `any` | `named-payment-helpers` |
|
|
12
|
+
| `choice-write` | `single_step_choice`, `single_step_choice_emoji`, `multi_select_choice` | `any` | `useStepChoices` |
|
|
13
|
+
| `email-capture` | `form_input` | `email-capture` | `submitEmailCapture` |
|
|
14
|
+
| `hardcoded-navigation` | _None_ | _None_ | `manifest-flow-controller` |
|
|
15
|
+
| `provider-direct-analytics` | _None_ | _None_ | `analytics-adapter-outbox` |
|
|
16
|
+
| `subscription-handoff` | `subscription_handoff`, `purchase_completed` | `any` | `runtime-handoff-helper` |
|
|
17
|
+
| `subscription-management` | `subscription_management`, `cancellation_offer` | `any` | `runtime-subscription-helpers` |
|
|
18
|
+
<!-- funnelsgrove:generated:end contract-v3/qa/local -->
|
|
19
|
+
|
|
20
|
+
## Automated gate
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
npm run test:run
|
|
24
|
+
npm run lint
|
|
25
|
+
fgrove validate
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Run the repository’s focused tests first, then its full validation gate. Also run `npm run docs:funnel-agent:check` when editing this source bundle.
|
|
29
|
+
|
|
30
|
+
## Manual gate
|
|
31
|
+
|
|
32
|
+
- Test small 375×667, medium 393×852, large 402×874, and desktop-small 1280×800.
|
|
33
|
+
- At every declared breakpoint, require no horizontal scrolling, clipping, or overlap. Hiding overflow does not pass when content is clipped.
|
|
34
|
+
- Keep the choice/input primary CTA visible without scrolling and every interactive tap target at least 44×44 CSS px.
|
|
35
|
+
- Check pointer, keyboard, focus, loading, error, retry, refresh, back, and exit.
|
|
36
|
+
- Verify answer persistence and manifest routes.
|
|
37
|
+
- Assert every `assetId` resolves. Inspect the network to prove only current and likely-next assets preload; metadata alone is not proof.
|
|
38
|
+
- Confirm theme values come from `src/theme/theme.ts` through emitted CSS variables rather than duplicated step-local constants.
|
|
39
|
+
- Verify preview suppresses remote API/provider delivery.
|
|
40
|
+
- Inspect the console and network for errors or duplicate requests.
|
|
41
|
+
|
|
42
|
+
Complete the type-specific checklist in the [step-type index](../steps/INDEX.md).
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# Paywall and checkout QA
|
|
2
|
+
|
|
3
|
+
<!-- funnelsgrove:generated:start contract-v3/qa/paywall-checkout -->
|
|
4
|
+
Step contract version: `3`
|
|
5
|
+
|
|
6
|
+
Contract hash: `d761e91d5ac6ff9e72c6d49c5bcd014270912473a66f99c49d726c65998085cf`
|
|
7
|
+
|
|
8
|
+
### Generated contract facts — do not edit
|
|
9
|
+
|
|
10
|
+
- Step contract version: `3`
|
|
11
|
+
- Contract hash: `d761e91d5ac6ff9e72c6d49c5bcd014270912473a66f99c49d726c65998085cf`
|
|
12
|
+
- Type: `paywall_offer`
|
|
13
|
+
- Family: `commerce`
|
|
14
|
+
- Description: A monetization offer that presents purchasable plans.
|
|
15
|
+
- Action owner: `step`
|
|
16
|
+
- Analytics role: `paywall`
|
|
17
|
+
- Terminal: `false`
|
|
18
|
+
- Required kind: `paywall`
|
|
19
|
+
- Allowed kinds: `paywall`
|
|
20
|
+
- Allowed semantic events: `checkout_started`, `add_payment_info`, `checkout_completed`
|
|
21
|
+
- Forbidden capabilities: `choice-write`, `email-capture`, `subscription-management`, `subscription-handoff`, `hardcoded-navigation`, `provider-direct-analytics`, `browser-registration-completed`
|
|
22
|
+
|
|
23
|
+
#### Choice contract
|
|
24
|
+
|
|
25
|
+
_Not a choice type._
|
|
26
|
+
|
|
27
|
+
#### Automatic lifecycle events
|
|
28
|
+
|
|
29
|
+
`first_step_clicked`, `first_step_viewed`, `funnel_started`, `step_completed`, `step_exited`, `step_started`
|
|
30
|
+
|
|
31
|
+
#### Approved capability owners
|
|
32
|
+
|
|
33
|
+
- `checkout` must be owned by `named-payment-helpers`.
|
|
34
|
+
|
|
35
|
+
#### Reserved identities
|
|
36
|
+
|
|
37
|
+
- `paywall`: id=`paywall`, name=`paywall`; type=`paywall_offer`; kind=`paywall`; primary=`true`; unique=`true`
|
|
38
|
+
- `paywall-variant`: idPattern=`^paywall-[a-z0-9-]+$`, namePattern=`^paywall-[a-z0-9-]+$`; type=`paywall_offer`; kind=`paywall`; primary=`false`; unique=`false`
|
|
39
|
+
<!-- funnelsgrove:generated:end contract-v3/qa/paywall-checkout -->
|
|
40
|
+
|
|
41
|
+
## Classification and metadata
|
|
42
|
+
|
|
43
|
+
- Confirm only screens with purchasable plans are paywalls.
|
|
44
|
+
- Confirm primary and variant identities, types, kinds, paths, and component parity.
|
|
45
|
+
- Confirm no secrets or provider IDs appear in JSX/client configuration.
|
|
46
|
+
|
|
47
|
+
## Purchase paths
|
|
48
|
+
|
|
49
|
+
- Verify every plan, price, currency, discount, and eligibility rule.
|
|
50
|
+
- Test card and every enabled wallet.
|
|
51
|
+
- Test validation, decline, retry, cancel, double-submit, and provider delay.
|
|
52
|
+
- Verify named checkout events, complete metadata, one event ID, and retry deduplication.
|
|
53
|
+
- Verify success routing and the `purchase_completed` terminal handoff.
|
|
54
|
+
|
|
55
|
+
Run `fgrove validate` after all checks.
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Publish QA
|
|
2
|
+
|
|
3
|
+
<!-- funnelsgrove:generated:start contract-v3/qa/publish -->
|
|
4
|
+
Step contract version: `3`
|
|
5
|
+
|
|
6
|
+
Contract hash: `d761e91d5ac6ff9e72c6d49c5bcd014270912473a66f99c49d726c65998085cf`
|
|
7
|
+
|
|
8
|
+
| Capability | Allowed types | Allowed identities | Required owner |
|
|
9
|
+
| --- | --- | --- | --- |
|
|
10
|
+
| `browser-registration-completed` | _None_ | _None_ | `trusted-subscription-claim-server` |
|
|
11
|
+
| `checkout` | `paywall_offer`, `upsell_offer`, `checkout` | `any` | `named-payment-helpers` |
|
|
12
|
+
| `choice-write` | `single_step_choice`, `single_step_choice_emoji`, `multi_select_choice` | `any` | `useStepChoices` |
|
|
13
|
+
| `email-capture` | `form_input` | `email-capture` | `submitEmailCapture` |
|
|
14
|
+
| `hardcoded-navigation` | _None_ | _None_ | `manifest-flow-controller` |
|
|
15
|
+
| `provider-direct-analytics` | _None_ | _None_ | `analytics-adapter-outbox` |
|
|
16
|
+
| `subscription-handoff` | `subscription_handoff`, `purchase_completed` | `any` | `runtime-handoff-helper` |
|
|
17
|
+
| `subscription-management` | `subscription_management`, `cancellation_offer` | `any` | `runtime-subscription-helpers` |
|
|
18
|
+
<!-- funnelsgrove:generated:end contract-v3/qa/publish -->
|
|
19
|
+
|
|
20
|
+
## Preview gate
|
|
21
|
+
|
|
22
|
+
1. Run `fgrove status`, `git status --short`, tests, lint, `fgrove validate`, and relevant local/analytics/payment QA.
|
|
23
|
+
2. Choose exactly one source path. GitHub-connected funnels use git push, `fgrove github pull`, terminal status, then publish; never use `fgrove sync up` for the same diff. Non-GitHub funnels use `fgrove sync up`.
|
|
24
|
+
3. Publish preview with a clear message.
|
|
25
|
+
4. Test the preview URL across supported breakpoints and real navigation entry points.
|
|
26
|
+
5. Confirm preview-mode suppression and production configuration separation.
|
|
27
|
+
6. Review route, analytics, answer, experiment, and payment evidence.
|
|
28
|
+
7. Confirm the `imageVariants` stage completed, supported browsers receive AVIF/WebP, and the original raster remains the fallback.
|
|
29
|
+
|
|
30
|
+
## Production gate
|
|
31
|
+
|
|
32
|
+
Publish production only after explicit approval and successful preview QA. Confirm the selected project/funnel/environment immediately before publishing, then smoke-test the live journey without creating duplicate conversions.
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Recipe: add an experiment
|
|
2
|
+
|
|
3
|
+
<!-- funnelsgrove:generated:start contract-v3/recipe/add-experiment -->
|
|
4
|
+
Step contract version: `3`
|
|
5
|
+
|
|
6
|
+
Contract hash: `d761e91d5ac6ff9e72c6d49c5bcd014270912473a66f99c49d726c65998085cf`
|
|
7
|
+
|
|
8
|
+
| Capability | Allowed types | Allowed identities | Required owner |
|
|
9
|
+
| --- | --- | --- | --- |
|
|
10
|
+
| `browser-registration-completed` | _None_ | _None_ | `trusted-subscription-claim-server` |
|
|
11
|
+
| `checkout` | `paywall_offer`, `upsell_offer`, `checkout` | `any` | `named-payment-helpers` |
|
|
12
|
+
| `choice-write` | `single_step_choice`, `single_step_choice_emoji`, `multi_select_choice` | `any` | `useStepChoices` |
|
|
13
|
+
| `email-capture` | `form_input` | `email-capture` | `submitEmailCapture` |
|
|
14
|
+
| `hardcoded-navigation` | _None_ | _None_ | `manifest-flow-controller` |
|
|
15
|
+
| `provider-direct-analytics` | _None_ | _None_ | `analytics-adapter-outbox` |
|
|
16
|
+
| `subscription-handoff` | `subscription_handoff`, `purchase_completed` | `any` | `runtime-handoff-helper` |
|
|
17
|
+
| `subscription-management` | `subscription_management`, `cancellation_offer` | `any` | `runtime-subscription-helpers` |
|
|
18
|
+
<!-- funnelsgrove:generated:end contract-v3/recipe/add-experiment -->
|
|
19
|
+
|
|
20
|
+
## Procedure
|
|
21
|
+
|
|
22
|
+
1. Build and validate every control/variant step before activation.
|
|
23
|
+
2. Give each variant a stable, contract-compliant identity and normal outgoing edge.
|
|
24
|
+
3. Create the experiment through FunnelsGrove so the platform owns the database row, feature flag, and generated experiment snapshot.
|
|
25
|
+
4. Keep variant keys, labels, traffic percentages, source step, and route targets aligned.
|
|
26
|
+
5. Resolve assignment and any redirect before creating the destination step visit.
|
|
27
|
+
6. Keep the default flow valid when the experiment is stopped or assignment is unavailable.
|
|
28
|
+
7. Run experiment-focused tests, then `fgrove validate`.
|
|
29
|
+
|
|
30
|
+
## Pre-activation QA
|
|
31
|
+
|
|
32
|
+
Force every assignment, verify analytics metadata and deduplication, confirm refresh keeps assignment, test missing/invalid flags, and leave inactive variants unreachable from the default flow.
|
|
33
|
+
|
|
34
|
+
Pre-activation, missing-assignment, invalid-assignment, and fallback paths must not create phantom `step_started`, `step_completed`, or `step_exited` events.
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Recipe: add a step
|
|
2
|
+
|
|
3
|
+
<!-- funnelsgrove:generated:start contract-v3/recipe/add-step -->
|
|
4
|
+
Step contract version: `3`
|
|
5
|
+
|
|
6
|
+
Contract hash: `d761e91d5ac6ff9e72c6d49c5bcd014270912473a66f99c49d726c65998085cf`
|
|
7
|
+
|
|
8
|
+
| Capability | Allowed types | Allowed identities | Required owner |
|
|
9
|
+
| --- | --- | --- | --- |
|
|
10
|
+
| `browser-registration-completed` | _None_ | _None_ | `trusted-subscription-claim-server` |
|
|
11
|
+
| `checkout` | `paywall_offer`, `upsell_offer`, `checkout` | `any` | `named-payment-helpers` |
|
|
12
|
+
| `choice-write` | `single_step_choice`, `single_step_choice_emoji`, `multi_select_choice` | `any` | `useStepChoices` |
|
|
13
|
+
| `email-capture` | `form_input` | `email-capture` | `submitEmailCapture` |
|
|
14
|
+
| `hardcoded-navigation` | _None_ | _None_ | `manifest-flow-controller` |
|
|
15
|
+
| `provider-direct-analytics` | _None_ | _None_ | `analytics-adapter-outbox` |
|
|
16
|
+
| `subscription-handoff` | `subscription_handoff`, `purchase_completed` | `any` | `runtime-handoff-helper` |
|
|
17
|
+
| `subscription-management` | `subscription_management`, `cancellation_offer` | `any` | `runtime-subscription-helpers` |
|
|
18
|
+
<!-- funnelsgrove:generated:end contract-v3/recipe/add-step -->
|
|
19
|
+
|
|
20
|
+
## Procedure
|
|
21
|
+
|
|
22
|
+
1. Choose the exact type from the [step-type index](../steps/INDEX.md).
|
|
23
|
+
2. Add the component and exported metadata.
|
|
24
|
+
3. Add matching manifest metadata, path, file path, and component key.
|
|
25
|
+
4. Add the registry entry.
|
|
26
|
+
5. Add content/editor definitions and registry entries only when builder-editable.
|
|
27
|
+
6. Add manifest edges, branches, assets, and tests required by the behavior.
|
|
28
|
+
7. Start from the type’s golden fixture and preserve answer/helper semantics.
|
|
29
|
+
8. Run focused tests, then `fgrove validate`.
|
|
30
|
+
|
|
31
|
+
## Manual QA
|
|
32
|
+
|
|
33
|
+
Render at all default breakpoints; test keyboard/pointer interaction, refresh/back/exit, answer persistence, lifecycle events, and every outgoing route. The recipe is complete only when the matching QA checklist passes.
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Recipe: edit a step
|
|
2
|
+
|
|
3
|
+
<!-- funnelsgrove:generated:start contract-v3/recipe/edit-step -->
|
|
4
|
+
Step contract version: `3`
|
|
5
|
+
|
|
6
|
+
Contract hash: `d761e91d5ac6ff9e72c6d49c5bcd014270912473a66f99c49d726c65998085cf`
|
|
7
|
+
|
|
8
|
+
| Capability | Allowed types | Allowed identities | Required owner |
|
|
9
|
+
| --- | --- | --- | --- |
|
|
10
|
+
| `browser-registration-completed` | _None_ | _None_ | `trusted-subscription-claim-server` |
|
|
11
|
+
| `checkout` | `paywall_offer`, `upsell_offer`, `checkout` | `any` | `named-payment-helpers` |
|
|
12
|
+
| `choice-write` | `single_step_choice`, `single_step_choice_emoji`, `multi_select_choice` | `any` | `useStepChoices` |
|
|
13
|
+
| `email-capture` | `form_input` | `email-capture` | `submitEmailCapture` |
|
|
14
|
+
| `hardcoded-navigation` | _None_ | _None_ | `manifest-flow-controller` |
|
|
15
|
+
| `provider-direct-analytics` | _None_ | _None_ | `analytics-adapter-outbox` |
|
|
16
|
+
| `subscription-handoff` | `subscription_handoff`, `purchase_completed` | `any` | `runtime-handoff-helper` |
|
|
17
|
+
| `subscription-management` | `subscription_management`, `cancellation_offer` | `any` | `runtime-subscription-helpers` |
|
|
18
|
+
<!-- funnelsgrove:generated:end contract-v3/recipe/edit-step -->
|
|
19
|
+
|
|
20
|
+
## Procedure
|
|
21
|
+
|
|
22
|
+
1. Read the current type page from the [step-type index](../steps/INDEX.md).
|
|
23
|
+
2. Decide whether the requested behavior still matches the existing type.
|
|
24
|
+
3. Preserve stable IDs, names, paths, answer keys, option IDs, and reserved identities unless the request is an explicit migration.
|
|
25
|
+
4. Update component, content/editor, registry, manifest, and tests only where the change requires.
|
|
26
|
+
5. Keep component and manifest metadata in parity.
|
|
27
|
+
6. Run focused tests, then `fgrove validate`.
|
|
28
|
+
|
|
29
|
+
## Manual QA
|
|
30
|
+
|
|
31
|
+
Re-run the complete current interaction, not just the changed visual state. Confirm existing analytics keys, answer shapes, lifecycle outcome, and routes remain intact.
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Step-type index
|
|
2
|
+
|
|
3
|
+
Choose the page whose type describes the screen's actual behavior. Do not classify from its position or visual treatment.
|
|
4
|
+
|
|
5
|
+
| Type | Family | Use |
|
|
6
|
+
| --- | --- | --- |
|
|
7
|
+
| [`cancellation_offer`](cancellation_offer.md) | `commerce` | A cancellation retention or downsell surface. |
|
|
8
|
+
| [`checkout`](checkout.md) | `commerce` | A dedicated payment-entry screen. |
|
|
9
|
+
| [`form_input`](form_input.md) | `form` | Non-choice structured input, including reserved email capture. |
|
|
10
|
+
| [`intro_hero`](intro_hero.md) | `content` | Opening promise or low-friction entry screen. |
|
|
11
|
+
| [`multi_select_choice`](multi_select_choice.md) | `choice` | Multiple options are selected before explicit completion. |
|
|
12
|
+
| [`paywall_offer`](paywall_offer.md) | `commerce` | A monetization offer that presents purchasable plans. |
|
|
13
|
+
| [`progress_interstitial`](progress_interstitial.md) | `transition` | Progress, calculation, loading, reveal, or transition screen. |
|
|
14
|
+
| [`purchase_completed`](purchase_completed.md) | `terminal` | The canonical terminal shown after a verified initial purchase. |
|
|
15
|
+
| [`single_step_choice`](single_step_choice.md) | `choice` | Exactly one standard option is selected. |
|
|
16
|
+
| [`single_step_choice_emoji`](single_step_choice_emoji.md) | `choice` | Exactly one emoji-led option is selected. |
|
|
17
|
+
| [`social_proof`](social_proof.md) | `content` | Testimonials, reviews, credibility, or evidence. |
|
|
18
|
+
| [`subscription_handoff`](subscription_handoff.md) | `commerce` | A non-terminal app, store, or deep-link handoff. |
|
|
19
|
+
| [`subscription_management`](subscription_management.md) | `commerce` | A screen for managing or inspecting an existing subscription. |
|
|
20
|
+
| [`summary_confirmation`](summary_confirmation.md) | `content` | A summary, review, or confirmation before the next action. |
|
|
21
|
+
| [`upsell_offer`](upsell_offer.md) | `commerce` | A post-purchase or upgrade offer. |
|
|
22
|
+
| [`value_prop_story`](value_prop_story.md) | `content` | Benefit, explanation, motivation, or narrative value screen. |
|
|
23
|
+
|
|
24
|
+
Contract version: `3`
|
|
25
|
+
|
|
26
|
+
Contract hash: `d761e91d5ac6ff9e72c6d49c5bcd014270912473a66f99c49d726c65998085cf`
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
# `cancellation_offer`
|
|
2
|
+
|
|
3
|
+
## Use when / do not use when
|
|
4
|
+
|
|
5
|
+
Use for cancellation retention or a downsell. Do not use for subscription overview, acquisition paywall, or ordinary upsell.
|
|
6
|
+
|
|
7
|
+
## Exact metadata contract
|
|
8
|
+
|
|
9
|
+
<!-- funnelsgrove:generated:start contract-v3/step/cancellation_offer -->
|
|
10
|
+
### Generated contract facts — do not edit
|
|
11
|
+
|
|
12
|
+
- Step contract version: `3`
|
|
13
|
+
- Contract hash: `d761e91d5ac6ff9e72c6d49c5bcd014270912473a66f99c49d726c65998085cf`
|
|
14
|
+
- Type: `cancellation_offer`
|
|
15
|
+
- Family: `commerce`
|
|
16
|
+
- Description: A cancellation retention or downsell surface.
|
|
17
|
+
- Action owner: `step`
|
|
18
|
+
- Analytics role: _none_
|
|
19
|
+
- Terminal: `false`
|
|
20
|
+
- Required kind: `cancellation`
|
|
21
|
+
- Allowed kinds: `cancellation`
|
|
22
|
+
- Allowed semantic events: _None_
|
|
23
|
+
- Forbidden capabilities: `choice-write`, `email-capture`, `checkout`, `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
|
+
- `subscription-management` must be owned by `runtime-subscription-helpers`.
|
|
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: 'save-offer',
|
|
48
|
+
name: 'save-offer',
|
|
49
|
+
path: '/save-offer',
|
|
50
|
+
filePath: 'src/steps/step-save-offer.tsx',
|
|
51
|
+
componentKey: 'stepSaveOffer',
|
|
52
|
+
type: 'cancellation_offer',
|
|
53
|
+
kind: 'cancellation',
|
|
54
|
+
title: 'Stay with us',
|
|
55
|
+
} as const satisfies FunnelManifestStep;
|
|
56
|
+
|
|
57
|
+
const componentMeta = {
|
|
58
|
+
id: 'save-offer',
|
|
59
|
+
name: 'save-offer',
|
|
60
|
+
type: 'cancellation_offer',
|
|
61
|
+
kind: 'cancellation',
|
|
62
|
+
figmaNodeId: 'golden:cancellation-offer',
|
|
63
|
+
title: 'Stay with us',
|
|
64
|
+
description: 'Offer a retention path before cancellation.',
|
|
65
|
+
} as const satisfies FunnelStepMeta;
|
|
66
|
+
|
|
67
|
+
export const goldenFixture = {
|
|
68
|
+
stepType: 'cancellation_offer',
|
|
69
|
+
manifestStep,
|
|
70
|
+
componentMeta,
|
|
71
|
+
helper: 'runtime subscription helpers',
|
|
72
|
+
} as const;
|
|
73
|
+
```
|
|
74
|
+
<!-- funnelsgrove:generated:end contract-v3/step/cancellation_offer -->
|
|
75
|
+
|
|
76
|
+
## Interaction and persisted answer shape
|
|
77
|
+
|
|
78
|
+
Use runtime subscription helpers for keep/cancel/offer actions. Do not persist provider state as a funnel answer.
|
|
79
|
+
|
|
80
|
+
## Automatic lifecycle events
|
|
81
|
+
|
|
82
|
+
The controller owns the step outcome; subscription APIs own cancellation state transitions.
|
|
83
|
+
|
|
84
|
+
## Required semantic conversions
|
|
85
|
+
|
|
86
|
+
None in the browser unless a separate server-owned event contract is added.
|
|
87
|
+
|
|
88
|
+
## Approved shared helpers
|
|
89
|
+
|
|
90
|
+
Use runtime subscription helpers and manifest routing.
|
|
91
|
+
|
|
92
|
+
## MUST rules
|
|
93
|
+
|
|
94
|
+
- Preserve the cancellation kind.
|
|
95
|
+
- Make accept, decline, and final cancellation outcomes unambiguous.
|
|
96
|
+
|
|
97
|
+
## NEVER rules
|
|
98
|
+
|
|
99
|
+
- Never claim a save before server confirmation.
|
|
100
|
+
- Never send provider analytics directly.
|
|
101
|
+
|
|
102
|
+
## Golden template or fixture
|
|
103
|
+
|
|
104
|
+
See the [embedded canonical fixture](#golden-fixture-source) generated from `cancellation_offer.fixture.ts`.
|
|
105
|
+
|
|
106
|
+
## Validation command
|
|
107
|
+
|
|
108
|
+
Run `fgrove validate`.
|
|
109
|
+
|
|
110
|
+
## Manual QA and completion criteria
|
|
111
|
+
|
|
112
|
+
Test keep, accept offer, continue cancellation, failures/retries, refreshed state, and every resulting route.
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# `checkout`
|
|
2
|
+
|
|
3
|
+
## Use when / do not use when
|
|
4
|
+
|
|
5
|
+
Use for a dedicated payment-entry screen. Do not use for plan merchandising without payment entry or for subscription management.
|
|
6
|
+
|
|
7
|
+
## Exact metadata contract
|
|
8
|
+
|
|
9
|
+
<!-- funnelsgrove:generated:start contract-v3/step/checkout -->
|
|
10
|
+
### Generated contract facts — do not edit
|
|
11
|
+
|
|
12
|
+
- Step contract version: `3`
|
|
13
|
+
- Contract hash: `d761e91d5ac6ff9e72c6d49c5bcd014270912473a66f99c49d726c65998085cf`
|
|
14
|
+
- Type: `checkout`
|
|
15
|
+
- Family: `commerce`
|
|
16
|
+
- Description: A dedicated payment-entry screen.
|
|
17
|
+
- Action owner: `step`
|
|
18
|
+
- Analytics role: _none_
|
|
19
|
+
- Terminal: `false`
|
|
20
|
+
- Required kind: _none_
|
|
21
|
+
- Allowed kinds: _None_
|
|
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
|
+
_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: 'checkout',
|
|
48
|
+
name: 'checkout',
|
|
49
|
+
path: '/checkout',
|
|
50
|
+
filePath: 'src/steps/step-checkout.tsx',
|
|
51
|
+
componentKey: 'stepCheckout',
|
|
52
|
+
type: 'checkout',
|
|
53
|
+
title: 'Secure checkout',
|
|
54
|
+
} as const satisfies FunnelManifestStep;
|
|
55
|
+
|
|
56
|
+
const componentMeta = {
|
|
57
|
+
id: 'checkout',
|
|
58
|
+
name: 'checkout',
|
|
59
|
+
type: 'checkout',
|
|
60
|
+
figmaNodeId: 'golden:checkout',
|
|
61
|
+
title: 'Secure checkout',
|
|
62
|
+
description: 'Collect payment through shared checkout UI.',
|
|
63
|
+
} as const satisfies FunnelStepMeta;
|
|
64
|
+
|
|
65
|
+
export const goldenFixture = {
|
|
66
|
+
stepType: 'checkout',
|
|
67
|
+
manifestStep,
|
|
68
|
+
componentMeta,
|
|
69
|
+
requiredEventMetadata: [
|
|
70
|
+
'funnelId',
|
|
71
|
+
'funnelVersionId',
|
|
72
|
+
'environment',
|
|
73
|
+
'stepContractVersion',
|
|
74
|
+
'stepId',
|
|
75
|
+
'stepName',
|
|
76
|
+
'stepType',
|
|
77
|
+
'eventId',
|
|
78
|
+
],
|
|
79
|
+
semanticHelpers: ['trackCheckoutStarted', 'trackPaymentInfoSubmitted', 'trackCheckoutCompleted'],
|
|
80
|
+
} as const;
|
|
81
|
+
```
|
|
82
|
+
<!-- funnelsgrove:generated:end contract-v3/step/checkout -->
|
|
83
|
+
|
|
84
|
+
## Interaction and persisted answer shape
|
|
85
|
+
|
|
86
|
+
The payment package owns payment state. Do not persist card, wallet, price, or provider data as funnel answers.
|
|
87
|
+
|
|
88
|
+
## Automatic lifecycle events
|
|
89
|
+
|
|
90
|
+
The controller owns step lifecycle. Payment helpers own semantic conversion boundaries and event IDs.
|
|
91
|
+
|
|
92
|
+
## Required semantic conversions
|
|
93
|
+
|
|
94
|
+
Use the named checkout-started, payment-info, and checkout-completed helpers with the complete required metadata returned by runtime context.
|
|
95
|
+
|
|
96
|
+
## Approved shared helpers
|
|
97
|
+
|
|
98
|
+
Use `trackCheckoutStarted`, `trackPaymentInfoSubmitted`, `trackCheckoutCompleted`, and shared checkout UI/runtime helpers.
|
|
99
|
+
|
|
100
|
+
## MUST rules
|
|
101
|
+
|
|
102
|
+
- Keep secrets server-side and provider IDs in configuration.
|
|
103
|
+
- Reuse one event ID per logical conversion and allow safe retries.
|
|
104
|
+
|
|
105
|
+
## NEVER rules
|
|
106
|
+
|
|
107
|
+
- Never capture raw payment details yourself.
|
|
108
|
+
- Never send incomplete, fabricated, or direct-provider analytics.
|
|
109
|
+
|
|
110
|
+
## Golden template or fixture
|
|
111
|
+
|
|
112
|
+
See the [embedded canonical fixture](#golden-fixture-source) generated from `checkout.fixture.ts`.
|
|
113
|
+
|
|
114
|
+
## Validation command
|
|
115
|
+
|
|
116
|
+
Run `fgrove validate`.
|
|
117
|
+
|
|
118
|
+
## Manual QA and completion criteria
|
|
119
|
+
|
|
120
|
+
Test all payment methods, validation, decline, retry, success, deduplication, required metadata, and post-success routing.
|
|
@@ -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.
|