feat: campaign funnel map — JSON graph + validation (#10)#11
feat: campaign funnel map — JSON graph + validation (#10)#11brettstirlingbond wants to merge 7 commits into
Conversation
Build-time funnel graph serialization from frontmatter routing fields. Generates funnel.json per campaign with nodes/edges, validates for broken links, orphan pages, missing terminals, asymmetric upsells, and missing entry points. Includes --lenient flag, dev server error surfacing, and 19 tests at 99.49% coverage. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
| // Find nodes that are dead ends (no outgoing edges) but aren't receipts | ||
| for (const node of graph.nodes) { | ||
| if (node.type === 'receipt') continue; | ||
| const outgoing = graph.edges.filter(e => e.source === node.id && nodeIds.has(e.target)); |
There was a problem hiding this comment.
WARNING: "Missing terminal" check is incomplete. It only detects nodes with ZERO outgoing edges (outgoing.length === 0), but doesn't verify paths actually reach a receipt. A funnel where checkout→upsell→checkout (cycle) with no receipt would pass validation since neither node has zero outgoing edges.
| // were processed and the graph would be incomplete. | ||
| const isPartialRebuild = opts.files !== undefined; | ||
| let funnelErrors = 0; | ||
| for (const [slug, pages] of isPartialRebuild ? [] : campaignPages) { |
There was a problem hiding this comment.
WARNING: Partial rebuilds skip funnel.json generation entirely. If a developer introduces broken links via frontmatter during dev, the existing funnel.json will be stale (from last full build) until the next full rebuild. Consider regenerating funnel.json even during partial rebuilds, or deleting the stale file.
| // Initial build | ||
| try { | ||
| const { built, errors, ms } = await build({ campaigns, mode: 'development' }); | ||
| const { built, errors, funnelErrors = 0, ms } = await build({ campaigns, mode: 'development' }); |
There was a problem hiding this comment.
WARNING: dev.js doesn't pass lenient to build(), so funnel validation errors always cause build failures in dev mode. This differs from build.js which supports --lenient. Either add lenient support to dev, or clarify that dev always validates strictly.
Code Review SummaryStatus: 1 Issue Remaining | Recommendation: Address or document Overview
Issue Details (click to expand)WARNING
Previously Fixed Issues
Files Reviewed (this commit — 9 files)
Other Observations (not in diff)The HTML visualization feature ( Reviewed by minimax-m2.7 · 392,825 tokens |
- Fix cycle detection in missing-terminal validation: replace dead-end check with reverse BFS from receipt nodes so cycles that never reach a receipt are caught (funnel.js) - Dev server defaults to lenient mode (--strict to override) so funnel validation errors don't block dev workflow (dev.js) - Clarify why partial rebuilds skip funnel.json regeneration (build.js) - Add cycle detection test (funnel.test.js) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
@alexphelps can you please review this branch, its for #10 (comment) |
Overall feeling on this we should get at least an initial v1 of the full "funnel visual graph" integrated to as part of this PR |
…ation - Move funnel.json from _site/ (deployed) to .cpk/ (developer-only) - Add opts.cpkPath to build() API, same pattern as opts.outputPath - Generate self-contained funnel.html with inline SVG visualization - Color-coded nodes by page_type, edge labels, validation error panel - Graph data embedded via JSON.stringify with </script> escaping - Visual generation is try/catch, never blocks the build - Add duplicate page validation rule (6th rule) - Layout computed at render time in browser JS, not stored in schema - 124 tests passing, 99.5% coverage Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Extract parseFlag() and formatBuildSummary() into shared config.js - Guard urlToNodeId against protocol-relative, mailto:, tel:, and other URI schemes - Strip query strings and fragments from URLs before node ID resolution - Wrap writeFunnelJson in try/catch (matching writeFunnelHtml pattern) - Add partial rebuild debug log for funnel skip reasoning - Fix lenient mode log order (errors first, then warnings) - Add 15 new tests covering all new behavior Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
@alexphelps, did you want to review this now? I'm going to keep the visual builder very basic for now, as we want to build out the Campaign Toolkit more. |
|
@brettstirlingbond Can you provide a guide on how to use this and also update associated guides in the readme for users to use it. I dont see any documentation or screenshots that demonstrate how this feature is supposed to work and validation it works as expected across real world examples.
How does this fit into the broader picture with Campaign Tool Kit? |
- New docs/funnel-map.md covers all 6 validation rules with example
errors and fixes, CLI flag behavior, a full 4-page demo, and the
programmatic API
- New docs/examples/demo-funnel/ — copy-pasteable 4-page campaign
(product → checkout → upsell → receipt) with minimal layout
- New docs/images/funnel-valid.png and funnel-broken.png — real
screenshots of the generated .cpk/{slug}/funnel.html
- README.md gains a "Funnel Map" section linking to the guide;
Commands table now documents --lenient and --strict flags
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
@alexphelps documentation added. "How does this fit into the broader picture with Campaign Tool Kit?" I'm thinking Campaign Page Kit is more of a developer tool than a marketer's tool. We still need to refine how Marketers interact with the Campaigns hosted on CPK. |
|
@alexphelps anymore feedback on this? Hoping to have this live before we get traffic from TechTopia and HydroNozzle. |
Example of missing entry warnings that is running against all campaigns even though I chose Olympus to run locally. Most campaigns I have ever seen don't have an index page, and that's by design warnings above are noise. Next problem I see is it doesnt support Main problem I see at this time is, it doesnt work with even the most basic flows so it's just going to added noise and confusion, questions, and bugs. This tool will be useful for campaigns with dozens of pages and possible paths, we should build it testing with complex campaign flows so can see all the issues with how the graph visualization handles them. |
Per Product Owner direction: pull the HTML/SVG funnel visualization and keep only funnel.json. Consumers can build their own visual from the stable JSON schema (D3, Cytoscape, Mermaid, etc.). - Remove lib/engine/funnel-visual.js (373 lines) - Remove writeFunnelHtml call from build pipeline - Remove 3 visual tests (writeFunnelHtml x2, escapeHtml) - Update build-cpkPath test to assert funnel.html is NOT generated - Rewrite docs/funnel-map.md to focus on the JSON schema and programmatic API; add full schema documentation with field tables - Update README.md Funnel Map section (drop visual references, emphasize JSON consumption) - Remove docs/images/funnel-*.png screenshots 137 tests pass, 99.3% coverage. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
Closing per PO direction — feature kept out for now. Summary of the feedback that led to this:
Keeping the branch |
Summary
Adds build-time funnel graph serialization and validation for campaign pages. During
npm run build, the tool now:next_success_url,next_upsell_accept,next_upsell_decline)funnel.jsonto.cpk/{slug}/(developer-only, not deployed)--lenientto downgrade to warnings)Consumers can build their own visualization from the stable JSON schema (D3, Cytoscape, Mermaid, etc.).
Closes #10
Changes
lib/engine/funnel.js(new) — graph generation, 6 validation rules (BFS + reverse BFS), JSON outputlib/engine/build.js— funnel pipeline integration,.cpk/output, partial rebuild safety, lenient modelib/config.js—getCpkPath(), sharedparseFlag()andformatBuildSummary()helperslib/actions/build.js—--lenientflag, funnelErrors in exit code, uses shared helperslib/actions/dev.js— lenient by default,--strictoverride, funnelErrors surfaced, uses shared helpersindex.js— exportsgenerateFunnelMapandvalidateFunnelfor programmatic use.gitignore—.cpk/excluded from version controlValidation rules (6)
Security
urlToNodeIdguards against external URLs, protocol-relative, mailto:, tel:, javascript:, and other URI schemesDocumentation
docs/funnel-map.md— comprehensive guide covering the JSON schema (with field tables), all 6 validation rules with example errors and fixes, CLI flag behavior (--lenient/--strict), a complete 4-page demo campaign, and the programmatic APIdocs/examples/demo-funnel/— copy-pasteable 4-page campaign (product → checkout → upsell → receipt) with minimal layout; users can drop it into their ownsrc/to see the full flowREADME.md— new "Funnel Map" section with quickstart and link to the full guide; Commands table documents--lenientand--strictflagsTest plan
.cpk/--lenientdowngrades errors to warnings, exits zerowriteFunnelJsonfailure is warning-only (never blocks build)require('next-campaign-page-kit').generateFunnelMapfunnel.htmlis NOT generated (JSON-only output enforced by test)Scope note
An HTML/SVG visualization was previously included in this PR but was removed per Product Owner direction — the JSON schema is the stable contract, and consumers are free to build whatever visualization fits their stack.
🤖 Generated with Claude Code