commit 9f70420c4e2db7edff168bdd657f107175234b2a Author: George Lambert Date: Fri Sep 11 18:39:02 2026 -0400 Initial import of zapier-decisions from zapier monorepo diff --git a/LOG.md b/LOG.md new file mode 100644 index 0000000..d714a0e --- /dev/null +++ b/LOG.md @@ -0,0 +1,67 @@ +# Action log + +## 2026-09-11 — bootstrap + +- Created this repo to record decisions while executing cleanup items 1–5 (and a second pass on 2–5). +- Assumption: single developer, lab only; breaking changes allowed. + +## Step 1 — account-balance is the prepaid source of truth + +- Persist books to `BOOKS_PATH` (atomic JSON). +- Mutations go through `balance.adjust` / `usage.recorded`; edge cache `balanceCents` is updated from the books reply only. +- Local cache mutate only when `NATS_URL` and `ACCOUNT_BALANCE_URL` are both unset (tests). + +## Step 2 — identity join + +- `zappier-identity` mailbox: `verae.identity.bind` / `verae.identity.lookup`. +- Portal + middleware tenants store `veraeUserId`; JWT never public. + +## Step 3 — access planes are the public doors + +- zappier-edge binds loopback (`127.0.0.1:3000`). +- Public: access-web `:3021`, access-api `:3022`, access-leaf `:3023`, access-zapier `:3024`, access-staff `:3025`. + +## Step 4 — leaf hardening + +- `verae-nats-accounts` holds nats.conf + subject policy. +- Leaf token required; billing subjects denied in policy file and access-leaf. + +## Step 5 — fleet spawn + +- Prefer local machines for HTTP `spawn.command` services. +- Disable lan-134 unless `FLEET_ENABLE_LAN134=1`. +- SSH spawn timeout 8s; failed hosts skipped. + +## 2026-09-11 — staff IAM + +- New `verae-staff-iam` :3028 — users, roles, permissions, sessions, audit UI. +- Admin login uses IAM when `STAFF_IAM_URL` is set; tabs hide without permission. +- CS/sales/accounting/access-staff/fleet mutating APIs check `cs.credit`, `sales.quote`, `accounting.export`, `fleet.operate`, etc. +- Seed: admin/cs/sales/accounting/operator. Shared staff key is fallback only. + +## 2026-09-11 — last three UI leftovers + +- Swagger `/docs` stays stock; banner names it OpenAPI explorer. +- Shared template `verae-staff-ui` for CS + access-staff. +- `STAFF_COOKIE_DOMAIN` + nginx example for multi-host. + +## 2026-09-11 — names, staff session, exclusive jobs.events + +- Account-balance stores display names (`customer.put` + lookup by name). Edge writes names on customer create/edit; CS/sales/accounting/staff join from edge if the ledger has no name. +- New repo `verae-staff-session` (:3027). Department HTML redirects when `STAFF_AUTH=1`. +- `JOBS_EVENTS_EXCLUSIVE=1` makes `verae-jobs-events` the durable consumer; middleware webhook router backs off. +- Catalog index is cards. Disabled fleet machines are grey, not degraded yellow. + +## 2026-09-11 — UI design-system pass + +- Restyled CS/sales/accounting/access-staff to portal indigo; dollars + names. +- Fleet ⋯ menus, role chips, Docs cards, 0.0.0.0 copy, simulator indigo (orange = faults). +- Portal masked API key; admin customer drawer; empty invoice illustrations. +- Catalog system-ui. New independent repo **UI-Docs** (walkthrough, screenshots, UI-REVIEW.pdf). + +## Second pass (2–5) + +- Identity used from portal when `IDENTITY_URL` set. +- Leaf loads allow-list from nats-accounts `policy.json`. +- Staff plane is a first-class mailbox (`verae-access-staff`). +- jobs.events mailbox process `verae-jobs-events` (passthrough + count). diff --git a/NATS.md b/NATS.md new file mode 100644 index 0000000..782a476 --- /dev/null +++ b/NATS.md @@ -0,0 +1,3 @@ +# NATS — zapier-decisions + +None. Documentation repo. diff --git a/README.md b/README.md new file mode 100644 index 0000000..58e5adb --- /dev/null +++ b/README.md @@ -0,0 +1,13 @@ +# zapier-decisions + +Lab log of architecture decisions, actions taken, and open todos while cleaning the Verae × Zapier stack. + +**Forgejo:** https://git.georgelambert.org/marchon/zapier-decisions + +| File | What | +|------|------| +| [LOG.md](LOG.md) | Chronological actions | +| [TODO.md](TODO.md) | Open items | +| [decisions/](decisions/) | One file per decision | + +No runtime. Not a NATS mailbox. diff --git a/TODO.md b/TODO.md new file mode 100644 index 0000000..153f9e5 --- /dev/null +++ b/TODO.md @@ -0,0 +1,9 @@ +# Open todos + +- [ ] Live `api.veraetime.net` with `MOCK_VERAE=false` and admin bind credentials. +- [ ] NATS nkeys/mTLS on a real three-node cluster (accounts file is the lab stand-in). +- [x] Exclusive JetStream consumer for `verae.zapier.jobs.events` on `verae-jobs-events` (`JOBS_EVENTS_EXCLUSIVE=1`; middleware skips the router). +- [x] Auth on CS/sales/accounting HTML via `verae-staff-session` (`STAFF_AUTH=1`). +- [x] Staff IAM: named users, roles, permissions (`verae-staff-iam` :3028). +- [ ] Zapier Platform `push` of a private app. +- [ ] Move portal static files fully into `verae-access-web` (today it proxies `/portal` to loopback edge). diff --git a/decisions/D001-prepaid-sot.md b/decisions/D001-prepaid-sot.md new file mode 100644 index 0000000..9b1bace --- /dev/null +++ b/decisions/D001-prepaid-sot.md @@ -0,0 +1,6 @@ +# D001 — Account-balance is the only prepaid writer + +**Status:** accepted +**Step:** 1 + +Prepaid cents, credits, usage, and payments persist in `zappier-account-balance` (`books.json`). zappier-edge `balanceCents` is a cache filled from the books reply. Tests without NATS/HTTP books still mutate the cache so unit tests stay hermetic. diff --git a/decisions/D002-identity.md b/decisions/D002-identity.md new file mode 100644 index 0000000..7548947 --- /dev/null +++ b/decisions/D002-identity.md @@ -0,0 +1,6 @@ +# D002 — veraeUserId is the join key, not the JWT + +**Status:** accepted +**Step:** 2 + +Public token remains the zappier API key. Chain JWT stays server-side (`tokenRef`). `zappier-identity` is the mailbox for bind/lookup so portal and middleware share one map. diff --git a/decisions/D003-public-doors.md b/decisions/D003-public-doors.md new file mode 100644 index 0000000..9d32527 --- /dev/null +++ b/decisions/D003-public-doors.md @@ -0,0 +1,6 @@ +# D003 — Access planes are the only public HTTP doors + +**Status:** accepted +**Step:** 3 + +Zapier → `:3024`, browser → `:3021`, customer API → `:3022`, leaf → `:3023`, staff → `:3025`. zappier-edge listens on `127.0.0.1:3000` for identity, Stripe, admin, and as upstream for those planes. diff --git a/decisions/D004-leaf-accounts.md b/decisions/D004-leaf-accounts.md new file mode 100644 index 0000000..65de80d --- /dev/null +++ b/decisions/D004-leaf-accounts.md @@ -0,0 +1,6 @@ +# D004 — Leaf cannot touch billing, even if authz is skipped + +**Status:** accepted +**Step:** 4 + +`verae-nats-accounts/policy.json` is the allow-list. access-leaf refuses any target not in the leaf set. nats.conf documents INTERNAL vs LEAF accounts for when the lab cluster is replaced with a real accounts-enabled nats-server. diff --git a/decisions/D005-fleet-local-first.md b/decisions/D005-fleet-local-first.md new file mode 100644 index 0000000..4df6ecd --- /dev/null +++ b/decisions/D005-fleet-local-first.md @@ -0,0 +1,6 @@ +# D005 — HTTP services spawn locally; lan-134 stays off + +**Status:** accepted +**Step:** 5 + +SSH to `70.88.205.134` blocked keepFloor. HTTP apps (`spawn.command`) prefer `kind=local`. `lan-134` is disabled unless `FLEET_ENABLE_LAN134=1`. Failed SSH hosts are skipped after 8s. diff --git a/package.json b/package.json new file mode 100644 index 0000000..a12c852 --- /dev/null +++ b/package.json @@ -0,0 +1,6 @@ +{ + "name": "zapier-decisions", + "version": "0.1.0", + "private": true, + "description": "Architecture decisions and action log for the Verae × Zapier stack" +}