Domain.Policy reference
Policy
Section titled “Policy”Source:
packages/domain/src/Policy.ts
“Whenever this happens, do that”: one of the business’s standing rules. On an event from an aggregate or a view, it decides what to do next and acts by sending commands and calling external systems. Policies run shortly after the event, never in the same step, so use them only for eventually consistent work. Delivery is at least once; the commands a policy sends get ids derived from the event, so a second run sends the same commands.
Policy: Reacting to an aggregate
Section titled “Policy: Reacting to an aggregate”import * as Domain from "@alchemy.run/domain";import * as Effect from "effect/Effect";import { Account, AccountId, OpenAccount } from "./Account.ts";import { Customer, CustomerRegistered } from "./Customer.ts";
export class MainAccountProvisioning extends Domain.Policy("MainAccountProvisioning", { from: Customer, on: [CustomerRegistered],}) {}
export const MainAccountProvisioningLive = MainAccountProvisioning.toLayer( Effect.gen(function* () { const accounts = yield* Account; return Effect.fn(function* ({ source }) { yield* accounts .send(AccountId.make(`${source.id}-main`), new OpenAccount({ owner: source.id })) .pipe(Effect.catchTag("AlreadyOpen", () => Effect.void)); }); }),);Policy: Calling an external system
Section titled “Policy: Calling an external system”import * as Domain from "@alchemy.run/domain";import * as Effect from "effect/Effect";import { Account, MoneyWithdrawn } from "./Account.ts";import { FraudCheck } from "./FraudCheck.ts";
export class FraudReview extends Domain.Policy("FraudReview", { from: Account, on: [MoneyWithdrawn],}) {}
export const FraudReviewLive = FraudReview.toLayer( Effect.gen(function* () { const fraud = yield* FraudCheck; return Effect.fn(function* ({ source, event }) { const { risk } = yield* fraud.score({ accountId: source.id, amount: event.amount }); yield* Effect.log(`risk ${risk} for ${source.id}`); }); }),);Policy: Annotating policies
Section titled “Policy: Annotating policies”The last argument is its annotations: data for what is built on the
model, read back as X.annotations. Add your own keys by augmenting
Domain.Annotations.
Nothing a client calls shows it; it is for the people and the tools that
read the model, as X.annotations.
export class MainAccountProvisioning extends Domain.Policy( "MainAccountProvisioning", { from: Customer, on: [CustomerRegistered] }, { description: "Opens a main account for every new customer." },) {}