Add developer credentials: URLs, lab keys, NATS token, staff IAM, git

This commit is contained in:
George Lambert 2026-09-14 13:50:45 -04:00
commit f850002f1c

125
03-zapier-verae-path.md Normal file
View file

@ -0,0 +1,125 @@
# Zapier → Verae API → Zapier
How a timestamp job is submitted, watched, and returned. Lab today: `MOCK_VERAE=true`. Live path is the same HTTP contract with `MOCK_VERAE=false`.
## Rule
```text
Zapier cloud --HTTPS only--> zap.zapier.georgelambert.org (access-zapier)
|
v HTTPS
middleware :3100 /zapier/v1
|
+---------------+----------------+
| HTTPS | NATS (private cluster)
v v
api.veraetime.net jobs.watch → poller
POST /api/timestamp GET /api/status/{jobId}
GET /api/status/{jobId} |
POST /api/verify v
jobs.events
|
+--------------------+--------------------+
| wait subscriber | webhook-deliver
v v
HTTP response to Zap POST hooks.zapier.com
```
Zapier never has `NATS_URL`. Verae never has `NATS_URL`.
## 1. Submit (async create)
1. Zap action **Create Timestamp** (or curl) `POST https://zap.zapier.georgelambert.org/zapier/v1/timestamp` with portal API key `zmw_…` (not a Verae JWT).
2. access-zapier / edge: authz, then `meter()` records cents; if `NATS_URL` is set, `natsPublish(verae.billing.usage.recorded)`.
3. Forwards to middleware `POST /zapier/v1/timestamp`.
4. Middleware `checkEntitlement` (local plan limits today).
5. `veraeClient.createTimestamp`:
- **Mock:** in-process job, fake `jobId`.
- **Live:** `POST https://api.veraetime.net/api/timestamp` with JWT → **202** `{ jobId }`.
6. Splitter (in-process): hash vs attachments; optional `verae.archive.put` (bytes never go to chain).
7. `enqueueWatch` → JetStream **`verae.zapier.jobs.watch`**.
8. HTTP **202** `{ jobId, sha256, existing }` back to Zapier immediately.
Same SHA-256 is idempotent (`existing: true`).
## 2. Monitor (job poller)
The poller is **in the middleware Node process** when `NATS_ENABLED=true` (`startJobPollerWorker`). Fleet does **not** spawn a second copy (`job-poller.enabled: false`).
1. Durable consumer `job-poller` on `ZAPIER_JOBS` / `verae.zapier.jobs.watch`.
2. Resolve `tokenRef` → tenant Verae password → `POST` login → JWT (stays in middleware).
3. `GET /api/status/{jobId}` (mock or live timestamp server).
4. `pending` → `nak` after `intervalMs` (retry).
5. `completed` → publish `jobs.events` `{ event: timestamp.completed, status, jobId, tenantId, traceId }`.
6. `failed` → `timestamp.failed`. Too many attempts → `timestamp.timeout`.
7. `ack` the watch message.
Live OpenAPI: poll until `completed` / `failed`. Hash lookup is **501** on live (`lookupHash`). Map `certificate`, `timestamp`, `blockIndex`, `sha256` into the receipt Zap samples expect.
## 3. Wait (sync Zap step)
**Create Timestamp and Wait** → `POST /zapier/v1/timestamp/wait`.
1. Same as submit (watch is already on NATS).
2. `waitForJobEvent(jobId, WAIT_TIMEOUT_MS)` subscribes to **`verae.zapier.jobs.events`**.
3. On matching `jobId` event: return status JSON (certificate / receipt).
4. On timeout: `{ status: pending, jobId }` so the REST Hook can finish the Zap.
`includeAttached`: after seal, aggregator should `verae.archive.query`; bloom hits merge extra receipts. **Simulator does this; live aggregator hook is TBD.**
## 4. Push back to Zapier
- **Wait response:** HTTP body on the same Zap step.
- **REST Hook:** Zapier subscribes `POST /zapier/v1/hooks`. On `jobs.events`, middleware enqueues **`verae.zapier.webhooks.deliver`**. Worker POSTs `targetUrl` (`hooks.zapier.com`).
- **Poll status:** Zap action **Find Job Status** → `GET /zapier/v1/status/{jobId}` → middleware `GET` Verae (or last event).
## 5. Verify
`POST /zapier/v1/verify` → middleware → Verae `POST /api/verify`. No job watch.
## 6. Batch Merkle (designed; same bus)
From `MESSAGE-FLOWS.md`:
1. `POST /v1/timestamp/batch` — one item per line.
2. Middleware hashes leaves, builds Merkle tree.
3. Chain seals **only the root** (`POST /api/timestamp` on the root).
4. Each leaf proof → `verae.archive.put` `kind: tree`.
5. Central hash lookup of a leaf misses unless `includeTree=true`.
6. Aggregator broadcasts `verae.archive.query` `kinds=["tree"]`.
7. Tree node bloom hit → `archive.reply.<id>` with proof.
Live wait path does not yet call the aggregator, so tree-leaf receipts are not merged on NS1.
## Connect live `api.veraetime.net`
Still blocked on operator bind credentials. When ready:
```bash
# middleware env
MOCK_VERAE=false
VERAE_API_BASE_URL=https://api.veraetime.net
NATS_ENABLED=true
NATS_URL=nats://10.10.10.21:4222,nats://10.10.10.22:4222,nats://10.10.10.23:4222
JETSTREAM_REPLICAS=3
```
Then: working Verae login, one live seal, confirm 202/status/verify, map receipt fields, REST Hook to a private Zap. See `zapier-decisions/STATUS.md` “Once MOCK_VERAE=false”.
## Billing on this path
| Hop | Designed | Running |
|-----|----------|---------|
| Edge meter | `verae.billing.usage.recorded` | **coded**; fires when edge has `NATS_URL` |
| Account-balance | subscribe + debit prepaid; 402 if empty | **subscriber running**; 402 from books not proven on every Zap |
| Middleware quota | local files via `recordUsage` | **running**; not NATS |
| `verae.zapier.usage` | optional JS meter | stream only |
## Connect a new internal process
```bash
export NATS_URL=nats://10.10.10.21:4222,nats://10.10.10.22:4222,nats://10.10.10.23:4222
# clone verae-nats-process, rename subjects, register in verae-fleet
```
Jobs stay: HTTP in from Zapier → HTTPS to Verae → NATS watch/events → HTTP back to Zapier.