aw-spec-cli 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (173) hide show
  1. package/assets/.agents/skills/aw-spec-addcomponent/SKILL.md +129 -0
  2. package/assets/.agents/skills/aw-spec-agent-context-update/SKILL.md +31 -0
  3. package/assets/.agents/skills/aw-spec-analyze/SKILL.md +296 -0
  4. package/assets/.agents/skills/aw-spec-checklist/SKILL.md +374 -0
  5. package/assets/.agents/skills/aw-spec-clarify/SKILL.md +320 -0
  6. package/assets/.agents/skills/aw-spec-constitution/SKILL.md +194 -0
  7. package/assets/.agents/skills/aw-spec-fast-implement/SKILL.md +268 -0
  8. package/assets/.agents/skills/aw-spec-foundation/SKILL.md +358 -0
  9. package/assets/.agents/skills/aw-spec-implement/SKILL.md +279 -0
  10. package/assets/.agents/skills/aw-spec-minimal-implementation/SKILL.md +209 -0
  11. package/assets/.agents/skills/aw-spec-plan/SKILL.md +221 -0
  12. package/assets/.agents/skills/aw-spec-select-domain/SKILL.md +73 -0
  13. package/assets/.agents/skills/aw-spec-specify/SKILL.md +382 -0
  14. package/assets/.agents/skills/aw-spec-tasks/SKILL.md +259 -0
  15. package/assets/.agents/skills/aw-spec-taskstoissues/SKILL.md +107 -0
  16. package/assets/.aw-spec/domain.json +3 -0
  17. package/assets/.aw-spec/extensions/.registry +19 -0
  18. package/assets/.aw-spec/extensions/agent-context/README.md +57 -0
  19. package/assets/.aw-spec/extensions/agent-context/agent-context-config.yml +4 -0
  20. package/assets/.aw-spec/extensions/agent-context/commands/aw-spec.agent-context.update.md +26 -0
  21. package/assets/.aw-spec/extensions/agent-context/extension.yml +34 -0
  22. package/assets/.aw-spec/extensions/agent-context/scripts/bash/update-agent-context.sh +201 -0
  23. package/assets/.aw-spec/extensions/agent-context/scripts/powershell/update-agent-context.ps1 +237 -0
  24. package/assets/.aw-spec/extensions.yml +23 -0
  25. package/assets/.aw-spec/feature.json +3 -0
  26. package/assets/.aw-spec/init-options.json +9 -0
  27. package/assets/.aw-spec/integration.json +15 -0
  28. package/assets/.aw-spec/integrations/aw-spec.manifest.json +17 -0
  29. package/assets/.aw-spec/integrations/claude.manifest.json +17 -0
  30. package/assets/.aw-spec/memory/constitution.md +50 -0
  31. package/assets/.aw-spec/scripts/bash/check-prerequisites.sh +189 -0
  32. package/assets/.aw-spec/scripts/bash/common.sh +582 -0
  33. package/assets/.aw-spec/scripts/bash/create-new-feature.sh +299 -0
  34. package/assets/.aw-spec/scripts/bash/setup-plan.sh +84 -0
  35. package/assets/.aw-spec/scripts/bash/setup-tasks.sh +91 -0
  36. package/assets/.aw-spec/templates/checklist-template.md +40 -0
  37. package/assets/.aw-spec/templates/constitution-template.md +57 -0
  38. package/assets/.aw-spec/templates/plan-template.md +113 -0
  39. package/assets/.aw-spec/templates/spec-template.md +131 -0
  40. package/assets/.aw-spec/templates/tasks-template.md +252 -0
  41. package/assets/.aw-spec/workflows/aw-spec/workflow.yml +77 -0
  42. package/assets/.aw-spec/workflows/workflow-registry.json +13 -0
  43. package/assets/.claude/skills/aw-spec-addcomponent/SKILL.md +129 -0
  44. package/assets/.claude/skills/aw-spec-agent-context-update/SKILL.md +31 -0
  45. package/assets/.claude/skills/aw-spec-analyze/SKILL.md +296 -0
  46. package/assets/.claude/skills/aw-spec-checklist/SKILL.md +374 -0
  47. package/assets/.claude/skills/aw-spec-clarify/SKILL.md +320 -0
  48. package/assets/.claude/skills/aw-spec-constitution/SKILL.md +194 -0
  49. package/assets/.claude/skills/aw-spec-fast-implement/SKILL.md +268 -0
  50. package/assets/.claude/skills/aw-spec-foundation/SKILL.md +358 -0
  51. package/assets/.claude/skills/aw-spec-implement/SKILL.md +279 -0
  52. package/assets/.claude/skills/aw-spec-minimal-implementation/SKILL.md +209 -0
  53. package/assets/.claude/skills/aw-spec-plan/SKILL.md +221 -0
  54. package/assets/.claude/skills/aw-spec-select-domain/SKILL.md +73 -0
  55. package/assets/.claude/skills/aw-spec-specify/SKILL.md +382 -0
  56. package/assets/.claude/skills/aw-spec-tasks/SKILL.md +259 -0
  57. package/assets/.claude/skills/aw-spec-taskstoissues/SKILL.md +107 -0
  58. package/assets/.kilocode/rules/specify-rules.md +4 -0
  59. package/assets/.kilocode/workflows/aw-spec-addcomponent.md +129 -0
  60. package/assets/.kilocode/workflows/aw-spec-agent-context.update.md +31 -0
  61. package/assets/.kilocode/workflows/aw-spec-analyze.md +296 -0
  62. package/assets/.kilocode/workflows/aw-spec-checklist.md +374 -0
  63. package/assets/.kilocode/workflows/aw-spec-clarify.md +320 -0
  64. package/assets/.kilocode/workflows/aw-spec-constitution.md +194 -0
  65. package/assets/.kilocode/workflows/aw-spec-fast-implement.md +263 -0
  66. package/assets/.kilocode/workflows/aw-spec-foundation.md +358 -0
  67. package/assets/.kilocode/workflows/aw-spec-implement.md +279 -0
  68. package/assets/.kilocode/workflows/aw-spec-minimal-implementation.md +204 -0
  69. package/assets/.kilocode/workflows/aw-spec-plan.md +221 -0
  70. package/assets/.kilocode/workflows/aw-spec-select-domain.md +73 -0
  71. package/assets/.kilocode/workflows/aw-spec-specify.md +382 -0
  72. package/assets/.kilocode/workflows/aw-spec-tasks.md +259 -0
  73. package/assets/.kilocode/workflows/aw-spec-taskstoissues.md +107 -0
  74. package/assets/docs/README.md +106 -0
  75. package/assets/docs/VerticalSlice/PACKAGING.md +185 -0
  76. package/assets/docs/VerticalSlice/VerticalSlice.pack.txt +2833 -0
  77. package/assets/docs/VerticalSlice/pack-foundation.ps1 +145 -0
  78. package/assets/docs/VerticalSlice/pack-foundation.sh +196 -0
  79. package/assets/docs/VerticalSlice/unpack-foundation.ps1 +126 -0
  80. package/assets/docs/VerticalSlice/unpack-foundation.sh +217 -0
  81. package/assets/docs/architecture/clean-architecture.md +71 -0
  82. package/assets/docs/architecture/cqrs.md +141 -0
  83. package/assets/docs/architecture/eventing.md +83 -0
  84. package/assets/docs/architecture/folder-structure.md +61 -0
  85. package/assets/docs/architecture/modular-monolith.md +47 -0
  86. package/assets/docs/architecture/persistence.md +269 -0
  87. package/assets/docs/architecture/testing.md +55 -0
  88. package/assets/docs/architecture/vertical-slices.md +201 -0
  89. package/assets/docs/command.txt +295 -0
  90. package/assets/docs/components/Email/README.md +112 -0
  91. package/assets/docs/components/Email/integration.md +260 -0
  92. package/assets/docs/components/Jobs/README.md +113 -0
  93. package/assets/docs/components/Jobs/integration.md +245 -0
  94. package/assets/docs/components/QrGenerator/README.md +78 -0
  95. package/assets/docs/components/QrGenerator/integration.md +185 -0
  96. package/assets/docs/components/README.md +57 -0
  97. package/assets/docs/domain/domain-driven-design.md +212 -0
  98. package/assets/docs/domainspecs/healthcare/ai-rules.domain.md +34 -0
  99. package/assets/docs/domainspecs/healthcare/api-versioning.domain.md +17 -0
  100. package/assets/docs/domainspecs/healthcare/auditing.domain.md +29 -0
  101. package/assets/docs/domainspecs/healthcare/authorization.domain.md +26 -0
  102. package/assets/docs/domainspecs/healthcare/clinical-terms.md +20 -0
  103. package/assets/docs/domainspecs/healthcare/coding-standards.domain.md +26 -0
  104. package/assets/docs/domainspecs/healthcare/comandrulemap.md +119 -0
  105. package/assets/docs/domainspecs/healthcare/consent.md +19 -0
  106. package/assets/docs/domainspecs/healthcare/cqrs.domain.md +12 -0
  107. package/assets/docs/domainspecs/healthcare/data-classification.domain.md +28 -0
  108. package/assets/docs/domainspecs/healthcare/dependency-policy.domain.md +11 -0
  109. package/assets/docs/domainspecs/healthcare/dicom.md +15 -0
  110. package/assets/docs/domainspecs/healthcare/domain-driven-design.domain.md +28 -0
  111. package/assets/docs/domainspecs/healthcare/domain-requirements.md +55 -0
  112. package/assets/docs/domainspecs/healthcare/eventing.domain.md +18 -0
  113. package/assets/docs/domainspecs/healthcare/fhir.md +36 -0
  114. package/assets/docs/domainspecs/healthcare/folder-structure.domain.md +23 -0
  115. package/assets/docs/domainspecs/healthcare/hipaa.md +34 -0
  116. package/assets/docs/domainspecs/healthcare/hl7.md +15 -0
  117. package/assets/docs/domainspecs/healthcare/integration-terms.md +21 -0
  118. package/assets/docs/domainspecs/healthcare/persistence.domain.md +20 -0
  119. package/assets/docs/domainspecs/healthcare/terminology.md +30 -0
  120. package/assets/docs/domainspecs/healthcare/testing.domain.md +15 -0
  121. package/assets/docs/domainspecs/healthcare/vertical-slices.domain.md +18 -0
  122. package/assets/docs/domainspecs/healthcare/zero-trust.domain.md +12 -0
  123. package/assets/docs/domainspecs/pharma/ai-rules.domain.md +32 -0
  124. package/assets/docs/domainspecs/pharma/api-versioning.domain.md +20 -0
  125. package/assets/docs/domainspecs/pharma/atc.md +22 -0
  126. package/assets/docs/domainspecs/pharma/auditing.domain.md +26 -0
  127. package/assets/docs/domainspecs/pharma/authorization.domain.md +25 -0
  128. package/assets/docs/domainspecs/pharma/coding-standards.domain.md +28 -0
  129. package/assets/docs/domainspecs/pharma/comandrulemap.md +136 -0
  130. package/assets/docs/domainspecs/pharma/cqrs.domain.md +16 -0
  131. package/assets/docs/domainspecs/pharma/data-classification.domain.md +24 -0
  132. package/assets/docs/domainspecs/pharma/data-provenance.md +21 -0
  133. package/assets/docs/domainspecs/pharma/dependency-policy.domain.md +11 -0
  134. package/assets/docs/domainspecs/pharma/domain-driven-design.domain.md +36 -0
  135. package/assets/docs/domainspecs/pharma/domain-requirements.md +99 -0
  136. package/assets/docs/domainspecs/pharma/eventing.domain.md +18 -0
  137. package/assets/docs/domainspecs/pharma/fhir.md +31 -0
  138. package/assets/docs/domainspecs/pharma/folder-structure.domain.md +24 -0
  139. package/assets/docs/domainspecs/pharma/hl7.md +17 -0
  140. package/assets/docs/domainspecs/pharma/idmp.md +26 -0
  141. package/assets/docs/domainspecs/pharma/integration-terms.md +21 -0
  142. package/assets/docs/domainspecs/pharma/ndc.md +28 -0
  143. package/assets/docs/domainspecs/pharma/persistence.domain.md +23 -0
  144. package/assets/docs/domainspecs/pharma/pharma-terms.md +27 -0
  145. package/assets/docs/domainspecs/pharma/product-lifecycle.domain.md +30 -0
  146. package/assets/docs/domainspecs/pharma/regulatory-compliance.md +19 -0
  147. package/assets/docs/domainspecs/pharma/terminology.md +32 -0
  148. package/assets/docs/domainspecs/pharma/testing.domain.md +19 -0
  149. package/assets/docs/domainspecs/pharma/vertical-slices.domain.md +17 -0
  150. package/assets/docs/domainspecs/pharma/zero-trust.domain.md +12 -0
  151. package/assets/docs/glossary/ai-rules.md +59 -0
  152. package/assets/docs/governance/api-versioning.md +99 -0
  153. package/assets/docs/governance/coding-standards.md +87 -0
  154. package/assets/docs/governance/dependency-policy.md +40 -0
  155. package/assets/docs/interop/ihe-conformance.md +31 -0
  156. package/assets/docs/pharma-constitution.my-ref.md +86 -0
  157. package/assets/docs/requirement-spec.txt +15 -0
  158. package/assets/docs/security/auditing.md +117 -0
  159. package/assets/docs/security/authorization-matrix.md +14 -0
  160. package/assets/docs/security/authorization.md +87 -0
  161. package/assets/docs/security/data-classification.md +38 -0
  162. package/assets/docs/security/zero-trust.md +76 -0
  163. package/assets/docs/technology-constitution.md +172 -0
  164. package/dist/commands/init.d.ts.map +1 -1
  165. package/dist/commands/init.js +3 -2
  166. package/dist/commands/init.js.map +1 -1
  167. package/dist/utils/copy-assets.d.ts +8 -1
  168. package/dist/utils/copy-assets.d.ts.map +1 -1
  169. package/dist/utils/copy-assets.js +1 -0
  170. package/dist/utils/copy-assets.js.map +1 -1
  171. package/dist/utils/paths.js +1 -1
  172. package/dist/utils/paths.js.map +1 -1
  173. package/package.json +1 -1
