Skip to main content

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.ai access runbook in upsquad-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-docs created (account Upsquad, account-id b12538c0dc2fb7882da39a7cc280596c). 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.ai attached to the project. Domain id: 8bd983c0-7330-453c-8b0f-96b92eddc75b. Status initializing — CF issues the TLS cert once (a) the DNS CNAME is proxied and (b) the first deployment is live.
  • DNS CNAME engupsquad-eng-docs.pages.dev, Proxied (orange-cloud), on zone upsquad.ai (zone-id e24cfac36c5c3806c364ef90cb8152cc). 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_TOKENlong-lived / no-expiry scoped token: Account → Cloudflare Pages: Edit, Account → Account Settings: Read, Account → Access: Apps and Policies: Edit, Zone → DNS: Edit (zone upsquad.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, domain eng.upsquad.ai (path /*), 24h session, OTP IdPs (copy the two IdP UUIDs from the existing UpsQuad Demo/UpsQuad Marketing app — 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.