Publishing Surface
This file documents the decision on where the knowledge hub is rendered and shared. Linear: NUD-246.
Decision (2026-05-03)
Single surface: Nextra on Vercel, password-protected.
Source of truth lives here, in this repo (docs/knowledge/). The Nextra site reads from this directory and renders it to a polished web hub at an internal URL.
Why this and not the alternatives
| Option | Verdict | Reason |
|---|---|---|
| Nextra on Vercel + Password Protection | ✅ Chosen | Stack-aligned (Next.js, Vercel — same as our 3 frontends). Vercel Pro deployment protection is included in our existing plan: $0 incremental cost. Single shared password = no per-seat friction for non-eng team. ~2 hr scaffold. |
| GitHub Pages (private) | ❌ Rejected | Requires GitHub Enterprise Cloud (~$21/user/month, +$1,400/yr for our team). Pages on Free/Pro/Team plans are public on the internet even from a private repo. Not worth the upgrade for one capability. |
| GitHub Pages (public) | ❌ Rejected | Hub contains internal-only content (sales playbook, competitor research, MEMORY-grade detail). Not suitable for public exposure. |
| Notion mirror | ❌ Skipped | Would have been the GTM-friendly option, but the team isn’t on Notion. Nextra serves both audiences if formatted for mixed readership. |
Public /learn site on nudg3.ai | ⏸️ Deferred | Right surface for geo/ and guides/ content once those epics ship. Not now — empty nav tabs hurt more than no site. Will revisit when NUD-242 + NUD-243 produce ≥10 customer-facing docs. |
Architecture
docs/knowledge/ ← source of truth (markdown + frontmatter)
product/, architecture/, geo/, guides/, reference/, _meta/
│
▼ (git submodule or sync script)
nudg3-knowledge-site/ ← separate standalone repo, Nextra app
content/ → reads from docs/knowledge
_meta.json files → sidebar nav order + labels
components/StatusBadge.tsx → renders frontmatter status/accuracy as coloured pill
│
▼ (Vercel auto-deploy on push)
learn.internal.nudg3.ai ← password-protected Vercel deploymentWhy standalone repo, not inside nudg3-frontend-combined
Considered putting this as apps/knowledge inside the existing Turborepo. Decided standalone for three reasons:
- Submodule of
nudg3-docs-internalis much cleaner in a single-purpose repo. Submoduling into one workspace of a Turborepo fights pnpm workspace resolution and surprises any engineer runninggit clone --recursiveon the wrong thing. - Different editorial workflow. Content writers edit markdown in
nudg3-docs-internal; the Nextra repo itself only gets touched twice a year for theme/version bumps. Doesn’t belong next to React product code that ships weekly. - Blast radius isolation. A bad
next.config.mjshere can’t break the dashboard, admin, or landing builds.
When the public nudg3.ai/learn surface eventually ships (Phase 3, deferred), that one does belong in nudg3-frontend-combined — it’s brand-coupled and shares design system with landing. Likely as apps/learn or a route on apps/landing. Two surfaces, two repos, two audiences.
Auth model
Cloudflare Access (free tier) at the domain layer in front of Vercel:
- Identity provider: One-time PIN (Cloudflare emails a 6-digit code; no external IdP needed)
- Policy: emails ending in
@nudg3.aiand@agenticza.comallowed - Session: 24 hours, then re-auth
- Free for up to 50 users
- $0 incremental cost
- DNS:
learn.internal.nudg3.aiCNAME → Vercel target, proxy ON (orange cloud) so Cloudflare can intercept - Cloudflare SSL mode: Full (strict) — CF validates Vercel’s TLS cert; user sees CF’s edge cert
Why not the alternatives:
- Vercel Password Protection: paywalled at $150/mo (Advanced Deployment Protection add-on, verified 2026-05-03)
- Vercel Standard Protection (Vercel team auth): free on Pro but requires every reader to be on the Vercel team; new seats $20/mo each
- Next.js middleware basic auth (initial approach): worked, but the browser-modal UX (
username:password) felt clunky for non-eng team. Removed in favour of CF Access magic-link UX.
The raw *.vercel.app deployment URL bypasses CF Access (CF only protects the custom domain). Acceptable risk for an internal docs site since the URL is unguessable and never shared. If it becomes a concern, re-add middleware with SITE_PASSWORD env var as a backstop, or restrict Vercel deployments to the custom domain only.
Sync model
Two viable patterns; pick one when standing the site up:
- Git submodule —
nudg3-knowledge-siterepo includes thisdocsrepo as a submodule. Vercel build pulls latest on every deploy. Cleanest; one source of truth, zero copy. - Manual copy — copy verified docs across when a doc is promoted from
draft→verified. Fine for the first few weeks while content moves slowly.
Default to submodule once the site is live. Manual is the bootstrap.
Promotion workflow
When a doc moves from draft → verified in this repo:
- Update frontmatter (
status,accuracy,verified_against_code) - Commit + push to
docsmaster - Trigger a Vercel redeploy (manual button or auto on submodule update)
- Drop a one-line note in #docs Slack channel
That’s the entire publishing pipeline. No CMS, no review queue, no separate publishing branch.
Status badge convention
Every page in the rendered Nextra site shows a coloured pill at the top derived from frontmatter:
| Status | Accuracy | Pill | Meaning |
|---|---|---|---|
canonical | verified | 🟢 green | Trustworthy. Quote freely internally. |
review | verified | 🔵 blue | Verified content, awaiting second-pair-of-eyes review. Trustworthy in spirit. |
draft | unverified | 🟡 yellow | Under construction. Read for context, do not quote externally. |
| any | outdated | 🔴 red | Behaviour changed since this was written. Do not trust. |
Implemented as a single MDX component in the Nextra site reading the frontmatter exposed by nextra/page-map. Rough scope: ~20 lines.
What this is NOT
- Not a public website. That’s a separate decision (NUD-246 follow-up) for when GEO + Guides content matures.
- Not a CMS. Edits happen in markdown files in this repo, in your editor, like any other code.
- Not a customer-facing surface. Customers eventually see a different, public-facing hub built from a curated subset of this content.
Action checklist (separate ticket)
Tracked in NUD-246. Roughly:
- Scaffold Nextra app under
nudg3-knowledge-site/(~1 hr) - Wire
_meta.jsonfor sidebar nav (~15 min) - Build
StatusBadge.tsxMDX component (~30 min) - Push to GitHub under NUDG3-AI org
- Connect to Vercel + enable Password Protection
- Add
learn.internal.nudg3.aicustom domain (DNS in Cloudflare) - Pin URL + password in #general or #gtm Slack