@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
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@funnelsgrove/cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.18",
|
|
4
4
|
"description": "FunnelsGrove command-line tools for editing, syncing, and publishing funnels",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -10,7 +10,13 @@
|
|
|
10
10
|
"files": [
|
|
11
11
|
"dist",
|
|
12
12
|
"README.md",
|
|
13
|
-
"
|
|
13
|
+
"contracts",
|
|
14
|
+
"template_docs",
|
|
15
|
+
"template_scaffold",
|
|
16
|
+
"!template_scaffold/node_modules",
|
|
17
|
+
"template_validation",
|
|
18
|
+
"docs-release-history.json",
|
|
19
|
+
"legacy-docs-catalog.json"
|
|
14
20
|
],
|
|
15
21
|
"publishConfig": {
|
|
16
22
|
"access": "public"
|
|
@@ -18,13 +24,16 @@
|
|
|
18
24
|
"scripts": {
|
|
19
25
|
"build": "rm -rf dist && tsc && chmod +x dist/cli.js",
|
|
20
26
|
"prepack": "npm run build",
|
|
27
|
+
"prepublishOnly": "node ../../scripts/check-cli-release-dependencies.mjs",
|
|
21
28
|
"test": "vitest run"
|
|
22
29
|
},
|
|
23
30
|
"dependencies": {
|
|
24
|
-
"
|
|
31
|
+
"@funnelsgrove/runtime": "0.1.59",
|
|
32
|
+
"commander": "^12.0.0",
|
|
33
|
+
"typescript": "^5.8.3"
|
|
25
34
|
},
|
|
26
35
|
"devDependencies": {
|
|
27
|
-
"
|
|
36
|
+
"@funnelsgrove/analytics": "0.1.36",
|
|
28
37
|
"vitest": "^3.0.0"
|
|
29
38
|
}
|
|
30
39
|
}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"bundleVersion": "2.0.6",
|
|
4
|
+
"stepContractVersion": 3,
|
|
5
|
+
"contractHash": "d761e91d5ac6ff9e72c6d49c5bcd014270912473a66f99c49d726c65998085cf",
|
|
6
|
+
"managedFiles": [
|
|
7
|
+
{
|
|
8
|
+
"path": "AGENTS.md",
|
|
9
|
+
"sha256": "952fbafb5841b8f2e6fadab5032374c98390ef90c1ca0ed27747a38d0cc009d7"
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
"path": "CLAUDE.md",
|
|
13
|
+
"sha256": "336cc4fbf19beaada7ccf9986414fa91851a8d7a07dfb3ccbe800a69eed0ab49"
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
"path": "docs/funnelsgrove/START-HERE.md",
|
|
17
|
+
"sha256": "638615b66f771a36015d747fd8e8a1bf0af311ed24631c3dd041388e8e73c09d"
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"path": "docs/funnelsgrove/contracts/analytics-events.md",
|
|
21
|
+
"sha256": "743ca0d6b3a19b3b9e0bd489b228dab7be73d26073a86aab513a90477da481c6"
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"path": "docs/funnelsgrove/contracts/content-answers.md",
|
|
25
|
+
"sha256": "403b286060dd6cda33757df7c55c5b0e17395f2d90aad0fc133d6ba1919a04b3"
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"path": "docs/funnelsgrove/contracts/flow-routing.md",
|
|
29
|
+
"sha256": "050564846bf7d44afb267e1321d6fe277f032fe7b6237441741570c723543d0e"
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
"path": "docs/funnelsgrove/contracts/payments.md",
|
|
33
|
+
"sha256": "1a003f83fa01dba60bd4bb3365fd0a753dadd73d13fed84fd16b70d1df3d2b60"
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
"path": "docs/funnelsgrove/contracts/step-metadata.md",
|
|
37
|
+
"sha256": "de89a1a672abbe82d0e9c44da536d2a00893bf85fdec225b3aff7ecd7a965f20"
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
"path": "docs/funnelsgrove/migrations/step-contract-v3.md",
|
|
41
|
+
"sha256": "ea1f65198292bfbb2f018fd39f583dfa5c6e1760b77612d804c91d59029ac98d"
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
"path": "docs/funnelsgrove/qa/analytics.md",
|
|
45
|
+
"sha256": "5ac36e547155546be230b9f1df144c7875824686627859c97b43e33d6e3e116d"
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
"path": "docs/funnelsgrove/qa/local.md",
|
|
49
|
+
"sha256": "97da7e26c5dbe8f63e654e4e0a035a4ecfbb9bcfd80db67d45c627141d6a2756"
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
"path": "docs/funnelsgrove/qa/paywall-checkout.md",
|
|
53
|
+
"sha256": "6fc887772e52ddd99ab70d898d8fd9b89869ca49ce1b49152d232cbe32865aae"
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
"path": "docs/funnelsgrove/qa/publish.md",
|
|
57
|
+
"sha256": "82b05b8c6eebf25d32d2cff6f05b08bc39661dcbb46caa6b912de6b803aed39c"
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
"path": "docs/funnelsgrove/recipes/add-experiment.md",
|
|
61
|
+
"sha256": "832b4331d6690d0596800c5aeb969f608dd62cf63d9ae527054e832fb60f8abd"
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
"path": "docs/funnelsgrove/recipes/add-step.md",
|
|
65
|
+
"sha256": "fba92b8394b0d622b9886a677af38ddb78042a633c60ab5cb6b1ff600abe2cb9"
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
"path": "docs/funnelsgrove/recipes/edit-step.md",
|
|
69
|
+
"sha256": "49eb688c0b3145c025dffe30a9be35e5f5e018da66cbeddf2a08af6a1cc250dc"
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
"path": "docs/funnelsgrove/steps/INDEX.md",
|
|
73
|
+
"sha256": "86db94292eae2fffcd89795dedeab1eca32ce4d360d36f5d4b0806698642384f"
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
"path": "docs/funnelsgrove/steps/cancellation_offer.md",
|
|
77
|
+
"sha256": "144e31d14c8a3cc832abcb5404f47da67308c412ec630f88b8ef54cb19a6f73a"
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
"path": "docs/funnelsgrove/steps/checkout.md",
|
|
81
|
+
"sha256": "272ce5ae593bd8354e18f20a529daf39005226ca3f57b89db20095017d64c94f"
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
"path": "docs/funnelsgrove/steps/form_input.md",
|
|
85
|
+
"sha256": "650a2d84cabf309f90fa7d37ac4101ea4002b2f2da4548ce80ed86f2194eba9e"
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
"path": "docs/funnelsgrove/steps/intro_hero.md",
|
|
89
|
+
"sha256": "85de9bd3e4f7ec6af3dedb44340de4087939f679748cf796b9f5214936a8737b"
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
"path": "docs/funnelsgrove/steps/multi_select_choice.md",
|
|
93
|
+
"sha256": "d9c6d7d75ccc6c50697033b3ad2a6383554d815d8f952c75f8319e73b09db1d1"
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
"path": "docs/funnelsgrove/steps/paywall_offer.md",
|
|
97
|
+
"sha256": "969ee556ca1da3bfa09c21f530726467735693537452fcbf3065f21644b90669"
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
"path": "docs/funnelsgrove/steps/progress_interstitial.md",
|
|
101
|
+
"sha256": "7ed2d0bf4ac45ee74e36bd87865c250206353ddbd6b34b93975bf87fb0ea09bb"
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
"path": "docs/funnelsgrove/steps/purchase_completed.md",
|
|
105
|
+
"sha256": "4fc5b6973ed5b9520619914e41f9633308ae3d46f391a57be44e5a1a7c210253"
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
"path": "docs/funnelsgrove/steps/single_step_choice.md",
|
|
109
|
+
"sha256": "63efe3cdf363342eda69522f9c549f11203b53d2afe10af6ebce4eff90e5a53c"
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
"path": "docs/funnelsgrove/steps/single_step_choice_emoji.md",
|
|
113
|
+
"sha256": "ed3593d6b1ff26dfccec515f858304001da1e3739dbc9a4d22dfafb5ebfbbc0c"
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
"path": "docs/funnelsgrove/steps/social_proof.md",
|
|
117
|
+
"sha256": "cae4611e44d020ebe7a1792f91666b1a8d9df2798a226808a830f903f58feccb"
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
"path": "docs/funnelsgrove/steps/subscription_handoff.md",
|
|
121
|
+
"sha256": "dd2e7fed11f1f08ecfa9a969ea0b55d7d41d28c5ab160f6e4a560ee2a7bc2ff3"
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
"path": "docs/funnelsgrove/steps/subscription_management.md",
|
|
125
|
+
"sha256": "291d2c39d414a8ece0c73840b20eed14c86f88700323835c86a518c91382d02d"
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
"path": "docs/funnelsgrove/steps/summary_confirmation.md",
|
|
129
|
+
"sha256": "a92a1a5c7e7072a0ac86f808940f72fd4be38f97624219d2a1e7a04580b73cc6"
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
"path": "docs/funnelsgrove/steps/upsell_offer.md",
|
|
133
|
+
"sha256": "832ffb5506ccdc72b28c839e1b574e5c9ba0c01755fa6c4be105dbe1136b21d0"
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
"path": "docs/funnelsgrove/steps/value_prop_story.md",
|
|
137
|
+
"sha256": "9c62b5c908ffade3dc478b95f67b574817af98d4e8c9359d7db20cccd5eca2b7"
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
"path": "funnel-docs.config.json",
|
|
141
|
+
"sha256": "1d255682f3394a650b2d1046de407d2772cec5049c6ff9872d66e893d30076d4"
|
|
142
|
+
}
|
|
143
|
+
]
|
|
144
|
+
}
|
package/template_docs/AGENTS.md
CHANGED
|
@@ -1,70 +1,42 @@
|
|
|
1
1
|
# AGENTS.md
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
This file is generated from the FunnelsGrove step contract. Start at [the agent documentation router](docs/funnelsgrove/START-HERE.md), then read the exact page for the step type you are changing.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Route by task
|
|
6
6
|
|
|
7
|
-
| Task | Read
|
|
8
|
-
| --- | --- |
|
|
9
|
-
| Add
|
|
10
|
-
|
|
|
11
|
-
|
|
|
12
|
-
|
|
|
13
|
-
| Edit
|
|
14
|
-
|
|
|
15
|
-
| Edit
|
|
16
|
-
|
|
|
17
|
-
|
|
|
18
|
-
|
|
|
7
|
+
| Task | Read first |
|
|
8
|
+
| --- | --- |
|
|
9
|
+
| Add a step | [Add a step](docs/funnelsgrove/recipes/add-step.md) |
|
|
10
|
+
| Edit a step | [Edit a step](docs/funnelsgrove/recipes/edit-step.md) |
|
|
11
|
+
| Change metadata or routing | [Step metadata](docs/funnelsgrove/contracts/step-metadata.md) and [flow routing](docs/funnelsgrove/contracts/flow-routing.md) |
|
|
12
|
+
| Add or edit choices | [Content and answers](docs/funnelsgrove/contracts/content-answers.md) |
|
|
13
|
+
| Edit product strategy, plan, or copy | [Content and answers](docs/funnelsgrove/contracts/content-answers.md) |
|
|
14
|
+
| Add an experiment | [Add an experiment](docs/funnelsgrove/recipes/add-experiment.md) |
|
|
15
|
+
| Edit email capture or analytics | [Analytics events](docs/funnelsgrove/contracts/analytics-events.md) |
|
|
16
|
+
| Edit paywall, checkout, or subscription flow | [Payments](docs/funnelsgrove/contracts/payments.md) |
|
|
17
|
+
| Edit theme, CSS, layout, or images | [Start here](docs/funnelsgrove/START-HERE.md), [flow routing](docs/funnelsgrove/contracts/flow-routing.md), and [local QA](docs/funnelsgrove/qa/local.md) |
|
|
18
|
+
| QA or publish | [Local QA](docs/funnelsgrove/qa/local.md), [analytics QA](docs/funnelsgrove/qa/analytics.md), and [publish QA](docs/funnelsgrove/qa/publish.md) |
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
## Non-negotiable workflow
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
1. Read the matching [step-type page](docs/funnelsgrove/steps/INDEX.md).
|
|
23
|
+
2. Keep manifest metadata and component metadata identical.
|
|
24
|
+
3. Use shared helpers for answers, conversions, checkout, handoff, and routing.
|
|
25
|
+
4. Run `fgrove validate` and the relevant manual QA checklist.
|
|
26
|
+
5. Publish preview first. Publish production only after explicit approval.
|
|
23
27
|
|
|
24
|
-
|
|
28
|
+
## Sync safety
|
|
25
29
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
-
|
|
29
|
-
-
|
|
30
|
+
1. Before edits run `fgrove status`, `git status --short`, and `fgrove github status` when the funnel is GitHub-connected.
|
|
31
|
+
2. Never run `fgrove sync down` over changed synced source. Use `--force` only to intentionally discard those local changes.
|
|
32
|
+
3. Sync-up uses remote compare-and-swap through the base draft version. On stale-draft rejection, download into a clean temporary directory, merge deliberately, rerun checks, and retry.
|
|
33
|
+
4. GitHub-connected changes 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`.
|
|
34
|
+
5. Use `fgrove env pull` when only the ignored `.env` must be refreshed. Environment files never belong in synced source.
|
|
30
35
|
|
|
31
|
-
|
|
36
|
+
Contract version: `3`
|
|
32
37
|
|
|
33
|
-
|
|
38
|
+
Contract hash: `d761e91d5ac6ff9e72c6d49c5bcd014270912473a66f99c49d726c65998085cf`
|
|
34
39
|
|
|
35
|
-
|
|
36
|
-
2. `git status --short` — if local changes exist, checkpoint them before any refresh.
|
|
37
|
-
3. `fgrove github status` — when GitHub is connected and remote is ahead, run `fgrove github pull`, then poll `fgrove github status` until the pull job is completed or skipped before syncing the latest draft into a clean directory and merging the local checkpoint intentionally.
|
|
38
|
-
4. When GitHub is not connected, use `fgrove sync down --funnel <id-or-slug> --dir <temp-dir>` or an already selected `fgrove use` context as the remote source, then merge that clean hosted draft with local changes before editing further.
|
|
39
|
-
5. Make the scoped edit per the topic doc.
|
|
40
|
-
6. `npm run test:run && npm run lint` (or the checks this tree defines).
|
|
41
|
-
7. `npm run dev` — verify in local preview at all four default breakpoints: small 375x667, medium 393x852, large 402x874, and desktop-small 1280x800 ([docs/step-ui-guidelines.md](docs/step-ui-guidelines.md)).
|
|
42
|
-
8. Run the relevant part of [docs/qa-checklist.md](docs/qa-checklist.md).
|
|
43
|
-
9. Ask the user before publishing. If GitHub is connected, commit and push with normal git, run `fgrove github pull`, then poll `fgrove github status` until the pull job is completed or skipped. Do not also run `fgrove sync up` for the same diff.
|
|
44
|
-
10. If GitHub is not connected, run `fgrove sync up --message '<summary>'`.
|
|
45
|
-
11. Publish preview with `fgrove publish --env preview --message '<summary>'`.
|
|
46
|
-
12. QA the preview URL. Production publish only on explicit request, after preview QA.
|
|
40
|
+
## Project-specific context
|
|
47
41
|
|
|
48
|
-
`
|
|
49
|
-
Do not run `fgrove sync down` over a dirty synced directory unless discarding
|
|
50
|
-
local changes is intentional and `--force` is passed. If `fgrove sync up`
|
|
51
|
-
reports that the remote draft changed since this directory was synced, download
|
|
52
|
-
the current draft into a temp directory, merge local changes, rerun checks, and
|
|
53
|
-
sync again.
|
|
54
|
-
For GitHub-connected funnels, source changes must flow through GitHub first:
|
|
55
|
-
`git push`, then `fgrove github pull`, then publish. Do not mix `fgrove sync up`
|
|
56
|
-
with the same local source diff.
|
|
57
|
-
|
|
58
|
-
## Behavioral Rules
|
|
59
|
-
|
|
60
|
-
1. **Think before coding.** State assumptions. If multiple interpretations exist, present them — don't pick silently. If something is unclear, ask before editing.
|
|
61
|
-
2. **Simplicity first.** Minimum code that solves the problem. No speculative abstractions, options, or error handling for impossible states.
|
|
62
|
-
3. **Surgical changes.** Touch only what the request requires. Match existing style. Remove only orphans your own change created. Every changed line should trace to the request.
|
|
63
|
-
4. **Goal-driven execution.** Define the success check before editing ("step renders at all default breakpoints and Continue advances to step-X"), then loop until it passes.
|
|
64
|
-
5. **Image performance locked.** Keep build-time raster compression plus AVIF/WebP variants enabled. For funnel step images, use `funnelManifest.assets` + step `assetIds`, priority/preload only for first-viewport images, and low-priority next-step warming from the shell. Do not preload the whole funnel image set.
|
|
65
|
-
6. **Meaningful URLs.** New step `path` values are public product routes, so use readable slugs like `/motivation`, `/fitness-goal`, or `/email-capture`. Sequential ids and `step-NN-*` filenames are okay for ordering, but do not create public routes like `/step-1`.
|
|
66
|
-
7. **Flow labeling hygiene.** When changing `edgesByStepId`, keep manifest `branches` current for conditional paths that own steps before reconverging. Keep builder metadata ClaimBee-style and source-readable: `edgesByStepId` keys/targets and `branches: [...]` must use inline string literals, not `someStep.id` variables or a `branches: flowBranches` indirection. Each branch needs a readable `name`, answer-derived `label` such as `yes-branch`, useful `tags`, and the owned `stepIds`. Running experiment variants need labels/tags like `paywall-test-control` and `paywall-test-variant-b`; stopped A/B variants or other inactive screens should keep stable tags and remain unreachable from the default flow so builder marks them `unused`.
|
|
67
|
-
|
|
68
|
-
Architecture docs are part of the change: if you change routing, runtime state, SDK contracts, URL handoff parameters, checkout behavior, analytics events, or shared package boundaries, update the matching doc in the same change.
|
|
69
|
-
|
|
70
|
-
Preserve existing step ids, paths, and answer keys unless the task is an explicit migration — they feed routes, persisted answers, analytics, and publish history.
|
|
42
|
+
If an unmanaged `AGENTS.project.md` exists, read and apply `AGENTS.project.md` after this managed contract. It may add product-specific constraints, but if it conflicts with this bundle, the managed contract wins. The docs generator never creates, hashes, copies, overwrites, or deletes that file.
|
package/template_docs/CLAUDE.md
CHANGED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# FunnelsGrove agent contract: start here
|
|
2
|
+
|
|
3
|
+
This bundle is the operating manual for agents that create or edit a synced funnel. It is generated and validated against the runtime step contract; follow it before changing funnel code.
|
|
4
|
+
|
|
5
|
+
<!-- funnelsgrove:generated:start contract-v3/overview/start-here -->
|
|
6
|
+
Step contract version: `3`
|
|
7
|
+
|
|
8
|
+
Contract hash: `d761e91d5ac6ff9e72c6d49c5bcd014270912473a66f99c49d726c65998085cf`
|
|
9
|
+
|
|
10
|
+
| Type | Family | Action owner | Required kind | Terminal | Meaning |
|
|
11
|
+
| --- | --- | --- | --- | --- | --- |
|
|
12
|
+
| `cancellation_offer` | `commerce` | `step` | `cancellation` | `false` | A cancellation retention or downsell surface. |
|
|
13
|
+
| `checkout` | `commerce` | `step` | — | `false` | A dedicated payment-entry screen. |
|
|
14
|
+
| `form_input` | `form` | `either` | — | `false` | Non-choice structured input, including reserved email capture. |
|
|
15
|
+
| `intro_hero` | `content` | `shared-shell` | — | `false` | Opening promise or low-friction entry screen. |
|
|
16
|
+
| `multi_select_choice` | `choice` | `either` | — | `false` | Multiple options are selected before explicit completion. |
|
|
17
|
+
| `paywall_offer` | `commerce` | `step` | `paywall` | `false` | A monetization offer that presents purchasable plans. |
|
|
18
|
+
| `progress_interstitial` | `transition` | `either` | — | `false` | Progress, calculation, loading, reveal, or transition screen. |
|
|
19
|
+
| `purchase_completed` | `terminal` | `step` | `subscription-handoff` | `true` | The canonical terminal shown after a verified initial purchase. |
|
|
20
|
+
| `single_step_choice` | `choice` | `step` | — | `false` | Exactly one standard option is selected. |
|
|
21
|
+
| `single_step_choice_emoji` | `choice` | `step` | — | `false` | Exactly one emoji-led option is selected. |
|
|
22
|
+
| `social_proof` | `content` | `shared-shell` | — | `false` | Testimonials, reviews, credibility, or evidence. |
|
|
23
|
+
| `subscription_handoff` | `commerce` | `step` | `subscription-handoff` | `false` | A non-terminal app, store, or deep-link handoff. |
|
|
24
|
+
| `subscription_management` | `commerce` | `step` | `manage-subscription` | `false` | A screen for managing or inspecting an existing subscription. |
|
|
25
|
+
| `summary_confirmation` | `content` | `either` | — | `false` | A summary, review, or confirmation before the next action. |
|
|
26
|
+
| `upsell_offer` | `commerce` | `step` | `upsell` | `false` | A post-purchase or upgrade offer. |
|
|
27
|
+
| `value_prop_story` | `content` | `shared-shell` | — | `false` | Benefit, explanation, motivation, or narrative value screen. |
|
|
28
|
+
|
|
29
|
+
### Reserved identities
|
|
30
|
+
|
|
31
|
+
| Contract | Match | ID | Name | Type | Kind | Primary | Unique |
|
|
32
|
+
| --- | --- | --- | --- | --- | --- | --- | --- |
|
|
33
|
+
| `email-capture` | `exact` | `email-capture` | `email-capture` | `form_input` | — | — | `true` |
|
|
34
|
+
| `manage-subscription` | `exact` | `manage-subscription` | `manage-subscription` | `subscription_management` | `manage-subscription` | — | `true` |
|
|
35
|
+
| `paywall` | `exact` | `paywall` | `paywall` | `paywall_offer` | `paywall` | `true` | `true` |
|
|
36
|
+
| `paywall-variant` | `pattern` | `^paywall-[a-z0-9-]+$` | `^paywall-[a-z0-9-]+$` | `paywall_offer` | `paywall` | `false` | `false` |
|
|
37
|
+
| `subscription-started` | `exact` | `subscription-started` | `subscription-started` | `purchase_completed` | `subscription-handoff` | — | `true` |
|
|
38
|
+
<!-- funnelsgrove:generated:end contract-v3/overview/start-here -->
|
|
39
|
+
|
|
40
|
+
## Choose the right document
|
|
41
|
+
|
|
42
|
+
- Step classification and parity: [step metadata](contracts/step-metadata.md) and the [step-type index](steps/INDEX.md).
|
|
43
|
+
- Analytics ownership and lifecycle: [analytics events](contracts/analytics-events.md).
|
|
44
|
+
- Manifest edges, reserved routes, branches, and experiments: [flow routing](contracts/flow-routing.md).
|
|
45
|
+
- Choice answers and email input: [content and answers](contracts/content-answers.md).
|
|
46
|
+
- Paywall, checkout, and subscription behavior: [payments](contracts/payments.md).
|
|
47
|
+
- New work: [add a step](recipes/add-step.md), [edit a step](recipes/edit-step.md), or [add an experiment](recipes/add-experiment.md).
|
|
48
|
+
- Verification: [local QA](qa/local.md), [analytics QA](qa/analytics.md), [paywall/checkout QA](qa/paywall-checkout.md), and [publish QA](qa/publish.md).
|
|
49
|
+
- Existing funnels: [step-contract v3 migration](migrations/step-contract-v3.md).
|
|
50
|
+
|
|
51
|
+
## Non-negotiable guardrails
|
|
52
|
+
|
|
53
|
+
- Classify a step by what the user can do, not its position, copy, or visual treatment.
|
|
54
|
+
- A paywall presents purchasable plans. A loading, reveal, or “ready” screen is an interstitial.
|
|
55
|
+
- Every choice declares `choice.answerKey`, stores stable option IDs in the exact scalar/array shape, and uses `useStepChoices`.
|
|
56
|
+
- Email capture uses `submitEmailCapture`; it never manually sends analytics or hard-codes paywall navigation.
|
|
57
|
+
- `subscription-started` is the `purchase_completed` terminal. Browser terminal reach is not Quiz completed; only the trusted backend records `purchase_completed` after verifying an initial purchase.
|
|
58
|
+
- Let the controller distinguish completion from exit and suppress provider delivery in preview.
|
|
59
|
+
|
|
60
|
+
## Standard workflow
|
|
61
|
+
|
|
62
|
+
1. Read the exact type page.
|
|
63
|
+
2. Change the smallest set of component, content/editor, registry, and manifest files needed.
|
|
64
|
+
3. Keep component and manifest metadata in parity.
|
|
65
|
+
4. Run `fgrove validate` and focused tests.
|
|
66
|
+
5. Perform the relevant manual QA.
|
|
67
|
+
6. Publish preview, inspect it, then publish production only with explicit approval.
|
|
68
|
+
|
|
69
|
+
## Theme and styling ownership
|
|
70
|
+
|
|
71
|
+
`src/theme/theme.ts` is the brand-token source. Preserve the typed `FunnelTheme` and `themeCssVariables = createThemeCssVariables(theme)`. Apply theme values through the emitted CSS variables: `globals.css` owns global reset, fonts, and root behavior; shared styles own repeated patterns; step-local CSS owns only genuinely local layout. Do not duplicate brand constants in step components.
|
|
72
|
+
|
|
73
|
+
Optional product-specific guidance belongs in `AGENTS.project.md`. That file is never managed by this bundle.
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# Analytics event ownership
|
|
2
|
+
|
|
3
|
+
Analytics is divided between controller-owned lifecycle events, explicit shared helpers, transactional server conversions, and trusted server claims.
|
|
4
|
+
|
|
5
|
+
<!-- funnelsgrove:generated:start contract-v3/contract/analytics-events -->
|
|
6
|
+
Step contract version: `3`
|
|
7
|
+
|
|
8
|
+
Contract hash: `d761e91d5ac6ff9e72c6d49c5bcd014270912473a66f99c49d726c65998085cf`
|
|
9
|
+
|
|
10
|
+
| Contract key | Public event | Raw event | Allowed step types | Allowed identities | Owner | Automatic | Dedupe | Required metadata |
|
|
11
|
+
| --- | --- | --- | --- | --- | --- | --- | --- | --- |
|
|
12
|
+
| `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` |
|
|
13
|
+
| `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` |
|
|
14
|
+
| `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` |
|
|
15
|
+
| `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` |
|
|
16
|
+
| `first_step_clicked` | `first_step_clicked` | `first_step_clicked` | `any` | `any` | `controller` | `true` | `step-visit` | `funnelId`, `funnelVersionId`, `environment`, `stepContractVersion`, `stepId`, `stepName`, `stepType` |
|
|
17
|
+
| `first_step_viewed` | `first_step_viewed` | `first_step_viewed` | `any` | `any` | `controller` | `true` | `step-visit` | `funnelId`, `funnelVersionId`, `environment`, `stepContractVersion`, `stepId`, `stepName`, `stepType` |
|
|
18
|
+
| `funnel_completed` | `funnel_completed` | `funnel_completed` | `purchase_completed` | `any` | `terminal-helper` | `false` | `funnel-run` | `funnelId`, `funnelVersionId`, `environment`, `stepContractVersion`, `stepId`, `stepName`, `stepType`, `eventId` |
|
|
19
|
+
| `funnel_started` | `funnel_started` | `funnel_start` | `any` | `any` | `controller` | `true` | `funnel-run` | `funnelId`, `funnelVersionId`, `environment`, `stepContractVersion` |
|
|
20
|
+
| `purchase_completed` | `purchase_completed` | `purchase_completed` | _None_ | _None_ | `trusted-server` | `false` | `provider-payment` | `funnelId`, `funnelVersionId`, `environment`, `stepContractVersion`, `projectId`, `funnelEndUserId`, `eventId`, `providerPaymentId`, `purchaseKind` |
|
|
21
|
+
| `registration_completed` | `registration_completed` | `registration_completed` | _None_ | _None_ | `trusted-server` | `false` | `subscription-claim` | `funnelId`, `funnelVersionId`, `environment`, `stepContractVersion`, `projectId`, `funnelEndUserId`, `eventId`, `subscriptionClaimId` |
|
|
22
|
+
| `step_completed` | `step_completed` | `step_end` | `any` | `any` | `controller` | `true` | `step-visit` | `funnelId`, `funnelVersionId`, `environment`, `stepContractVersion`, `stepId`, `stepName`, `stepType` |
|
|
23
|
+
| `step_engaged` | `step_engaged` | `step_engaged` | `any` | `any` | `controller` | `false` | `step-visit` | `funnelId`, `funnelVersionId`, `environment`, `stepContractVersion`, `stepId`, `stepName`, `stepType`, `durationMs` |
|
|
24
|
+
| `step_exited` | `step_exited` | `step_exit` | `any` | `any` | `controller` | `true` | `step-visit` | `funnelId`, `funnelVersionId`, `environment`, `stepContractVersion`, `stepId`, `stepName`, `stepType` |
|
|
25
|
+
| `step_started` | `step_started` | `step_start` | `any` | `any` | `controller` | `true` | `step-visit` | `funnelId`, `funnelVersionId`, `environment`, `stepContractVersion`, `stepId`, `stepName`, `stepType` |
|
|
26
|
+
|
|
27
|
+
The `purchase_completed` event is owned by `trusted-server` and is recorded only after the backend verifies a successful initial purchase. Entering the browser terminal or emitting `funnel_completed` does not create this business conversion. The separate `registration_completed` event remains owned by `trusted-server` for the later app-link claim. The `email_captured` event is owned by `transactional-server` and uses `logical-email-conversion` deduplication.
|
|
28
|
+
<!-- funnelsgrove:generated:end contract-v3/contract/analytics-events -->
|
|
29
|
+
|
|
30
|
+
## Ownership rules
|
|
31
|
+
|
|
32
|
+
- The flow controller emits lifecycle events. Step components do not duplicate them.
|
|
33
|
+
- `step_engaged` is non-automatic and absent by default; only an explicit, centralized, tested policy may emit it through the approved controller/helper boundary.
|
|
34
|
+
- `submitEmailCapture` creates `email_captured` transactionally, then routes only after success.
|
|
35
|
+
- Named payment helpers emit checkout semantic events at real payment boundaries.
|
|
36
|
+
- The terminal helper owns funnel completion.
|
|
37
|
+
- A trusted backend owns `purchase_completed` after verifying an initial subscription or one-time payment; browser code never emits it, and terminal reach does not count as Quiz completed.
|
|
38
|
+
- A separate trusted server claim owns `registration_completed` when the purchased subscription is later linked in the app.
|
|
39
|
+
- Provider adapters and the durable outbox own PostHog and server Meta delivery.
|
|
40
|
+
|
|
41
|
+
## Privacy boundary
|
|
42
|
+
|
|
43
|
+
- Never put raw email or other PII in analytics event metadata or logs.
|
|
44
|
+
- Only the server delivery boundary may use raw email as Meta hashing input.
|
|
45
|
+
- PostHog properties must remain non-PII.
|
|
46
|
+
|
|
47
|
+
## Completion versus exit
|
|
48
|
+
|
|
49
|
+
Completion means the step’s intended action succeeded and navigation was committed. Back, close, unload, replaced visits, and abandoned payment are exits. The controller deduplicates each visit outcome. Preview suppresses API/provider delivery.
|
|
50
|
+
|
|
51
|
+
## Email capture sequence
|
|
52
|
+
|
|
53
|
+
1. Call `submitEmailCapture` once for the in-flight submit.
|
|
54
|
+
2. On API failure, do not mutate answer state, lifecycle, or route.
|
|
55
|
+
3. On a newly created conversion, browser Pixel/Google may fan out with the server event ID.
|
|
56
|
+
4. On a duplicate, skip browser fanout and continue safely.
|
|
57
|
+
5. Never call `trackLead`, PostHog, Meta CAPI, or a provider from the email step.
|
|
58
|
+
|
|
59
|
+
Use the [analytics QA checklist](../qa/analytics.md) for journey-level evidence.
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# Content, choices, and persisted answers
|
|
2
|
+
|
|
3
|
+
Content labels may change; analytics-safe option IDs and answer keys must remain stable.
|
|
4
|
+
|
|
5
|
+
<!-- funnelsgrove:generated:start contract-v3/contract/content-answers -->
|
|
6
|
+
Step contract version: `3`
|
|
7
|
+
|
|
8
|
+
Contract hash: `d761e91d5ac6ff9e72c6d49c5bcd014270912473a66f99c49d726c65998085cf`
|
|
9
|
+
|
|
10
|
+
| Type | Cardinality | Presentation | Completion | allowEmpty config |
|
|
11
|
+
| --- | --- | --- | --- | --- |
|
|
12
|
+
| `multi_select_choice` | `many` | `standard` | `explicit` | `true` |
|
|
13
|
+
| `single_step_choice` | `one` | `standard` | `selection` | `false` |
|
|
14
|
+
| `single_step_choice_emoji` | `one` | `emoji` | `selection` | `false` |
|
|
15
|
+
|
|
16
|
+
| Capability | Allowed types | Allowed identities | Required owner |
|
|
17
|
+
| --- | --- | --- | --- |
|
|
18
|
+
| `choice-write` | `single_step_choice`, `single_step_choice_emoji`, `multi_select_choice` | `any` | `useStepChoices` |
|
|
19
|
+
| `email-capture` | `form_input` | `email-capture` | `submitEmailCapture` |
|
|
20
|
+
<!-- funnelsgrove:generated:end contract-v3/contract/content-answers -->
|
|
21
|
+
|
|
22
|
+
## Choice rules
|
|
23
|
+
|
|
24
|
+
- Declare `choice.answerKey` in manifest and component metadata.
|
|
25
|
+
- Use stable option IDs, never labels, array positions, or entire objects.
|
|
26
|
+
- Persist a scalar ID for single-choice types and an ID array for multi-select.
|
|
27
|
+
- Represent an allowed empty multi-select as `[]`.
|
|
28
|
+
- Use `useStepChoices` for write, completion, and routing order.
|
|
29
|
+
|
|
30
|
+
## Form and email rules
|
|
31
|
+
|
|
32
|
+
Ordinary form inputs validate and persist through their owning runtime path. The reserved email form calls `submitEmailCapture`; it never sends analytics manually and never decides the next route.
|
|
33
|
+
|
|
34
|
+
## Content/editor parity
|
|
35
|
+
|
|
36
|
+
Keep builder-editable values in content definitions, expose matching editor sections, and register them once. Do not move stable IDs or answer keys into editable copy.
|
|
37
|
+
|
|
38
|
+
## Product strategy and plan ownership
|
|
39
|
+
|
|
40
|
+
- `PRODUCT_SENSE.md` owns audience, promise, positioning, objections, value stack, and brand direction. Preserve `## Strategic Pre-Work` and its exact five columns.
|
|
41
|
+
- `PLAN.md` owns the ordered screen contract, exact screen structure and copy, shared design system/components, and `## Funnel Fuel`. Keep one row per planned screen.
|
|
42
|
+
- Update the owning artifact in the same change. Never implement a step absent from `PLAN.md`.
|
|
43
|
+
|
|
44
|
+
See the exact choice and form pages in the [step-type index](../steps/INDEX.md). Run `fgrove validate` and test reload persistence before completion.
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# Flow routing contract
|
|
2
|
+
|
|
3
|
+
The manifest graph owns routes. Components request an outcome; they do not choose a hard-coded destination.
|
|
4
|
+
|
|
5
|
+
<!-- funnelsgrove:generated:start contract-v3/contract/flow-routing -->
|
|
6
|
+
Step contract version: `3`
|
|
7
|
+
|
|
8
|
+
Contract hash: `d761e91d5ac6ff9e72c6d49c5bcd014270912473a66f99c49d726c65998085cf`
|
|
9
|
+
|
|
10
|
+
| Contract | Match | ID | Name | Type | Kind | Primary | Unique |
|
|
11
|
+
| --- | --- | --- | --- | --- | --- | --- | --- |
|
|
12
|
+
| `email-capture` | `exact` | `email-capture` | `email-capture` | `form_input` | — | — | `true` |
|
|
13
|
+
| `manage-subscription` | `exact` | `manage-subscription` | `manage-subscription` | `subscription_management` | `manage-subscription` | — | `true` |
|
|
14
|
+
| `paywall` | `exact` | `paywall` | `paywall` | `paywall_offer` | `paywall` | `true` | `true` |
|
|
15
|
+
| `paywall-variant` | `pattern` | `^paywall-[a-z0-9-]+$` | `^paywall-[a-z0-9-]+$` | `paywall_offer` | `paywall` | `false` | `false` |
|
|
16
|
+
| `subscription-started` | `exact` | `subscription-started` | `subscription-started` | `purchase_completed` | `subscription-handoff` | — | `true` |
|
|
17
|
+
|
|
18
|
+
The `hardcoded-navigation` capability is owned by `manifest-flow-controller`.
|
|
19
|
+
<!-- funnelsgrove:generated:end contract-v3/contract/flow-routing -->
|
|
20
|
+
|
|
21
|
+
## Rules
|
|
22
|
+
|
|
23
|
+
- Give public paths meaningful product slugs.
|
|
24
|
+
- Keep `edgesByStepId` sources and targets as explicit string literals.
|
|
25
|
+
- Model conditional ownership in `branches`, including readable labels, tags, and owned step IDs.
|
|
26
|
+
- Keep every experiment control and variant as a real step with normal outgoing edges.
|
|
27
|
+
- Configure the email-to-offer edge in the manifest; the email component never names a paywall route.
|
|
28
|
+
- Keep inactive variants unreachable from the default flow rather than deleting their identity.
|
|
29
|
+
|
|
30
|
+
## Lifecycle-safe navigation
|
|
31
|
+
|
|
32
|
+
Use the flow controller so answer writes, semantic conversions, completion, and route commits stay ordered. A stale visit must not complete or navigate after a newer visit takes ownership.
|
|
33
|
+
|
|
34
|
+
For experiments, follow [the add-experiment recipe](../recipes/add-experiment.md). Run `fgrove validate` after any graph change.
|
|
35
|
+
|
|
36
|
+
## Asset and preload metadata
|
|
37
|
+
|
|
38
|
+
- Give each funnel-critical image a stable `funnelManifest.assets` entry and attach it through the owning step's `assetIds`; every ID must resolve.
|
|
39
|
+
- `assetIds` is routing/preload metadata, not an optimization opt-in. Use framework `priority` only for current first-viewport images.
|
|
40
|
+
- `preload: 'idle'` is effective only when a tested shell consumer exists. Warm likely next-step assets only, never the full funnel; do not claim preload behavior from metadata alone.
|
|
41
|
+
- Publish optimization is separate: the image-variants stage creates AVIF/WebP sidecars while retaining the original raster fallback.
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Payments and subscription contract
|
|
2
|
+
|
|
3
|
+
Commerce steps use shared plan, checkout, wallet, handoff, and subscription helpers. Components own presentation and user intent, not provider integration.
|
|
4
|
+
|
|
5
|
+
<!-- funnelsgrove:generated:start contract-v3/contract/payments -->
|
|
6
|
+
Step contract version: `3`
|
|
7
|
+
|
|
8
|
+
Contract hash: `d761e91d5ac6ff9e72c6d49c5bcd014270912473a66f99c49d726c65998085cf`
|
|
9
|
+
|
|
10
|
+
| Type | Family | Action owner | Required kind | Terminal | Meaning |
|
|
11
|
+
| --- | --- | --- | --- | --- | --- |
|
|
12
|
+
| `cancellation_offer` | `commerce` | `step` | `cancellation` | `false` | A cancellation retention or downsell surface. |
|
|
13
|
+
| `checkout` | `commerce` | `step` | — | `false` | A dedicated payment-entry screen. |
|
|
14
|
+
| `paywall_offer` | `commerce` | `step` | `paywall` | `false` | A monetization offer that presents purchasable plans. |
|
|
15
|
+
| `subscription_handoff` | `commerce` | `step` | `subscription-handoff` | `false` | A non-terminal app, store, or deep-link handoff. |
|
|
16
|
+
| `subscription_management` | `commerce` | `step` | `manage-subscription` | `false` | A screen for managing or inspecting an existing subscription. |
|
|
17
|
+
| `upsell_offer` | `commerce` | `step` | `upsell` | `false` | A post-purchase or upgrade offer. |
|
|
18
|
+
|
|
19
|
+
| Capability | Allowed types | Allowed identities | Required owner |
|
|
20
|
+
| --- | --- | --- | --- |
|
|
21
|
+
| `checkout` | `paywall_offer`, `upsell_offer`, `checkout` | `any` | `named-payment-helpers` |
|
|
22
|
+
| `subscription-handoff` | `subscription_handoff`, `purchase_completed` | `any` | `runtime-handoff-helper` |
|
|
23
|
+
| `subscription-management` | `subscription_management`, `cancellation_offer` | `any` | `runtime-subscription-helpers` |
|
|
24
|
+
<!-- funnelsgrove:generated:end contract-v3/contract/payments -->
|
|
25
|
+
|
|
26
|
+
## Paywall definition
|
|
27
|
+
|
|
28
|
+
A paywall presents purchasable plans. A reveal, loading state, calculation, or “your plan is ready” bridge is a progress interstitial even when it precedes a paywall.
|
|
29
|
+
|
|
30
|
+
## Payment rules
|
|
31
|
+
|
|
32
|
+
- Resolve plans, prices, discounts, currencies, provider IDs, and payment mode from shared configuration.
|
|
33
|
+
- Use named checkout helpers at actual checkout-started, payment-info, and completed boundaries.
|
|
34
|
+
- Reuse the same event ID when retrying the same logical conversion.
|
|
35
|
+
- Keep secrets and trusted provider calls server-side.
|
|
36
|
+
- Route post-purchase behavior through the manifest and runtime handoff helper.
|
|
37
|
+
|
|
38
|
+
## Purchase completion separation
|
|
39
|
+
|
|
40
|
+
The canonical `subscription-started` route keeps its stable identity but uses the `purchase_completed` terminal type in contract v3. It may emit lifecycle-only `funnel_completed`, but entering it never counts as Quiz completed. Only the trusted backend emits `purchase_completed` after verifying an initial subscription or one-time payment; renewals, pending payments, and browser checkout returns do not qualify. `registration_completed` remains the later app-link conversion.
|
|
41
|
+
|
|
42
|
+
Before publishing, complete [paywall/checkout QA](../qa/paywall-checkout.md) and [publish QA](../qa/publish.md).
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# Step metadata contract
|
|
2
|
+
|
|
3
|
+
Step metadata is an analytics and runtime API, not descriptive decoration. Choose the type from actual behavior and preserve stable identity.
|
|
4
|
+
|
|
5
|
+
<!-- funnelsgrove:generated:start contract-v3/contract/step-metadata -->
|
|
6
|
+
Step contract version: `3`
|
|
7
|
+
|
|
8
|
+
Contract hash: `d761e91d5ac6ff9e72c6d49c5bcd014270912473a66f99c49d726c65998085cf`
|
|
9
|
+
|
|
10
|
+
| Type | Family | Action owner | Required kind | Terminal | Meaning |
|
|
11
|
+
| --- | --- | --- | --- | --- | --- |
|
|
12
|
+
| `cancellation_offer` | `commerce` | `step` | `cancellation` | `false` | A cancellation retention or downsell surface. |
|
|
13
|
+
| `checkout` | `commerce` | `step` | — | `false` | A dedicated payment-entry screen. |
|
|
14
|
+
| `form_input` | `form` | `either` | — | `false` | Non-choice structured input, including reserved email capture. |
|
|
15
|
+
| `intro_hero` | `content` | `shared-shell` | — | `false` | Opening promise or low-friction entry screen. |
|
|
16
|
+
| `multi_select_choice` | `choice` | `either` | — | `false` | Multiple options are selected before explicit completion. |
|
|
17
|
+
| `paywall_offer` | `commerce` | `step` | `paywall` | `false` | A monetization offer that presents purchasable plans. |
|
|
18
|
+
| `progress_interstitial` | `transition` | `either` | — | `false` | Progress, calculation, loading, reveal, or transition screen. |
|
|
19
|
+
| `purchase_completed` | `terminal` | `step` | `subscription-handoff` | `true` | The canonical terminal shown after a verified initial purchase. |
|
|
20
|
+
| `single_step_choice` | `choice` | `step` | — | `false` | Exactly one standard option is selected. |
|
|
21
|
+
| `single_step_choice_emoji` | `choice` | `step` | — | `false` | Exactly one emoji-led option is selected. |
|
|
22
|
+
| `social_proof` | `content` | `shared-shell` | — | `false` | Testimonials, reviews, credibility, or evidence. |
|
|
23
|
+
| `subscription_handoff` | `commerce` | `step` | `subscription-handoff` | `false` | A non-terminal app, store, or deep-link handoff. |
|
|
24
|
+
| `subscription_management` | `commerce` | `step` | `manage-subscription` | `false` | A screen for managing or inspecting an existing subscription. |
|
|
25
|
+
| `summary_confirmation` | `content` | `either` | — | `false` | A summary, review, or confirmation before the next action. |
|
|
26
|
+
| `upsell_offer` | `commerce` | `step` | `upsell` | `false` | A post-purchase or upgrade offer. |
|
|
27
|
+
| `value_prop_story` | `content` | `shared-shell` | — | `false` | Benefit, explanation, motivation, or narrative value screen. |
|
|
28
|
+
|
|
29
|
+
### Reserved identities
|
|
30
|
+
|
|
31
|
+
| Contract | Match | ID | Name | Type | Kind | Primary | Unique |
|
|
32
|
+
| --- | --- | --- | --- | --- | --- | --- | --- |
|
|
33
|
+
| `email-capture` | `exact` | `email-capture` | `email-capture` | `form_input` | — | — | `true` |
|
|
34
|
+
| `manage-subscription` | `exact` | `manage-subscription` | `manage-subscription` | `subscription_management` | `manage-subscription` | — | `true` |
|
|
35
|
+
| `paywall` | `exact` | `paywall` | `paywall` | `paywall_offer` | `paywall` | `true` | `true` |
|
|
36
|
+
| `paywall-variant` | `pattern` | `^paywall-[a-z0-9-]+$` | `^paywall-[a-z0-9-]+$` | `paywall_offer` | `paywall` | `false` | `false` |
|
|
37
|
+
| `subscription-started` | `exact` | `subscription-started` | `subscription-started` | `purchase_completed` | `subscription-handoff` | — | `true` |
|
|
38
|
+
<!-- funnelsgrove:generated:end contract-v3/contract/step-metadata -->
|
|
39
|
+
|
|
40
|
+
## Required parity
|
|
41
|
+
|
|
42
|
+
For each step, the manifest and exported component metadata must agree on `id`, `name`, `type`, optional `kind`, and optional `choice`. Keep `path`, `filePath`, `componentKey`, and title in the manifest. IDs and names are durable analytics keys.
|
|
43
|
+
|
|
44
|
+
## Classification method
|
|
45
|
+
|
|
46
|
+
1. Identify the screen’s user interaction and business purpose.
|
|
47
|
+
2. Open the matching [step-type page](../steps/INDEX.md).
|
|
48
|
+
3. Copy the fixture structure, then adapt only product-specific IDs, paths, copy, and content.
|
|
49
|
+
4. Run `fgrove validate` before preview.
|
|
50
|
+
|
|
51
|
+
## Protected metadata
|
|
52
|
+
|
|
53
|
+
Do not rename an existing step, answer key, reserved identity, or analytics meaning as cleanup. Treat such changes as migrations with compatibility and measurement review.
|
|
54
|
+
|
|
55
|
+
## Completion check
|
|
56
|
+
|
|
57
|
+
Validation passes, metadata parity has no diagnostics, every reserved identity is exact, and analytics receives stable type/name values.
|