[pm-manager/pm-coder][pricing-fallback-landing] add /pricing and /get-started fallback landing page - #144
Conversation
EPIC 24 - Pricing Page + GTM Surface. Two slices, one PR: - #5824: knowcap.ai/pricing - the locked 4-tier ladder (Free/Pro/Business/ Enterprise), wired into the shared editorial nav + footer + sitemap. - #7670: knowcap.ai/get-started - a plain, self-owned ad-landing fallback in case the agency's campaign page slips before the 16 Aug launch. Prices verified live against the public.plans table (Supabase), not copied from the Odoo card: free=$0, pro=$20/seat, business=$40/seat, enterprise= custom. No annual toggle on either page - #6953 (sibling ticket, same epic) found the app currently mischarges anyone who picks annual and is removing the annual offer everywhere before launch; showing it here would be the same false promise on the marketing site. Both pages forward utm_source/utm_medium/utm_campaign/utm_content/utm_term/ gclid/fbclid into the app.knowcap.ai/register link (app/lib/campaign.ts) so a paid-ad tag survives the click into signup - including the shared header/ footer's generic "Get Started Free" button (shell.tsx gains an optional registerHref override, backward-compatible, verified against all 20 existing callers). Built on the shared EditorialShell design system (matches /for/saudi-arabia) rather than the two dead components named in the ticket (hero-section.tsx, beta-hero-section.tsx - confirmed zero importers). Agent: pm-manager / pm-coder - run 11 Odoo: https://smetools.odoo.com/odoo/project.task/7670 Odoo: https://smetools.odoo.com/odoo/project.task/5824
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Warning Review limit reached
Next review available in: 13 minutes You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. 📝 WalkthroughWalkthroughAdded a no-index ChangesPricing and landing flow
Estimated code review effort: 3 (Moderate) | ~25 minutes Sequence Diagram(s)sequenceDiagram
participant Visitor
participant GetStartedPage
participant CampaignUtility
participant EditorialShell
participant Registration
Visitor->>GetStartedPage: Open page with campaign parameters
GetStartedPage->>CampaignUtility: Build registration URL
CampaignUtility-->>GetStartedPage: Return campaign-aware URL
GetStartedPage->>EditorialShell: Provide registerHref
EditorialShell->>Registration: Render campaign-aware CTA
Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@app/app/get-started/page.tsx`:
- Around line 107-109: Update the pricing Link in the get-started page to build
its href with withCampaignParamsRelative('/pricing', searchParams,
'get_started_fallback'), preserving campaign parameters for paid-ad visitors
while retaining the existing link text and destination.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: d10b2706-3325-4dad-a81c-58bc0fe9470c
📒 Files selected for processing (6)
app/app/get-started/page.tsxapp/app/pricing/page.tsxapp/app/sitemap.tsapp/components/editorial/shell.tsxapp/lib/campaign.tsapp/lib/pricing.ts
| <p className="gs-price-link"> | ||
| Full plan details on the <Link href="/pricing">pricing page</Link>. | ||
| </p> |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
Preserve campaign parameters on the pricing-page link.
When a paid-ad visitor selects this link, /pricing receives no campaign parameters. Its registration CTA then uses utm_source=pricing_page instead of the original campaign attribution.
Build the pricing href with withCampaignParamsRelative('/pricing', searchParams, 'get_started_fallback').
Proposed fix
-import { withCampaignParams } from '`@/lib/campaign`'
+import { withCampaignParams, withCampaignParamsRelative } from '`@/lib/campaign`'
@@
const registerUrl = withCampaignParams('https://app.knowcap.ai/register', searchParams, 'get_started_fallback')
+ const pricingUrl = withCampaignParamsRelative('/pricing', searchParams, 'get_started_fallback')
@@
- Full plan details on the <Link href="/pricing">pricing page</Link>.
+ Full plan details on the <Link href={pricingUrl}>pricing page</Link>.📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| <p className="gs-price-link"> | |
| Full plan details on the <Link href="/pricing">pricing page</Link>. | |
| </p> | |
| <p className="gs-price-link"> | |
| Full plan details on the <Link href={pricingUrl}>pricing page</Link>. | |
| </p> |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@app/app/get-started/page.tsx` around lines 107 - 109, Update the pricing Link
in the get-started page to build its href with
withCampaignParamsRelative('/pricing', searchParams, 'get_started_fallback'),
preserving campaign parameters for paid-ad visitors while retaining the existing
link text and destination.
…t the code refuses The Pro tier advertised 'Connect your own tools over MCP'. The live entitlement code requires the Business plan for both mcp_analyze and mcp_write and returns 'This MCP tool requires the Business plan.' to a Pro customer who tries it (entitlementService.ts). A $20/seat customer was being promised a feature the server blocks and then asked to pay double for it. The June feature matrix attached to EPIC 24's parent card (#6071) made the SAME assumption, so reading that document would not have caught this — the gate moved to Business about a week after the matrix was locked. Only the shipped code did. Pro's fourth bullet now names the personal integrations it genuinely has (personal_integrations IS in Pro's capability list). Business's MCP bullet now reads as the tier where MCP starts, dropping the 'not just read' phrasing that implied Pro had read-only access. Prices, the 5-meeting free cap, and every other Business/Enterprise bullet were verified against the live plans table and the code's own FEATURE_MIN_TIER map — all correct, no other change needed. Odoo: https://smetools.odoo.com/odoo/project.task/5824 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
What this is
EPIC 24 - Pricing Page + GTM Surface. Both open slices, one branch, one PR (pm-coder's standing rule: an epic's slices are never built separately):
/get-started) - insurance for the 16 Aug paid-ad launch in case the StratDev agency page slips./pricing) - the marketing site had no pricing surface at all.#6953 (the third child of this epic) was NOT touched - it already sits at stage "Push to Production" with its own fix landed.
Agent: pm-manager / pm-coder - run 11
Odoo: https://smetools.odoo.com/odoo/project.task/7670
Odoo: https://smetools.odoo.com/odoo/project.task/5824
A repo deviation, flagged on purpose
pm-coder's standing routine assumes the core
knowcapapp repo (worktrees offorigin/hassan, PRs tohassan). This ticket's code lives inknowcap-website, a different, satellite repo - confirmed directly (EditorialShell,/for/saudi-arabia,hero-section.tsxall live here, not in the app repo). Its own rules differ: trunk ismain(nohassanbranch exists here), so this worktree was cut fromorigin/mainand this PR targetsmain.Numbers verified against the live database, not copied from the ticket
Queried
public.plansdirectly (Supabase):monthly_price_centsper_seat_pricingFeature bullets per tier are drawn from each plan's own
capabilitiesjsonb column (capture / chat / ask / broadcast / extraction / artifacts / graph / personal_integrations / team_governance / admin_analytics / confirm_hierarchy / mcp_analyze / mcp_write / vertical_template), not invented.No annual toggle on either page. #6953 (this epic's sibling ticket, same launch window) found the app currently mischarges anyone who picks annual billing - no annual Stripe price exists - and is removing the annual offer everywhere (paywall, settings, pricing page, marketing site) before 16 Aug for exactly that reason. Showing "2 months free" here would be the identical false promise on the marketing site, so it's deliberately absent. Revisit once #6953 Part B ships a real annual price.
Design system
Both pages use the shared
EditorialShell(matches the live/for/saudi-arabiapage), nothero-section.tsx/beta-hero-section.tsx- both confirmed dead (zero importers, grepped) per the ticket's own warning. The oldcomponents/navbar.tsx/components/footer.tsxare ALSO dead (zero importers, not used by the homepage or anywhere else) - not touched.Wired "Pricing" into
EditorialHeader's nav andEditorialFooter's Product column, and both new routes intositemap.ts(/pricingincluded;/get-starteddeliberately excluded +robots: {index:false}, same treatment as the existing/betaad-funnel page - it's an ad destination, not an SEO surface).Campaign-tag attribution (#7670's own success criterion)
app/lib/campaign.tsforwardsutm_source/utm_medium/utm_campaign/utm_content/utm_term/gclid/fbclidfrom the incoming query string into theapp.knowcap.ai/registerlink. Verified live in a browser this carries through correctly, including a malformed/truncated tag (page still loads, link still works - no crash).Found and fixed a real gap while proving this live: the shared header/footer's generic "Get Started Free" button did NOT carry the tag - only the page's own two buttons did. A mobile visitor tapping the top-right button instead of the page's main CTA would have silently lost attribution. Fixed by giving
EditorialShellan optionalregisterHrefoverride (backward-compatible - verified all 20 existing callers ofEditorialShellpass no such prop, so their behavior is byte-for-byte unchanged).The app itself (
knowcap Main, a different repo) does not yet persist these params into the account record on registration - that's explicitly out of this slice's scope ("any change to what signup does" - #7670's own words). This only keeps the tag alive through the click.Browser proof (Stage 8)
Ran
next devlocally against this branch's own code (no live backend dependency - these are static content pages), driven in the shared automation Edge via Playwright./pricing: loads clean, 0 console errors, all 4 tiers render with correct prices/features, all register/book links carry forwarded campaign params. Screenshot at desktop (1280px) and mobile (390px) - both clean, tiers stack to one column on mobile./get-started: loads clean, 0 console errors (one unrelated Next.js dev-only HMR/bfcache websocket message, not a real app error - doesn't exist in production). All 4 register links (2 page CTAs + shared header + shared footer) verified carrying the tag. OG/Twitter card tags confirmed present and resolving to a real 328KB image (WhatsApp/LinkedIn share preview criterion). Screenshot at desktop and mobile - both clean, CTA reachable above the fold on a phone.?utm_source=%E2%9C%93%00trunc&utm_campaign=- page loads fine, 0 errors.Gates (both run as real, independent subagent invocations - no self-review)
/security-review: CLEAN, 0 findings. Query-string values only ever reach the link viaURLSearchParams.set()(auto-encoded) + React's own attribute escaping - two independent layers close the injection/XSS/open-redirect angle. All base URLs confirmed hardcoded, never user-derived, so SSRF doesn't apply./bug-radar(quick, adapted): CLEAN, 0 findings. Note: this skill's escapes ledger is written for the core app repo (auth/DB/org-scoping bugs) - none of those classes are structurally possible on this diff (no DB routes, no auth surface touched), checked and confirmed rather than skipped. Silent-failure sweep, new-discriminant lens, and the shared-component regression check (all 20 existingEditorialShellcallers) all came back clean.engineering/qa-manager/state/radar-health.jsonthis run - that file is under heavy, live concurrent write traffic from qa-manager's own dark-watcher fleet, and this is a one-off adapted cross-repo check, not a literal scheduled bug-radar run against the app. Gate results recorded here and in pm-coder's own state instead.Holding at PR - not merging (Type-1 surface)
This page makes public price promises and IS launch copy.
knowcap-websiteis a satellite repo whose PRs normally auto-merge once the gate passes - but per pm-coder's dispatch brief, a page that makes public pricing promises to the world is exactly the kind of Type-1 surface reserved for Hassan's own click, not an automatic merge. Holding here rather than assuming the satellite auto-merge rule covers this content.What Hassan gets from merging this
/pricingand/get-startedgo live on knowcap.ai once this merges (Vercel auto-deploysmain). Both are ready destinations for the 16 Aug ad campaign if the agency's own page isn't ready in time.Summary by CodeRabbit