| name | ddd-service |
| description | Scaffolds a complete DDD service following The Standard architecture with Broker, Foundation Service, Processing/Orchestration layers, partial class separation, TryCatch pattern, OpenTelemetry tracing, and MSTest tests for the arolariu.ro backend. |
| lastReviewed | 2026-05-08T00:00:00.000Z |
DDD Service Scaffolding
Generates a complete service following The Standard architecture for the arolariu.ro backend API.
Agent Contract
Scope
Scaffolding a DDD service in sites/api.arolariu.ro/ — Broker, Foundation, Processing/Orchestration layers with partial-class separation, the TryCatch pattern, OpenTelemetry tracing, and MSTest coverage. Does not cover endpoint routing, frontend consumers, or persistence schema design.
Required Inputs
- The target bounded context under
sites/api.arolariu.ro/src/** and the aggregate or entity being served.
.github/instructions/backend.instructions.md and .github/instructions/csharp.instructions.md.
- RFC 2001 (DDD), RFC 2002 (OpenTelemetry), RFC 2003 (The Standard), RFC 2004 (XML docs).
- An existing sibling service to match for structure and naming.
Execution Constraints
- Respect the layer hierarchy: Endpoints → Processing → Orchestration → Foundation → Brokers. No Foundation→Foundation sideways calls.
- Brokers are thin wrappers with no business logic; obey the Florance Pattern (max 2-3 dependencies per service).
- Wrap service methods in the TryCatch pattern with an OpenTelemetry
Activity.
- XML docs on every public API;
.ConfigureAwait(false) throughout; no sync-over-async.
TreatWarningsAsErrors is enabled — fix diagnostics at the source, never with NoWarn or #pragma.
- Generated tests use MSTest:
[TestClass] on every test class, and Assert.ThrowsExactly/ThrowsExactlyAsync for exact-type exception expectations (MSTest's bare Assert.Throws also matches derived types).
Validation
dotnet build sites/api.arolariu.ro/src/Core
dotnet test sites/api.arolariu.ro/tests
Escalation Conditions
Stop and ask the user before proceeding when the work creates a new bounded context, changes a Cosmos or SQL schema, touches authentication or authorization, or adds a NuGet dependency. See Ask-User Criteria under Execution Contract for the full rule.
When to Use
- Creating a new CRUD service for a domain entity
- Adding a new bounded context
- Extending an existing domain with new capabilities
Architecture Layers
Generate artifacts in this order (bottom-up):
1. Broker (Data Access Layer)
Create interface and implementation for external data access.
Interface ([Domain]/Brokers/I[Entity][Storage]Broker.cs):
public interface I[Entity]NoSqlBroker
{
Task Create[Entity]Async([Entity] entity);
Task<[Entity]?> Read[Entity]Async(Guid identifier, Guid? partitionKey = null);
Task Update[Entity]Async([Entity] entity, Guid? partitionKey = null);
Task Delete[Entity]Async(Guid identifier, Guid? partitionKey = null);
}
Implementation ([Domain]/Brokers/[Entity]NoSqlBroker.cs):
public sealed class [Entity]NoSqlBroker(CosmosClient cosmosClient) : I[Entity]NoSqlBroker
{
private readonly Container _container = cosmosClient
.GetDatabase("arolariu")
.GetContainer("[entities]");
public async Task Create[Entity]Async([Entity] entity) =>
await _container.CreateItemAsync(entity,
new PartitionKey(entity.UserIdentifier.ToString()))
.ConfigureAwait(false);
}
Rules:
- NO business logic in Brokers
- Always use
.ConfigureAwait(false)
- Use primary constructors
- Seal the class
2. Foundation Service (CRUD + Validation)
Create using partial class separation:
Main file ([Domain]/Services/Foundation/[Entity]StorageFoundationService.cs):
public partial class [Entity]StorageFoundationService(
I[Entity]NoSqlBroker broker,
ILoggerFactory loggerFactory) : I[Entity]StorageFoundationService
{
public async Task Create[Entity]Object([Entity] entity, Guid? userIdentifier = null) =>
await TryCatchAsync(async () =>
{
using var activity = [Domain]PackageTracing.StartActivity(nameof(Create[Entity]Object));
activity?.SetTag("[entity].id", entity.id.ToString());
Validate[Entity]InformationIsValid(entity);
await broker.Create[Entity]Async(entity).ConfigureAwait(false);
}).ConfigureAwait(false);
}
Exceptions partial ([Domain]/Services/Foundation/[Entity]StorageFoundationService.Exceptions.cs):
public partial class [Entity]StorageFoundationService
{
private async Task TryCatchAsync(Func<Task> returningFunction)
{
try { await returningFunction(); }
catch (CosmosException ex) { throw new [Entity]DependencyException(ex); }
catch (Exception ex) { throw new [Entity]ServiceException(ex); }
}
}
Validations partial ([Domain]/Services/Foundation/[Entity]StorageFoundationService.Validations.cs):
public partial class [Entity]StorageFoundationService
{
private static void Validate[Entity]InformationIsValid([Entity] entity)
{
if (entity is null) throw new [Entity]ValidationException("Entity cannot be null.");
if (entity.id == Guid.Empty) throw new [Entity]ValidationException("Entity ID is required.");
}
}
3. DI Registration
[Domain]/[Domain]Extensions.cs:
public static IServiceCollection Add[Domain]Services(this IServiceCollection services)
{
services.AddScoped<I[Entity]NoSqlBroker, [Entity]NoSqlBroker>();
services.AddScoped<I[Entity]StorageFoundationService, [Entity]StorageFoundationService>();
return services;
}
4. Tests
tests/[Domain]/Services/Foundation/[Entity]StorageFoundationServiceTests.cs:
[TestClass]
public class [Entity]StorageFoundationServiceTests
{
private readonly Mock<I[Entity]NoSqlBroker> _mockBroker = new();
private readonly [Entity]StorageFoundationService _service;
public [Entity]StorageFoundationServiceTests()
{
_service = new [Entity]StorageFoundationService(
_mockBroker.Object,
new NullLoggerFactory());
}
[TestMethod]
public async Task Create[Entity]Object_ValidInput_CreatesSuccessfully()
{
var entity = [Entity]Builder.CreateRandom[Entity]();
await _service.Create[Entity]Object(entity);
_mockBroker.Verify(b => b.Create[Entity]Async(entity), Times.Once);
}
[TestMethod]
public async Task Create[Entity]Object_NullInput_ThrowsValidationException()
{
await Assert.ThrowsExactlyAsync<[Entity]ValidationException>(
() => _service.Create[Entity]Object(null!));
}
}
Checklist
RFC Grounding Checklist (Mandatory)
Before final output or code changes:
- Map task scope to relevant RFC IDs using
.github/agent-governance/rfc-grounding-protocol.md.
- Read the referenced source files and verify RFC guidance is still current.
- If RFC and source conflict, follow source-of-truth code and record RFC drift for remediation.
- Include concrete evidence in outputs (file paths, command results, and validation notes).
Execution Contract
Prerequisites
- Confirm feature scope and expected behavior before creating or modifying files.
- Identify whether this task changes architecture-sensitive behavior and trigger RFC grounding.
Required Context Reads
.github/instructions/backend.instructions.md
.github/instructions/csharp.instructions.md
docs/rfc/2001-domain-driven-design-architecture.md
docs/rfc/2003-the-standard-implementation.md
docs/rfc/2004-comprehensive-xml-documentation-standard.md
File Mutation Boundaries
- Allowed:
sites/api.arolariu.ro/src/**, sites/api.arolariu.ro/tests/**.
- Disallowed: unrelated frontend files unless explicitly requested.
Validation Commands
dotnet build sites/api.arolariu.ro/src/Core
dotnet test sites/api.arolariu.ro/tests
Success Output Contract
- Return created/updated file paths.
- Summarize validation commands and outcomes.
- Report assumptions made during generation.
Failure Output Contract
- Report failing step and exact error output.
- Provide impacted files and rollback-safe next steps.
- Request user confirmation when risk or ambiguity blocks safe continuation.
Self-Audit and Uncertainty Protocol (Mandatory)
For non-trivial tasks, complete this checklist before final output:
- Assumptions: list non-obvious assumptions that influenced decisions.
- Risk Flags: identify security, behavior, deployment, or data risks.
- Confidence: report
high, medium, or low with brief justification.
- Evidence: cite changed files, executed commands, and validation outcomes.
Escalate to the user before continuing when security/auth/infra/destructive or major behavior-changing decisions are involved.