<!--
Topical Authority Playbook

Part of the free Claude Code template library from BILT AI — https://biltai.io/claude-templates

These are the actual playbooks used to build and ship production SaaS apps with
Claude Code. They're written to be handed to an agent as-is: point Claude at one
and it has the full pattern, the schema, the gotchas, and the "don't do this"
list. Paths, project refs, and org names have been replaced with placeholders
(<your-app>, <supabase-project-ref>, <your-github-org>) — search for "<" and
fill in your own before running.

Free to use, modify, and ship. No attribution required.
-->

# Topical Authority Playbook

**Portable spec for building SEO + GEO topical authority for any new SaaS app.**
Built from the Kompozy / BILT KONTENT ENGINE buildout (2026-04-23 → 2026-05-20). Reusable across the 10-app portfolio: cold email engine, cold SMS, cold DMs, cold WhatsApp, affiliate platform, giveaway app, lead scraper, AI cold caller, and any future SaaS.

Hand this spec to a Claude Code agent on a new app project. Tell the agent: **"Execute this playbook against [APP_NAME] in [DOMAIN], ICP is [ICP], primary keyword cluster is [KEYWORD]."** The agent will know exactly what to build.

---

## 0. Use this spec

**Inputs the agent needs from the user before starting:**

1. **APP_NAME** — e.g. "Kompozy"
2. **DOMAIN** — e.g. "kompozy.io" (must be registered + Vercel-attached before the agent runs)
3. **ONE_LINER** — e.g. "Autonomous content engine — ingest one source, fan out to 5 output buckets, publish to 9 platforms."
4. **ICP** — specific buyer (e.g. "real estate agents", "B2B SaaS founders running outbound", "creator-operators with podcast + newsletter")
5. **PRIMARY_KEYWORD_CLUSTER** — 1-3 head keywords (e.g. "AI content tools", "cold email automation", "lead scraping")
6. **TOP_5_COMPETITORS** — exact brand names + URLs (e.g. OpusClip, Submagic, HeyGen)
7. **PRICING_TIERS** — name + monthly price + credits/seats per tier
8. **FOUNDER_BIO** — 2-3 sentences (used in `Person` schema + About page)

**Outputs the agent will produce:**
- 250-350 prerendered SEO pages on the marketing surface
- 15-25 free interactive tools at `/tools`
- Full schema.org graph (Organization, Article, FAQPage, HowTo, SoftwareApplication, Person, BreadcrumbList)
- Sitemap + robots.txt + llms.txt
- Email auth recipe (SPF + DKIM + DMARC)
- A `docs/outreach/seo-geo-todos.csv` operator checklist
- A weekly LLM citation tracker (optional — Phase 3)

Total agent time: **~40-60 hours of focused build work** depending on app complexity, spread across 4-6 weeks calendar time. Founder time: **~30-50 hours** (mostly outreach, reviews, content review).

---

## 1. The 5-layer topical authority model

Every layer reinforces every other layer. Don't skip layers.

```
┌────────────────────────────────────────────────────────┐
│  L5: Research                                           │  Original data, "Index" pieces (citation magnets)
│  Examples: AI Tells Index, deliverability benchmarks    │
├────────────────────────────────────────────────────────┤
│  L4: Tools (free, indexable)                            │  Pure-math calculators + LLM-powered tools
│  Examples: Stack Cost Comparison, AI Tells Detector     │
├────────────────────────────────────────────────────────┤
│  L3: Spokes                                             │  /guides, /roundups, /migrate, /alternatives,
│                                                          │   /workflows, /outputs, /integrations, /for, /blog
├────────────────────────────────────────────────────────┤
│  L2: Cluster Hubs                                       │  10-12 pillar pages, one per topic family
│  Examples: /repurpose, /autonomous, /brand-voice        │
├────────────────────────────────────────────────────────┤
│  L1: Homepage + Brand Surface                           │  Single page, full Organization schema
└────────────────────────────────────────────────────────┘
```

