Skip to main content
new-domain-event Add a new domain event type to the transactional outbox system. Use when adding events like invitation.accepted, user.deleted, or any new aggregate event.
Aller à l'installation Skills Marketplace Découvrez et explorez les compétences IA créées par la communauté.
Installer avec Codex ou Claude Copiez ce prompt, collez-le dans Codex, Claude ou un autre assistant, puis laissez-le vérifier la page du skill et l'installer pour vous.
Copier le promptAfficher les détails du prompt Une commande directe contourne le prompt de vérification. Examinez la source avant de l'exécuter.
npx skills add https://github.com/jamesaphoenix/tx-agent-kit --skill new-domain-eventLa commande reste sur une seule ligne. Faites défiler horizontalement pour la vérifier avant de la copier.
Vous préférez une copie locale ? Téléchargez les fichiers actuellement disponibles dans SkillsMP.
Télécharger Zip Téléchargement... Métiers associés SOC
Basé sur la classification professionnelle SOC
name new-domain-event description Add a new domain event type to the transactional outbox system. Use when adding events like invitation.accepted, user.deleted, or any new aggregate event. argument-hint <aggregate>.<past-tense-verb>
Add a New Domain Event Type
Add a new event type to the transactional outbox system. The event name must follow <aggregate>.<past-tense-verb> convention (e.g. invitation.accepted, user.deleted).
Steps
1. Register the event type in contracts
File: packages/contracts/src/literals.ts
Add the new event type string to domainEventTypes and (if new aggregate) to domainEventAggregateTypes:
export const domainEventTypes = ['organization.created' , '$ARGUMENTS' ] as const
2. Add payload interface in the domain layer
File: packages/core/src/domains/<aggregate>/domain/<aggregate>-events.ts
Create or extend the events file with a typed payload interface. The interface name must be <PascalCaseEventType>EventPayload:
export interface <PascalCase > {
}
EventPayload
If the file already exists (e.g. organization-events.ts), add the new interface alongside existing ones.
3. Re-export from the domain's public events.ts File: packages/core/src/domains/<aggregate>/events.ts
Re-export the payload type and add the event discriminant + version:
export type { <PascalCase >EventPayload } from './domain/<aggregate>-events.js'
export const <aggregate>Events = {
<verb>: '<aggregate>.<verb>' ,
} as const
export const <aggregate>EventVersions = {
'<aggregate>.<verb>' : 1 ,
} as const
If events.ts doesn't exist yet, create it. This is the public cross-domain contract — other domains may ONLY import from this file.
4. Export from packages/core/src/index.ts export { <aggregate>Events , <aggregate>EventVersions } from './domains/<aggregate>/events.js'
export type { <PascalCase >EventPayload } from './domains/<aggregate>/events.js'
5. Add payload schema in temporal-client File: packages/temporal-client/src/types/domain-event.ts
Add a matching effect/Schema struct. The export name must be <PascalCaseEventType>EventPayloadSchema:
export const <PascalCase >EventPayloadSchema = Schema .Struct ({
})
Re-export from packages/temporal-client/src/index.ts if not already.
6. Add handler case in the worker workflow dispatcher File: apps/worker/src/workflows.ts
Add a case inside the switch (event.eventType) block in outboxPollerWorkflow:
case '<aggregate>.<verb>' : {
break
}
Requirements enforced by lint:
workflowId must contain event.id (idempotent dispatch)
workflowIdReusePolicy: 'REJECT_DUPLICATE'
parentClosePolicy: ParentClosePolicy.ABANDON
No as type assertions on .payload
7. Add the handler workflow function File: apps/worker/src/workflows.ts
export async function <eventName>Workflow (event : SerializedDomainEvent ): Promise <void > {
}
8. Add activity if needed File: apps/worker/src/activities.ts
Add the activity function and register it in the activities object.
9. Write the event transactionally File: packages/infra/db/src/repositories/<aggregate>.ts
Either reuse the existing createWithEvent pattern or add a new *WithEvent method that writes the domain event inside db.transaction().
10. Wire through the port and adapter
Port: packages/core/src/domains/<aggregate>/ports/<aggregate>-ports.ts — add method signature
Adapter: packages/core/src/domains/<aggregate>/adapters/<aggregate>-adapters.ts — wire to repository
Service: packages/core/src/domains/<aggregate>/application/<aggregate>-service.ts — call the port method
11. Add integration tests File: packages/testkit/src/domain-events-outbox.integration.test.ts
Test that the event is written transactionally, has correct payload, and follows the full lifecycle.
12. Verify pnpm lint
pnpm type-check
pnpm test
pnpm test :integration
Enforcement Rules The lint script scripts/lint/enforce-domain-event-contracts.mjs checks:
Every eventType: 'x.y' string is registered in domainEventTypes
Each event type has a *EventPayload interface in the domain layer
Each event type has a *EventPayloadSchema in temporal-client
Service layer cannot import domain-events repository directly
Domain event inserts must be inside db.transaction()
Every registered event type has a case in the workflow dispatcher
startChild calls include event.id in workflowId
No as type assertions on .payload in worker files
Event type names match <lowercase>.<lowercase> convention
apps/api/ cannot import @temporalio/*
Run pnpm lint after each step — it tells you exactly what's missing.
Reference Files File Role packages/contracts/src/literals.tsEvent type registry packages/core/src/domains/<domain>/events.tsPublic cross-domain event contract packages/core/src/domains/*/domain/*-events.tsInternal payload interfaces packages/temporal-client/src/types/domain-event.tsPayload schemas apps/worker/src/workflows.tsPoller dispatcher + handler workflows apps/worker/src/activities.tsActivity implementations packages/infra/db/src/repositories/*.tsTransactional write (outbox pattern) scripts/lint/enforce-domain-event-contracts.mjsStructural enforcement