Skip to content

Deployment and Operations

SMEPro IOS edited this page Oct 15, 2026 · 3 revisions

Deployment and Operations

The idea in one paragraph

There are no hand-built servers. The site, the two API environments, the token host and the operator console are all deployed from the public repository by GitHub Actions, after the test suites pass, to Cloudflare's edge. A change to the API contract regenerates the routes, runs all 51 operations against a local build, deploys to the sandbox, smoke tests it, deploys to production, smoke tests that, and then republishes the site reference from what the two hosts actually serve. If you can read the repository, you can see exactly what is running and how it got there.

What runs where

Environments

Host What Keys Database
id-me.ai Site, docs, console, User Center, Contact Sales function none igl-intake (inquiries, console sign-in attempts)
sandbox.id-me.ai Platform API, self-serve signup igl_test_ igl-api-sandbox
api.id-me.ai Platform API, production igl_live_ igl-api-production
auth.id-me.ai Token endpoint and JWKS for production (served by the production Worker)
ops.id-me.ai Operator console sign-in reads all three

The four Worker hostnames are Cloudflare Custom Domains. The first deploy creates each DNS record and certificate; nothing is added to DNS by hand.

The pipelines

Workflow Runs when What it does
CI Every push and pull request ESLint, a type check over the JavaScript, the runtime suite on Node 20 and 22, dependency audit, lint of the contract, and a summary check named test that the branch rule on main requires
Deploy id-me.ai platform/site, the contract or the served-operations file change on main, or on request Checks the committed reference is current, asks both API hosts what they serve and regenerates the reference, applies the intake schema, publishes to Cloudflare Pages
Deploy API platform/api or the contract change on main Checks the generated routes match the contract, runs the conformance suite on a local build, deploys sandbox and smoke tests it, deploys production and smoke tests it, then starts the site deploy
Deploy ops console platform/ops changes on main Runs the console's suite (including the sign-in flow), applies the intake schema, deploys
Release A v* tag, or on request from the Actions page Runs the suite, tags main with the package version when started by hand, publishes a GitHub release with notes from the changelog, the npm tarball, the contract and checksums, and publishes to npm when an NPM_TOKEN secret exists
CodeQL, Scorecard, Dependency review, DCO Pushes and pull requests Static analysis, supply chain scoring, dependency checks, sign-off checks

Actions never commit to main. The branch is protected: the test check must pass and changes arrive through pull requests.

Secrets, and where they live

Secret Where Purpose
CLOUDFLARE_API_TOKEN, CLOUDFLARE_ACCOUNT_ID GitHub repository secrets Deploys (Workers, Pages, D1, routes)
ANTHROPIC_API_KEY Worker secret on igl-api and igl-api-sandbox The four intelligence operations; the other 42 work without it
BOOTSTRAP_TOKEN Worker secret on igl-api The one-time call that creates the platform tenant; can be removed afterwards
SIGNING_KEY_PEM Worker secret, optional The receipt signing key; without it a key is generated once and kept in the database
OPS_ADMIN_PASSWORD, CLOUDFLARE_API_TOKEN, GITHUB_TOKEN Worker secrets on igl-ops Console sign-in, site traffic, repository traffic
NPM_TOKEN GitHub repository secret, optional Publishing the package

Secrets are set in the Cloudflare dashboard (Workers and Pages, the Worker, Settings, Variables and Secrets, tick Secret) or with wrangler secret put. They are never in the repository, never in chat, and never in a plain variable. The dashboard saves a secret as a new version; make sure that version is the active deployment before expecting it to take effect.

First run on production

Once, after the first production deploy, create the platform tenant:

Invoke-RestMethod -Method Post -Uri "https://api.id-me.ai/admin/bootstrap" `
  -Headers @{ "X-IGL-Bootstrap" = "<the BOOTSTRAP_TOKEN value>" } `
  -ContentType "application/json" -Body '{"name":"Smeprotech platform"}'

The answer is the platform tenant and one igl_live_ key with the igl.platform scope. Store it in a password manager. Every customer tenant and key is then issued with it (POST /admin/tenants, POST /admin/keys), and a second bootstrap call is refused while that key is active. To rotate the platform key, revoke it with POST /admin/keys/revoke and run the bootstrap call again: it reuses the platform tenant and issues a new key. If a key is ever exposed, revoke it first and ask questions later.

Day to day

Logs and traces for every Worker are in the Cloudflare dashboard under Observability. The console at ops.id-me.ai is the morning view. Rate limits are a bucket of 120 refilled at 2 per second on production and 60 at 1 per second on the sandbox, per key; reads cost 1, writes 5, MCP calls 2. The intake schema and both API schemas are applied idempotently on every deploy, so adding a table is a pull request, not a maintenance window.

Email

Addresses for id-me.ai (support, sales, partners, security, and the role aliases) are planned on Google Workspace, with MX, SPF, DKIM and DMARC records on the zone. The runbook with the exact records and the group layout is docs/ops/EMAIL.md. Until it is applied, the Contact Sales form stores every inquiry in the intake database and shows it in the console, so nothing is lost.

Clone this wiki locally