feat(partners): wire the RPO/MSP application funnel end-to-end#241
Conversation
The application backend (POST /api/partners/apply → partner_applications insert + founder alert + branded welcome email, migration 005) had existed and been tested for months, but no UI ever called it: every /partners and /partners/kit CTA pointed at the generic /contact form. So the Stage-1 channel #1 funnel never ran — no RPO landed in partner_applications, no founder alert fired, no welcome email sent. The classic "capability with no caller" dangling thread. This ships the missing caller: - app/partners/apply/PartnerApplyForm.tsx — honest-fetch application form. Payload maps 1:1 to the route's zod schema (name, company, email, partnerType, numeric clientCount, message). Shows success only on res.ok && data.success; degrades to a direct, monitored inbox on any failure — never a fake success (the 2026-07-12 lead-shredder pattern). - app/partners/apply/page.tsx — SEO'd application page (canonical + OG, sitemap entry), offer recap, and a "what happens next" strip mirroring the welcome email's two-business-day promise. - Repointed all three partner CTAs (/partners x2, /partners/kit) from /contact to /partners/apply. Channel doctrine preserved: the form states the C3PAO exclusion (32 CFR Part 170 — assessors cannot refer tools to clients they assess). Guards: +18 tests. PartnerApplyForm.test.tsx (validation, exact payload shape, success-only-on-ok, honest fallback on both failure modes, C3PAO copy) and apply-funnel-contract.test.ts (regression guard: the route has a caller, no partner CTA falls back to /contact, page in sitemap, no-fake- success pattern holds). tsc 0 · lint 0 (new files) · full suite 1497/1497 · build clean. Docs: docs/PARTNER-APPLICATION-FUNNEL.md. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019737b2ENNDFaA7gPyg5hJo
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
This pull request has been ignored for the connected project Preview Branches by Supabase. |
The Proxy Build & Test job was red on main (predates this PR's funnel work, which touches no proxy files). Root cause: dependabot bumped better-sqlite3 12 → 13 (#232); v13's native binding requires Node >=22, but the proxy CI job pinned Node 20, so `npm ci` warned EBADENGINE and vitest's worker forks crashed on import ("Worker exited unexpectedly") — 0 tests ran. Fix: set the proxy job's node-version to 22 and correct proxy/package.json `engines.node` to `>=22.0.0` so the declared engine matches the dependency's actual requirement (was lying at >=20). Validated locally on Node v22.22.2: proxy tsc 0 · tests 61/61 · bench p99 1.049ms (<10ms contract) · build 0. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019737b2ENNDFaA7gPyg5hJo
|
Proxy Build & Test went red on the first commit, but the cause was pre-existing on Root cause: dependabot's Since it was blocking this PR from reaching all-green, I fixed it here (7019c47): bumped the proxy CI job to Node 22 and corrected Generated by Claude Code |
Continuity update: mark the funnel build gate green, note the PR #241 draft + Vercel preview, and log the pre-existing Proxy Build & Test fix so the next session starts accurate. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019737b2ENNDFaA7gPyg5hJo
Retrospective continuity note (todo log only): PR #241 merged to main as squash 002c97d — the RPO/MSP application funnel is live on houndshield.com, and the proxy Node-22 fix flips main's CI red→green (had been failing since the better-sqlite3@13 bump #232). Updates the "next action" line to reviewing partner_applications. No code change. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019737b2ENNDFaA7gPyg5hJo
Description
The RPO/MSP application backend —
POST /api/partners/apply→partner_applicationsinsert + founder alert + branded welcome email, plus migration005— has existed and been tested for months, but no UI ever called it. Every CTA on/partnersand/partners/kitpointed at the generic/contactform, so the Stage-1 channel #1 funnel never ran: no RPO landed inpartner_applications, no founder alert fired, no welcome email sent. The classic "capability with no caller" dangling thread (tasks/lessons.md, 2026-07-04).This ships the missing caller and closes the loop:
app/partners/apply/PartnerApplyForm.tsx— honest-fetch application form. Payload maps 1:1 to the route's zod schema (name,company,email,partnerType, numericclientCount,message). Shows success only onres.ok && data.success; degrades to a direct, monitored inbox (contact@houndshield.com) on any failure — never a fake success (the 2026-07-12 lead-shredder pattern).app/partners/apply/page.tsx— SEO'd application page (canonical + OG, sitemap entry), offer recap ($299 wholesale · 14-day local · no exclusivity · local-only), and a "what happens next" strip mirroring the welcome email's two-business-day promise./partners×2,/partners/kit) from/contact→/partners/apply.Channel doctrine preserved: the form states the C3PAO exclusion (32 CFR Part 170 — assessors cannot refer tools to clients they assess). No fabricated metrics, no sub-$499 pricing, no second grid.
Fixes # (no tracked issue — dangling-thread cleanup surfaced during the OODA session)
Type of change
Jordan's Test Plan (CMMC Buyer — required before merge)
npm run buildpasses incompliance-firewall-agent/(exit 0;/partners/applyprerenders static ○,/api/partners/applywired ƒ)proxy/patterns/not modifiedpartner_applicationsis a marketing lead table (name/company/email), never CUIVerification
npm run buildsucceeds locally (exit 0)eslint .= 0 errors; new files 0 warningstsc --noEmit= 0New guards (+18):
PartnerApplyForm.test.tsx— validation, exact payload shape (numericclientCount, omitted when blank), success-only-on-ok, honest fallback on both failure modes, C3PAO exclusion copy.apply-funnel-contract.test.ts— source-level regression guard: the route has a caller, the page renders the form, no partner CTA falls back to/contact, page in sitemap, no-fake-success pattern holds.Checklist
/contact)docs/PARTNER-APPLICATION-FUNNEL.md)anytypes added in compliance-critical code🤖 Generated with Claude Code
https://claude.ai/code/session_019737b2ENNDFaA7gPyg5hJo
Generated by Claude Code