All guides

Deployment & rollout

First client — preflight checklist

Role-based / vendor-neutral version: first-client-preflight-checklist-role-based.md (same flow; no specific reader, SBC, or pass-vendor names).

Org-level decisions (kickoff workshop, sponsor-facing): org-platform-decision-guide.md—including how long implementations usually take (roughly one to three weeks, depending on decisions, customization, and site hardware).

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

There is no single mandatory path. First-client readiness depends on how the organization operates, how they take payment, how many sites they have, and how members enter. Use the table below to decide what is in scope, what is N/A, and what needs extra verification for this client—then mark skipped rows explicitly (e.g. “N/A — staff gate only”).

DimensionTypical variantsSections most affected
Payment & membershipOff-site proof + Approvals; promos; recurring vs visit-credit products; future card checkout2, 4–5 (emails, Payments hub, lifecycle)
Trust / activationManual approval for every join vs trusted auto-activate for some members5
Brand footprintSingle facility; multi-facility same org; different managers per site4 (org linkage, slugs, who gets alerts)
Pass channelDirect signing, hosted pass templates, Google Wallet, combinations; optional phone tap at reader vs not6 (and 7 when a reader stack is in play)
Physical entry modelUnattended credential reader only; phone wallet tap at reader; staff manual gate only; mixed0, 7, 8 — skip sections that describe hardware or flows the client does not use
Edge & supportController on Ethernet vs Wi‑Fi; Tailscale vs other remote access0, 7.12
Payments platformOperator billing vs bring-your-own acquirer (when your product distinguishes these)Product env / Billing docs alongside 2–5

Practical rule: Confirm the profile in writing with the client (or internal sponsor) before you treat every line item as blocking. Items in §0 matter only where there is on-site unattended or door hardware; items in §8 matter only where staff admit from a browser.


0. On-site physical requirements (what must exist at the facility)