**Why this stack:** Google + LLMs both reward topical depth. A single 5,000-word post on "AI content tools" loses to 100 pages where every page covers one specific facet of the topic and they all link to each other.

**Cluster count discipline:** 10-12 cluster hubs is the sweet spot. Fewer = thin authority. More = diluted attention; you can't service 30 clusters well as a small team.

---

## 2. File / folder architecture

Mirror this exactly in the new app's Next.js App Router project. Paths shown are `src/app/...`.

```
src/app/
├── page.tsx                          # Homepage — Organization schema, full ICP messaging
├── about/page.tsx                    # Organization + Person schema (founder)
├── pricing/page.tsx                  # Pricing tiers + Offer schema
├── pricing/calculator/page.tsx       # Interactive pricing calculator (tool)
├── signup/page.tsx                   # Conversion endpoint, NoIndex meta
├── compare/page.tsx                  # Master competitor comparison grid
│
│   # ─────── L2: Cluster hubs (one folder per cluster) ───────
├── [cluster-1-slug]/page.tsx         # e.g. /repurpose, /autonomous, /brand-voice
├── [cluster-1-slug]/[slug]/page.tsx  # Cluster spokes (10-15 per cluster)
├── [cluster-2-slug]/...
│   # ... 10-12 total cluster hubs ...
│
│   # ─────── L3: Spokes (cross-cutting page types) ───────
├── guides/page.tsx                   # Index of long-form guides
├── guides/[slug]/page.tsx            # Article schema, TOC, direct-answer, FAQ
├── roundups/page.tsx                 # "Best [X]" listicle index
├── roundups/[slug]/page.tsx          # Article + ItemList + FAQPage schema
├── migrate/page.tsx                  # Migration guides index
├── migrate/from-[competitor]/page.tsx # HowTo + FAQPage schema
├── alternatives/page.tsx             # Alternatives hub
├── workflows/[slug]/page.tsx         # Source → destination workflow pages
├── outputs/[slug]/page.tsx           # One per output type your product produces
├── integrations/[slug]/page.tsx      # One per 3rd-party integration
├── for/[slug]/page.tsx               # ICP / industry-specific landing pages
├── blog/page.tsx                     # Blog hub
├── blog/[slug]/page.tsx              # Article schema (NO opengraph-image.tsx — see §10)
├── research/page.tsx                 # Original-data studies index
├── research/[slug]/page.tsx          # The citation-magnet pieces
├── reviews/page.tsx                  # Customer reviews aggregator
├── case-studies/page.tsx             # Named customer stories
├── glossary/page.tsx                 # Term index
├── glossary/[slug]/page.tsx          # DefinedTerm schema
├── faq/page.tsx                      # FAQPage aggregator
├── changelog/page.tsx                # Product update log
│
│   # ─────── L4: Tools (free, indexable) ───────
├── tools/page.tsx                    # Tool gallery index
├── tools/[tool-slug]/page.tsx        # SoftwareApplication + HowTo schema
│
│   # ─────── L5: Research ───────
├── research/[slug]/page.tsx          # Same path as L3 — same data study layer
│
│   # ─────── Discoverability files ───────
├── sitemap.ts                        # Generates from src/lib/* manifests
├── robots.ts                         # Allow / + disallow /dashboard, /admin, /api
├── llms.txt/route.ts                 # LLM-readable site map
├── opengraph-image.tsx               # ROOT ONLY — never per-slug (see §10 lab note)
├── icon.svg                          # Brand favicon
├── apple-icon.png                    # 180x180 PNG (NOT SVG — iOS rejects)
└── not-found.tsx                     # 404 with noindex meta
```

**Library / data files** (where content lives, separate from page components):

