Design: Public Docs Site Scaffold — docs.raxx.app
Status: Accepted Date: 2026-05-15 UTC Owner: software-architect Parent card: #104 ADRs: 0088
1. Context
Operator decision 2026-05-15 UTC: the public docs site (docs.raxx.app) is in
v1 scope. T-8 days to launch (2026-05-23 UTC). The existing epic #104 has a
custom Python static-site builder (scripts/build-customer-docs.py) approach
locked in from earlier grooming passes, and a deploy workflow
(.github/workflows/deploy-customer-docs.yml) already in the repo. A CF Pages
project named raxx-docs is already registered in docs/architecture/cloudflare-pages-projects.md.
This design supersedes the "post-launch" deferral recorded on #423 and re-scopes the v1 deliverable to a minimum viable public docs site that can ship before 2026-05-23 UTC.
The audience is integrators and developers using the Raxx platform
programmatically. Operators use internal-docs.raxx.app (already live).
2. Invariants
The following platform invariants apply to this surface:
- No stored credentials. The site is static HTML. No authentication, no user session. Nothing to store.
- No vendor names in customer-facing copy. No broker/aggregator names appear in any content file. Build script enforces via lint at build time.
- No forward-looking framing. All copy describes what the platform does, not what it will do. No predictive AI claims. Any AI references are retrospective ("surfaces patterns in your historical data").
- Brand placeholders. Wordmark, tagline, and pillar copy use
data-brand-placeholderattributes until formal brand system ships (~2026-11). Seeproject_brand_six_month_defer. - noindex pre-launch.
X-Robots-Tag: noindexheader via CF Pages headers config until launch day. Flip toindex, followin the launch-day runbook. - Audit row on every deploy. Per
new-surface-convention.mdinvariant 2. - Deploy-freeze gate. Per
new-surface-convention.mdinvariant 3. - Status tile mandatory.
config/status-surfaces.yamlentry required before first production deploy. - No public API reference at v1. There is no public API at v1. The
docs/API.mdanddocs/API_DOCUMENTATION.mdfiles exist but are operator-internal. They are excluded from the customer-docs build manifest.
3. Data model
Static site — no database, no PII collected, no user accounts.
Content manifest (explicit allowlist, not exclusion)
| Source path | Output section | Notes |
|---|---|---|
docs/customer/getting-started.md |
/getting-started/ |
New file, SC-D3 |
docs/customer/concepts.md |
/concepts/ |
New file, SC-D5 |
docs/customer/faq.md |
/faq/ |
Partial stub exists (#518, closed) |
docs/customer/privacy-terms.md |
/privacy-terms/ |
Mirror from legal, SC-D7 |
docs/customer/index.md |
/ |
Landing page, SC-D3 |
Release notes (docs/release_notes/) are excluded from v1. They depend on
99 (semver + GitHub Releases) which is still open. Release notes section lands
post-v1.
API reference is excluded from v1 — no public API at v1.
4. APIs / contracts
None. The site is static HTML served from Cloudflare Pages.
CF Pages project: raxx-docs
Custom domain: docs.raxx.app
CF Access gate: None (public).
Deploy trigger paths:
docs/customer/**
scripts/build-customer-docs.py
scripts/build-customer-docs/**
frontend/docs/_headers ← noindex/index flip lives here
.github/workflows/deploy-customer-docs.yml
The existing deploy-customer-docs.yml workflow already covers these paths.
SC-D10 will verify and extend it to include the _headers file path.
5. State machine / sequence
Deploy sequence
sequenceDiagram
participant GH as GitHub (push to main)
participant CI as GH Actions
participant V as Infisical vault
participant CF as Cloudflare Pages
participant DNS as CF DNS (raxx.app zone)
GH->>CI: push to main (docs/customer/** or builder)
CI->>CI: deploy-freeze check
CI->>V: load CF_PAGES_DEPLOY_TOKEN
CI->>CI: python3 scripts/build-customer-docs.py
Note over CI: broker-name lint runs inside builder<br/>exits non-zero on violation
CI->>CF: wrangler pages deploy dist-customer-docs/ --project-name raxx-docs
CF-->>CI: deploy URL
CI->>CI: health-check docs.raxx.app (expect 200)
CI->>CI: emit audit row → POST /api/internal/audit
CI->>CI: Slack DM on health-check failure
noindex → index flip (launch day)
stateDiagram-v2
[*] --> PreLaunch : site first deploys
PreLaunch : X-Robots-Tag: noindex\n(via _headers)
PreLaunch --> Launch : launch-day runbook step
Launch : X-Robots-Tag: index, follow\n(via _headers)
Launch --> [*]
The flip is a one-line edit to frontend/docs/_headers (or
docs/customer/_headers — SC-D9 picks the exact path) followed by a merge to
main. No redeploy ceremony needed; CI picks it up automatically.
6. Migrations
No schema migrations. Static site.
Rollback: Cloudflare Pages keeps the previous deployment. If a deploy ships broken content, roll back via CF Pages dashboard instant rollback or by reverting the commit and merging to main (CI redeploys in ~2 min).
7. Rollout plan
| Phase | Gate | What ships |
|---|---|---|
| Dark | CF Pages project exists, noindex header, no external links |
SC-D1 + SC-D2 |
| Flag | Content pages merged, still noindex |
SC-D3 – SC-D8 |
| Beta | Complete content, brand placeholders in place, noindex |
SC-D9 (pre-launch config) |
| GA | Launch-day runbook flips noindex → index, follow |
SC-D9 (flip) + SC-D10 |
Target: all phases complete by 2026-05-22 UTC (1 day buffer before launch).
8. Security considerations
PII collected: None. No forms, no analytics, no user sessions at v1.
Retention: N/A — static site with no data store.
DSR (data subject request): N/A at v1. If analytics are added post-v1, revisit.
Audit log: Every CF Pages deploy emits a row to the console audit endpoint
per new-surface-convention.md. Logs retained per platform-wide retention
policy (90 days active, 1 year cold).
Credentials / replay risk: None. No credentials accepted or stored.
Breach notification: No user data means no breach-notification obligation for this surface specifically.
Secrets: CF_PAGES_DEPLOY_TOKEN lives in Infisical vault
(/MooseQuest/CF_PAGES_DEPLOY_TOKEN, prod environment). Rotatable without
redeploy (vault-load step runs at job start).
Kill-switch: Remove docs.raxx.app custom domain from CF Pages project, or
flip the CF Access policy from "none" to "block all" in Cloudflare dashboard.
Takes effect in seconds, no deploy required.
Broker-name leak prevention: scripts/build-customer-docs.py lints every
output HTML file for known vendor strings before the deploy step runs. Build
exits non-zero on violation; CI blocks the deploy.
9. Open questions
None blocking v1 sub-cards. The following are post-v1 decisions:
- Search. Client-side search (e.g. pagefind) vs. no search. Defer to post-v1 — not in scope for T-8 delivery.
- Release notes section. Depends on #99 (semver + GitHub Releases). Excluded from v1 build manifest; add post-#99.
- "fur-docs" custom theme. The MooseQuest comment from 2026-04-22 proposed a custom moose-colored theme. Decision: v1 ships with brand-placeholder styling aligned to getraxx.com light theme. Full "fur-docs" theme is a post-launch design card.
- Localization. Quebec geo-block is in place at signup. Docs-site localization (fr-CA) is post-v1; re-evaluate if Canadian customers are accepted.
Sub-cards (v1 delivery set)
| ID | Title | Size | Priority | Depends on |
|---|---|---|---|---|
| SC-D1 | Bootstrap Docusaurus project + CF Pages binding verification | xs | P0 | — |
| SC-D2 | DNS + CF Pages custom domain confirmation | xs | P0 | — |
| SC-D3 | Landing + getting-started page content | s | P0 | SC-D1 |
| SC-D4 | Concepts page content | s | P1 | SC-D1 |
| SC-D5 | FAQ page content (10 entries) | xs | P1 | SC-D1 |
| SC-D6 | Privacy + terms mirror page | xs | P1 | SC-D1 |
| SC-D7 | Brand placeholder integration (data-brand-placeholder) |
xs | P1 | SC-D3 |
| SC-D8 | noindex _headers config + launch-day flip runbook step |
xs | P0 | SC-D1 |
| SC-D9 | Deploy automation verification + health-check + audit emit | s | P0 | SC-D1 |
| SC-D10 | Broker-name lint CI enforcement + smoke test | xs | P1 | SC-D9 |
First-wave dispatch (fire in parallel): SC-D1, SC-D2, SC-D8