Skip to content

Deployment & handover ​

This is the guide for taking over or contributing to NanaSelect — running it, deploying it, and knowing where things live. It's written for a new contributor arriving cold (hello, Aziz 👋).

How to read it: do the Start here section first — that's everything you need to run the app and understand the shape of it. The Deploy and Add a reviewer sections are the day-to-day operations. Everything under Going deeper is ops depth you can safely ignore until you need it. Don't try to read it all at once.


Start here (your first hour) ​

1. What NanaSelect is ​

NanaSelect is a standalone product-selection app that guides architects, builders, and homeowners to the right-sized NanaWall system, then hands off into the nanawall.com configurator. It runs on its own and augments the legacy nanawall.com (Drupal) site — it owns its own product database and talks to Drupal over JSON. For the full "why", read the product vision; for the "how it fits together", the data access reference.

Stack: SvelteKit · Cloudflare Workers · D1 (SQLite at the edge, via Drizzle) · Tailwind · Vitest.

2. Run it locally ​

You don't need a Cloudflare account to run NanaSelect locally — Wrangler runs D1 on your machine.

sh
pnpm install
dev-up            # migrate -> seed -> serve -> health-check, in one step

Then open http://localhost:6650. Locally the admin signs you in automatically (a dev bypass badge), so /admin just works. If you'd rather run the steps yourself, the README quick start lists the underlying pnpm commands.

Next, walk the Set up your first track tutorial — it's the fastest way to understand what the app actually does.

3. Where things live ​

src/routes/          UI pages + server endpoints (guided flow, comparison, admin)
src/lib/server/db/   Drizzle schema + client — the single source of truth
drizzle/             D1 migrations (generated by drizzle-kit)
seed/                CSV -> D1 ingestion (see seed/README.md)
docs/                This documentation site

The hosting model ​

NanaSelect deploys to Cloudflare:

  • The app is a single Worker named nanaselect (see wrangler.jsonc), serving the SvelteKit build.
  • Data lives in a D1 database, nanaselect-db, bound to the Worker as DB.
  • The /admin area is gated at the edge by Cloudflare Access (Zero Trust) — see admin access for the full model.
  • This docs site is a separate deploy (Cloudflare Pages), published by CI — see Building & publishing the docs site.

The app deploy is manual today (there is no app CI/CD pipeline — only the docs site auto-deploys). That keeps you in control of when production changes.


Deploy the app ​

One-time setup:

sh
wrangler login                       # authenticate to the Cloudflare account
# The D1 database already exists (id is in wrangler.jsonc). If you ever need a
# fresh one: wrangler d1 create nanaselect-db, then put the id in wrangler.jsonc.

Each deploy:

sh
pnpm db:apply:remote    # apply any new migrations to the remote D1 (first time / after schema changes)
pnpm seed:remote        # load/refresh the seed catalogue on remote D1 (when data changes)
pnpm run deploy         # deploy gate -> build -> wrangler deploy

pnpm run deploy runs the deploy gate (#1058, security review F-D1) before anything ships: it refuses to publish a wrangler.jsonc whose vars leave CF_ACCESS_TEAM_DOMAIN/CF_ACCESS_AUD empty or contain ADMIN_DEV_BYPASS in any form — the config combination that would open /admin without Access. Run it alone with pnpm run deploy:gate; a drift-guard spec (deploy-gate.spec.ts) also fails the suite if the committed config ever regresses. Deploying with a raw wrangler deploy skips the gate — don't.

There's also a small companion Worker for session cleanup — deploy it with pnpm run deploy:purge when its code changes.

Production hostname

Production must be served from a .nanawall.com subdomain for consent (Iubenda/GTM) to work — see admin access and the consent model. The public app + docs hostnames and their shared access allowlist are tracked in #560; until they're set up, treat deploys as staging.


Add a reviewer (grant access) ​

Two things gate who can do what:

  1. Reaching /admin at all — the person's email must be allowed by the Cloudflare Access policy in the Zero Trust dashboard (add their email to the Access application in front of /admin*).
  2. What they can do once in — their email must have a role in the admin_users table (data_editor / rules_editor / admin). Add them in seed/sql/010-admin-users.sql (or insert directly); emails are stored lower-cased.

Full step-by-step (including the one-time Zero Trust application + AUD/team-domain setup) is in admin access. For the POC review host (nanaselect.iwpi.com) — where the whole site, not just /admin, is behind the allowlist — invite/removal steps are in POC access.


Where to get help ​


Going deeper (ops — read when you need it) ​

You can skip this on day one.

  • Migrations. Schema is defined in src/lib/server/db/schema.ts; generate a migration with pnpm db:generate, apply locally with pnpm db:apply:local, remotely with pnpm db:apply:remote. See audit & validation for how edits are validated.
  • Seed data. pnpm seed:local / pnpm seed:remote build seed.sql from the CSVs, load it, then apply the catalog fragments through the shared runner — the fragments rebuild what seed.sql's attribute REPLACE cascades away, so both steps are required. Seed covers all lifecycle states; new features ship seed data in the same change.
  • Reset local data. pnpm db:reset:local wipes and rebuilds the local D1.
  • Consent & retention. Iubenda (via GTM) is the consent source of truth; the IUBENDA_* and SESSION_TTL_DAYS vars in wrangler.jsonc drive the 2-tier consent + retention model. The session-purge Worker enforces retention.
  • Drupal sync. DRUPAL_BASE_URL points at nanawall.com; the app ingests Drupal media/content — see the corpus refresh how-to.

Keep this guide honest: the commands above mirror package.json and wrangler.jsonc. If you change a script or the hosting model, update this page in the same change.