```
src/lib/
├── clusters.ts                       # Cluster hub definitions (slug, hubTitle, faq, spokes[])
├── spokes.ts                         # Spoke posts under each cluster
├── use-cases.ts                      # /for/[slug] ICP pages
├── seo-collections.ts                # TEMPLATES, OUTPUTS, WORKFLOWS, INTEGRATIONS arrays
├── guides.ts                         # Long-form guide entries
├── roundups.ts                       # "Best [X]" listicle entries
├── migrations.ts                     # Per-competitor migration guides
├── vs-comparisons.ts                 # Comparison page data
├── glossary.ts                       # Glossary terms
├── blog-posts.ts                     # Blog post entries (BlogPost type)
├── tools-manifest.ts                 # Tools index (status: 'live' | 'soon')
├── glossary-autolink.ts              # Auto-link first occurrence of glossary terms
└── research/[study-slug].ts          # One file per data study
```

**Shared components:**

```
src/components/
├── MarketingPage.tsx                 # Outer chrome (header, footer, nav)
├── ClusterHubPage.tsx                # L2 hub layout (renders hub + cluster spokes)
├── ClusterSpokePage.tsx              # L3 spoke layout
├── ToolShell.tsx                     # Tool page wrapper (JSON-LD + breadcrumbs + CTA)
├── Breadcrumb.tsx                    # Single breadcrumb component used everywhere
└── EmbeddedVideo.tsx                 # YouTube embed + VideoObject schema (optional)
```

---

## 3. Schema discipline by page type

**Every page MUST emit at least one schema.org type.** Pages without schema get ignored by LLM citation systems.

| Page type | Required schemas | Required fields |
|---|---|---|
| Homepage | `Organization` + `WebSite` + `BreadcrumbList` | `name`, `url`, `logo`, `sameAs[]` (LinkedIn, X, YouTube, GitHub, Crunchbase), `founder`, `description` |
| About | `Organization` + `Person` (founder) + `BreadcrumbList` | `Person.name`, `Person.url`, `Person.image`, `Person.sameAs[]`, `Person.affiliation` |
| Cluster hub | `WebPage` + `BreadcrumbList` + `FAQPage` (5-7 FAQs) | `name`, `description`, FAQ Q&A pairs |
| Cluster spoke | `Article` + `FAQPage` + `BreadcrumbList` | `headline`, `author` (Person), `datePublished`, `dateModified`, `publisher` (Organization) |
| Guide / blog post | `Article` + `FAQPage` + `BreadcrumbList` | Same as spoke. Add direct-answer 40-80 word paragraph for LLM citation. |
| Roundup | `Article` + `ItemList` + `FAQPage` + `BreadcrumbList` | ItemList items name each competitor with `Product` schema if appropriate |
| Migration guide | `HowTo` + `FAQPage` + `BreadcrumbList` | Numbered steps with `HowToStep.name` + `HowToStep.text` |
| Comparison page | `Article` + `BreadcrumbList` | Mention competitor as `Product` if defensible |
| Tool page | `SoftwareApplication` + `HowTo` + `FAQPage` + `BreadcrumbList` | `name`, `applicationCategory`, `operatingSystem`, `offers` (Price: $0) |
| Research / data study | `Article` + `Dataset` + `BreadcrumbList` | `Dataset.name`, `Dataset.distribution[]` (link to Hugging Face if published) |
| Reviews | `CollectionPage` + `BreadcrumbList` | **Only emit `AggregateRating` + `Review` schema when you have 3+ NAMED, verifiable reviewers.** Google penalizes anonymous review markup. |
| FAQ | `FAQPage` + `BreadcrumbList` | One FAQPage per page; merge into Article schemas where appropriate |
| Glossary term | `DefinedTerm` + `BreadcrumbList` | `name`, `description`, `inDefinedTermSet` |

**JSON-LD emission pattern (consistent across the codebase):**

```tsx
const jsonLd = {
  '@context': 'https://schema.org',
  '@graph': [
    { '@type': 'Article', '@id': `${url}#article`, ... },
    { '@type': 'FAQPage', mainEntity: [...] },
    { '@type': 'BreadcrumbList', itemListElement: [...] },
  ],
};

