| name | add-module |
| description | Create a new module (bounded context) — runtime + Contracts projects, IModule, DbContext, permissions, migrations, and the four registration sites. Use when adding a distinct business domain. For a feature in an existing module, use add-feature. |
| argument-hint | [ModuleName] |
Add Module
High-ceremony. The part people get wrong is registration — a module must be wired in FOUR places
(see Step 6). Architecture rules: .agents/rules/architecture.md.
Projects
src/Modules/{Name}/
├── Modules.{Name}/ ← runtime (internal): Domain/, Data/, Features/v1/, {Name}Module.cs
└── Modules.{Name}.Contracts/ ← public API: v1/ (commands/queries), Dtos/, Authorization/, Events/
Copy an existing module's two .csproj files (e.g. Modules.Catalog) and rename — don't hand-write
project references. The runtime project references its Contracts project + the BuildingBlocks it needs;
the Contracts project references Mediator + shared contracts.
Step 1 — [FshModule] is an ASSEMBLY attribute (not class-level)
In {Name}Module.cs, above the namespace:
[assembly: FshModule(typeof(FSH.Modules.{Name}.{Name}Module), 900)]
namespace FSH.Modules.{Name};
public sealed class {Name}Module : IModule
{
{
ArgumentNullException.ThrowIfNull(builder);
PermissionConstants.Register({Name}Permissions.All);
builder.Services.AddHeroDbContext<{Name}DbContext>();
builder.Services.AddScoped<IDbInitializer, {Name}DbInitializer>();
builder.Services.AddHealthChecks()
.AddDbContextCheck<{Name}DbContext>(name: );
}
{ }
{
ArgumentNullException.ThrowIfNull(endpoints);
versionSet = endpoints.NewApiVersionSet().HasApiVersion( ApiVersion()).ReportApiVersions().Build();
= endpoints.MapGroup()
.WithTags().WithApiVersionSet(versionSet).RequireAuthorization();
}
}