> ## Documentation Index
> Fetch the complete documentation index at: https://docs.findmydata.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Cloudflare runbook

# Cloudflare domain runbook — findmydata.io

Operating discipline and intended configuration for the `findmydata.io` domain
(registered through Cloudflare). The first live changes were applied on
2026-07-15 to bring the canonical marketing site online via GitHub Pages — see
the **change log** at the bottom. Any further change must be inspected first,
applied reversibly, validated, and recorded there.

## Guardrails (do not violate)

* **Inspect before changing.** Read the current registrar, DNS, DNSSEC, SSL/TLS,
  email records (MX/SPF/DKIM/DMARC), redirects, Pages/Workers, Access policies,
  and WAF/security state before any edit.
* **Preserve** registrar ownership, transfer lock, recovery contacts,
  nameservers, DNSSEC, and email delivery unless a specific, understood change is
  required.
* **Never** transfer the domain, purchase paid services to complete a task,
  weaken account/security settings, expose secrets, publish an unrestricted dev
  environment, or commit browser sessions / API tokens / origin credentials /
  zone secrets to the repository.
* **Reversible + logged.** Every DNS/application/access change gets a change-log
  row (below) with purpose, validation, and rollback. Prefer least-privileged,
  scoped API tokens if automation is later added.
* **Confirmation required.** Live changes to a production domain are outward-
  facing; make them only with explicit per-change approval.

## Intended host map (suggested; consolidate freely)

Reserve names and add them intentionally — not every host is needed on day one.
Do **not** create `app.findmydata.io` (that would imply a shared SaaS data
plane; the product is customer-hosted). See ADR-0015.

| Host                      | Purpose                                                 | Suggested origin   | Proxy (orange cloud) | Access policy                                      |
| ------------------------- | ------------------------------------------------------- | ------------------ | -------------------- | -------------------------------------------------- |
| `findmydata.io`           | Canonical marketing site (`site/`)                      | Cloudflare Pages   | Yes                  | Public                                             |
| `www.findmydata.io`       | 301 redirect → apex                                     | Redirect rule      | Yes                  | Public                                             |
| `account.findmydata.io`   | Human customer portal                                   | App host (later)   | Yes                  | Public app auth                                    |
| `control.findmydata.io`   | Machine activation / entitlement renewal / fleet health | Narrow API (later) | Yes                  | Workload auth / mTLS                               |
| `docs.findmydata.io`      | Documentation (or fold into marketing)                  | Pages              | Yes                  | Public                                             |
| `support.findmydata.io`   | Knowledge base + authenticated cases                    | Support platform   | Yes                  | Public + auth                                      |
| `demo.findmydata.io`      | Isolated synthetic demo of the product                  | Isolated instance  | Yes                  | Controlled                                         |
| `dev.findmydata.io`       | Internal engineering only                               | Private            | Yes                  | **Cloudflare Access (SSO+MFA), narrow membership** |
| `status.findmydata.io`    | Vendor service status                                   | Status provider    | Yes                  | Public                                             |
| `downloads.findmydata.io` | Optional entitled artifact origin                       | Object storage     | selective            | Short-lived signed URLs from Account               |
| `app.findmydata.io`       | **Reserved, unused**                                    | —                  | —                    | —                                                  |

## Live DNS records (as of 2026-07-15)

The site is hosted on **GitHub Pages** (repo `clarkdickens/FindMyData`, `site/`
published by `.github/workflows/pages.yml`), not Cloudflare Pages. To let GitHub
issue and manage the Let's Encrypt certificate for the apex, the records are
**DNS-only (grey cloud)** — a deliberate deviation from the proxied posture in
the intended host map below. GitHub Pages custom-domain verification requires
the public A records to resolve to GitHub's IPs, which Cloudflare proxying would
mask.