Profile: Omit or mark N/A entirely if there is no on-site unattended reader deployment for this rollout (phone-wallet tap only, 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.

#ItemPass/failVerified by / dateNotes
0.1NFC / RFID reader installed and cabled (WalletMate II Mini for unattended; simple USB reader for manned)Model + serial recorded
0.2Controller (Raspberry Pi for unattended; staff laptop/PC for manned) running the reader client, mounted and poweredDevice model / OS version
0.3Power: reader + controller on reliable outlets; consider surge protection; note if UPS is required for your SLA
0.4Network: Ethernet to controller preferred over Wi‑Fi for unattended gates; if Wi‑Fi only, document SSID constraints and who owns password rotation
0.5Internet reachability: site can reach your production API host (HTTPS outbound); no captive portal blocking the edge controllerTest from same VLAN as reader
0.6Physical placement: reader at correct height/line-of-tap; cable strain relief; enclosure if exposed to dust/moisturePhoto optional
0.7Labeled assets: Controller, reader, and power brick labeled (facility name + support contact); MAC address or Tailscale name recorded off-site
0.8Spares / plan: spare NFC tag for tests; local contact who can power-cycle or reseat USB 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

#ItemNotes
1.1Production deploy is current (known-good commit / tag)
1.2DATABASE_URI / DATABASE_URL points at production Postgres
1.3All db-infra migrations applied to production (including entry_channel, vetting, wallet fields as needed)
1.4Supabase project linked; SUPABASE_* and service role / admin keys match production
1.5NEXT_PUBLIC_ROOT_DOMAIN (or default) matches live hostname (e.g. pass host)
1.6Object storage (e.g. R2) configured; payment proof bucket works

2. Email (Resend)

#ItemNotes
2.1RESEND_API_KEY set in production
2.2RESEND_FROM_DOMAIN verified in Resend; sending domain aligned with product
2.3Test: member receives confirm / magic link after join
2.4Test: org owner/manager receives pending member alert (facility must have organization_id)
2.5Test: after approval (or trusted auto-activate), member receives key activated email
2.6Test: member payment proof upload notifies admins (non-trusted path)

3. Auth & accounts

#ItemNotes
3.1Login / logout / session on production domain (no loops, correct redirects)
3.2At least one org owner (or manager) can open /portal/{facility-slug}/admin
3.3Member can open /portal/{facility-slug}/dashboard after verify
3.4Password / magic link flow matches what you communicate to the client

4. Facility & org data model

#ItemNotes
4.1Facility exists with correct slug (used in URLs and gate payloads)
4.2Facility linked to organization (organization_id set) — required for admin alert emails
4.3At least one owner or manager on user_organizations for that org
4.4Facility currency, payment instructions, and collection mode (Payments hub); membership products and promos wherever this org uses them (Packages / Promotions) — depth varies by payment profile (see § “How this checklist varies”)

5. Member lifecycle (end-to-end)

Applies differently if the client uses trusted auto-activation vs full manual Approvals-only—confirm which paths are live.

#ItemNotes
5.1Join (/portal/{slug}/join): creates pending user + pass + optional payment row
5.2Member sees pending state on dashboard; can upload proof (if applicable)
5.3Approvals queue shows pending member; Approve activates pass + payment
5.4Reject path works and member state is coherent
5.5If using trusted members: proof upload → auto-activate without manual approve

6. Digital pass (Apple / Google)

Only complete the sub-rows that match this org’s pass profile (direct signing vs hosted templates, Google Wallet, etc.). Other rows may be explicitly N/A.

#ItemNotes
6.1Apple Wallet issuance matches intent: platform-signed (.pkpass) vs hosted / third-party template (or neither)
6.2Native / direct signing: signing secrets + certs in env; Add to Apple Wallet mint works end-to-end
6.3Hosted pass template: template IDs + credentials wired; issuance API responds 200 (not 4xx) where your integration exposes one
6.4Google Wallet (if used): issuer + template IDs match your deployment
6.5Phone wallet tap at reader (if used): reader/controller integration exercised end-to-end; successful verify records entry_channel: vas; Organization → Gate activity (logs) and Manual Gate Recent admits show Wallet tap where configured

7. Unattended entry (first client: single reader)

Skip this entire section if the client has no unattended NFC reader at the door (staff gate only, or phone tap path without UID reader — align with agreed entry profile).

#ItemNotes
7.1GATE_INGEST_SECRET set in production; reader sends Authorization: Bearer <secret>
7.2Portal admin → Reader (/portal/{slug}/admin/access-point): register one access point (name + unique serial)
7.3Copy facilityId and accessPointId into reader config
7.4access-engine/device.env sets door strike / relay targets (IP, hostname, API mode, timers) per your hardware—variable names follow the integration in repo / internal runbook
7.5Deploy pipeline copies device.env and remote access-engine/deploy.sh writes runtime .env on the controller
7.6Reader keeps a local SQLite token cache (members.db): tap decisions do not require internet in the hot path
7.7Test members have nfc_uid set (matches value reader sends as uid)
7.8Active pass + active account test: access granted and strike / relay fires
7.9Inactive account (or unknown token) test: access denied, strike / relay does not fire
7.10Wrong accessPointId for facility → 400 (no bogus linkage)
7.11Organization → Gate activity shows Unattended reader for the standard reader path, Wallet tap when entry_channel is vas (phone wallet path), and Staff admit for Manual Gate (legacy unlabeled rows acceptable)

Edge runtime — Member Access OS access-engine (Edge Controller / Raspberry Pi)

Verify after deploy while SSH’d into the gate host (not on macOS — there is no journalctl there):

ItemNotes
member-access.service starts cleanlysudo journalctl -u member-access.service -n 80 shows startup without ModuleNotFoundError — the engine venv must run pip install -r requirements.txt (must include supabase for sync_service). Fix-forward deploys pull requirements.txt from repo; older devices may need a manual pip install -r once. First install on a Raspberry Pi often needs 20 to 30 minutes; do it in the lab, wait for completion, then verify the service and a full tap cycle.
Relay smoke testFrom the controller, run the HTTP pulse your relay documents (IP + API style from device.env) and confirm the strike energizes.
Which logs to tailmember-access.service runs main.py (UID read → SQLite → relay). If you deploy a separate phone-wallet tap service, it is usually another systemd unit—tail the unit name from your deployment recipe.

7.12 Edge host (Linux) — remote access for support

The gate 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, updates, log checks, and troubleshooting without a site visit.

Recommended (default): Tailscale

  • Install Tailscale on the controller and on each support engineer laptop (same tailnet).
  • Why: Encrypted mesh VPN, no router port-forwarding, works behind NAT/captive-ish home-style networks, ACLs can restrict which machines reach the controller.
  • Ops checklist: Document the controller’s Tailscale name (e.g. tye-gate-host) in your runbook; use SSH over Tailscale (ssh user@tye-gate-host); keep the controller’s OS and Tailscale agent on auto-updates or a monthly patch window.

Alternatives (when Tailscale is not acceptable)

ApproachBest forCaveat
WireGuard to a small VPSFull control, no third-party control planeYou operate keys, firewall rules, and monitoring
Cloudflare Tunnel (cloudflared)Expose SSH or a local debug HTTP endpoint without opening inbound portsRequires Cloudflare account; scope access carefully
Reverse SSH (autossh)Very small deploymentsFragile if middle host changes; document recovery
Router port-forward (22 → Pi)Legacy sitesHigh 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.
  • Firewall on controller: allow only what you need (often: nothing inbound if using Tailscale-only).
  • Time sync (systemd-timesyncd or chrony) so logs correlate with cloud.
#ItemNotes
7.12.1Remote path chosen (Tailscale recommended) and documented in client runbook
7.12.2Test SSH (or agreed remote shell) from support laptop without being on-site LAN
7.12.3Controller hostname / Tailscale name and OS image version recorded

Fleet inventory (device registry + deployment log): fleet-checkin-device-registry.md.


8. Optional: manual gate

Skip if client is unattended only.

#ItemNotes
8.1Staff can open /facility/{slug}/gate (or rely on portal staff URLs per your IA)
8.2Search → Admit / Deny writes entry_channel: staff_manual
8.3Recent entries can show Wallet for rows admitted elsewhere with entry_channel: vas (phone tap is not a staff admit)

9. Observability & support

#ItemNotes
9.1Production logs / alerts reachable (Vercel, Supabase, Resend dashboards)
9.2Escalation contact and rollback plan documented for the client
9.3Backup admin account exists (not only one person’s email)

10. Security & compliance (minimum)

#ItemNotes
10.1No service role or DB URLs in client-visible code or public repos
10.2Gate ingest URL + secret treated as sensitive (rotate if leaked)
10.3Privacy: 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-events in-memory lastScan is for demo/NFC registration polling only — not reliable on multi-instance; unattended decisions must use POST response allowed.

Sign-off

RoleNameDateSignature / note
Org profile summarized (payments, passes, entry model; what was N/A)
Engineering
Client / ops