return (
  <>
    <script type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }} />
    {/* page content */}
  </>
);
```

Always inline (`dangerouslySetInnerHTML`), never use `<Script>`. Google parses inline JSON-LD on initial HTML; deferred script tags can be missed by some crawlers.

---

## 4. The free tools layer

**The tools layer is the highest-ROI investment for both SEO and GEO.** Each tool is a standalone page that ranks for a specific question + acts as a citation magnet because LLMs love linking to interactive tools.

**Three zones** by build cost vs runtime cost:

| Zone | Type | Build cost | Runtime cost | Examples |
|---|---|---|---|---|
| Zone 1 | Pure-math calculator | Low (2-4 hr/tool) | $0 | Cost calculators, ROI estimators, break-even, comparison checkboxes |
| Zone 2 | Light LLM tool | Medium (4-6 hr/tool) | ~$0.001-0.005/call | Subject line testers, niche validators, voice analyzers |
| Zone 3 | Heavy LLM / vision tool | High (6-10 hr/tool) | ~<credit-price>-0.02/call | Thumbnail CTR predictors (vision), brand voice analyzers (multi-input), transcript clip pickers |

**Target mix for a new app:** 12 Zone-1 + 5 Zone-2 + 3 Zone-3 = 20 tools minimum. This matches the Kompozy launch (21 tools shipped).

**Manifest pattern** ([src/lib/tools-manifest.ts](Active/BILT-KONTENT-ENGINE/src/lib/tools-manifest.ts) is the reference):

```ts
export type ToolEntry = {
  slug: string;
  name: string;
  description: string;
  category: ToolCategory;
  keywords: string[];
  runtime: 'static' | 'llm';
  status: 'live' | 'soon';
};