| Name                                     | Type  | Content                                                                      | Proxy    | TTL  |
| ---------------------------------------- | ----- | ---------------------------------------------------------------------------- | -------- | ---- |
| `findmydata.io`                          | CNAME | `clarkdickens.github.io` (apex — Cloudflare flattens to 185.199.108–111.153) | DNS only | Auto |
| `www.findmydata.io`                      | CNAME | `clarkdickens.github.io`                                                     | DNS only | Auto |
| `docs.findmydata.io`                     | CNAME | `cname.mintlify.builders`                                                    | DNS only | Auto |
| `_acme-challenge.docs.findmydata.io`     | TXT   | Mintlify/Cloudflare-for-SaaS cert-validation token                           | DNS only | Auto |
| `_cf-custom-hostname.docs.findmydata.io` | TXT   | Mintlify custom-hostname ownership token                                     | DNS only | Auto |
| `account.findmydata.io`                  | CNAME | `findmydata-account.fly.dev`                                                 | DNS only | Auto |
| `clerk.findmydata.io`                    | CNAME | `frontend-api.clerk.services`                                                | DNS only | Auto |
| `accounts.findmydata.io`                 | CNAME | `accounts.clerk.services`                                                    | DNS only | Auto |
| `clkmail.findmydata.io`                  | CNAME | `mail.i9yyeobi14fl.clerk.services`                                           | DNS only | Auto |
| `clk._domainkey.findmydata.io`           | CNAME | `dkim1.i9yyeobi14fl.clerk.services`                                          | DNS only | Auto |
| `clk2._domainkey.findmydata.io`          | CNAME | `dkim2.i9yyeobi14fl.clerk.services`                                          | DNS only | Auto |

* **`docs.` → Mintlify** hosts the documentation site (repo `clarkdickens/FindMyData`,
  `docs/` published via the Mintlify GitHub App on every push to `main`). The two
  TXT records prove ownership and let Mintlify's Cloudflare-for-SaaS issue the TLS
  cert; the CNAME must stay **DNS-only** (proxying would mask the SaaS hostname).