@@ -0,0 +1,71 @@
1
+ # Clean Architecture Standards
2
+
3
+ > Pure technology (domain-agnostic). NON-NEGOTIABLE. Commands: `/aw-spec-plan`, `/aw-spec-tasks`, `/aw-spec-implement`.
4
+
5
+ ## Dependency direction
6
+
7
+ Dependencies flow **inward only**:
8
+
9
+ ```
10
+ API -> Application (Features) -> Domain <- Infrastructure
11
+ ```
12
+
13
+ The Domain is the innermost ring; everything depends on it and it depends on nothing.
14
+
15
+ ## Layer responsibilities
16
+
17
+ - **API** — HTTP surface (FastEndpoints). Translates transport to/from mediator
18
+ messages. MUST NOT contain business logic.
19
+ - **Application (Features)** — Command/Query handlers, validators, orchestration.
20
+ Dispatched via `IMediator`. MUST NOT depend on API frameworks or concrete EF Core types.
21
+ - **Domain** — aggregates, entities, value objects, domain events, specifications.
22
+ Framework-agnostic.
23
+ - **Infrastructure** — EF Core, external service clients, persistence configuration.
24
+ Depends inward on Domain abstractions.
25
+
26
+ ## Allowed dependencies / annotations in Domain
27
+
28
+ The Domain layer is framework-agnostic. The **only** allowed annotations are:
29
+
30
+ - `[NotMapped]`
31
+ - `[ValueObject<T>]` (Vogen)
32
+ - `System.ComponentModel.DataAnnotations.Schema`
33
+
34
+ ## Infrastructure boundaries
35
+
36
+ - EF Core mapping lives **only** in `{Module}/Persistence/<Aggregate>Configuration.cs` and is
37
+ applied via `ApplyConfigurationsFromAssembly`.
38
+ - **Endpoints MUST NOT** call repositories, `DbContext`, or `IUnitOfWork` directly; they
39
+ **MUST** call `IMediator.Send(...)`.
40
+ - **Application Features MUST NOT** depend on API frameworks or concrete EF Core types.
41
+ - Direct `DbContext` access from Endpoints or Application Features (outside the
42
+ repository / specification surface) is FORBIDDEN.
43
+
44
+ ## Canonical example (agent reference — `<SampleProjectName>` sample)
45
+
46
+ The dependency rule in practice — the **API** layer depends inward via `IMediator` only
47
+ (never `IRepository`/`DbContext`); the **Application** layer depends on Domain abstractions
48
+ (`IRepository<Project>`), never on concrete EF Core types:
49
+
50
+ ```csharp
51
+ // API layer — <SampleProjectName>.Service/Projects/Features/CreateProject/CreateProjectEndpoint.cs
52
+ public class CreateProjectEndpoint(IMediator _mediator)
53
+ : SecureFastEndpoint<CreateProjectRequest, ProjectDto>
54
+ {
55
+ protected override Task<Result<ProjectDto>> ExecuteAsync(
56
+ CreateProjectRequest req, CancellationToken ct)
57
+ => _mediator.Send(new CreateProjectCommand(
58
+ req.Code, req.Name, req.Description, req.StartDate, req.EndDate, req.OwnerId), ct);
59
+ }
60
+
61
+ // Application layer — depends on Domain abstractions, not EF Core
62
+ public class CreateProjectCommandHandler(
63
+ IRepository<Project> _repo, IUnitOfWork _uow, IPublisher _eventBus)
64
+ : ICommandHandler<CreateProjectCommand, Result<ProjectDto>> { /* ... */ }
65
+ ```
66
+
67
+ ## Related
68
+
69
+ - [[cqrs]] — how the Application layer dispatches work
70
+ - [[persistence]] — repository + specification surface, EF Core conventions
71
+ - [[vertical-slices]] — physical organization of the layers per feature
@@ -0,0 +1,141 @@
1
+ # CQRS + Mediator Standards
2
+
3
+ > Pure technology (domain-agnostic) — domain additions in [[cqrs.domain]]. NON-NEGOTIABLE. Commands: `/aw-spec-plan`, `/aw-spec-tasks`, `/aw-spec-implement`.
4
+
5
+ ## Command / query patterns
6
+
7
+ - All application logic is dispatched through **`AppWeaver.Mediator`** (NOT MediatR).
8
+ - **Commands:** `record XxxCommand(...) : ICommand<Result<TDto>>` or `ICommand<Result>`.
9
+ - **Queries:** `record XxxQuery(...) : IQuery<Result<TDto>>`.
10
+ - Handlers use **primary-constructor DI** and return `ValueTask<Result<T>>`.
11
+
12
+ ## Mediator conventions
13
+
14
+ - Endpoints call `IMediator.Send(...)` — never repositories/`DbContext`/`IUnitOfWork` directly.
15
+ - Raw `Guid` parameters at the Application boundary **MUST be wrapped** into strongly-typed
16
+ IDs at the handler edge.
17
+
18
+ ## Pipeline behaviors
19
+
20
+ Enabled at startup, in order:
21
+
22
+ 1. Logging behavior
23
+ 2. FluentValidation behavior
24
+
25
+ > Additional cross-cutting behaviors (e.g. domain access-audit behaviors) may be appended —
26
+ > see [[cqrs.domain]] for the domain audit-pipeline behavior.
27
+
28
+ ## Result pattern
29
+
30
+ - Errors are returned as `Result<T>.Failure(new Error(code, message, status, resource))`.
31
+ - **Exceptions MUST NOT** be used for expected business outcomes (validation, not-found,
32
+ conflict, concurrency). `DomainException` is reserved for invariant violations and is
33
+ caught by the centralized exception handler.
34
+ - **Error code** MUST be a stable dot-namespaced slug — e.g. `resource.not_found`,
35
+ `concurrency.conflict`, `resource.duplicate`.
36
+ - **resource** MUST be the kebab-case resource name.
37
+
38
+ ## Handler responsibilities
39
+
40
+ - **Read handlers** inject `IReadRepository<TAggregate>`.
41
+ - **Write handlers** inject `IRepository<TAggregate>` + `IUnitOfWork` (+ `IPublisher`
42
+ when domain events are produced).
43
+ - Validators check **request shape only**; invariants are enforced inside the aggregate.
44
+ - No business logic in handlers (anemic-domain anti-pattern — see [[domain-driven-design]]).
45
+
46
+ ## Transaction handling
47
+
48
+ - Write handlers **MUST** wrap mutating work in
49
+ `IUnitOfWork.ExecuteInTransactionAsync(..., IsolationLevel.ReadCommitted, ct)` and call
50
+ `SaveChangesAsync` **inside** the lambda.
51
+ - They **MUST** publish domain events and call `ClearDomainEvents()` before returning.
52
+ - **One command mutates one aggregate per transaction** — cross-aggregate effects flow
53
+ through domain events or follow-up commands (see [[eventing]]).
54
+
55
+ ## Canonical example (agent reference — `<SampleProjectName>` sample)
56
+
57
+ Command as a `record`, write handler with transaction + event publication, and a read handler
58
+ returning `Result.Failure(...)` for the expected not-found outcome (no exceptions):
59
+
60
+ ```csharp
61
+ // Command — record implementing ICommand<Result<TDto>>
62
+ public record CreateProjectCommand(
63
+ string Code, string Name, string? Description,
64
+ DateOnly StartDate, DateOnly? EndDate, Guid? OwnerId
65
+ ) : ICommand<Result<ProjectDto>>;
66
+
67
+ // Write handler — primary-ctor DI, transaction, publish + clear events, Result<T>
68
+ public class CreateProjectCommandHandler(
69
+ IRepository<Project> _repo, IUnitOfWork _uow, IPublisher _eventBus
70
+ ) : ICommandHandler<CreateProjectCommand, Result<ProjectDto>>
71
+ {
72
+ public async ValueTask<Result<ProjectDto>> Handle(
73
+ CreateProjectCommand request, CancellationToken ct)
74
+ => await _uow.ExecuteInTransactionAsync(async () =>
75
+ {
76
+ var ownerId = request.OwnerId.HasValue
77
+ ? TaskUserId.From(request.OwnerId.Value) : (TaskUserId?)null;
78
+ var entity = new Project(request.Code, request.Name, request.StartDate, ownerId);
79
+
80
+ await _repo.AddAsync(entity, ct);
81
+ await _uow.SaveChangesAsync(ct);
82
+
83
+ foreach (var e in entity.DomainEvents) await _eventBus.Publish(e, ct);
84
+ entity.ClearDomainEvents();
85
+
86
+ return Result<ProjectDto>.Ok(entity.ToDto());
87
+ }, IsolationLevel.ReadCommitted, ct);
88
+ }
89
+
90
+ // Read handler — IReadRepository + Specification; not-found is a Result, not an exception
91
+ public class GetProjectByIdQueryHandler(IReadRepository<Project> _repo)
92
+ : IQueryHandler<GetProjectByIdQuery, Result<ProjectDto>>
93
+ {
94
+ public async ValueTask<Result<ProjectDto>> Handle(
95
+ GetProjectByIdQuery request, CancellationToken ct)
96
+ {
97
+ Guard.NotDefault(request.Id, nameof(request.Id));
98
+ var entity = await _repo.FirstOrDefaultAsync(
99
+ new ProjectWithTasksSpec(ProjectId.From(request.Id)), ct);
100
+
101
+ return entity is null
102
+ ? Result<ProjectDto>.Failure(new Error(
103
+ "project.not_found", $"Project {request.Id} not found", 404, "projects"))
104
+ : Result<ProjectDto>.Ok(entity.ToDto());
105
+ }
106
+ }
107
+ ```
108
+
109
+ Commands with no return payload use `ICommand<Result>` (e.g. delete) and return
110
+ `Result.Success()` / `Result.Failure(...)`:
111
+
112
+ ```csharp
113
+ public record DeleteProjectCommand(Guid Id, string RowVersionBase64) : ICommand<Result>;
114
+
115
+ public class DeleteProjectCommandHandler(IRepository<Project> _repo, IUnitOfWork _uow, IPublisher _bus)
116
+ : ICommandHandler<DeleteProjectCommand, Result> { /* ... returns Result.Success() */ }
117
+ ```
118
+
119
+ Composition — register the mediator with the logging + validation pipeline behaviors,
120
+ the validators, and the in-process event bus (one-time startup wiring):
121
+
122
+ ```csharp
123
+ // <SampleProjectName>.Service/Extensions/ApplicationServiceRegistration.cs
124
+ services.AddMediator(builder =>
125
+ {
126
+ builder.UseDefault()
127
+ .UseBehaviors()
128
+ .AddLoggingBehavior()
129
+ .AddFluentValidationBehavior(); // domain projects also add PHI-audit — see [[cqrs.domain]]
130
+ }, options => options.Provider = "Default");
131
+
132
+ services.AddAppWeaverMediatorHandlersFrom(typeof(ApplicationServiceRegistration));
133
+ services.AddValidatorsFromAssembly(typeof(ApplicationServiceRegistration).Assembly);
134
+
135
+ services.AddEventBus(b => b.UseDefaultEventBus(o =>
136
+ o.RegisterServicesFromAssembly(typeof(ApplicationServiceRegistration).Assembly)));
137
+ ```
138
+
139
+ ## Related
140
+
141
+ - [[clean-architecture]] · [[persistence]] · [[eventing]] · [[domain-driven-design]] · [[cqrs.domain]]
@@ -0,0 +1,83 @@
1
+ # Eventing Standards
2
+
3
+ > Pure technology (domain-agnostic) — domain additions in [[eventing.domain]]. Commands: `/aw-spec-plan`, `/aw-spec-tasks`, `/aw-spec-implement`.
4
+
5
+ ## Domain events
6
+
7
+ - Domain Events derive from `DomainEventBase`, are **immutable**, and are added **inside**
8
+ aggregate methods via `AddDomainEvent(...)`.
9
+ - They are published **explicitly** by command handlers: `foreach` over `entity.DomainEvents`,
10
+ then `ClearDomainEvents()` before returning. See [[cqrs]].
11
+ - Cross-aggregate effects flow through domain events or follow-up commands — never a
12
+ multi-aggregate transaction.
13
+
14
+ ## CloudEvents conventions
15
+
16
+ - Asynchronous propagation of domain events to downstream consumers uses a **durable event
17
+ stream**: **CloudEvents** over the configured broker (e.g. Azure Service Bus, AWS SQS/SNS,
18
+ or RabbitMQ).
19
+ - Each module owns its **public events**; downstream consumers subscribe to them rather than
20
+ reading the OLTP database.
21
+
22
+ ## Event immutability
23
+
24
+ - Published events are immutable facts. Consumers build their own read models; they
25
+ **MUST NOT** query the source OLTP database directly.
26
+ - Analytics / reporting is built from emitted events — **never** by querying the OLTP DB
27
+ directly.
28
+
29
+ ## Event versioning
30
+
31
+ - The service publishes a versioned, machine-readable **AsyncAPI** document for event
32
+ contracts.
33
+ - Breaking changes to a domain-event contract are **MAJOR** version bumps and require the
34
+ AsyncAPI document to regenerate cleanly (CI gate). See [[api-versioning]].
35
+
36
+ ## Broker integration patterns
37
+
38
+ - The message broker is declared as an Aspire resource and referenced via `.WithReference(...)`;
39
+ connection details are discovered through Aspire, never hard-coded.
40
+ - Trace context **MUST** propagate across `IMediator.Send`, `HttpClient`, and EF Core; bypassing
41
+ the framework's `HttpClientFactory` is forbidden.
42
+ (Outbound domain-protocol propagation is covered in [[eventing.domain]].)
43
+
44
+ ## Inbound integration rule (generic)
45
+
46
+ - Inbound integrations flow through **Interop adapters** that translate to internal commands;
47
+ they **MUST NOT** write directly to aggregates. (Domain feed types in [[eventing.domain]].)
48
+
49
+ ## Canonical example (agent reference — `<SampleProjectName>` sample)
50
+
51
+ Immutable domain event, raised inside the aggregate, published explicitly by the handler:
52
+
53
+ ```csharp
54
+ // <SampleProjectName>.Service/Projects/Domain/Events/ProjectCreatedEvent.cs
55
+ public class ProjectCreatedEvent(Guid projectId, string code, string name) : DomainEventBase
56
+ {
57
+ public Guid ProjectId { get; } = projectId; // get-only — immutable
58
+ public string Code { get; } = code;
59
+ public string Name { get; } = name;
60
+ }
61
+ ```
62
+
63
+ ```csharp
64
+ // Raised inside the aggregate method (never in the handler):
65
+ AddDomainEvent(new ProjectCreatedEvent(Id.Value, Code.Value, Name));
66
+
67
+ // Published by the command handler after SaveChanges, then cleared:
68
+ foreach (var domainEvent in entity.DomainEvents)
69
+ await _eventBus.Publish(domainEvent, ct); // IPublisher — in-process today, broker tomorrow
70
+ entity.ClearDomainEvents();
71
+ ```
72
+
73
+ Composition — register the event bus (handlers discovered from the assembly):
74
+
75
+ ```csharp
76
+ // <SampleProjectName>.Service/Extensions/ApplicationServiceRegistration.cs
77
+ services.AddEventBus(b => b.UseDefaultEventBus(o =>
78
+ o.RegisterServicesFromAssembly(typeof(ApplicationServiceRegistration).Assembly)));
79
+ ```
80
+
81
+ ## Related
82
+
83
+ - [[cqrs]] · [[modular-monolith]] · [[api-versioning]] · [[eventing.domain]]
@@ -0,0 +1,61 @@
1
+ # Mandatory Folder Structure
2
+
3
+ > Pure technology (domain-agnostic) — domain additions (Interop adapters, conformance tests, fixtures) in [[folder-structure.domain]]. NON-NEGOTIABLE. Commands: `/aw-spec-plan`, `/aw-spec-tasks`, `/aw-spec-implement`.
4
+ >
5
+ > Replace `<SampleProjectName>` with the project name (e.g. `Acme.Billing`).
6
+
7
+ ## Layout
8
+
9
+ ```
10
+ src/
11
+ <SampleProjectName>.AppHost/ Aspire composition root (Program.cs)
12
+ <SampleProjectName>.ServiceDefaults/ OTel + Serilog + resilience + service discovery
13
+ <SampleProjectName>.Service/ headless API runtime (a.k.a. <SampleProjectName>.Api)
14
+ Program.cs composition only
15
+ GlobalUsings.cs
16
+ appsettings.json / appsettings.{Env}.json
17
+ Common/ PagedResult<T> + shared value objects
18
+ Extensions/ ApplicationServiceRegistration (mediator/eventbus),
19
+ InfrastructureServiceRegistration (DbContext/repos),
20
+ Aspire/Host extensions, SpecificationExtensions
21
+ Infrastructure/
22
+ ApplicationDbContext.cs ContextAwareDbContext<T>
23
+ *DbContextFactory.cs design-time factories
24
+ Migrations/
25
+ Utilities/ ETag/HTTP helpers (HttpRequest/Response ETag ext)
26
+ <Module>/ one folder per bounded context
27
+ Domain/
28
+ <Aggregate>.cs
29
+ <ChildEntity>.cs
30
+ <ValueObject>.cs
31
+ <Aggregate>Id.cs [ValueObject<Guid>] partial struct
32
+ Enums/ (optional) status/priority enums
33
+ Events/ DomainEventBase descendants
34
+ Specifications/ Specification<TAggregate>
35
+ Persistence/
36
+ <Aggregate>Configuration.cs (+ <ChildEntity>Configuration.cs)
37
+ Features/<FeatureName>/ Command/Query + Handler + Endpoint + Validator
38
+ Shared/ module-public DTOs + ToDto mapping extensions
39
+ tests/
40
+ <SampleProjectName>.UnitTests/
41
+ <SampleProjectName>.IntegrationTests/ Testcontainers-driven
42
+ <SampleProjectName>.TestFixtures/ shared test fixtures
43
+ helm/
44
+ <SampleProjectName>.Api/
45
+ docs/ engineering standards (see [[README]] + context map)
46
+ ```
47
+
48
+ ## Rules
49
+
50
+ - Each **module** is a top-level folder with `Domain / Features / Persistence / Shared`
51
+ (see [[modular-monolith]], [[vertical-slices]]).
52
+ - Each **feature** is a self-contained vertical slice (Command/Query + Handler + Endpoint +
53
+ Validator co-located).
54
+ - Cross-cutting files (`Program.cs`, `GlobalUsings.cs`, `Directory.Build.props`,
55
+ `Directory.Packages.props`, `global.json`) MUST stay at the level they occupy in the
56
+ AppWeaver template.
57
+ - New folders outside this structure require a constitution amendment.
58
+
59
+ ## Related
60
+
61
+ - [[modular-monolith]] · [[vertical-slices]] · [[clean-architecture]] · [[folder-structure.domain]]
@@ -0,0 +1,47 @@
1
+ # Modular Monolith Standards
2
+
3
+ > Pure technology (domain-agnostic). NON-NEGOTIABLE where marked. Commands: `/aw-spec-plan`, `/aw-spec-tasks`, `/aw-spec-implement`.
4
+
5
+ ## Module boundaries
6
+
7
+ - The runtime is a **single deployable service** partitioned into bounded contexts (modules).
8
+ - Each module is a **top-level folder** containing four mandatory child folders:
9
+ `Domain`, `Features`, `Persistence`, `Shared` (plus `Interop` where applicable).
10
+ - A module **owns** its aggregates, persistence configurations, DTOs, integration
11
+ adapters/projectors, and public events. Nothing outside the module may reach past these.
12
+
13
+ ## Cross-module communication
14
+
15
+ - Modules **MUST NOT** reference another module's `Domain` types except through
16
+ **strongly-typed IDs** or the other module's **`Shared` DTOs**.
17
+ - Modules **MUST NOT** take EF Core `DbSet` dependencies on entities they do not own.
18
+ - **Cross-module reads** go through the other module's `Shared` DTOs or its `IMediator`
19
+ queries — never through its `DbContext` entities.
20
+ - **Cross-module writes** go through commands published to `IMediator` (in-process today,
21
+ on the event bus tomorrow). A module **MUST NOT** acquire a write lock on another
22
+ module's aggregate.
23
+ - No horizontal "Services/Managers" layers across slices.
24
+
25
+ ## Schema-per-module guidance
26
+
27
+ - Per-module schemas in PostgreSQL (**schema-per-module**) are RECOMMENDED so a future
28
+ service extraction is a clean cutover.
29
+
30
+ ## Module isolation / testability
31
+
32
+ - Every module **MUST be testable in isolation**: its unit tests and handler tests
33
+ **MUST NOT** require any other module to be loaded.
34
+
35
+ ## Future microservice extraction strategy
36
+
37
+ - Today's modules are tomorrow's services. Splitting a module into its own service
38
+ **MUST require zero changes to the domain code of other modules**.
39
+ - Migration to microservices is **approved by amendment** when a module's deployment
40
+ cadence, scaling profile, team ownership, or regulatory boundary materially diverges
41
+ from the rest of the monolith.
42
+
43
+ ## Related
44
+
45
+ - [[vertical-slices]] — feature organization within a module
46
+ - [[clean-architecture]] — dependency rule across layers
47
+ - [[eventing]] — async cross-module/event-bus propagation
@@ -0,0 +1,269 @@
1
+ # Persistence Standards
2
+
3
+ > Pure technology (domain-agnostic) — domain additions in [[persistence.domain]]. NON-NEGOTIABLE where marked. Commands: `/aw-spec-plan`, `/aw-spec-tasks`, `/aw-spec-implement`.
4
+
5
+ ## EF Core conventions
6
+
7
+ - The `DbContext` is a `ContextAwareDbContext<TContext>` and is **provider-aware**.
8
+ - EF Core mapping lives **only** in `{Module}/Persistence/<Aggregate>Configuration.cs`,
9
+ applied via `ApplyConfigurationsFromAssembly`.
10
+ - `DateTimeOffset` columns **MUST** be re-mapped to `timestamptz` when the provider is Npgsql.
11
+ - Cross-cutting behaviors are applied via `modelBuilder.ApplyCrossCuttingBehaviors(this)`:
12
+ soft-delete global filters, tenant filters, base concurrency-token configuration.
13
+
14
+ ## Repository rules
15
+
16
+ - **Read handlers** inject `IReadRepository<TAggregate>`; **write handlers** inject
17
+ `IRepository<TAggregate>` + `IUnitOfWork`.
18
+ - No "repository as data-access god object" — **no custom methods** beyond
19
+ `IRepository<T>` / `IReadRepository<T>` + `Specification<T>`.
20
+ - Direct `DbContext.Set<T>()` LINQ inside Application Features is FORBIDDEN — use
21
+ `IReadRepository<T>` + a `Specification<T>` only.
22
+
23
+ ## Specification pattern
24
+
25
+ - Every non-trivial query is encapsulated in a `Specification<TAggregate>` under
26
+ `{Module}/Domain/Specifications/`.
27
+ - Specifications **MUST be composable**; paging via `WithPaging(pageNumber, pageSize)`.
28
+ - Ordering uses shared generic helpers (`OrderByIdAsc`, `OrderByIdDesc`, `OrderByNameAsc`);
29
+ ad-hoc `OrderBy` in handlers is forbidden when a typed helper exists.
30
+ - **Cross-aggregate joins via EF navigation properties are FORBIDDEN** — reference parent
31
+ aggregates by strongly-typed ID and project client-side.
32
+
33
+ ## Concurrency handling
34
+
35
+ - Every mutable aggregate **MUST** implement `IConcurrencyTracked`.
36
+ - Concurrency tokens are **client-managed**: `byte[] RowVersion`,
37
+ `IsConcurrencyToken().ValueGeneratedNever()`, refreshed by a `SaveChanges` interceptor.
38
+ - SQL Server `IsRowVersion()` semantics **MUST NOT** leak into entity configurations.
39
+ - ETag / `If-Match` at the edge: see [[api-versioning]].
40
+ - Server sets the ETag header on every create/read/update via `SetETagFromBase64(...)`.
41
+ - Update/Delete endpoints extract `If-Match` via `GetIfMatchBase64Token()` and pass it
42
+ to the command; mismatch returns `409 concurrency.conflict`.
43
+ - `DbUpdateConcurrencyException` is translated to the same `409 concurrency.conflict`.
44
+
45
+ ## Soft-delete rules
46
+
47
+ - Soft delete is enabled via `EnableSoftDelete()`.
48
+ - **Hard deletes are FORBIDDEN** for any aggregate flagged as retention-protected / regulated;
49
+ deletion is logical via `MarkAsDeleted(...)`. (See [[persistence.domain]] for which data
50
+ classes are retention-protected.)
51
+ - Append-only aggregates have no delete path at all.
52
+
53
+ ## Tenancy patterns
54
+
55
+ - Tenancy is enabled via `EnableTenancy()` and `RegisterDefaultContexts(...)`.
56
+ - Tenant resolution **MUST be transparent** to handlers.
57
+ - Default model: **tenant-per-row** with tenant-aware global filters; deployments MAY opt
58
+ into tenant-per-database via configuration.
59
+
60
+ ## Migrations policy
61
+
62
+ - Migrations are authored against **PostgreSQL** (production provider). Development MAY run
63
+ on SQLite (non-sensitive development data only).
64
+ - Multi-provider warnings (`PendingModelChangesWarning`) **MUST** be suppressed only at the
65
+ runtime registration site, **never** in migration code.
66
+ - Migrations **MUST** apply cleanly to a fresh PostgreSQL instance (CI gate).
67
+
68
+ ## Provider profile
69
+
70
+ - Production: PostgreSQL 16+ (encryption-at-rest profile in [[persistence.domain]]);
71
+ per-module schemas where reasonable.
72
+ - Development: PostgreSQL via Aspire containers; SQLite only for in-memory unit-test fixtures.
73
+
74
+ ## Canonical example (agent reference — `<SampleProjectName>` sample)
75
+
76
+ EF Core configuration (Vogen ID + value object conversions, unique business key,
77
+ cross-aggregate FK stored as a raw `Guid` with no navigation):
78
+
79
+ ```csharp
80
+ // <SampleProjectName>.Service/Projects/Persistence/ProjectConfiguration.cs
81
+ public class ProjectConfiguration : IEntityTypeConfiguration<Project>
82
+ {
83
+ public void Configure(EntityTypeBuilder<Project> builder)
84
+ {
85
+ builder.ToTable("Projects");
86
+ builder.HasKey(e => e.Id);
87
+
88
+ // Strongly-typed Vogen ID -> Guid, never DB-generated
89
+ builder.Property(e => e.Id)
90
+ .HasConversion(id => id.Value, v => ProjectId.From(v))
91
+ .ValueGeneratedNever();
92
+
93
+ // Value object -> column + unique business key
94
+ builder.Property(e => e.Code)
95
+ .HasConversion(c => c.Value, v => ProjectCode.From(v))
96
+ .HasColumnName("Code").HasMaxLength(20).IsRequired();
97
+ builder.HasIndex(e => e.Code).IsUnique();
98
+
99
+ builder.Property(e => e.Status).HasConversion<string>().HasMaxLength(30).IsRequired();
100
+
101
+ // Cross-aggregate FK as nullable Guid — NO EF navigation to TaskUser
102
+ builder.Property(e => e.OwnerId)
103
+ .HasConversion(
104
+ id => id.HasValue ? id.Value.Value : (Guid?)null,
105
+ v => v.HasValue ? TaskUserId.From(v.Value) : (TaskUserId?)null)
106
+ .HasColumnName("OwnerId");
107
+ }
108
+ }
109
+ ```
110
+
111
+ Composable specification (filter + include + paging):
112
+
113
+ ```csharp
114
+ // {Module}/Domain/Specifications/ProjectSearchSpec.cs
115
+ public sealed class ProjectSearchSpec : Specification<Project>
116
+ {
117
+ public ProjectSearchSpec(string? search, ProjectStatus? status = null)
118
+ {
119
+ Query.Include(p => p.Tasks);
120
+ if (!string.IsNullOrWhiteSpace(search))
121
+ {
122
+ var s = search.Trim().ToLowerInvariant();
123
+ Query.Where(p => p.Code.Value.ToLower().Contains(s) || p.Name.ToLower().Contains(s));
124
+ }
125
+ if (status.HasValue) Query.Where(p => p.Status == status.Value);
126
+ }
127
+
128
+ public ProjectSearchSpec WithPaging(int pageNumber, int pageSize)
129
+ {
130
+ Query.Skip(Math.Max(0, (pageNumber - 1) * pageSize)).Take(Math.Max(1, pageSize));
131
+ return this;
132
+ }
133
+ }
134
+ ```
135
+
136
+ Read handler using the spec + typed ordering helper, returning `PagedResult<T>`:
137
+
138
+ ```csharp
139
+ var spec = new ProjectSearchSpec(request.Search, request.Status)
140
+ .OrderByIdDesc<ProjectSearchSpec, Project, ProjectId>(); // typed helper, not ad-hoc OrderBy
141
+
142
+ var total = await _repo.CountAsync(spec, ct);
143
+ var items = await _repo.ListAsync(spec.WithPaging(request.PageNumber, request.PageSize), ct);
144
+
145
+ return Result<PagedResult<ProjectDto>>.Ok(new PagedResult<ProjectDto>
146
+ {
147
+ Items = items.ToDtoList(), TotalCount = total,
148
+ PageNumber = request.PageNumber, PageSize = request.PageSize
149
+ });
150
+ ```
151
+
152
+ Owned child-entity configuration (separate table, FK + cascade, soft-delete mirror filter,
153
+ no EF navigation to other aggregates):
154
+
155
+ ```csharp
156
+ // {Module}/Persistence/ProjectTaskConfiguration.cs
157
+ public class ProjectTaskConfiguration : IEntityTypeConfiguration<ProjectTask>
158
+ {
159
+ public void Configure(EntityTypeBuilder<ProjectTask> builder)
160
+ {
161
+ builder.ToTable("ProjectTasks");
162
+ builder.HasKey(e => e.Id);
163
+ builder.Property(e => e.Id)
164
+ .HasConversion(id => id.Value, v => ProjectTaskId.From(v)).ValueGeneratedNever();
165
+
166
+ builder.Property(e => e.ProjectId) // FK back to the root
167
+ .HasConversion(id => id.Value, v => ProjectId.From(v)).IsRequired();
168
+
169
+ builder.Property(e => e.Title) // Vogen value object
170
+ .HasConversion(t => t.Value, v => TaskTitle.From(v)).HasMaxLength(300).IsRequired();
171
+ builder.Property(e => e.Status).HasConversion<string>().HasMaxLength(30).IsRequired();
172
+
173
+ // Cross-aggregate ref stored as raw Guid — NO navigation to TaskUser
174
+ builder.Property(e => e.AssigneeId)
175
+ .HasConversion(
176
+ id => id.HasValue ? id.Value.Value : (Guid?)null,
177
+ v => v.HasValue ? TaskUserId.From(v.Value) : (TaskUserId?)null);
178
+
179
+ builder.HasOne(e => e.Project).WithMany(p => p.Tasks) // owned collection
180
+ .HasForeignKey(e => e.ProjectId).OnDelete(DeleteBehavior.Cascade);
181
+
182
+ // Mirror the parent's ISoftDeletable filter onto the required dependent
183
+ builder.HasQueryFilter(t => !t.Project.IsDeleted);
184
+ builder.HasIndex(e => e.ProjectId);
185
+ builder.HasIndex(e => e.AssigneeId);
186
+ }
187
+ }
188
+ ```
189
+
190
+ DbContext — `ContextAwareDbContext`, assembly-scanned configs, provider-aware `timestamptz`,
191
+ cross-cutting behaviors, and the client-managed concurrency token override:
192
+
193
+ ```csharp
194
+ // <SampleProjectName>.Service/Infrastructure/ApplicationDbContext.cs
195
+ public class ApplicationDbContext(
196
+ DbContextOptions<ApplicationDbContext> options, ICurrentTenant? tenant = null)
197
+ : ContextAwareDbContext<ApplicationDbContext>(options, tenant)
198
+ {
199
+ protected override void OnModelCreating(ModelBuilder modelBuilder)
200
+ {
201
+ modelBuilder.ApplyConfigurationsFromAssembly(typeof(ApplicationDbContext).Assembly);
202
+
203
+ if (Database.ProviderName == "Npgsql.EntityFrameworkCore.PostgreSQL")
204
+ foreach (var et in modelBuilder.Model.GetEntityTypes())
205
+ foreach (var p in et.GetProperties()
206
+ .Where(p => p.ClrType == typeof(DateTimeOffset) || p.ClrType == typeof(DateTimeOffset?)))
207
+ p.SetColumnType("timestamptz");
208
+
209
+ modelBuilder.ApplyCrossCuttingBehaviors(this); // soft-delete + tenant filters + audit
210
+
211
+ // Client-managed concurrency token (works on SQLite + PostgreSQL; not SQL Server IsRowVersion)
212
+ foreach (var et in modelBuilder.Model.GetEntityTypes())
213
+ if (typeof(IConcurrencyTracked).IsAssignableFrom(et.ClrType))
214
+ modelBuilder.Entity(et.ClrType).Property<byte[]>("RowVersion")
215
+ .IsConcurrencyToken().ValueGeneratedNever();
216
+
217
+ base.OnModelCreating(modelBuilder);
218
+ }
219
+
220
+ public DbSet<Project> Projects => Set<Project>();
221
+ public DbSet<ProjectTask> ProjectTasks => Set<ProjectTask>();
222
+ }
223
+ ```
224
+
225
+ Soft-delete: logical delete via `MarkAsDeleted(...)` + `DeleteAsync` (never a hard delete),
226
+ and a separate `IgnoreQueryFilters()` spec for admin/audit reads:
227
+
228
+ ```csharp
229
+ // Delete handler — soft delete + concurrency guard (returns Result, no DTO)
230
+ var entity = await _repo.GetByIdAsync(ProjectId.From(request.Id), ct);
231
+ if (entity is null)
232
+ return Result.Failure(new Error("project.not_found", $"Project {request.Id} not found", 404, "projects"));
233
+ // ... concurrency token check (see api-versioning) ...
234
+ entity.MarkAsDeleted(); // sets IsDeleted/DeletedOn + raises ProjectDeletedEvent
235
+ await _repo.DeleteAsync(entity, ct); // framework translates to UPDATE, not DELETE
236
+
237
+ // Admin/audit spec that bypasses the global soft-delete filter
238
+ public sealed class ProjectSearchIncludeDeletedSpec : Specification<Project>
239
+ {
240
+ public ProjectSearchIncludeDeletedSpec(string? search, ProjectStatus? status = null)
241
+ {
242
+ Query.Include(p => p.Tasks).IgnoreQueryFilters(); // include soft-deleted rows
243
+ // ... same Where filters as ProjectSearchSpec ...
244
+ }
245
+ }
246
+ ```
247
+
248
+ Composition — repository + cross-cutting behaviors registered once at startup:
249
+
250
+ ```csharp
251
+ // <SampleProjectName>.Service/Extensions/InfrastructureServiceRegistration.cs
252
+ services.AddRepositories(builder =>
253
+ {
254
+ builder
255
+ .UseSingleDbContextEFRepositories<ApplicationDbContext>(db => db.UseSqlite(/* or UseNpgsql */)
256
+ .ConfigureWarnings(w => w.Ignore(RelationalEventId.PendingModelChangesWarning)))
257
+ .EnableTenancy()
258
+ .EnableSoftDelete()
259
+ .EnableClientManagedConcurrency()
260
+ .EnableAuditing().EnableAdvancedAuditing() // see [[auditing]]
261
+ .Done();
262
+ }, options => options.Provider = "EfCore");
263
+
264
+ services.TryAddScoped(typeof(IUnitOfWork), typeof(EfUnitOfWork<ApplicationDbContext>));
265
+ ```
266
+
267
+ ## Related
268
+
269
+ - [[clean-architecture]] · [[cqrs]] · [[domain-driven-design]] · [[api-versioning]] · [[persistence.domain]]