> ## 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.

# Demo and dev environments

# Demo & dev environments — runbook

Two isolated, non-production surfaces from the design:

* **`demo.findmydata.io`** — a public, isolated demonstration of the real product
  running on **synthetic data only**, safe for anyone to poke at.
* **`dev.findmydata.io`** — a private engineering environment behind
  identity-aware access; never public, never customer data.

Neither touches a customer tenant or the vendor commercial plane.

## 1. Demo mode (product) — built

The product has a fail-closed **demo mode** (`FMD_DEMO_MODE=true`,
`kernel/config.ts`). When set, the deployment **refuses to boot** unless it is
safe as a public demo:

* `FMD_CONNECTOR_MODE` **must** be `mock` — a demo uses synthetic data via the
  mock M365 tenant, never a live Graph tenant. (Boot fails on `graph`.)
* Live **label writes** (`FMD_FEATURE_PURVIEW_LABEL_WRITE`) and **directory sync**
  (`FMD_FEATURE_ENTRA_DIRECTORY_SYNC`) are forbidden (boot fails if enabled).
* `demoMode` is surfaced at `GET /api/ready`; the web UI shows a persistent
  "Demo environment — synthetic data only" banner.

So even a misconfigured demo cannot reach a real tenant or write anything back.

**Run a demo locally:**

```bash theme={null}
FMD_DEMO_MODE=true FMD_CONNECTOR_MODE=mock FMD_AUTH_MODE=dev \
  bun run --cwd packages/server start
# then seed synthetic data:
bun run --cwd packages/server seed
```

**Reset on a schedule** (wipe + reseed) so the public demo stays clean and can't
accumulate abuse. The demo DB is disposable — reset = delete the DB file (or
volume) and re-run migrate + seed:

```bash theme={null}
rm -f "$FMD_DB_PATH" && bun run --cwd packages/server migrate && bun run --cwd packages/server seed
```

Wire that into a scheduled job (cron / Container Apps job / GitHub Actions
`schedule`) at whatever cadence you like (e.g. every 6 h).

### Hosting the demo

The product is a long-running Bun + SQLite container, so it needs a container
host (not Cloudflare Workers). Reuse the existing **Azure Container Apps** IaC
(`infra/main.bicep`) with a demo profile — set `FMD_DEMO_MODE=true`,
`FMD_CONNECTOR_MODE=mock`, `FMD_AUTH_MODE=dev` (or a demo IdP), an **ephemeral
volume** (so a restart is a clean slate), and low CPU/memory + max-replicas=1 to
bound cost. Fly.io / Render work equally well. Then:

* Cloudflare DNS: `demo` → the container host (proxied is fine here — no GitHub
  Pages cert dependency).
* Put **Cloudflare Turnstile** (or Bot Fight Mode) in front to bound abuse.
* Point the scheduled reset job at the demo instance's volume/DB.

Distinguish this safe public demo from disposable Microsoft CDX engineering
resources (see [ADR-0012](adr/ADR-0012-cdx-strategy.md)) — CDX is for live-tenant
engineering, not a public demo.

## 2. Protected dev — `dev.findmydata.io` via Cloudflare Access

Do **not** rely on an obscure hostname. Gate the dev instance with **Cloudflare
Access** (Zero Trust) — an identity-aware proxy with SSO/MFA and narrow
membership. Access is **free up to 50 users**.

Setup (Cloudflare dashboard → Zero Trust):

1. **Cloudflare Tunnel** (`cloudflared`) from the dev host so it needs **no public
   inbound ports** — the tunnel dials out to Cloudflare, which routes
   `dev.findmydata.io` to it. Create the tunnel, run `cloudflared` on the dev box,
   and add a public hostname `dev.findmydata.io` → `http://localhost:8710`.
2. **Access application** for `dev.findmydata.io`:
   * Policy: **Allow** only a named list of emails / an identity-provider group
     (e.g. your Google Workspace), require **MFA**.
   * Session duration short (e.g. 24 h); everything else **blocked by default**.
3. Cloudflare DNS: the Tunnel creates the `dev` CNAME automatically (proxied).
4. Validate: an unauthenticated request to `https://dev.findmydata.io` is
   challenged by Access; only allowlisted, MFA'd identities get through.

The dev instance runs like any deployment (dev auth or an IdP) but is reachable
only through the Access-protected tunnel — no ports open to the internet, no
customer data.

### Change discipline

Record each Access application / policy / tunnel change in
[docs/cloudflare-runbook.md](cloudflare-runbook.md) with purpose + rollback, per
the domain guardrails (inspect first, reversible, preserve registrar/DNSSEC/email
posture). Cloudflare Access + Tunnel changes are additive and reversible (delete
the application/tunnel to remove them).

## Cost summary

| Surface            | Approach                                                                | Cost                        |
| ------------------ | ----------------------------------------------------------------------- | --------------------------- |
| Demo hosting       | Azure Container Apps (or Fly/Render), 1 small replica, ephemeral volume | container host only (small) |
| Demo abuse control | Cloudflare Turnstile / Bot Fight Mode                                   | Free                        |
| Dev access         | Cloudflare Access + Tunnel                                              | Free (≤ 50 users)           |