export const TOOLS: ToolEntry[] = [/* ... */];
```

**Shared LLM endpoint** ([src/app/api/tools/llm/route.ts](Active/BILT-KONTENT-ENGINE/src/app/api/tools/llm/route.ts)):
- Single endpoint, tool discriminator in body
- Per-tool system prompt + Zod input schema
- Rate-limited per-IP (8/hr) + global (1500/hr) via Upstash
- Anonymous — no auth required (proxy.ts must include `/api/tools` in `PUBLIC_API_PREFIXES`)
- Provider-agnostic — supports OpenAI + Anthropic with automatic `max_completion_tokens` retry for reasoning models
- Image-aware — vision tools pass `images: [{ src, label }]` with base64 data URLs or HTTPS

**ToolShell component** ([src/components/ToolShell.tsx](Active/BILT-KONTENT-ENGINE/src/components/ToolShell.tsx)):
- Wraps every tool page
- Emits `SoftwareApplication` + `BreadcrumbList` + `FAQPage` JSON-LD from a single ToolEntry
- Renders the widget as children
- Adds related-tools cross-links footer
- Adds CTA to signup at the bottom

This pattern means each new tool = ~50 lines (a `Widget.tsx` client component) + ~25 lines (a `page.tsx` server wrapper). 21 tools in 3 commits is achievable.

---

## 5. Technical SEO hygiene checklist

Run this before public launch:

**Sitemap** ([src/app/sitemap.ts](Active/BILT-KONTENT-ENGINE/src/app/sitemap.ts) is reference)
- [ ] Auto-generates from all `src/lib/*` manifests (don't maintain a parallel list — drift kills you)
- [ ] All URLs return 200 (HEAD-test every sitemap URL pre-launch)
- [ ] Priorities tiered: homepage 1.0, cluster hubs 0.95, pillar pages 0.9, supporting pages 0.7-0.85
- [ ] Real `lastModified` dates per entry (not "now" — Google's freshness signals care)

**Robots** ([src/app/robots.ts](Active/BILT-KONTENT-ENGINE/src/app/robots.ts))
- [ ] Disallow: `/dashboard/`, `/admin/`, `/api/`, `/auth/`, `/onboarding/`, `/signin`
- [ ] Sitemap declared
- [ ] No wildcards that accidentally block sub-paths

**llms.txt** ([src/app/llms.txt/route.ts](Active/BILT-KONTENT-ENGINE/src/app/llms.txt/route.ts))
- [ ] Site map in LLM-readable format
- [ ] Generated from same manifests as sitemap.ts
- [ ] Returns text/plain

**Redirects** ([next.config.ts](Active/BILT-KONTENT-ENGINE/next.config.ts))
- [ ] All `permanent: true` (308) for moved URLs
- [ ] Never link internally to a URL that 308s — point at canonical directly (Bing/Google mark the source URL "excluded: redirect")

**Internal-link density**
- [ ] Every long-form post has 5-8 internal links minimum
- [ ] Glossary auto-linker active ([src/lib/glossary-autolink.ts](Active/BILT-KONTENT-ENGINE/src/lib/glossary-autolink.ts)) — first occurrence of each glossary term auto-links to its term page
- [ ] No internal 308s (run a HEAD-audit pre-launch)

**Core Web Vitals**
- [ ] LCP < 2.5s on Slow 4G + Moto-G-class CPU
- [ ] CLS < 0.1
- [ ] INP < 200ms (measured once you have real traffic via CrUX)
- [ ] Run Lighthouse on landing + one cluster hub + one spoke pre-launch
- [ ] Inline CSS via `experimental.inlineCss: true` in next.config.ts (saves 1-1.3s mobile LCP)

**OG images**
- [ ] Per-route static OG PNG generated at build time via `scripts/generate-og-images.mjs`
- [ ] **NEVER use per-slug `opengraph-image.tsx`** — Satori/Resvg variable-font glyph table can crash Vercel prerender (BKE lab note 2026-04-24). Use static PNGs only.
- [ ] Apple touch icon: 180x180 **PNG** (NOT SVG — iOS rejects SVG)

**Domain auth (SPF + DKIM + DMARC)**
- [ ] SPF: `v=spf1 include:<ESP> -all` (single TXT, strict `-all`, includes for every sending provider)
- [ ] DKIM: provider-specific selector configured per ESP
- [ ] DMARC: start at `v=DMARC1; p=quarantine; rua=mailto:dmarc@<DOMAIN>; ruf=mailto:dmarc@<DOMAIN>; fo=1; adkim=r; aspf=r; pct=100;` — tighten to `p=reject` after 4-8 weeks of clean reports
- [ ] CAA records for HTTPS issuance (pki.goog, sectigo.com, letsencrypt.org)
- [ ] Verified via the deliverability checker — grade A minimum

**Search Console (Google + Bing)**
- [ ] Google Search Console: domain property, verify via DNS TXT, submit sitemap
- [ ] Bing Webmaster Tools: import from GSC OR verify separately, submit sitemap
- [ ] Both indexed: confirm pages flow into the index within 7 days

---

## 6. GEO (Generative Engine Optimization) infrastructure

Everything above also helps GEO, but these items are GEO-specific:

**Direct-answer paragraph per page** — every long-form post and cluster hub has a 40-80 word self-contained paragraph that answers the page's primary question. LLMs preferentially quote this format.

**FAQ schema on every page** — LLMs harvest FAQPage Q&A as quote candidates.

**Person schema with full sameAs** — every author byline has a `Person` schema with `sameAs[]` linking to LinkedIn, X, GitHub, personal site. Entity graph for LLM author authority.

**Original data studies** — minimum 1, ideally 3 per year. Format: 60-90 minute survey or product-data analysis published as research/[slug]. Adds `Dataset` schema with `distribution[]` linking to Hugging Face Datasets when published there. This is the single highest-leverage GEO asset type.

**Brand entity disambiguation:**
- [ ] Wikidata item created with founder, founding date, industry, official URL
- [ ] Crunchbase founder-claimed listing
- [ ] Owler company profile

**Third-party citation magnets:**
- [ ] G2 + Capterra + Product Hunt listings (claim + bootstrap 5+ named reviews each)
- [ ] Pitch 3-5 listicle authors per category (Zapier blog, Buffer blog, HubSpot blog, Backlinko, Search Engine Journal, category-specific blogs)
- [ ] Plant 10-15 substantive Reddit + HN + IndieHackers answers across ICP queries

**LLM-readable content patterns:**
- [ ] Every long-form post ends with a direct-answer block (LLM quote bait)
- [ ] Comparison tables in HTML, not images (LLMs can't read image text reliably)
- [ ] Specific numbers, not vague claims ("48% improvement" beats "significant improvement")

**Video signal (if applicable):**
- [ ] Embed YouTube video on every long-form post via `<EmbeddedVideo>` component
- [ ] VideoObject schema with `name`, `description`, `thumbnailUrl`, `uploadDate`, `contentUrl`, `embedUrl`, `transcript`
- [ ] Transcript pasted on the page (collapsed by default for UX, full text for crawlers)

---

## 7. Sequencing (4-6 week launch curve)

**Week 0 — Prelaunch (founder + agent overlap)**
- Domain registered + Vercel-attached
- Brand assets: logo SVG + 180x180 apple-icon PNG + apple-icon.png
- Founder bio + Person schema fields gathered
- Top-5 competitors + their URLs listed
- Pricing tiers + credit/seat counts finalized
- Email provider chosen (recommend Postmark) + SPF/DKIM/DMARC records added
- GSC + Bing Webmaster Tools domain verified

**Week 1 — Foundation + cluster hubs**
Agent ships:
- Homepage + About + Pricing + Compare + Alternatives + FAQ + Glossary stubs
- 10-12 cluster hub pages with the cluster.ts manifest
- Sitemap + robots + llms.txt
- Per-route static OG images
- Person + Organization schema with founder bio

**Week 2 — Spokes + roundups + migrations**
Agent ships:
- 80-120 cluster spokes (one per significant sub-topic per cluster)
- 5 roundup posts ("best [X] tool 2026" — one per major category in your space)
- 8-12 migration guides (one per top competitor)
- 4 long-form guides (one per cluster theme), including one original-data study
- /reviews + /case-studies stubs (no schema until 3+ named reviewers)

**Week 3 — Tools layer**
Agent ships:
- 12 Zone-1 tools (pure-math calculators)
- 5 Zone-2 tools (light LLM)
- 3 Zone-3 tools (heavy LLM / vision)
- ToolShell + shared LLM endpoint with provider fallback chain

**Week 4 — Polish + indexing**
Agent ships:
- Glossary auto-linker wired into long-form rendering
- Internal-link density audit
- CWV audit + fixes
- Reviews aggregator page (still no AggregateRating until 3+ named)
- llms.txt + sitemap final pass

Founder executes:
- GSC sitemap submission + first-batch URL indexing requests
- Bing sitemap submission + URL inspection
- First 3-5 outreach emails to listicle authors
- First 5 G2 / Capterra / Product Hunt review-asks to warm customers

**Months 2-3 — Compounding**
Founder executes:
- Continue GSC + Bing indexing batches (~10 URLs/day per platform)
- Plant Reddit / HN / IndieHackers answers (1-2/week, 10-15 total)
- Submit Wikidata + Crunchbase + Owler entries
- 5-8 more outreach emails to listicle authors
- Continue G2 / Capterra review-asks weekly
- Land 1 research-grade citation (Search Engine Land, Marketing Brew, Capiche, Hugging Face dataset publication)

Agent (optional) ships:
- LLM citation tracker (weekly cron + admin dashboard)
- Per-tool OG images
- VideoObject schema + YouTube embeds on long-form posts (if founder is producing video)

**Months 4-6 — Authority gravity**
- Track LLM citation rate weekly across 20 standardized queries
- Tighten DMARC from quarantine to reject
- Add Webflow / Ghost / Wix adapter integrations if customer demand surfaces
- Publish 1 more original-data study (compounding citation magnet)

---

## 8. Tracking & measurement

**Operator checklist CSV** ([docs/outreach/seo-geo-todos.csv](Active/BILT-KONTENT-ENGINE/docs/outreach/moe-seo-geo-todos.csv) is reference)
- Columns: id, category, task, why_it_matters, blocker_type, est_time, status
- ~18 founder-only items at launch
- Updated as items close (status column gains a DONE date + completion notes)

**LLM citation tracker** (Phase 3, optional but recommended)
- Trigger.dev cron, weekly Mondays 9am
- 15-20 standardized queries across OpenAI + Anthropic + Perplexity + Gemini APIs
- Parses each response: did the brand appear, list position, competitor mention share, source URLs cited
- Writes to `llm_citation_runs` Supabase table
- Surfaces at `/admin/llm-citations` dashboard
- Cost: ~$3-8/week in API spend

**Weekly metrics to track**:
- GSC: impressions, clicks, average position, indexed URL count
- Bing Webmaster Tools: same + AI Performance Copilot citations
- LLM citation rate (your tracker)
- Referring domain count via Ahrefs / Semrush (when you have budget)
- G2 / Capterra review count
- Reddit / HN organic mention frequency (manual weekly grep)

---

## 9. Templates

**Cluster hub template** ([src/components/ClusterHubPage.tsx](Active/BILT-KONTENT-ENGINE/src/components/ClusterHubPage.tsx) is reference)
- Hero with cluster title + 1-paragraph subtitle
- Direct-answer block (40-80 words, LLM quote bait)
- 5-7 FAQs with FAQPage schema
- 10-15 spoke link cards (Title + 1-line description)
- Cross-cluster CTA (link to 2-3 related clusters)
- Footer CTA (signup / pricing)

**Cluster spoke template** ([src/components/ClusterSpokePage.tsx](Active/BILT-KONTENT-ENGINE/src/components/ClusterSpokePage.tsx) is reference)
- Article schema (headline, author, datePublished, dateModified, publisher)
- TOC if 4+ H2 headings
- FAQ section (3-5 questions with FAQPage schema)
- Direct-answer block at the end
- Related-posts cross-links (3-5 spokes from the same cluster + 2-3 from related clusters)

**Roundup template**
- Article + ItemList + FAQPage schema
- Decision matrix table (competitors as rows, criteria as columns)
- Brief verdict per competitor (200-400 words)
- The new app placed in the top 3 with a fair, defensible verdict
- 3-5 FAQs
- Direct-answer block

**Migration guide template**
- HowTo + FAQPage schema
- 8-12 numbered migration steps
- Per-step `HowToStep.name` + `HowToStep.text`
- Consolidation math callout (cost savings of switching)
- 4-5 FAQs (export, cancel, data portability, refund, support)
- Direct-answer block

**Tool template** ([src/components/ToolShell.tsx](Active/BILT-KONTENT-ENGINE/src/components/ToolShell.tsx) is reference)
- SoftwareApplication + HowTo + FAQPage schema
- Widget (client component, isolated state)
- 3-step HowTo description (Input → Compute → Result)
- 4 FAQs minimum (what is this, accuracy, when to use, what's missing)
- Related-tools footer (3 related tool cross-links)
- Signup CTA

---

## 10. What NOT to do (lessons from the BKE build)

These are real failure modes from the Kompozy buildout. Don't repeat them.

**❌ Don't use per-slug `opengraph-image.tsx`** — Satori/Resvg variable-Inter glyph-table crash kills Vercel prerender. Generate static OG PNGs at build time and reference them from `metadata.openGraph.images`. Inherited from BKE commit a060489 + the 2026-04-23 lab note.

**❌ Don't parallelize Supabase auth-validating calls at boot** — gotrue Web Lock serializes them anyway; cascades to orphan-lock errors. Hoist a single `auth.getUser()` to the top and pass the user down. BKE lab note 2026-05-06.

**❌ Don't `git add -A` or `git add .`** — multiple Claude sessions edit the same repo. Stage by exact path only. If status shows unrelated files, exclude silently and commit only your session's changes.

**❌ Don't store provider URLs for generated media** — DALL-E / Kie / PiAPI / HeyGen URLs expire in 30-60 min. Persist to Supabase Storage via `persistMediaToStorage` (server) or `/api/media/persist` (client). BKE lab note 2026-04-24.

**❌ Don't write destructive sync routines** — bulk-replace patterns (DELETE non-matching + UPSERT) have wiped user data twice on BKE. Sync is upsert-only. Deletes only fire from explicit user actions. BKE lab note 2026-04-23.

**❌ Don't link internally to URLs that 308-redirect** — Bing/Google mark the source URL "excluded: redirect" and the PageRank flow takes a hit. Point at canonical destinations directly. BKE 2026-05-20 audit.

**❌ Don't emit AggregateRating/Review schema without 3+ named, verifiable reviewers** — Google penalizes anonymized review markup. Keep the /reviews page schema-free until you cross 3 named reviewers.

**❌ Don't centralize "coming soon" gate lists** — keep them in `src/lib/formats.ts` (or equivalent) as a single Set, never copy locally. Drift kills you. BKE lab note 2026-04-18.

**❌ Don't tighten dispatch-route Zod schemas on recovery-context fields** — recovery paths must degrade gracefully. Required fields turn missing-data into a 400, which is worse than the silent drop recovery exists to prevent. Keep workspaceId and similar `.optional()` on all dispatch routes. BKE lab note 2026-05-05.

**❌ Don't use Turbopack on Next.js dev** — root inference bug causes memory pile-up. Always use webpack (`--webpack` flag if needed; default in Next 16.x).

**❌ Don't pitch backlinks via generic blast outreach** — hand-personalize the first sentence. The 30-target Tier 1/2/3 ladder lives in [docs/outreach/ai-tells-index-distribution.md](Active/BILT-KONTENT-ENGINE/docs/outreach/ai-tells-index-distribution.md) as a reference template.

**❌ Don't skip the email-auth recipe** — Gmail / Yahoo enforce SPF + DKIM + DMARC on bulk senders (>5k/day) since Feb 2024. Without all three, you're structurally non-compliant before you ship a single campaign. BKE 2026-05-20 fix.

**❌ Don't track outreach in a separate tool from execution** — keep the CSV in `docs/outreach/` so it's version-controlled and visible to every agent + founder session.

---

## 11. The agent kickoff prompt

When you're ready to apply this spec to a new app, hand a Claude Code agent this prompt:

> Execute the Topical Authority Playbook at `<workspace>/templates/TOPICAL-AUTHORITY-PLAYBOOK.md` against the new app project at `<workspace>/Active/[NEW_APP_FOLDER]/`.
>
> **Inputs:**
> - APP_NAME: [name]
> - DOMAIN: [domain]
> - ONE_LINER: [one-sentence pitch]
> - ICP: [specific buyer]
> - PRIMARY_KEYWORD_CLUSTER: [head keywords]
> - TOP_5_COMPETITORS: [name + URL each]
> - PRICING_TIERS: [tier name + $ + credits/seats]
> - FOUNDER_BIO: [2-3 sentences]
>
> Start with Week 0 prelaunch checklist, then Week 1 foundation. Pause for review after the first cluster hub ships so I can confirm voice and direction. Skip Week 0 items that I've already completed (I'll tell you which).
>
> Use the BKE codebase as the reference implementation for every pattern. Don't re-derive — read the relevant file from `<reference-app>/src/` and mirror the structure into the new app.
>
> Maintain a `docs/outreach/seo-geo-todos.csv` operator checklist as you go. Commit per phase, push to master, deploy to Vercel.

---

## 12. Reference implementation

The BKE / Kompozy codebase IS the reference implementation for this spec. Every pattern lives there.

- Repo: [reference app](Active/BILT-KONTENT-ENGINE/)
- Production: https://kompozy.io
- Sitemap (291 URLs as of 2026-05-20): https://kompozy.io/sitemap.xml
- llms.txt: https://kompozy.io/llms.txt
- Tools index: https://kompozy.io/tools
- Operator CSV: [docs/outreach/moe-seo-geo-todos.csv](Active/BILT-KONTENT-ENGINE/docs/outreach/moe-seo-geo-todos.csv)

When in doubt about how a pattern should look, **read the BKE file** rather than re-inventing the structure.

---

**Last updated:** 2026-05-20. This spec evolves — append "what's new" notes as future apps surface patterns worth lifting back into BKE.