* **`account.` → Fly.io** hosts the live Account portal (app `findmydata-account`,
  image `ghcr.io/clarkdickens/findmydata`). Fly issues the TLS cert (Let's Encrypt)
  once the hostname resolves, so the CNAME must stay **DNS-only** (Fly needs to see
  its own edge, not Cloudflare's).
* **`clerk.` / `accounts.` / `clkmail.` / `clk._domainkey` / `clk2._domainkey` →
  Clerk** are the 5 records for the Clerk **production** instance on `findmydata.io`
  (Frontend API, account portal, and email/DKIM). All **DNS-only**. They resolve
  correctly on public resolvers; Clerk's own DNS verification is asynchronous and
  may lag — the portal keeps running on the Clerk **development** instance (via a
  Fly secrets override) until Clerk marks the domain verified. See
  [deploy-fly.md](deploy-fly.md).
* Email: **Google Workspace** MX records (`aspmx.l.google.com` + alts) route mail
  for the domain (added by the owner for `bob@findmydata.io`). **Leave untouched**
  unless the mail setup is intentionally changed.
* DNSSEC: not enabled at the zone (no DS record) — unchanged.
* **Optional future hardening:** once GitHub's cert is stable, the records may be
  switched to proxied (orange cloud) with SSL/TLS mode **Full** to gain
  Cloudflare's WAF/CDN/DDoS edge. GitHub re-verifies the domain periodically, so
  test cert renewal after any such switch.

## Intended edge security posture

* SSL/TLS mode **Full (strict)**; always-use-HTTPS; HSTS with a conservative
  `max-age` first, increased after validation; do not preload until confident.
* Security headers via a Cloudflare rule/Worker: `Content-Security-Policy`
  (the marketing page is self-contained, so a strict `default-src 'self'` +
  `img-src 'self' data:` policy fits), `X-Content-Type-Options: nosniff`,
  `Referrer-Policy: strict-origin-when-cross-origin`, `X-Frame-Options: DENY`.
* WAF managed rules on; rate limiting + Turnstile/bot protection on public
  registration, login, activation, support upload, and download endpoints when
  those exist.
* `dev.findmydata.io` behind **Cloudflare Access** (identity-aware, MFA) — never
  relying on an obscure hostname.
* Scope cookies to the smallest host/path; **no** wildcard `.findmydata.io`
  session cookie (design §10). Secure, HttpOnly, SameSite.

## Validation checklist (run after any change)

1. `dig findmydata.io` / `dig www.findmydata.io` resolve as intended.
2. `https://findmydata.io` serves the marketing page over TLS; `www` 301-redirects.
3. Security headers present (`curl -I`); HSTS as configured.
4. `dev.` requires the Access identity; unauthenticated requests are challenged.
5. Email deliverability unaffected (MX/SPF/DKIM/DMARC unchanged).
6. Rollback verified: the previous record/rule values are recorded below.

## Change log

Record every future change here.

| Date       | Change                                                                                                                                                                                            | Purpose                                                              | Applied by                                                                                        | Validation                                                                                                                                                                                                                              | Rollback                                                                                                                                    |
| ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
| 2026-07-15 | Inspected zone: Cloudflare NS (`alec`/`hadlee.ns.cloudflare.com`), **0 DNS records**, no MX, no DS/DNSSEC, apex served nothing.                                                                   | Establish clean-slate baseline before edits.                         | Automation (authorized)                                                                           | `dig` + Cloudflare dashboard both showed empty zone.                                                                                                                                                                                    | n/a (read-only).                                                                                                                            |
| 2026-07-15 | Added `findmydata.io` **CNAME → clarkdickens.github.io**, DNS-only, TTL Auto (apex; Cloudflare flattens to GitHub Pages IPs).                                                                     | Serve the canonical marketing site from GitHub Pages over the apex.  | Automation (authorized)                                                                           | `dig +short findmydata.io A` → 185.199.108–111.153 (via 1.1.1.1 + CF NS); `curl http://findmydata.io` → 200, correct `<title>`.                                                                                                         | Delete the record in Cloudflare → DNS (apex stops resolving; reversible).                                                                   |
| 2026-07-15 | Added `www.findmydata.io` **CNAME → clarkdickens.github.io**, DNS-only, TTL Auto.                                                                                                                 | Serve/route `www` to the same GitHub Pages site.                     | Automation (authorized)                                                                           | `dig +short www.findmydata.io` → CNAME then GitHub IPs.                                                                                                                                                                                 | Delete the record in Cloudflare → DNS.                                                                                                      |
| 2026-07-15 | Set GitHub Pages custom domain = `findmydata.io` (`gh api PUT …/pages cname`).                                                                                                                    | Bind the Pages site to the custom domain + trigger TLS issuance.     | Automation (authorized)                                                                           | `gh api …/pages` shows `cname: findmydata.io`; HTTP live. TLS cert auto-provisioning (Let's Encrypt) — enforce HTTPS once issued.                                                                                                       | Clear the custom domain in repo Settings → Pages.                                                                                           |
| 2026-07-15 | Cert provisioning stalled (`cert_state: null` \~100 min) → removed + re-added the custom domain to retrigger issuance; cert issued (Let's Encrypt, CN=findmydata.io); set `https_enforced: true`. | Serve the site over TLS with HTTP→HTTPS redirect.                    | Automation (authorized)                                                                           | `https://findmydata.io` 200 (TLS verify ok, HTTP/2), `www` 200, `http://` 301 → `https://`.                                                                                                                                             | Set `https_enforced: false` via `gh api PUT …/pages`; clearing the custom domain removes the cert binding.                                  |
| 2026-07-16 | Added `docs.findmydata.io` **CNAME → cname.mintlify.builders** + two Mintlify validation TXT records (`_acme-challenge.docs`, `_cf-custom-hostname.docs`), all DNS-only, TTL Auto.                | Serve the Mintlify-hosted documentation site at a branded subdomain. | User (Cloudflare sign-in + record entry authorized in chat)                                       | Both TXT `dig +short TXT …` match the tokens; Mintlify domain status → **Connected**; `curl https://docs.findmydata.io` → 200, TLS verify ok, `<title>Index - Find My Data`.                                                            | Delete the three `docs` records in Cloudflare → DNS (subdomain stops resolving; reversible).                                                |
| 2026-07-16 | Added `account.findmydata.io` **CNAME → findmydata-account.fly.dev**, DNS-only, TTL Auto (after `fly certs add account.findmydata.io`).                                                           | Serve the live Account portal (Fly.io) at a branded subdomain.       | User (deploy authorized in chat); record added via automation on the user's authenticated session | `dig +short account.findmydata.io` → `findmydata-account.fly.dev` → 66.241.125.49; `fly certs check` → **Issued**; `curl https://account.findmydata.io/account` → 200, TLS verify ok; Clerk sign-in loads (no origin errors).           | Delete the `account` record in Cloudflare → DNS + `fly certs remove account.findmydata.io`.                                                 |
| 2026-07-16 | Added the 5 **Clerk production** CNAMEs (`clerk`, `accounts`, `clkmail`, `clk._domainkey`, `clk2._domainkey`), all DNS-only, TTL Auto, via BIND-less inline entry.                                | Promote Clerk to a production instance on `findmydata.io`.           | Automation on the user's authenticated Cloudflare session (Clerk promotion authorized in chat)    | All 5 `dig +short CNAME …` (via 1.1.1.1 + 8.8.8.8) return the exact Clerk targets. Clerk later verified the domain; `clerk.findmydata.io` Frontend API + JWKS → 200; portal flipped to Clerk **production** (`pk_live`, no dev banner). | Delete the 5 `clerk*/accounts/clkmail` records in Cloudflare → DNS (+ re-apply the dev-Clerk Fly secrets override to keep sign-in working). |
