Founder HQ — Expected Output Spec
1. Why this exists
Founder request, verbatim (2026-09-11): "I don't want to look up stuff in files. for whatever i might need for testing, i need all links available in some UI screen... a robust dashboard like the realtor one with an ARIA that knows my system and everything inside out... tabs for sections and all the links I would need as CEO."
This is NOT a replacement for the existing /founder/[token] operations dashboard (metrics,
watchtower, outreach, QA — FounderDashboard.tsx). Founder HQ is a link directory + assistant:
a single page that answers "where do I click to test/see/manage X" without opening a file or
asking an agent. It is linked from the existing dashboard header.
2. Non-goals (v1)
- No writes to prod data. Every action on this page either navigates away (a link) or answers
a question in a chat box. Nothing on
/hqitself mutatespremium_churches,churches, Stripe, or any customer table. - No customer data display beyond counts. No church names, no contact PII, no transcripts. The
assistant may state aggregate facts already public in
PRICING.md/knowledge/data/*.yaml/product_knowledge, never per-customer records. - No secrets committed. Any link containing
FOUNDER_TOKENor an admin token is built server-side at render time from env/DB. The registry source file never contains a literal token. - Not a second QA tool. It links to
/ensure-solidoutput and readiness docs; it does not reimplement them. - Not host-aliased.
/founder/*is not rewritten by any brand-host middleware branch (verified — nopathname.startsWith('/founder')branch exists insrc/middleware.ts). One canonical URL:churchwiseai.com/founder/[token]/hq, reachable from any host that resolves to the deployment (including*.vercel.apppreviews) since nothing here depends on host-based rewriting.
3. Auth model
Same pattern as every other /founder/[token]/* page (morning-brief, root dashboard):
- Server component reads
params.token, compares toprocess.env.FOUNDER_TOKEN. - Mismatch or unset env var →
notFound()(Next.js 404), not a 403 — indistinguishable from a route that doesn't exist, matchingdemo-record-mode's stated rationale. export const dynamic = 'force-dynamic'(no ISR/caching of a token-gated page).robots: 'noindex, nofollow'inherited from the existingfounder/[token]/layout.tsx.- The chat API route (
/api/founder/hq-chat) re-validates the token independently — a page render passing auth does not imply the API trusts the same request. Token accepted viaAuthorization: Bearer <token>header or JSON body{ token }; either must equalFOUNDER_TOKEN.
4. Data model — the registry is the product
src/lib/founder/hq-links.ts exports a typed, static structure:
type StaticHqLink = { kind: 'static'; label: string; url: string; note?: string; badge?: string };
type ResolvedHqLink = {
kind: 'resolve';
label: string;
resolve: (token: string) => string | null; // null = cannot resolve server-side
note?: string;
badge?: string;
fallbackNote: string; // shown when resolve() returns null
};
type HqLinkEntry = StaticHqLink | ResolvedHqLink;
type HqSection = { id: string; label: string; description: string; links: HqLinkEntry[] };
export const HQ_SECTIONS: HqSection[];
staticentries are literal, public URLs (property homepages, docs portal, GitHub).resolveentries are for anything that must embedFOUNDER_TOKENor another secret — the function takes the already-validated founder token and returns a live URL, ornullif the required env/DB value is missing (rendered withfallbackNoteinstead of a dead link, never a broken href).- The page (
hq/page.tsx) is a server component: it calls aresolveHqSections(token)helper that walksHQ_SECTIONS, calls everyresolve(), and passes the fully-resolved plain-URL structure to the client component. Noresolvefunction or token ever reaches client-side JS — the client component receives only strings. - This registry doubles as the daily QA sweep's link-liveness source (future work, not v1): any
automated "check every founder-facing link" job should import
HQ_SECTIONSrather than maintaining a second list. v1 ships the registry + a unit test that every staticurlparses as a valid URL and the source file contains no literal token value (grepping for the env var nameFOUNDER_TOKENbeing used, never a token string).
5. Tabs — what each shows
Six tabs, tab bar mirrors the ChurchWiseAI design system (.btn-gold active state, navy/gold/cream
cards) at the same visual bar as /realtor/app and the existing FounderDashboard.tsx.
5.1 Test & Demo
churchwiseai.com/demo— live browser voice+chat demo./s/gospel-fellowship-b1d6— the church Pro Website demo tenant referenced indemo-record-mode's own instructions page./realestate-demo— the real-estate demo chooser index./wiseaiagency/playground— multi-vertical demo playground (funeral/vet/dental/restaurant/etc.).- Demo dial-in numbers, sourced from
src/lib/phone-registry.tsPHONE_REGISTRY, filtered to entries withagent !== null(i.e. actually routed) —demoUS(469) 615-2221anddemoCA(365) 825-4095, both Grace Community Church.spareCA(+13658253552) is EXCLUDED even though the source file's own comment calls it "unassigned" — per founder-confirmed fact (2026-09-10), that number is now Team Beckett's real production line and must never be listed as a test/demo number. This is a deliberate override of a stale code comment, noted inline in the registry source. - Sales/support toll-free
(888) 603-0316— listed as "call the AI sales agent yourself," not a demo line. - Demo recording-mode toggle: two
resolvelinks,/api/founder/demo-record-mode?token=…(ON, 24h) and the same with&off=1(OFF), each labelled with what it does per the route's own docstring. /bookon each live host with a voice/chat demo path: churchwiseai.com, wiseaiagency.com, funeralwiseai.com, veterinarywiseai.com (booking calendar + copy is host-aware persrc/lib/booking-calendars.ts).
5.2 Properties
One row per property in knowledge/readiness/*.yaml, production_url field, with the yaml's
status rendered as a badge (live / coming_soon / pre-launch):
| Property | URL | Status |
|---|---|---|
| ChurchWiseAI | churchwiseai.com | live |
| PewSearch | pewsearch.com | live |
| IllustrateTheWord | illustratetheword.com | live |
| SermonWise | sermonwise.ai | live |
| ShareWiseAI | sharewiseai.com | coming_soon |
| WiseAI Agency | wiseaiagency.com | live |
| FuneralWiseAI | funeralwiseai.com | live |
| VetWiseAI | veterinarywiseai.com | pre-launch |
| Pro Website | churchwiseai.com/pro-website | live |
| RealtyWiseAI | realtywiseai.com | live — see §6 |
| CompareLocal.ca | comparelocal.ca | live (3 markets) |
| johnmoelker.com | johnmoelker.com | live |
Each row's static child links (pricing/contact/blog) are only added where the page is confirmed to
exist in src/app/<brand>/*; wiseaiagency.com/chamber gets its own row per the founder's Sept 17
event. No child link is invented from a URL pattern guess — every one is verified against a
page.tsx in the current tree before being added to the registry (Hard Guardrail: "don't guess
URLs, verify in code").
5.3 Admin
/admin/[token](resolve, church admin dashboard,FOUNDER_TOKENused only if it happens to equal a real admin token — see §6 open item) — actually resolves against the demo church admin token, notFOUNDER_TOKEN(they are different secrets); documented as an open item since the page cannot look up a real customer's admin token without a DB read the spec's non-goals forbid wiring in v1. Rendered withfallbackNotepointing at the DB query to run instead.- Every existing
/founder/[token]/*sibling page, enumerated from the current directory tree:morning-brief,daily-ops,demo-tour,growth(+growth/geo,growth/campaigns),guide-review,internal-contacts,outreach,outreach-engine,sermon-quality,submissions,voice-clients,webhook-inbox. /realtor/app— WiseAI Realtor customer dashboard (for QA'ing the customer experience directly).wiseaiagency.com/business/<admin_token>— noted asresolve-shaped but not resolvable server-side without a DB lookup (out of v1 scope) → rendered with a "look up inlocal_business_setup_profiles" fallback note rather than a guessed/dead link.
5.4 Sales & CRM
- GoHighLevel login (
app.gohighlevel.com) + one deep link per sub-account (app.gohighlevel.com/v2/location/<locationId>/dashboard) using the three location IDs on record: churchwiseai45se8cO8HtXSwLmCL9vw, wiseaiagency5JXMml9xsYhsk2bLsNYN, johnmoelkergfmy9CQ3wB52trxeWL9T. - Both Google Business Profiles + their official public review links: WiseAI Agency
g.page/r/CRj28zWUWiC_EBM/review, ChurchWiseAI LTDg.page/r/CZ4BxRKaQfhJEBM/review. - Stripe live dashboard (
dashboard.stripe.com/acct_1SSPz2FaoK5IPzNo/dashboard). - All five GHL booking calendar public widget URLs, derived by calling
bookingWidgetUrl()fromsrc/lib/booking-calendars.tsonCHURCHWISEAI,WISEAIAGENCY,funeralwiseai,vetwiseai, andTHIRTY_MIN— never retyped as literal calendar IDs, so a future calendar rebuild (like the 2026-09-08 round-robin migration) cannot leave this page stale.
5.5 Ops
- Vercel dashboard, GitHub repo (
github.com/ChurchWiseAI/churchwiseai-web) + open-PRs filter, Supabase project dashboard (wrwkszmobuhvcfjipasi), LiveKit Cloud project (cwa-voice-9x077mph/p_5u9xu5ysoly),docs.churchwiseai.com. - Daily Brief artifact (the standing URL:
https://claude.ai/code/artifact/6baf7fc5-b237-4aa7-a773-e1afd186b5cd). C:\dev(the knowledge/ops monorepo) does have a remote —github.com/ChurchWiseAI/DEV, default branchmaster— soDECISION_LOG.md,BACKLOG.md, and the QA sweep outputs get realgithub.com/ChurchWiseAI/DEV/blob/master/<file>links, not local-path placeholders.
5.6 Chamber (Sept 17)
wiseaiagency.com/chamber(live page).- Runway checklist rendered as static text (not links): Sept 12 print, Sept 14 run-throughs, Sept 16 Angela/AV check, Sept 17 arrive 11:15.
- Packet file list rendered as plain text (local paths under
C:\dev\CHAMBER_PACKETS\), explicitly NOT as clickable links (they are local files, not URLs — a fake link would violate the "don't-guess-URLs" guardrail).
6. Open items — could not resolve server-side (flagged for founder/lead decision)
- RealtyWiseAI status contradiction. The task brief that requested this page described
realtywiseai.com as "DORMANT (DNS unpointed)." Live verification in
knowledge/readiness/realtywise.yaml(dated 2026-09-10) found the OPPOSITE: the domain resolves, returns HTTP 200, and serves real marketing page code (src/app/realtywiseai/page.tsx). This spec and the registry mark it live, per the more recent, code-verified source. Needs founder/lead reconciliation on which claim was stale. /admin/[token]andwiseaiagency.com/business/<admin_token>cannot be resolved to a working URL without a live DB read (which admin token for which church?) — out of scope for a registry that must not perform DB writes/reads at import time. Rendered with a fallback note, not a dead or guessed link.- GHL sub-account deep-link URL shape (
app.gohighlevel.com/v2/location/<id>/dashboard) is the standard GHL pattern but was not click-verified in this session (no browser session available to the agent building this). Flagged as best-effort, not verified.