One builder for 260 practice brands — and the console to run them all.
This is the working brief for the SGA practice-website builder. We tore down nine best-in-class sites, separated every takeaway by discipline, turned them into a build-ready module list, and specced the control plane that turns a pile of static sites into a governed fleet. It is written to be handed to an engineer.
What this document is — and how to read it
Who it's for
The engineer(s) building the site builder and its management layer, plus the marketing lead who owns the outcome. Sections 02–03 are the evidence; 04–07 are the build.
The one decision it drives
Which patterns become default, automatic modules across all 260 sites — and in what order to build them, given that forms, analytics, and a site registry don't exist yet.
How it's organized
Sources → Findings by discipline → Modules → Control plane → Roadmap. Every finding links to the site it came from and to the module it becomes. Use the left outline to jump.
The headline
Eight of the nine sites leave their structured data incomplete. Only Aspen ships the full schema stack. Emitting it automatically on every site is our cheapest, biggest edge.
Disciplines
Build status
#schedule anchorWhat exists today, and the three things that don't
Grounded in the current codebase: the builder is a module + recipe assembler that emits static HTML (47 modules in site-builder/modules/, 14 page recipes). It is a solid foundation — but three capabilities the management layer depends on are literally absent.
No lead forms gap
Every CTA is an in-page #schedule anchor. There is no <form>, no backend, no submission store, and no leads table in packages/shared-types.
No analytics gap
No GA/GTM/CF beacon on any generated site. There is no traffic, conversion, or funnel data to roll up — so nothing to manage yet.
No site registry gap
project-registry.json tracks tooling, not practice sites. No per-site record of domain, host, code path, owner, forms, or analytics exists anywhere.
Schema is placeholder partial
One live JSON-LD block hardcodes telephone:'[PHONE]', ratingValue:'5.0', reviewCount:'100'. Two renderers (site-builder/ + design/sga-worker/) also duplicate assembly logic.
Phase 0 has to come first
None of the patterns in this brief are measurable or governable until forms, analytics, and the registry exist. That is why the roadmap starts at Phase 0 and the control plane leads with the registry, not the dashboards.
The nine sites we benchmarked
Four local-service exemplars plus five chosen to fill their blind spots — dental at DSO scale, booking UX, DTC intake funnels, answer-engine authority, and procedure AEO. Each card links to the live site and the exact pages audited. Discipline chips show where each site is strongest.
FAQPage/AggregateRating schema; no OG cards./llms.txt, real FAQPage JSON-LD, programmatic neighborhood pages, no-PII cost calculator, named 3-year guarantee.{service}×{city} page grid, phone-first sticky top+bottom bars, 5-field form + named lead magnet + callback SLA, founder E-E-A-T on every page.FAQPage/Review/Service schema, no before/after gallery, no blog.flagship theme + per-brand --brand-* tokens, a ZIP→location resolver front door, entity-linked @graph JSON-LD, pooled national rating, site-wide GTM + Optimizely.FAQPage.MedicalBusiness+geo+hours+AggregateRating+50 Reviews+OfferCatalog+FAQPage+Breadcrumb+ReserveAction), localized office pages, structured offer with expiry.service×city pages, thin city hubs, client-only booking. We win on authenticity — a real local dentist per brand.{procedure} cost in {city} guides with a Key-Takeaways box.MedicalWebPage+MedicalCondition schema, and the "Reviewed by Dr. X, DDS · Updated {date}" E-E-A-T byline. Hub-and-spoke clusters.SearchAction/EntryPoint (free AEO surface), worked $/mo payment examples instead of ranges, a no-PII "am I a candidate?" quiz, provider-tier badges.FAQPage+Organization; blank locator results.What each discipline tells us to build
The same nine teardowns, reorganized by lens so the read is clean: from a Design perspective this, from an SEO perspective that, from an AEO perspective this. Each finding names the site it came from (linked) and the module it becomes (jump to the catalog).
Design
Visual system, layout, typography, brand tokens, imagery, and motion — how a site looks and feels, and how one component library can produce 260 distinct brands.
Lead with the patient's barrier (anxiety, shame about lapsed care), not the practice's credentials. Single repeated CTA, no competing buttons.
A single library re-skinned per practice via --brand-* CSS variables off practice_brand — Aspen & Groundworks both run hundreds of pages this way. Same skeleton, 260 skins.
Real project/space/team photography over stock, generous whitespace, one display + one text face. Matches SGA's light/white rule.
Slider comparing outcomes — the dental analog to Craftwork's before/after rooms. Three variants already exist; promote to a default.
SEO
Crawlable structure — URLs and IA, metadata, sitemaps, internal linking, and programmatic pages — that wins classic search at scale.
A generator that spins /services/{procedure}/{city} pages from the practice's service list + geo radius — the growth engine Craftwork, Manchester, and Groundworks all run. Aspen notably lacks it (white space).
Flat, keyword-only URLs, a {City} {Neighborhood} Dentist Near Me | {Brand} title formula, self-canonical, and BreadcrumbList on every page.
Per service line, auto-scaffold a pillar page + spoke pages on a fixed spine with a dense internal-link mesh — how Healthline concentrates topical authority.
Give each dentist a real URL (bio, credentials, own slots, own reviews) instead of a buried grid tile — strong for E-E-A-T and "Dr. {Name} {City}" queries.
AEO — answer-engine optimization
Structured data and answer-first content — how AI answer engines (Google AI Overviews, ChatGPT, Perplexity, Gemini) extract and cite a page. This is where the biggest, cheapest edge lives.
Auto-emit the complete graph from the practice record: Dentist/MedicalBusiness + geo + hours + AggregateRating + Review[] + OfferCatalog + FAQPage + Breadcrumb + ReserveAction. Aspen is the reference implementation to match.
Single-source the visible accordion and the FAQPage JSON-LD so they never drift. Only Craftwork does this; Tend, Manchester, Groundworks & Invisalign all skip it.
A curated, LLM-readable positioning file + link index generated per practice. Only Craftwork ships one — first-mover advantage across 260 sites at near-zero cost.
Question-H2 → 1-sentence answer → bullets, with a Key-Takeaways box as the 2nd element and worked $/mo cost examples — the exact shape AI Overviews lift.
"Reviewed by Dr. X, DDS · Updated {date}" wired to real staff + MedicalWebPage/MedicalCondition schema and a sources/history block. A near-free YMYL trust win.
Encode the "find a practice" ZIP field as a real SearchAction/EntryPoint JSON-LD — eligible for a Google sitelinks search box and a clean routing contract.
CRO — conversion
Hero, CTAs, booking/intake, forms, offers, and insurance/financing — how a visit becomes a booked patient. Requires the Phase-0 forms backend to be real.
One question per screen, progress bar, early name personalization, an earned "your visit plan" reveal, PII captured last as "so the office can confirm." PHI Phase-A, non-clinical question set.
Surface 4–6 real open times ("Next available: tomorrow 9:40") so a browse becomes a book at the list level; slot-first, PII-last. Needs the appointments feed; "request these times" fallback otherwise.
Low-friction intake with a named lead magnet + callback SLA, a honeypot, and a real backend that routes to a per-practice inbox. This is the Phase-0 foundation.
A persistent mobile bar with Book + the practice's local tel: number — the single biggest mobile conversion lever, present on all four round-1 sites.
A carrier-logo grid + "most PPO accepted" + plan lookup, answered before booking — removes the #1 dental objection at the decision point.
CareCredit / in-house plan "from $X/mo" and worked payment examples (fees − insurance = balance → $/mo) instead of vague ranges. A top dental lever Craftwork omits.
"$XX exam + X-rays / $0 with insurance" as a configurable component with a dollar value + expiration field so offers auto-expire and stay compliant.
Trust & credibility
Reviews, ratings, provider authority, guarantees, and transparency — the credibility that closes a hesitant patient.
Pull live Google reviews (never hand-typed), label "verified patient" from booked-and-attended appointments, show multi-axis stars (wait time, comfort) + earned ops badges, and emit Review/AggregateRating schema. Two-tier: network + local rating.
A named provider with photo, credentials, and philosophy on service pages turns an anonymous practice into an accountable person — where the individual-brand model beats a national chain.
A branded promise ("The {Practice} Promise") + a "what to expect at your first visit" block — anxiety reduction is dental-specific gold.
Platform & governance
The architecture that lets you run 260 brands at scale — routing, analytics/experimentation, one build path, and the control plane itself.
A network "find-a-practice" front door routing by geography over the Master Crosswalk (reusing lookup_practice), with service-aware pre-filter and "Center of Excellence" tier badges. Each brand keeps its own identity.
One shared GTM container across the fleet + an experiment slot baked into every template (Groundworks' Optimizely model), so you test once and roll the winner to all 260.
Collapse the two renderers (site-builder/ + design/sga-worker/) into one, and stand up the system-of-record every management surface reads from. This is the backbone of the control plane.
Module catalog
Every pattern above, as a discrete builder module — filter by discipline, read the source and status, and see relative build priority. Grounded in the current codebase (47 modules, 14 recipes, static-HTML assembler).
| Module | Discipline | Source | Priority | Status |
|---|---|---|---|---|
| Schema Graph Generator FAQPage · Dentist · Service · Review · AggregateRating · OfferCatalog · ReserveAction · Breadcrumb | AEO | All 9 · Aspen benchmark | Upgrade | |
| /llms.txt Generator per-practice LLM positioning + link index | AEO | Craftwork | Net-new | |
| FAQ Block (visible + schema) accordion single-sourced to FAQPage JSON-LD | AEO | Craftwork · Tend · Manchester · Aspen | Upgrade | |
| Service / Cost Answer Page "{procedure} cost in {city}", Key-Takeaways box, $/mo examples | AEO | Zocdoc · Invisalign · Healthline | Net-new | |
| Medical Review Byline + E-E-A-T "Reviewed by Dr. X, DDS" + MedicalWebPage/Condition | AEO | Healthline | Net-new | |
| SearchAction Resolver + COE Tiers ZIP box as SearchAction JSON-LD, service pre-filter | AEO PLT | Invisalign · Aspen | Upgrade | |
| Location Page Generator service×city + neighborhood mesh + sitemaps + titles | SEO | Craftwork · Manchester · Groundworks · Aspen | Net-new | |
| Topical Cluster Generator pillar + spokes per service line, internal-link mesh | SEO | Healthline | Net-new | |
| Provider Profile Pages indexable page per dentist — bio, credentials, slots | SEO TRU | Zocdoc · Aspen · Manchester | Upgrade | |
| Lead Forms + Submission Store 5-field intake, honeypot, routing, per-practice inbox | CRO | Manchester | Net-new | |
| Intake Funnel one-Q-per-screen, progress, "your plan" reveal, PII last | CRO | Hers/Hims | Net-new | |
| Live Slot Grid real open times on hero; slot-first, PII-last | CRO | Zocdoc | Net-new | |
| Sticky Action Bar mobile Book + local click-to-call, always visible | CRO | All round-1 | Net-new | |
| Emotional Hero barrier-dismissing headline + reassurance + one CTA | CRO DES | Tend | Upgrade | |
| Insurance Check carrier grid, "most PPO accepted", plan lookup | CRO | Tend · Zocdoc · Aspen | Net-new | |
| Financing Badge · Cost Estimator CareCredit / membership "from $X/mo"; no-PII price ranges | CRO | Manchester · GW · Aspen · Invisalign | Net-new | |
| New-Patient Offer Card "$XX exam / $0 w/ insurance", value + auto-expiry | CRO | Aspen · Hers/Hims | Net-new | |
| Verified Reviews + Rating Badges booked-&-attended "verified", multi-axis, ops badges | TRU | Zocdoc · Aspen · Groundworks | Upgrade | |
| Doctor / Founder E-E-A-T named provider, photo, philosophy, credentials | TRU | Manchester · Tend · Aspen | Upgrade | |
| Named Guarantee + First-Visit "The {Practice} Promise" + "what to expect" | TRU | Craftwork · Tend | Net-new | |
| Before / After Smile Gallery slider, per-brand themed | TRU DES | Craftwork | In builder | |
| Brand Token System one component set, per-practice --brand-* from practice_brand | DES PLT | Groundworks · Aspen · Invisalign | Upgrade | |
| ZIP → Practice Resolver parent find-a-practice directory over Master Crosswalk | PLT SEO | Groundworks · Invisalign | Net-new | |
| Analytics + Experiment Slot one shared GTM container, standing A/B slot per template | PLT | Groundworks | Net-new | |
| Canonical Build Path collapse site-builder/ + design/sga-worker/ into one renderer | PLT | internal (codebase) | Upgrade | |
| Site Registry + Control Plane 4 tables + 6-surface console (see §05) | PLT | internal (net-new) | Net-new |
Priority bars are relative build-sequence weight, not certainty. Status: In builder ships today · Upgrade exists but incomplete · Net-new does not exist. The schema block's placeholder values ([PHONE], 5.0, 100)† must be replaced with real per-practice data before scaling.
Control plane & data model
A single console over all 260 sites. Its first job isn't dashboards — it's to create the system-of-record that doesn't exist: one queryable place for every site's code, hosting, forms, and analytics. Six surfaces, backed by four new Drizzle tables in packages/shared-types.
Illustrative wireframe — the summary strip every surface shares.
Site Registry
One row per practice site: brand, city, live URL, domain, CF account, code path, recipe + package, owner, last build, form endpoint, analytics ID.
Health & Uptime
Uptime, Core Web Vitals, SSL & domain expiry, broken-link sweep — a fleet heatmap that surfaces the few sites needing attention.
Lead Desk
Where every submission lands, who can see it, and the SLA clock on follow-up — the question that has no answer today.
Analytics Rollup
Traffic → lead → booking funnel per site and portfolio-wide, off one shared GTM container.
SEO / AEO Coverage
Schema-coverage %, /llms.txt presence, service×city counts, sitemap status, review freshness — with drift alerts.
Publish & Deploy
One canonical build path, CF-account routing + 100-project cap management, one-click rebuild, per-site template version.
New data model — four tables
| Table | Purpose | Key fields |
|---|---|---|
| sites | system of record per practice site | practice_id · domain · live_url · cf_account · code_path · recipe · package · template_version · owner · form_endpoint · analytics_id · gbp_url |
| deployments | every build + publish, per site | site_id · commit · status · built_at · deployed_by · duration · cf_project |
| form_submissions | lead capture + routing (PHI-aware) | site_id · type · payload(non-PHI) · routed_to · sla_due · status · created_at |
| site_health_checks | uptime, CWV, SSL, schema drift | site_id · checked_at · uptime · lcp · cls · schema_coverage · ssl_expiry · broken_links |
Registry — a worked row
| Practice | Live URL | Code path | Host | Forms → | Analytics | Status |
|---|---|---|---|---|---|---|
| Ressler Dental | resslerdental.com | docs/practices/ressler | CF · sga | → inbox + CRM | GA4-RSL | Live |
| — example — | {brand}.com | docs/practices/{slug} | CF · {acct} | → {endpoint} | GA4-{id} | Stale |
| — example — | {brand}.com | docs/practices/{slug} | CF · {acct} | unrouted | none | Not deployed |
Forms stay in Phase A
Booking step 1 and the lead store capture non-clinical selections only (new patient, cleaning, cosmetic consult, emergency) plus name/phone/email to confirm. Robots hide any portal/auth route. No patient records or clinical detail until a BAA is in place (Phase B).
RACI — who owns what
Fifteen elements across build, content, SEO/AEO, forms, hosting, monitoring, and improvement — centered on the SGA Marketing team, with the adjacent roles the fleet needs. Roles are placeholders; confirm the real owner per column.
| Element | Marketing | Platform/Build | Market Mgrs | Practice Staff | Analytics | Compliance |
|---|---|---|---|---|---|---|
| Template & module development | C | R/A | I | I | C | C |
| Brand tokens & visual identity | R/A | C | C | I | · | · |
| Copywriting (AI draft → review) | R/A | R | C | C | · | C |
| Photography & media | A | I | C | R | · | · |
| Technical SEO (schema, sitemaps, llms.txt) | C | R/A | · | · | C | · |
| SEO/AEO content production | R/A | C | C | · | C | · |
| Local listings / GBP / reviews | A | C | R | C | · | · |
| Forms & lead-routing config | C | R/A | C | I | · | C |
| Lead follow-up & SLA | I | · | A | R | C | · |
| Hosting, domains & deploys | I | R/A | · | · | · | · |
| Uptime & performance monitoring | I | R/A | · | · | C | · |
| Analytics, tracking & reporting | C | C | I | · | R/A | · |
| CRO / A-B experiments | R/A | C | I | · | C | · |
| Accessibility & HIPAA / PHI | I | C | · | · | · | R/A |
| Registry / system-of-record upkeep | I | R/A | C | · | C | · |
Each row has exactly one A. Where Marketing and Platform both build, the split is intent vs. mechanism — Marketing owns what it should say, Platform owns that it works.
Roadmap — the order it has to happen in
A real dependency chain, not a menu. Nothing downstream is measurable or governable until the foundation exists — so it goes first.
Forms, analytics, and the registry
The three things that are literally zero today. Without them there is no data to manage and no console to build.
- Create
sites · deployments · form_submissions · site_health_checks; backfill the registry from existing deploys. - Ship a real lead-form backend + submission store (PHI Phase A), wired into every generated site.
- Drop one shared GTM container on all sites; collapse the two renderers into one build path.
Schema graph, llms.txt, answer-first pages
Turn structured data from a spec into automatic output — the advantage no competitor is executing.
- Full JSON-LD generator matching Aspen's stack, replacing the placeholder block.
- Per-practice
/llms.txt, auto sitemaps + robots, service×city generator with question banks. - Answer-first Service/Cost pages (Key-Takeaways, $/mo), the "Reviewed by Dr. X, DDS" byline, topical clusters.
Visits → booked patients
Ship the CRO + trust modules as inherited defaults, not per-site decisions.
- Intake funnel + live-slot booking as the primary path; sticky dual CTA, insurance check, financing, offer card.
- Emotional hero, named guarantee, first-visit, verified reviews + badges, before/after gallery, provider profiles.
The six-surface control plane
Now that the data exists, give it a front-end — and add the network front door.
- Registry, Health, Lead Desk, Analytics, SEO/AEO Coverage, Publish & Deploy over the Phase-0 tables.
- ZIP → practice resolver + parent "find-a-practice" directory (as a
SearchAction) over the Master Crosswalk.
The improvement engine
Make the fleet get better on a cadence, owned per the RACI.
- Content engine, CRO experimentation, reputation velocity, per-site scorecards.
- Performance budget + nightly coverage audits + quarterly template upgrades propagating fleet-wide.
Standing programs so the fleet compounds
A builder that ships and forgets decays. Each program has a cadence and an owner, and each is possible only once Phase 0's data exists.
AEO / SEO content engine Weekly
Expand per-service question banks, extend service×city coverage, refresh each /llms.txt; monthly guides + blog. Fed by the coverage surface's gaps.
CRO experimentation Monthly
A standing experiment slot per template; test hero, CTA, and funnel on high-traffic sites; roll winners fleet-wide in one push.
Reputation & review velocity Continuous
Live GBP pull keeps ratings honest; a monthly review-generation push raises count + recency, the signals engines weight.
Performance budget Per-change
CWV monitored continuously; a Lighthouse gate on every template change so a fleet-wide push can't regress speed.
Schema & SEO coverage audit Nightly
Coverage % per site; drift alerts when a page loses FAQPage, NAP, or sitemap entries. "Did it ship everywhere?" becomes a dashboard.
Per-site scorecard Monthly
Traffic → lead → booking + trust + coverage into one practice grade (reuse sga-scorecard), so Market Managers see their portfolio ranked.