Skip to content

Domain.Policy reference

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.

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));
});
}),
);
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}`);
});
}),
);

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." },
) {}