Deployment & rollout
First client — preflight checklist (role-based)
Vendor-neutral version: describes roles (gate controller, reader, pass issuance mode) without tying the checklist to a specific single-board computer, relay, or reader SKU. Use with any hardware that fills the same role.
For a variant that names concrete products where helpful, see first-client-preflight-checklist.md.
Calendar planning for sponsors (typical rollout duration and what drives it): org-platform-decision-guide.md#implementation-timeline.
Go-live handover (what receiving teams should confirm): new-organization-handover-package.md.
Run this in order before go-live. Record pass/fail and who verified (name + date).
How this checklist varies by org profile
Requirements are not identical for every client. Before you chase every row, agree the payment path, approval vs trusted activation, brand footprint, pass issuance mode, and physical entry model with the sponsor. Use the How this checklist varies by org profile section in the detailed checklist—including which sections matter most. Mark checklist rows N/A when they describe hardware or flows this deployment does not use.
0. On-site physical requirements (what must exist at the facility)
Profile: This entire section may be N/A when there is no unattended lane or on-site reader in scope (credentials-only from phone, desk-only ops, etc.).
This section is separate from cloud configuration: it is the hardware and environment at the door or desk where members tap in.
| # | Item | Pass/fail | Verified by / date | Notes |
|---|---|---|---|---|
| 0.1 | Credential reader (NFC/RFID or equivalent) installed and cabled to on-site computer or staff PC, or integrated per your deployment guide | Model + serial recorded | ||
| 0.2 | On-site gate controller (small PC, industrial box, or staff workstation) running the reader client, mounted and powered (not loose on a shelf) | Hardware class + OS recorded | ||
| 0.3 | Power: reader + controller on reliable outlets; consider surge protection; note if UPS is required for your SLA | |||
| 0.4 | Network: Ethernet to gate controller preferred over Wi‑Fi for unattended lanes; if Wi‑Fi only, document SSID constraints and who owns password rotation | |||
| 0.5 | Internet reachability: site can reach your production API host (HTTPS outbound); no captive portal blocking the controller | Test from same VLAN as reader | ||
| 0.6 | Physical placement: reader at correct height/line-of-tap; cable strain relief; enclosure if exposed to dust/moisture | Photo optional | ||
| 0.7 | Labeled assets: controller, reader, and power brick labeled (facility name + support contact); MAC address or mesh VPN node name recorded off-site | |||
| 0.8 | Spares / plan: spare credential for tests; local contact who can power-cycle or reseat reader cable during business hours |
Distinction: Automatic welcome emails and portal configuration are not “on-site.” Items 0.x are what a technician must touch at the building.
1. Infrastructure & environment
| # | Item | Notes |
|---|---|---|
| 1.1 | Production deploy is current (known-good commit / tag) | |
| 1.2 | DATABASE_URI / DATABASE_URL points at production Postgres | |
| 1.3 | All db-infra migrations applied to production (including entry_channel, vetting, wallet fields as needed) | |
| 1.4 | Supabase project linked; SUPABASE_* and service role / admin keys match production | |
| 1.5 | NEXT_PUBLIC_ROOT_DOMAIN (or default) matches live hostname (e.g. pass host) | |
| 1.6 | Object storage (e.g. R2) configured; payment proof bucket works |
2. Email (Resend)
| # | Item | Notes |
|---|---|---|
| 2.1 | RESEND_API_KEY set in production | |
| 2.2 | RESEND_FROM_DOMAIN verified in Resend; sending domain aligned with product | |
| 2.3 | Test: member receives confirm / magic link after join | |
| 2.4 | Test: org owner/manager receives pending member alert (facility must have organization_id) | |
| 2.5 | Test: after approval (or trusted auto-activate), member receives key activated email | |
| 2.6 | Test: member payment proof upload notifies admins (non-trusted path) |
3. Auth & accounts
| # | Item | Notes |
|---|---|---|
| 3.1 | Login / logout / session on production domain (no loops, correct redirects) | |
| 3.2 | At least one org owner (or manager) can open /portal/{facility-slug}/admin | |
| 3.3 | Member can open /portal/{facility-slug}/dashboard after verify | |
| 3.4 | Password / magic link flow matches what you communicate to the client |
4. Facility & org data model
| # | Item | Notes |
|---|---|---|
| 4.1 | Facility exists with correct slug (used in URLs and gate payloads) | |
| 4.2 | Facility linked to organization (organization_id set) — required for admin alert emails | |
| 4.3 | At least one owner or manager on user_organizations for that org | |
| 4.4 | Payment instructions / currency / promos (if used) set under portal admin Packages as needed |
5. Member lifecycle (end-to-end)
| # | Item | Notes |
|---|---|---|
| 5.1 | Join (/portal/{slug}/join): creates pending user + pass + optional payment row | |
| 5.2 | Member sees pending state on dashboard; can upload proof (if applicable) | |
| 5.3 | Approvals queue shows pending member; Approve activates pass + payment | |
| 5.4 | Reject path works and member state is coherent | |
| 5.5 | If using trusted members: proof upload → auto-activate without manual approve |
6. Digital membership pass (phone wallets)
| # | Item | Notes |
|---|---|---|
| 6.1 | Pass issuance mode matches intent: direct signing (your keys/certs) vs hosted template service (vendor mints passes from your templates) | |
| 6.2 | Direct signing: secrets and signing material in env; member obtains install link and adds pass to Apple or Google wallet on device | |
| 6.3 | Hosted template: external template IDs, vendor API credentials, and mint route return success (no 4xx from your integration) | |
| 6.4 | Google wallet pass (if used): issuer / service account / template config aligned with the same architectural choice as Apple | |
| 6.5 | Express phone tap at reader (if used): reader/controller credentials exercised end-to-end; entry_channel: vas in data; Organization → Gate activity shows Wallet tap (and Manual Gate Recent admits matches) |
7. Unattended entry (first client: single reader)
| # | Item | Notes |
|---|---|---|
| 7.1 | GATE_INGEST_SECRET set in production; reader sends Authorization: Bearer <secret> | |
| 7.2 | Portal admin → Reader (/portal/{slug}/admin/access-point): register one access point (name + unique serial) | |
| 7.3 | Copy facilityId and accessPointId into reader config | |
| 7.4 | Reader/controller env sets relay target: LAN IP preferred when both IP and hostname are configured (offline resilience); hostname-only for mesh VPN / mDNS-only sites; API mode for your relay firmware (RPC vs legacy coil URL per vendor docs) | |
| 7.5 | Remote deploy pipeline copies the staged device env and regenerates runtime .env on the controller | |
| 7.6 | Controller maintains a local credential/pass-state cache so tap authorization works without internet in the hot path | |
| 7.7 | Test members have nfc_uid set (matches value reader sends as uid) | |
| 7.8 | Active pass + active account test: access granted and relay triggers | |
| 7.9 | Inactive account (or unknown token) test: access denied, relay does not trigger | |
| 7.10 | Wrong accessPointId for facility → 400 (no bogus linkage) | |
| 7.11 | Organization → Gate activity shows Unattended reader for standard reader path, Wallet tap for entry_channel: vas (phone tap path), Staff admit for Manual Gate (legacy unlabeled rows acceptable) |
Edge runtime — unattended controller (Linux gate host)
Confirm on the gate OS via SSH (not from a developer laptop shell unless using remote SSH):
| Item | Notes |
|---|---|
| Access-engine service starts | Logs show no crash loop from missing Python deps — runtime pip install -r requirements.txt must satisfy sync_service (Member Access OS supabase client). First venv install on low-power ARM hardware often needs 20 to 30 minutes; run in staging, then retest end-to-end before production. |
| Relay protocol matches hardware | Gen2/Gen3 relays often require vendor RPC-style URLs; legacy /relay/0-style triggers may return HTTP success but not energize the coil — validate with a curl smoke test from the controller to the relay IP. |
| Separate reader daemons | If both a plain NFC UID stack and a phone-wallet tap daemon run, they may be different systemd units — tail the unit that matches the integration under test. |
7.12 On-site gate controller — remote access for support
The unattended stack usually only needs outbound HTTPS to your app; you do not need to expose the controller to the public internet for normal operation. Remote access is for SSH (or equivalent), updates, log checks, and troubleshooting without a site visit.
Recommended (default): Tailscale
- Install Tailscale on the gate controller and on each support engineer laptop (same tailnet).
- Why: Encrypted mesh VPN, no router port-forwarding, works behind NAT, ACLs can restrict which machines reach the controller.
- Ops checklist: Document the controller’s Tailscale name (e.g.
facility-a-gate-01) in your runbook; use SSH over Tailscale; keep OS and Tailscale agent patched on a defined cadence.
Alternatives (when Tailscale is not acceptable)
| Approach | Best for | Caveat |
|---|---|---|
| WireGuard to a small VPS | Full control, no third-party control plane | You operate keys, firewall rules, and monitoring |
Cloudflare Tunnel (cloudflared) | Expose SSH or a local debug HTTP endpoint without opening inbound ports | Requires Cloudflare account; scope access carefully |
| Reverse SSH (autossh) | Very small deployments | Fragile if middle host changes; document recovery |
| Router port-forward (SSH → controller) | Legacy sites | High risk unless combined with VPN, fail2ban, key-only SSH, non-default port; many ISPs use CGNAT |
Baseline hardening (any method)
- SSH: key-based auth, disable password login if possible; non-default SSH port optional.
- Dedicated deploy/support user; document who has keys.
- Host firewall on controller: allow only what you need (often: nothing inbound if using mesh VPN only).
- Time sync so logs correlate with cloud.
| # | Item | Notes |
|---|---|---|
| 7.12.1 | Remote path chosen (Tailscale recommended) and documented in client runbook | |
| 7.12.2 | Test SSH (or agreed remote shell) from support laptop without being on-site LAN | |
| 7.12.3 | Controller hostname / mesh VPN name and OS image version recorded |
Fleet inventory: For device_id, hostname, Tailscale metadata, reader serial, and a deployment log (who deployed where and when), use fleet-checkin-device-registry.md.
8. Optional: manual gate
Skip if client is unattended only.
| # | Item | Notes |
|---|---|---|
| 8.1 | Staff can open /facility/{slug}/gate (or rely on portal staff URLs per your IA) | |
| 8.2 | Search → Admit / Deny writes entry_channel: staff_manual | |
| 8.3 | Recent entries may show Wallet for entry_channel: vas (not staff-initiated) |
9. Observability & support
| # | Item | Notes |
|---|---|---|
| 9.1 | Production logs / alerts reachable (Vercel, Supabase, Resend dashboards) | |
| 9.2 | Escalation contact and rollback plan documented for the client | |
| 9.3 | Backup admin account exists (not only one person’s email) |
10. Security & compliance (minimum)
| # | Item | Notes |
|---|---|---|
| 10.1 | No service role or DB URLs in client-visible code or public repos | |
| 10.2 | Gate ingest URL + secret treated as sensitive (rotate if leaked) | |
| 10.3 | Privacy: confirm what you log (PII in entry_logs, retention) with the client |
Known gaps to track (not blockers for all pilots)
- Several portal admin server actions historically relied on UI-only gating; prioritize smoke-testing critical paths and consider a follow-up authorization audit on mutations.
GET /api/gate-eventsin-memorylastScanis for demo / credential registration polling only — not reliable on multi-instance; unattended decisions must usePOSTresponseallowed.
Sign-off
| Role | Name | Date | Signature / note |
|---|---|---|---|
| Engineering | |||
| Client / ops |