// `orders.approve` — DESCRIPTOR (browser-safe). // // The human-approval surface: a client calls this with the order id + // the decision; the executor injects the matching `approval` signal into // the parked `orders.fulfill` run. This is a non-row-writing mutation // (it pokes a workflow, not the orders table), so it declares no // optimistic `target` and no `op` against `orders`. import { defineMutation } from '@voltro/protocol' import { Schema } from 'effect' export const approveOrder = defineMutation({ name: 'orders.approve', // This is the human-APPROVAL surface, so state plainly what "open" costs // here rather than hiding it behind the word demo: whoever can call this // decides whether an order ships. `assertOwnTenant` confines the signal to // the caller's own tenant and the executionId is DERIVED from // `{ orderId, tenantId }` (so no caller-supplied id can address another // tenant's run), but nothing in this template distinguishes an approver from // anyone else — it configures no auth strategy and no rbac, so an anonymous // Subject with no scopes is the only caller that exists and a // `guards: [{ scope: 'orders:approve' }]` would deny 100% of traffic. // // This is THE procedure in this template to guard first. Add an auth // strategy (`api-auth`) or rbac (`api-rbac`), then that guard. openAccess: 'injects the approval signal into the caller\'s own tenant\'s parked fulfilment run — the ' + 'executionId is derived from `{ orderId, tenantId }` and `assertOwnTenant` rejects a ' + 'mismatch, so no other tenant\'s run is addressable. It still decides whether an order ' + 'ships: the first procedure here to grow an `orders:approve` guard once an identity exists.', input: Schema.Struct({ orderId: Schema.String, tenantId: Schema.String, approved: Schema.Boolean, }), output: Schema.Struct({ orderId: Schema.String, eventId: Schema.String, }), })