eng.upsquad.ai — Eng Docs Site Access & Provisioning Runbook
The internal engineering docs site at https://eng.upsquad.ai is the human
view (pillar 1) of the docs-engineer mandate: a Docusaurus site that renders
the canonical markdown under docs/**. It is gated behind a
Cloudflare Access policy allowing the entire @upsquad.ai email
domain — internal-only, same provisioning shape as demo.upsquad.ai.
This runbook mirrors the
demo.upsquad.aiaccess runbook inupsquad-client(demo/docs/access-management.md). Read that for deeper CF API quirks; this doc captures the eng-docs-specific resource IDs and the @upsquad.ai gate.
1. Architecture (one-paragraph mental model)
eng.upsquad.ai is a static Docusaurus site built from docs-site/ in
upsquad-ai/upsquad-core, rendering the canonical markdown in docs/**. Every
push to main touching docs-site/**, docs/**, or the workflow triggers
.github/workflows/docs-site-pages.yml, which runs npm run build and pushes
docs-site/build/ to the Cloudflare Pages project upsquad-eng-docs.
Cloudflare serves the static bundle from its edge. In front sits a
Cloudflare Access self-hosted application matching eng.upsquad.ai/*,
gated to the @upsquad.ai email domain.
@upsquad.ai engineer browser
│ HTTPS
▼
┌──────────────────────────────────┐
│ Cloudflare edge │
│ ├── Access (PIN gate, @upsquad.ai)
│ └── Pages: upsquad-eng-docs │ ← static build from CI
└──────────────────────────────────┘
No backend. The Access allowlist (whole @upsquad.ai domain) is the only gate.
2. Provisioning checklist (one-time)
Status as of this PR: the docs-engineer (operating as
upsquad-devops-engineer[bot]/founder CF token) provisioned the Pages project
and attached the custom domain. DNS + the Access app/policy still need a
broader CF token (the token available to the agent was Pages-scope only).
- Cloudflare Pages project
upsquad-eng-docscreated (accountUpsquad, account-idb12538c0dc2fb7882da39a7cc280596c). Project id:09c15776-fea4-494c-8bdd-59a4b7901843. Subdomain:upsquad-eng-docs.pages.dev. Production branch:main. Connection method: Direct upload — builds come from GitHub Actions. Do not toggle "Connect to Git" (it would try to build the parent repo). - Custom domain
eng.upsquad.aiattached to the project. Domain id:8bd983c0-7330-453c-8b0f-96b92eddc75b. Statusinitializing— CF issues the TLS cert once (a) the DNS CNAME is proxied and (b) the first deployment is live. - DNS CNAME
eng→upsquad-eng-docs.pages.dev, Proxied (orange-cloud), on zoneupsquad.ai(zone-ide24cfac36c5c3806c364ef90cb8152cc). Needs a token with Zone:DNS:Edit.bash CF_TOK=... # token with Zone DNS:Edit on upsquad.ai ZONE=e24cfac36c5c3806c364ef90cb8152cc curl -s -X POST -H "Authorization: Bearer $CF_TOK" \ -H "Content-Type: application/json" \ --data '{"type":"CNAME","name":"eng","content":"upsquad-eng-docs.pages.dev","proxied":true,"ttl":1}' \ "https://api.cloudflare.com/client/v4/zones/$ZONE/dns_records" - GitHub secrets on
upsquad-ai/upsquad-core(Settings → Secrets and variables → Actions): -CF_API_TOKEN— long-lived / no-expiry scoped token: Account → Cloudflare Pages: Edit, Account → Account Settings: Read, Account → Access: Apps and Policies: Edit, Zone → DNS: Edit (zoneupsquad.ai). Do not reuse a short-TTL token — a 3-day-TTL token expired and broke the demo deploy twice ("Authentication error code 10000"). -CF_ACCOUNT_ID=b12538c0dc2fb7882da39a7cc280596c. - Access application
UpsQuad Eng Docs, self-hosted, domaineng.upsquad.ai(path/*), 24h session, OTP IdPs (copy the two IdP UUIDs from the existingUpsQuad Demo/UpsQuad Marketingapp — see the demo runbook §10). Needs a token with Access: Apps and Policies: Edit. - Access policy on that app: a single Allow policy, Include rule
Emails ending in →
@upsquad.ai(domain rule, not per-email — this is the key difference from the demo's per-email NDA allowlist). CF denies by default when no Allow matches, so no explicit Block policy is needed.bash CF_TOK=... # token with Access: Apps and Policies: Edit ACCT=b12538c0dc2fb7882da39a7cc280596c # 1) create the app curl -s -X POST -H "Authorization: Bearer $CF_TOK" -H "Content-Type: application/json" \ --data '{"name":"UpsQuad Eng Docs","domain":"eng.upsquad.ai","type":"self_hosted","session_duration":"24h","http_only_cookie_attribute":true,"app_launcher_visible":false}' \ "https://api.cloudflare.com/client/v4/accounts/$ACCT/access/apps" # 2) add the @upsquad.ai domain allow policy (use the app id from step 1) curl -s -X POST -H "Authorization: Bearer $CF_TOK" -H "Content-Type: application/json" \ --data '{"name":"upsquad.ai staff","decision":"allow","include":[{"email_domain":{"domain":"upsquad.ai"}}]}' \ "https://api.cloudflare.com/client/v4/accounts/$ACCT/access/apps/<APP_ID>/policies"
When DNS + secrets + Access are in place, trigger the
Eng Docs Pages (eng.upsquad.ai) workflow (push to main touching docs/**
or docs-site/**, or workflow_dispatch) to publish the first build.
3. Granting / revoking access
Because the gate is the whole @upsquad.ai domain, any @upsquad.ai mailbox
gets in automatically — no per-person allowlisting. To grant a non-staff
person, add their email to the Include rule (Access → Applications →
UpsQuad Eng Docs → Policies → upsquad.ai staff → add another →
Save). To revoke an individual, add a higher-precedence Block policy for
that email, or remove them from the domain. To evict everyone immediately
(suspected leak), Access → Applications → UpsQuad Eng Docs → ⋯ → Revoke
all sessions.
4. Build broken?
Check the latest Eng Docs Pages (eng.upsquad.ai) run on main. Build rules
live in docs-site/README.md. The build warns on broken doc links (it does
not fail) — those warnings are coherence findings, not deploy blockers.
Owner: founder + docs-engineer. Implementation: upsquad-core#1212.