Add a feature
The slice to copy when you add a use case.
A feature is a folder, not a new layer. Copy the nearest existing slice. Application/Features/Messages/GetMessageStatus/ is a small read. Application/Features/Branding/CreateBrandProfile/ is a small write. Template and provider behavior already live under src/Mursil/Modules/.
Order of work
- Decide the rule. If the rule is an invariant (a version cannot publish twice, a domain name is required), put it on the domain type. If it is coordination (load, validate, save), put it in the handler.
- Add the contract in
Mursil.Contractswhen the HTTP body or response gains a field. Keep the DTO free of behavior. - Add the handler as a MediatR
IRequestHandler. Place a FluentValidation validator beside it when the command has input rules. Return aResult. Do not throw for a validation failure the caller can correct. - Persist through a repository or specification. Do not put an EF Core query in the handler.
- Translate HTTP in the endpoint. The endpoint reads headers through
MursilRequestContextResolver, sends the command, and mapsResultto a status code. It does not decide business outcomes. - Add an admin page only when an operator must see the feature. Pages live in
Mursil.Adminand callIMursilOperationsClient. Authorize the page with an existing policy (Viewer,TemplateEditor,Operators,TenantOwner). - Test the behavior. Domain rules belong in
src/Tests/Mursil/Core/Mursil.Domain.UnitTests. Handler behavior belongs insrc/Tests/Mursil/Application/Mursil.Application.UnitTests. Run those projects withdotnet run --project.
Endpoint shape
Mursil.Server groups every product route under /api/v1/mursil:
var mursilApi = app.MapGroup("/api/v1/mursil");
mursilApi.MapMursilEndpoints();
mursilApi.MapMursilTemplateEndpoints();
mursilApi.MapMursilProviderEndpoints();
A new route joins the registration that already owns that area. Require an existing policy. Read the tenant with TryReadTenant. That method ignores any caller-supplied tenant id while Mursil:MultiTenancy is false and uses the deployment tenant. Read the application and client with TryReadApplicationScope on routes that act for one application.
Database changes
Add an EF Core migration through Mursil.Migrator. Prefer an expand-and-contract change when a column is already in use. Do not edit a migration that has already been applied.
What this repository does not take
Do not add a CleanArch Pro project reference. Do not vendor framework source. Do not add a new architectural layer. Do not put business rules in the Razor page or the minimal API method. Do not create a Mursil admin or UI package. The portal remains Mursil.Admin.