Consume raw arma-sync-events into a validated, idempotent operation ledger: contract v1, reject/dead-letter with zero effects, effect keys with unique-constraint race handling, and a staged-activation flag hook. Registers the operations permission domains. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
108 lines
No EOL
3 KiB
TypeScript
108 lines
No EOL
3 KiB
TypeScript
import type { CollectionConfig } from "payload";
|
|
|
|
/**
|
|
* Derived-effect ledger for validated operation events.
|
|
*
|
|
* One row per (event, effect type) pair, keyed by `effectKey` =
|
|
* `${eventId}:${effectType}` so an exact retry is a no-op. Effects are the
|
|
* only place derived operation state may be recorded; they always carry
|
|
* provenance back to both the operation event and the raw source event.
|
|
*
|
|
* Writes are internal only (create/update/delete denied; the bridge writes
|
|
* via `overrideAccess`). Read is open to any logged-in user.
|
|
*/
|
|
export const OperationEffects: CollectionConfig = {
|
|
slug: "operation-effects",
|
|
admin: {
|
|
group: "Operations",
|
|
useAsTitle: "effectKey",
|
|
defaultColumns: ["effectKey", "operationId", "effectType", "status", "appliedAt"],
|
|
},
|
|
access: {
|
|
read: ({ req }) => !!req.user,
|
|
create: () => false,
|
|
update: () => false,
|
|
delete: () => false,
|
|
},
|
|
fields: [
|
|
{
|
|
name: "operationEvent",
|
|
type: "relationship",
|
|
relationTo: "operation-events",
|
|
required: true,
|
|
index: true,
|
|
admin: {
|
|
description: "The validated operation event this effect derives from.",
|
|
},
|
|
},
|
|
{
|
|
name: "sourceEvent",
|
|
type: "relationship",
|
|
relationTo: "arma-sync-events",
|
|
required: true,
|
|
index: true,
|
|
admin: {
|
|
description: "The raw source event this effect derives from.",
|
|
},
|
|
},
|
|
{
|
|
name: "operationId",
|
|
type: "text",
|
|
required: true,
|
|
index: true,
|
|
},
|
|
{
|
|
name: "effectKey",
|
|
type: "text",
|
|
required: true,
|
|
unique: true,
|
|
index: true,
|
|
admin: {
|
|
description: "Idempotency key: `${eventId}:${effectType}`.",
|
|
},
|
|
},
|
|
{
|
|
name: "effectType",
|
|
type: "select",
|
|
required: true,
|
|
options: [
|
|
{ label: "Operation Started", value: "operation.started" },
|
|
{ label: "Operation Ended", value: "operation.ended" },
|
|
{ label: "Objective Updated", value: "operation.objective-updated" },
|
|
{ label: "Extraction Recorded", value: "operation.extraction-recorded" },
|
|
{ label: "Inventory Recorded", value: "operation.inventory-recorded" },
|
|
],
|
|
},
|
|
{
|
|
name: "status",
|
|
type: "select",
|
|
required: true,
|
|
defaultValue: "applied",
|
|
options: [
|
|
{ label: "Applied", value: "applied" },
|
|
{ label: "Pending", value: "pending" },
|
|
{ label: "Failed", value: "failed" },
|
|
{ label: "Reversed", value: "reversed" },
|
|
],
|
|
},
|
|
{ name: "payload", type: "json" },
|
|
{
|
|
name: "reversalOf",
|
|
type: "relationship",
|
|
relationTo: "operation-effects",
|
|
admin: {
|
|
description: "Set when this effect reverses another effect.",
|
|
},
|
|
},
|
|
{
|
|
name: "reversedBy",
|
|
type: "relationship",
|
|
relationTo: "operation-effects",
|
|
admin: {
|
|
description: "Set when this effect has been reversed.",
|
|
},
|
|
},
|
|
{ name: "reconciliationNotes", type: "textarea" },
|
|
{ name: "appliedAt", type: "date" },
|
|
],
|
|
}; |