@drunkcoding/dknet-implementation-skills 0.1.0
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.
- package/.claude-plugin/marketplace.json +22 -0
- package/.claude-plugin/plugin.json +38 -0
- package/LICENSE +21 -0
- package/README.md +261 -0
- package/agents/dknet-architect.md +49 -0
- package/agents/dknet-bdd-engineer.md +62 -0
- package/agents/dknet-implementer.md +75 -0
- package/package.json +52 -0
- package/plugin.json +26 -0
- package/skills/README.md +47 -0
- package/skills/dknet-auth-and-ownership/SKILL.md +418 -0
- package/skills/dknet-bdd-tests/SKILL.md +355 -0
- package/skills/dknet-bdd-tests/checklist.md +39 -0
- package/skills/dknet-crud/SKILL.md +483 -0
- package/skills/dknet-ddd-principles/SKILL.md +87 -0
- package/skills/dknet-docs/SKILL.md +296 -0
- package/skills/dknet-docs/checklist.md +58 -0
- package/skills/dknet-docs/templates/README-template.md +68 -0
- package/skills/dknet-docs/templates/api-reference-template.md +275 -0
- package/skills/dknet-docs/templates/architecture-template.md +166 -0
- package/skills/dknet-docs/templates/data-model-template.md +99 -0
- package/skills/dknet-docs/templates/events-template.md +155 -0
- package/skills/dknet-dto-mapping/SKILL.md +278 -0
- package/skills/dknet-efcore-config/SKILL.md +379 -0
- package/skills/dknet-endpoint/SKILL.md +458 -0
- package/skills/dknet-entity/SKILL.md +483 -0
- package/skills/dknet-feature/SKILL.md +139 -0
- package/skills/dknet-feature-lifecycle/SKILL.md +144 -0
- package/skills/dknet-feature-remove/SKILL.md +131 -0
- package/skills/dknet-messaging-events/SKILL.md +395 -0
- package/skills/dknet-package-adoption/SKILL.md +252 -0
- package/skills/dknet-platform-config/SKILL.md +342 -0
- package/skills/dknet-project-structure/SKILL.md +148 -0
- package/skills/dknet-queries-specs/SKILL.md +330 -0
- package/skills/dknet-scaffold/SKILL.md +209 -0
- package/skills/dknet-unit-tests/SKILL.md +382 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json.schemastore.org/claude-code-marketplace",
|
|
3
|
+
"name": "dknet-marketplace",
|
|
4
|
+
"owner": {
|
|
5
|
+
"name": "baoduy",
|
|
6
|
+
"email": "baoduy2412@gmail.com",
|
|
7
|
+
"url": "https://github.com/baoduy"
|
|
8
|
+
},
|
|
9
|
+
"metadata": {
|
|
10
|
+
"description": "Claude Code plugins for the DKNet ecosystem — ships dknet-minimal, the agent skills and subagents for solutions generated from DKNet.Minimal.Template."
|
|
11
|
+
},
|
|
12
|
+
"plugins": [
|
|
13
|
+
{
|
|
14
|
+
"name": "dknet-minimal",
|
|
15
|
+
"source": ".",
|
|
16
|
+
"description": "Skills (Claude Code plugin + Agent Skills standard) and subagents for building vertical-slice features on the DKNet.Minimal.Template: endpoints, actions, queries, validation, DTO mapping, entities, seeding, SlimMessageBus/Azure Service Bus events, auth/ownership, platform flags, tests, and end-to-end /dknet-feature workflows.",
|
|
17
|
+
"category": "development",
|
|
18
|
+
"homepage": "https://github.com/baoduy/DKNet.Templates",
|
|
19
|
+
"keywords": ["dotnet","csharp","ddd","cqrs","efcore","aspire","slimmessagebus","scaffold","agent-skills"]
|
|
20
|
+
}
|
|
21
|
+
]
|
|
22
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json.schemastore.org/claude-code-plugin",
|
|
3
|
+
"name": "dknet-minimal",
|
|
4
|
+
"displayName": "DKNet Minimal Template",
|
|
5
|
+
"description": "Skills and subagents that teach an agent how to build features on the DKNet.Minimal.Template (.NET 10, vertical-slice DDD/CQRS): endpoints (hand-mapped, generated CRUD, generic helpers), actions and queries, FluentValidation + Mapster DTOs, domain entities and static seeding, SlimMessageBus internal and Azure Service Bus events, auth/ownership and every platform flag — plus slash workflows that scaffold a slice end-to-end.",
|
|
6
|
+
"version": "0.1.0",
|
|
7
|
+
"author": {
|
|
8
|
+
"name": "baoduy",
|
|
9
|
+
"email": "baoduy2412@gmail.com",
|
|
10
|
+
"url": "https://drunkcoding.net"
|
|
11
|
+
},
|
|
12
|
+
"homepage": "https://github.com/baoduy/DKNet.Templates",
|
|
13
|
+
"repository": "https://github.com/baoduy/DKNet.Templates",
|
|
14
|
+
"license": "MIT",
|
|
15
|
+
"keywords": [
|
|
16
|
+
"dotnet",
|
|
17
|
+
"csharp",
|
|
18
|
+
"ddd",
|
|
19
|
+
"cqrs",
|
|
20
|
+
"vertical-slice",
|
|
21
|
+
"efcore",
|
|
22
|
+
"aspire",
|
|
23
|
+
"minimal-api",
|
|
24
|
+
"slimmessagebus",
|
|
25
|
+
"azure-service-bus",
|
|
26
|
+
"fluentvalidation",
|
|
27
|
+
"mapster",
|
|
28
|
+
"reqnroll",
|
|
29
|
+
"bdd",
|
|
30
|
+
"scaffold",
|
|
31
|
+
"agent-skills"
|
|
32
|
+
],
|
|
33
|
+
"agents": [
|
|
34
|
+
"./agents/dknet-architect.md",
|
|
35
|
+
"./agents/dknet-bdd-engineer.md",
|
|
36
|
+
"./agents/dknet-implementer.md"
|
|
37
|
+
]
|
|
38
|
+
}
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Steven Hoang (baoduy)
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
# DKNet API Solution Template
|
|
2
|
+
|
|
3
|
+
[](https://www.nuget.org/packages/DKNet.Minimal.Template)
|
|
4
|
+
[](https://opensource.org/licenses/MIT)
|
|
5
|
+
|
|
6
|
+
`dotnet new` solution template for an ASP.NET Core microservice built as vertical slices over
|
|
7
|
+
DDD/CQRS — for a team starting a new .NET 10 service that wants the layering, the hardening and the
|
|
8
|
+
CRUD plumbing decided before the first feature is written.
|
|
9
|
+
|
|
10
|
+
Take it when your service is a handful of aggregates behind an HTTP API, persisted in PostgreSQL and
|
|
11
|
+
run under .NET Aspire. Skip it if you need a different persistence story or a single-project API —
|
|
12
|
+
the layer boundaries here are enforced by tests, not suggestions.
|
|
13
|
+
|
|
14
|
+
## Why take it
|
|
15
|
+
|
|
16
|
+
- **The layering is held by the build, not by review.** Every project reference points inward, so an
|
|
17
|
+
outward one is a circular reference MSBuild refuses; NetArchTest rules in
|
|
18
|
+
`Minimal.App.Tests/Architecture/` fail the test run on the shape rules a compiler cannot see —
|
|
19
|
+
`internal sealed` endpoints and handlers, an explicit max length on every mapped string,
|
|
20
|
+
`HasConversion<string>()` on every mapped enum, Npgsql-only packages.
|
|
21
|
+
- **The HTTP surface ships hardened.** Default-deny authorization, security response headers, stated
|
|
22
|
+
request bounds (30 s / 1 MB / 10 s), a status-only public health probe, an enumerated CORS
|
|
23
|
+
allow-list, a non-root image, and a dependency audit that fails the build — all on in the base
|
|
24
|
+
`appsettings.json` and relaxable for local work by configuration alone.
|
|
25
|
+
- **Most CRUD is declared, not written.** Four attributes produce the requests, handlers, routes and
|
|
26
|
+
DTO for an aggregate, domain actions included — so you write the aggregate and the operations that
|
|
27
|
+
actually carry business orchestration.
|
|
28
|
+
- **Both test levels are already scaffolded** — xUnit + Shouldly unit/integration tests, and
|
|
29
|
+
Reqnroll + NUnit BDD tests against a real host.
|
|
30
|
+
- **One image, one entry point.** With no argument the service serves; with a registered job name it
|
|
31
|
+
runs that job and exits on its own status, so the same image migrates the database as a Kubernetes
|
|
32
|
+
`Job` and serves as a `Deployment`.
|
|
33
|
+
|
|
34
|
+
## Quick start
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
# 1. add the feed, install the template
|
|
38
|
+
dotnet nuget add source --username <GITHUB_USERNAME> --password <GITHUB_PAT_WITH_READ_PACKAGES> \
|
|
39
|
+
--store-password-in-clear-text --name github "https://nuget.pkg.github.com/baoduy/index.json"
|
|
40
|
+
dotnet new install DKNet.Minimal.Template --nuget-source "https://nuget.pkg.github.com/baoduy/index.json"
|
|
41
|
+
|
|
42
|
+
# 2. scaffold (a dotted name works: -n DKNet.Accounts)
|
|
43
|
+
dotnet new dknet-minimal -n MyCompany.MyService
|
|
44
|
+
cd MyCompany.MyService
|
|
45
|
+
|
|
46
|
+
# 3. run the full stack — Aspire provisions Redis and PostgreSQL via Docker
|
|
47
|
+
dotnet run --project MyCompany.MyService.ApiEndpoints/MyCompany.MyService.AppHost
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
`dotnet run --project <Name>.ApiEndpoints/<Name>.Api` starts the API alone, without containers.
|
|
51
|
+
|
|
52
|
+
> **`--TenantId` and `--ApiAudience` ship as placeholders, not working values.** Left as shipped, the
|
|
53
|
+
> OIDC metadata fetch runs against a tenant that does not exist and every token is rejected on
|
|
54
|
+
> audience mismatch. Replace them before you turn on `FeatureManagement:RequireAuthorization` — see
|
|
55
|
+
> [what you must change before shipping](docs/template-usage.md#what-you-must-change-before-shipping).
|
|
56
|
+
|
|
57
|
+
Every scaffold parameter, plus the run/test/migrate/pack commands:
|
|
58
|
+
[`docs/template-usage.md`](docs/template-usage.md).
|
|
59
|
+
|
|
60
|
+
## The shape your endpoints should take
|
|
61
|
+
|
|
62
|
+
**Composite-first.** One endpoint class per aggregate: map the generated CRUD composite at the top,
|
|
63
|
+
each generated route carrying its own authorization, then hand-write below it only the routes that
|
|
64
|
+
carry real orchestration. Generated and hand-written routes live in the same group — this is not a
|
|
65
|
+
choice between two styles of endpoint.
|
|
66
|
+
|
|
67
|
+
`ProductV1Endpoint` (`Minimal.Api/ApiEndpoints/AutomatedSample/ProductV1Endpoint.cs`) is that shape,
|
|
68
|
+
trimmed here to its structure:
|
|
69
|
+
|
|
70
|
+
```csharp
|
|
71
|
+
public void Map(RouteGroupBuilder group)
|
|
72
|
+
{
|
|
73
|
+
group.MapProductCrud(o =>
|
|
74
|
+
{
|
|
75
|
+
o.Exclude("Discontinue"); // hand-written below
|
|
76
|
+
|
|
77
|
+
o.Configure(CrudOp.GetById, rb => rb.RequireAuthorization(ProductScopes.Read));
|
|
78
|
+
o.Configure(CrudOp.Create, rb => rb.RequireAuthorization(ProductScopes.Write));
|
|
79
|
+
o.Configure("Approve", rb => rb.RequireAuthorization(ProductScopes.Write));
|
|
80
|
+
// its own scope — holding products.write must not be enough to assign a supplier reference
|
|
81
|
+
o.Configure("AssignSupplierReference", rb => rb.RequireAuthorization(ProductScopes.Supplier));
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
// writes two aggregates in one transaction — outside what the generator can express
|
|
85
|
+
group.MapPut("{id:guid}/discontinue", /* ... */).Produces<ProductDto>();
|
|
86
|
+
|
|
87
|
+
// a response shape the generator has none for
|
|
88
|
+
group.MapGet("summary", /* ... */).Produces<ProductPriceSummaryDto>();
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Seven of the nine routes come from `MapProductCrud`. Scopes are applied only when
|
|
93
|
+
`FeatureManagement:RequireAuthorization` is on, so a stock Development run enforces none of them.
|
|
94
|
+
|
|
95
|
+
### When an operation needs a hand-written route
|
|
96
|
+
|
|
97
|
+
The criterion is stated once, in
|
|
98
|
+
[Manual vs. Automated — At a glance](docs/samples/manual-vs-automated.md#at-a-glance-which-one-should-i-copy),
|
|
99
|
+
and this README does not carry a second version of it. Read it before you hand-write a handler: the
|
|
100
|
+
list is shorter than most readers expect, and two of the cases that look like they belong on it do
|
|
101
|
+
not.
|
|
102
|
+
|
|
103
|
+
- **A rule that refuses an operation after reading stored data does not force a hand-written route.**
|
|
104
|
+
A FluentValidation validator written against the *generated* request runs on the generated route —
|
|
105
|
+
the group-level `AddFluentValidationAutoValidation()` filter applies to every route in the group.
|
|
106
|
+
`CreateProductRequestValidator` refuses a name already taken and `DeleteProductRequestValidator`
|
|
107
|
+
refuses a product still for sale, both with `409`, and neither operation has a hand-written route,
|
|
108
|
+
request or handler.
|
|
109
|
+
- **A response value the generator's naming convention cannot produce does not force one either.**
|
|
110
|
+
`ProductDto.GrossMargin` (`Price` minus `SupplierCostPrice`) is derived from two columns, so the
|
|
111
|
+
convention cannot emit it — one property on the generated `partial record` plus a Mapster
|
|
112
|
+
`IRegister` puts it on the response, with no route, request or handler written for it. See
|
|
113
|
+
[a response value the convention cannot produce](docs/samples/automated-products/README.md#a-response-value-the-convention-cannot-produce).
|
|
114
|
+
|
|
115
|
+
Both samples ship in full: [`docs/samples/automated-products/`](docs/samples/automated-products/)
|
|
116
|
+
(generator-driven `Product`) and
|
|
117
|
+
[`docs/samples/manual-purchase-orders/`](docs/samples/manual-purchase-orders/) (hand-written
|
|
118
|
+
`PurchaseOrder`). The end-to-end steps for a feature of your own are in
|
|
119
|
+
[`docs/ddd-implementation-guide.md`](docs/ddd-implementation-guide.md).
|
|
120
|
+
|
|
121
|
+
## Architecture
|
|
122
|
+
|
|
123
|
+
A generated solution is layered onion-style — each layer knows only about the layers inside it:
|
|
124
|
+
|
|
125
|
+

|
|
126
|
+
|
|
127
|
+
`Minimal.Domains` references nothing above it. `Minimal.AppServices` depends only on `Domains` (plus
|
|
128
|
+
`Share`); `Minimal.Infra` and `Minimal.Api` depend on both, never the reverse. `Minimal.Share` is the
|
|
129
|
+
one cross-cutting exception, and `Minimal.AppHost` is the Aspire orchestrator, carrying no business
|
|
130
|
+
logic.
|
|
131
|
+
|
|
132
|
+

|
|
133
|
+
|
|
134
|
+
A request reaches an `IEndpointConfig` route, is validated and has its `[FromClaim]` properties
|
|
135
|
+
populated, then dispatches over the in-memory SlimMessageBus to a handler in `Minimal.AppServices`,
|
|
136
|
+
which calls a method on a `Minimal.Domains` aggregate. `CoreDbContext.SaveChanges` persists it;
|
|
137
|
+
around the save, `DataOwnerHook` stamps `CreatedBy`/`UpdatedBy` and queued domain events are
|
|
138
|
+
dispatched — and forwarded to Azure Service Bus when one is configured. Stage by stage:
|
|
139
|
+
[`docs/api-pipeline.md`](docs/api-pipeline.md).
|
|
140
|
+
|
|
141
|
+
## Documentation
|
|
142
|
+
|
|
143
|
+
**Start at [`docs/index.md`](docs/index.md)** — it indexes every page and carries the
|
|
144
|
+
capability-to-attribute tables ("I want X; which attribute or call gives it to me").
|
|
145
|
+
|
|
146
|
+
| First stop | For |
|
|
147
|
+
|---|---|
|
|
148
|
+
| [`docs/template-usage.md`](docs/template-usage.md) | Scaffold parameters, run/test/migrate/publish |
|
|
149
|
+
| [`docs/ddd-implementation-guide.md`](docs/ddd-implementation-guide.md) | Adding a vertical slice, entity to endpoint |
|
|
150
|
+
| [`docs/crud-attributes.md`](docs/crud-attributes.md) | The four attributes behind the generated slice |
|
|
151
|
+
| [`docs/samples/manual-vs-automated.md`](docs/samples/manual-vs-automated.md) | Which sample to copy, and every trade-off behind that call |
|
|
152
|
+
| [`docs/configuration-reference.md`](docs/configuration-reference.md) | Every `appsettings` key a generated solution reads |
|
|
153
|
+
| [`docs/extension-points.md`](docs/extension-points.md) | Where your own code attaches, and the boundaries the tests hold |
|
|
154
|
+
|
|
155
|
+
[AGENTS.md](AGENTS.md) is the condensed architecture reference used by AI coding agents.
|
|
156
|
+
|
|
157
|
+
> These guides are visible on GitHub but are **not** packaged into scaffolded solutions — the
|
|
158
|
+
> nuspec's file list doesn't ship `docs/`. Copy what you need into the generated solution, or add it
|
|
159
|
+
> to the nuspec.
|
|
160
|
+
|
|
161
|
+
## AI Plugin — Claude Code, GitHub Copilot, and any agent that reads SKILL.md
|
|
162
|
+
|
|
163
|
+
This repository root is also the `dknet-minimal` plugin: `.claude-plugin/plugin.json` + `skills/` +
|
|
164
|
+
`agents/` (Claude Code), `plugin.json` (GitHub Copilot), `package.json` (npm). One set of
|
|
165
|
+
[Agent Skills](https://agentskills.io) teaches an AI coding agent how to build on this template: the
|
|
166
|
+
layer boundaries, every endpoint shape (hand-mapped, generated `Map<Entity>Crud()`, or the generic
|
|
167
|
+
route helpers), actions and queries, FluentValidation + Mapster DTOs, domain entities and static
|
|
168
|
+
seeding, SlimMessageBus internal events and Azure Service Bus forwarding, auth/ownership and every
|
|
169
|
+
`FeatureManagement` flag. Eight of the skills are slash workflows that scaffold a vertical slice end to
|
|
170
|
+
end; three Claude Code subagents (`dknet-architect`, `dknet-implementer`, `dknet-bdd-engineer`) back
|
|
171
|
+
`/dknet-feature`. Index of every skill: [`skills/README.md`](skills/README.md).
|
|
172
|
+
|
|
173
|
+
`dotnet new dknet-minimal` does **not** copy the plugin into a generated solution (only `AGENTS.md`
|
|
174
|
+
ships) — install it into the generated repo with one of the channels below.
|
|
175
|
+
|
|
176
|
+
**Claude Code**
|
|
177
|
+
|
|
178
|
+
```text
|
|
179
|
+
/plugin marketplace add baoduy/DKNet.Templates
|
|
180
|
+
/plugin install dknet-minimal@dknet-marketplace
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
Skills then load on demand as `dknet-minimal:<skill-name>`; workflows are `/dknet-minimal:dknet-feature` etc.
|
|
184
|
+
|
|
185
|
+
**GitHub Copilot**
|
|
186
|
+
|
|
187
|
+
```bash
|
|
188
|
+
# Copilot reads .agents/skills/ in the workspace; the skills CLI installs there for it
|
|
189
|
+
npx skills add baoduy/DKNet.Templates -a github-copilot
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
**Any agent (Codex, Cursor, Gemini CLI, Windsurf, …) via the skills CLI**
|
|
193
|
+
|
|
194
|
+
```bash
|
|
195
|
+
npx skills add baoduy/DKNet.Templates # pick the skills and the agents to install into
|
|
196
|
+
npx skills add baoduy/DKNet.Templates -s '*' -y # everything, no prompts
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
**From npm (pins the version with your project)**
|
|
200
|
+
|
|
201
|
+
```bash
|
|
202
|
+
npm i -D @drunkcoding/dknet-implementation-skills
|
|
203
|
+
claude --plugin-dir node_modules/@drunkcoding/dknet-implementation-skills # Claude Code
|
|
204
|
+
npx skills experimental_sync -a '*' # any agent: node_modules -> .agents/skills/ etc.
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
**Working on this repository**
|
|
208
|
+
|
|
209
|
+
```bash
|
|
210
|
+
claude --plugin-dir . # loads skills/ and agents/ from the checkout
|
|
211
|
+
./validate-plugin.sh # manifests, README install channels, skill portability
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
| Workflow | Purpose |
|
|
215
|
+
|---|---|
|
|
216
|
+
| `/dknet-feature <Feature> <Entity> [mode=manual\|auto] [props…]` | Full vertical slice: plan → entity → CRUD → endpoint → tests → BDD → docs |
|
|
217
|
+
| `/dknet-feature-remove <Feature>` | Retire a slice, its touchpoints and its tables (drop migration) |
|
|
218
|
+
| `/dknet-entity <Feature> <Entity> [mode=…] [props…]` | Domain entity + EF mapper + migration |
|
|
219
|
+
| `/dknet-crud <Feature> <Entity> [mode=…]` | AppServices CRUD (DTO + Create/Update/Delete + spec + event), or the generator attributes |
|
|
220
|
+
| `/dknet-endpoint <Feature> <Entity> [mode=…]` | Minimal API `IEndpointConfig` — hand-mapped with idempotency, or `Map<Entity>Crud()` |
|
|
221
|
+
| `/dknet-unit-tests <Feature> <Entity> [mode=…]` | xUnit + Shouldly tests through `ApiFixture` + `IMessageBus` |
|
|
222
|
+
| `/dknet-bdd-tests <Feature>` | Reqnroll + NUnit BDD scenarios |
|
|
223
|
+
| `/dknet-docs <Feature>` | Feature documentation under `docs/features/<feature>/` |
|
|
224
|
+
|
|
225
|
+
| Reference skill | Teaches |
|
|
226
|
+
|---|---|
|
|
227
|
+
| `dknet-project-structure` | Layers, folder footprint, auto-discovery, which skill for what — read first |
|
|
228
|
+
| `dknet-ddd-principles` | Aggregate boundaries, invariants, when an event is warranted |
|
|
229
|
+
| `dknet-feature-lifecycle` | Manual vs automated flow decision, feature footprint, removal rules |
|
|
230
|
+
| `dknet-scaffold` | `dotnet new dknet-minimal`, parameters, first run, deleting the samples, installing this plugin |
|
|
231
|
+
| `dknet-entity` | `AggregateRoot` entities, `[CrudCreate]`/`[CrudUpdate]`/`[CrudAction]`/`[RaisesEvent]`, `IOwnedBy`, `[SensitiveData]` |
|
|
232
|
+
| `dknet-efcore-config` | Mappers, static data seeding (both wiring paths), `CoreDbContext`, migrations |
|
|
233
|
+
| `dknet-crud` | Commands, FluentValidation (incl. 409 preconditions), handlers, generated requests |
|
|
234
|
+
| `dknet-queries-specs` | `Specification<T>`, query handlers, paging, the generic filter/search/order list route |
|
|
235
|
+
| `dknet-dto-mapping` | Hand-written vs `[GenerateDto]` DTOs, Mapster config and `IRegister` custom mapping, `ResultOf` |
|
|
236
|
+
| `dknet-endpoint` | `IEndpointConfig`; raw routes, `Map<Entity>Crud()` + `CrudMapOptions`, generic helpers; idempotency; scopes |
|
|
237
|
+
| `dknet-messaging-events` | SlimMessageBus in-memory bus, domain events (manual/declared), Azure Service Bus Produce/Consume |
|
|
238
|
+
| `dknet-auth-and-ownership` | JWT + scopes, demo auth, `[FromClaim]`, `DataOwnerHook`, row-level isolation, sensitive data |
|
|
239
|
+
| `dknet-platform-config` | Start-up order, every `FeatureManagement` flag and config section, Aspire, jobs, health, OpenAPI |
|
|
240
|
+
| `dknet-unit-tests` / `dknet-bdd-tests` | What each suite owns, fixtures, worked examples, the business-tests-only rule |
|
|
241
|
+
| `dknet-docs` | README + Mermaid architecture + API reference for a finished feature |
|
|
242
|
+
| `dknet-package-adoption` | Using DKNet packages in a project not created from the template |
|
|
243
|
+
|
|
244
|
+
**Release.** Versions stay `0.0.0` in git. `publish-nuget-github.yml` computes the release version from
|
|
245
|
+
tags on `main`, packs and publishes the NuGet template, creates the GitHub release, then stamps the same
|
|
246
|
+
version into `package.json` / `plugin.json` / `.claude-plugin/plugin.json` (`npm version` →
|
|
247
|
+
`scripts/sync-version.mjs`), validates the skills (`agentskills validate`, `claude plugin validate`,
|
|
248
|
+
`npx skills add --list`, `./validate-plugin.sh`) and publishes `@drunkcoding/dknet-implementation-skills` to npm
|
|
249
|
+
with OIDC trusted publishing. A version already on npm is skipped.
|
|
250
|
+
|
|
251
|
+
## Release notes
|
|
252
|
+
|
|
253
|
+
**Breaking change — status-counts default window (DRK-521).** Status-counts endpoints (the `GET`
|
|
254
|
+
route `MapGetStatusCounts<TEntity>` maps, at the `status` segment by default) no longer default to
|
|
255
|
+
the last 30 days when no `from`/`to` bounds are supplied. An unbounded call now reports counts over
|
|
256
|
+
the **entire history**. Explicit `from`/`to` bounds are unaffected — pass them to preserve a bounded
|
|
257
|
+
window.
|
|
258
|
+
|
|
259
|
+
## License
|
|
260
|
+
|
|
261
|
+
MIT © [Steven Hoang](https://drunkcoding.net)
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: dknet-architect
|
|
3
|
+
description: Use when planning a new feature in a DKNet.Minimal.Template solution before any code is written — produces a vertical-slice plan covering Domains/Infra/AppServices/Api layers, identifies aggregates, events, validators, specs, and endpoints, and surfaces architectural risks. Read-only research; does not modify code.
|
|
4
|
+
tools: Read, Grep, Glob, Bash, WebFetch, TodoWrite
|
|
5
|
+
model: opus
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
You are the DKNet Architect. You design vertical-slice features for solutions generated from `DKNet.Minimal.Template` and hand off a precise, layer-by-layer plan to implementers. You never write code yourself — you write the plan that others execute.
|
|
9
|
+
|
|
10
|
+
## Inputs you expect
|
|
11
|
+
|
|
12
|
+
- A natural-language feature request, plus any constraints (security, perf, data shape).
|
|
13
|
+
- Optional: existing artifacts in `specs/<feature>/` and `docs/features/<feature>/`.
|
|
14
|
+
|
|
15
|
+
## Required reading before you plan
|
|
16
|
+
|
|
17
|
+
Always start by reading:
|
|
18
|
+
- the `dknet-project-structure` skill for layer boundaries and folder layout.
|
|
19
|
+
- the `dknet-ddd-principles` skill for aggregate boundary, entity-vs-value-object, invariant, and domain-event judgment calls — apply these when deciding what the new aggregate owns and what triggers an event.
|
|
20
|
+
- `CLAUDE.md` and `AGENTS.md` for current layer rules and conventions.
|
|
21
|
+
- The two existing exemplar slices, and the `dknet-feature-lifecycle` skill §1 for the layer-by-layer trade-off between them:
|
|
22
|
+
- Hand-written — `Minimal.Domains/Features/ManualSample/Entities/PurchaseOrder.cs`, `Minimal.Infra/Features/ManualSample/`, `Minimal.AppServices/ManualSample/V1/`, `Minimal.Api/ApiEndpoints/ManualSample/PurchaseOrderV1Endpoint.cs`.
|
|
23
|
+
- Generator-driven — `Minimal.Domains/Features/AutomatedSample/Entities/Product.cs` (`[RaisesEvent]`/`[CrudCreate]`/`[CrudUpdate]`), `Minimal.AppServices/AutomatedSample/V1/ProductDto.cs` (`[GenerateDto]`), `Minimal.Api/ApiEndpoints/AutomatedSample/ProductV1Endpoint.cs`.
|
|
24
|
+
- The skill that matches the layer you're planning (the `dknet-entity` skill, `dknet-efcore-config`, `dknet-crud`, `dknet-endpoint`, `dknet-bdd-tests`, `dknet-unit-tests`).
|
|
25
|
+
|
|
26
|
+
## Output contract
|
|
27
|
+
|
|
28
|
+
Produce a single markdown plan with these sections, no more no less:
|
|
29
|
+
|
|
30
|
+
1. **Aggregates & owned types** — name, schema prefix for `DomainSchemas`, immutable vs. mutable fields, mutation methods, sequence usage. State explicitly which fields are entities vs. value objects and why (per `dknet-ddd-principles`), and what the aggregate's consistency boundary is. Also state up front which shape this feature should take: hand-written (`PurchaseOrder`-style — needed for idempotent writes, an operation that writes more than one aggregate in one transaction, filtered queries, or a DTO that hides fields; a rule that merely refuses an operation is a FluentValidation validator on the generated request instead) or generator-driven (`Product`-style — a genuinely plain CRUD entity whose validation is fully expressible as DataAnnotations). The `dknet-feature-lifecycle` skill §1 is the deciding reference.
|
|
31
|
+
2. **EF Core mapping** — table name, indexes, max lengths, column types, owned-type registrations, seed data. Both sample shapes hand-write this layer — no generator touches `IEntityTypeConfiguration<T>`.
|
|
32
|
+
3. **AppServices actions (V1)** — for the hand-written shape: for each of Create/Update/Delete, request shape, validator rules, duplicate spec, domain events emitted, lazy-mapping decision (mirror `PurchaseOrder`'s `Actions/Create.cs`/`Update.cs`/`Cancel.cs`/`Delete.cs`). For the generator-driven shape: which entity members carry `[CrudCreate]`/`[CrudUpdate]`/`[RaisesEvent]`, and the one-line `[GenerateDto(typeof(Entity))]` DTO — flag explicitly that generated-route validation is enforced only when the entity's endpoint uses literal `Map*(string, Delegate)` calls, not the generic `Map*<TRequest,TDto>` wrapper (see `Product`'s confirmed-live gap: `POST /v1/products` with a negative price returns `201`).
|
|
33
|
+
4. **Query specs** — `SpecGet<Entity>` constructor parameters; expected callers. N/A for the generator-driven shape (GetById/GetList map straight to `DKNet.AspCore.Extensions`'s generic `MapGetById`/`MapGetList` — no per-entity query object exists).
|
|
34
|
+
5. **Endpoint contract** — `IEndpointConfig` group path, version, mapping style (literal `group.MapPost/MapGet/MapPut/MapDelete` for hand-written, or the generated `Map<Entity>Crud()` extension for generator-driven), idempotency requirements (`.RequiredIdempotentKey()` for POST — required whenever the plan calls for idempotent writes; the generated CRUD route does not add this), auth/`RequireAuthorization` decisions.
|
|
35
|
+
6. **Tests** — unit test coverage targets (happy path, validation, duplicates, not-found, events) and BDD scenarios (happy, business-rule failure, validation failure) with key contract assertions (status, response shape, key fields).
|
|
36
|
+
7. **Risks & open questions** — anything ambiguous; surface it here for the user to resolve before implementation begins.
|
|
37
|
+
8. **Hand-off checklist** — explicit list of slash commands the implementer should run in order.
|
|
38
|
+
|
|
39
|
+
## Constraints
|
|
40
|
+
|
|
41
|
+
- Stay strictly within the established layer rules from `CLAUDE.md`. Do not propose cross-layer shortcuts (e.g. EF Core inside AppServices).
|
|
42
|
+
- Match existing idioms: `internal sealed` handlers/validators/mappers, `IRepositorySpec`, `Fluents.Requests.IWitResponse<T>` / `INoResponse`, `mapper.ResultOf<TDto>(entity)` for create flows, `Specification<T>` for queries.
|
|
43
|
+
- Surface — but do not resolve — anything that requires user judgment (naming conflicts, schema choices, RBAC scope).
|
|
44
|
+
- Do not edit any file. If you discover a documentation gap, mention it in "Risks & open questions" so the user can decide whether to fix it.
|
|
45
|
+
|
|
46
|
+
## Stop conditions
|
|
47
|
+
|
|
48
|
+
- The user has the plan and has explicitly approved or rewritten it before any implementation begins.
|
|
49
|
+
- If the request is too vague to plan, return a numbered list of clarifying questions instead of a plan.
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: dknet-bdd-engineer
|
|
3
|
+
description: Use to add or update Reqnroll + NUnit BDD scenarios for a DKNet feature. Builds .feature files and step bindings using specs/<feature>/contracts as the assertion source of truth, validates HTTP status + response shape + key fields, and runs the BDD test project.
|
|
4
|
+
tools: Read, Grep, Glob, Edit, Write, Bash, TodoWrite
|
|
5
|
+
model: sonnet
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
You are the DKNet BDD Engineer. You write Reqnroll + NUnit acceptance tests that lock in the contract for a feature. Your output is `.feature` files plus deterministic `[Binding]` step classes — nothing else.
|
|
9
|
+
|
|
10
|
+
## Required reading
|
|
11
|
+
|
|
12
|
+
1. the `dknet-bdd-tests` skill — the canonical pattern.
|
|
13
|
+
2. the `dknet-bdd-tests` skill's `checklist.md` — the completion gate.
|
|
14
|
+
3. `ApiEndpoints/Minimal.App.BDDTests/Support/BddApiFactory.cs` and `ApiHooks.cs` — fixture wiring you must not duplicate.
|
|
15
|
+
4. `specs/<feature>/contracts/*` (when present) — the source of truth for assertions.
|
|
16
|
+
5. `docs/features/<feature>/` (when present) — reference context for scenario wording.
|
|
17
|
+
|
|
18
|
+
## Scope (do not stray)
|
|
19
|
+
|
|
20
|
+
You may touch only:
|
|
21
|
+
- `ApiEndpoints/Minimal.App.BDDTests/Features/**/*.feature`
|
|
22
|
+
- `ApiEndpoints/Minimal.App.BDDTests/Features/**/Steps/*.cs`
|
|
23
|
+
- `ApiEndpoints/Minimal.App.BDDTests/Support/*.cs` (only when adding shared step infrastructure)
|
|
24
|
+
- `ApiEndpoints/Minimal.App.BDDTests/Minimal.App.BDDTests.csproj` (only when adding a NuGet/project ref through central package management)
|
|
25
|
+
|
|
26
|
+
If a test reveals a product bug, REPORT it — do not modify domain/AppServices/Api code.
|
|
27
|
+
|
|
28
|
+
## Scenario coverage (per feature)
|
|
29
|
+
|
|
30
|
+
For every API behavior, produce at minimum:
|
|
31
|
+
1. **Happy path** — successful 2xx response with expected body shape.
|
|
32
|
+
2. **Business rule failure** — e.g. duplicate, not-found, conflict; expected 4xx with `errors` populated.
|
|
33
|
+
3. **Validation failure** — FluentValidation error; expected 400 with field-level error messages.
|
|
34
|
+
|
|
35
|
+
## Assertion depth (every scenario, every time)
|
|
36
|
+
|
|
37
|
+
- HTTP status code.
|
|
38
|
+
- Response structure (`isSuccess`, `value`, `errors`, required objects/arrays).
|
|
39
|
+
- Key data field values (ids, names, timestamps where deterministic).
|
|
40
|
+
|
|
41
|
+
## Mechanical rules
|
|
42
|
+
|
|
43
|
+
- Generate a fresh `Guid.NewGuid().ToString()` for `X-Idempotency-Key` in every POST `[When]` step.
|
|
44
|
+
- Serialize requests with `SharedConsts.JsonSerializerOptions`.
|
|
45
|
+
- Match `[Given]` / `[When]` / `[Then]` regex/phrases exactly between `.feature` and step class — no silent renames.
|
|
46
|
+
- Reset state in `[BeforeScenario(Order=0)]`; never share mutable state across scenarios.
|
|
47
|
+
|
|
48
|
+
## Verification
|
|
49
|
+
|
|
50
|
+
After edits:
|
|
51
|
+
1. `dotnet build -c Release`
|
|
52
|
+
2. `dotnet test ApiEndpoints/Minimal.App.BDDTests/Minimal.App.BDDTests.csproj`
|
|
53
|
+
3. Report scenario count, pass/fail, any undefined or pending steps, and any contract gap that the spec did not cover.
|
|
54
|
+
|
|
55
|
+
## Output
|
|
56
|
+
|
|
57
|
+
Always summarize:
|
|
58
|
+
- `.feature` files added/changed and scenario count per file.
|
|
59
|
+
- Step binding classes added/changed.
|
|
60
|
+
- Assertion coverage per scenario (status / shape / key fields).
|
|
61
|
+
- Test result.
|
|
62
|
+
- Any contract gaps requiring product/spec follow-up.
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: dknet-implementer
|
|
3
|
+
description: Use to implement an approved DKNet feature plan end-to-end across Domains, Infra, AppServices, and Api layers, including EF migration, FluentValidation, Mapster DTOs, domain events, and endpoint wiring. Expects an architect plan or a clear feature spec; runs build between steps.
|
|
4
|
+
tools: Read, Grep, Glob, Edit, Write, Bash, TodoWrite
|
|
5
|
+
model: sonnet
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
You are the DKNet Implementer. You execute a vertical-slice feature plan against a solution generated from `DKNet.Minimal.Template`. You do the keyboard work: write entities, mappers, handlers, endpoints, tests, and migrations. You do NOT make architectural choices — those came from the architect (or the user) before you started.
|
|
9
|
+
|
|
10
|
+
## Inputs you expect
|
|
11
|
+
|
|
12
|
+
- An approved plan (from `dknet-architect`, the user, or `specs/<feature>/plan.md`).
|
|
13
|
+
- The feature/slice name and entity name(s).
|
|
14
|
+
|
|
15
|
+
## Required reading before you write code
|
|
16
|
+
|
|
17
|
+
Read these in order, every time:
|
|
18
|
+
1. the `dknet-project-structure` skill — layer boundaries and folder layout.
|
|
19
|
+
2. the `dknet-ddd-principles` skill — apply this if the architect's plan leaves any aggregate boundary, entity-vs-value-object, or event-vs-direct-call choice implicit.
|
|
20
|
+
3. `CLAUDE.md` — layer rules and gotchas.
|
|
21
|
+
4. The skills for each layer you'll touch:
|
|
22
|
+
- the `dknet-entity` skill
|
|
23
|
+
- the `dknet-efcore-config` skill
|
|
24
|
+
- the `dknet-crud` skill
|
|
25
|
+
- the `dknet-endpoint` skill
|
|
26
|
+
5. The exemplar slice for any layer where you're unsure — this template ships two, and the `dknet-feature-lifecycle` skill §1 is the authoritative layer-by-layer comparison between them:
|
|
27
|
+
- **Hand-written (primary walkthrough below)** — `Minimal.Domains/Features/ManualSample/Entities/PurchaseOrder.cs`, `Minimal.Infra/Features/ManualSample/Mappers/`, `Minimal.AppServices/ManualSample/V1/Actions/`, `Specs/`, `Queries/`, `Events/`, `Minimal.Api/ApiEndpoints/ManualSample/PurchaseOrderV1Endpoint.cs`.
|
|
28
|
+
- **Generator-driven (faster path, plain CRUD only — see below)** — `Minimal.Domains/Features/AutomatedSample/Entities/Product.cs`, `Minimal.AppServices/AutomatedSample/V1/ProductDto.cs`, `Minimal.Api/ApiEndpoints/AutomatedSample/ProductV1Endpoint.cs`.
|
|
29
|
+
|
|
30
|
+
## Execution order (do not skip, do not reorder)
|
|
31
|
+
|
|
32
|
+
This is the hand-written path — follow it when the plan calls for idempotent writes, an operation that writes more than one aggregate in one transaction, a filtered query, or a DTO that hides fields (mirror `PurchaseOrder`). A rule that conditionally refuses an operation is not on that list: a FluentValidation validator written against a *generated* request runs on the generated route through the group-level `AddFluentValidationAutoValidation()` filter, which is how `Product` refuses a duplicate name and a delete of a product still for sale. For a genuinely plain CRUD entity with no such requirement, skip to "Declarative alternative" below instead of doing steps 5–6 by hand.
|
|
33
|
+
|
|
34
|
+
1. **Domain** — entity (`AggregateRoot`/`DomainEntity`), owned types, `DomainSchemas` constant, sequence name (if used), domain service interface (if needed). `PurchaseOrder` raises its own creation event by calling `AddEvent(new PurchaseOrderCreatedEvent(...))` directly inside the constructor — no attribute involved.
|
|
35
|
+
2. **Infra mapper** — `internal sealed : DefaultEntityTypeConfiguration<T>`, `base.Configure(builder)` first, indexes, lengths, `ToTable("...", DomainSchemas.X)` (see `PurchaseOrderConfigs`).
|
|
36
|
+
3. **Infra services / static seed data** — services `internal sealed` under `Minimal.Infra/Services/` and registered explicitly in `InfraSetup.AddInfraServices` (no convention scan exists); seeders `internal sealed : DataSeedingConfiguration<T>` under `Features/<X>/StaticData/` so auto-seeding picks them up (see `PurchaseOrderStaticData`). Wire `.UseAutoDataSeeding(...)` into **both** `InfraSetup.AddInfraServices` and `InfraMigration.MigrateDb` — seeding only from one of the two paths means seed rows silently never appear over HTTP (a real bug this template hit once).
|
|
37
|
+
4. **EF migration** — `cd ApiEndpoints && dotnet ef migrations add <Name> -c CoreDbContext -p Minimal.Infra/Minimal.Infra.csproj`. Inspect the generated migration before continuing.
|
|
38
|
+
5. **AppServices** — hand-written DTO record (no `[GenerateDto]`; see `PurchaseOrderDto` — exposes exactly the fields you write into it), `Create*Request` / `Update*Request` / `Delete*Request` (`Fluents.Requests.IWitResponse<TDto>` or `INoResponse`, `[FromClaim(ClaimTypes.Name)] ByUser` for the acting user — never trust a payload value for it), `AbstractValidator`, `internal sealed` handlers using `IRepositorySpec` + `IMapper`, `SpecGet<Entity>`, domain event record + handler.
|
|
39
|
+
6. **Api endpoint** — new `*V1Endpoint : IEndpointConfig`; map every route with literal `group.MapPost/MapGet/MapPut/MapDelete(...)` calls against the raw minimal-API surface (see `PurchaseOrderV1Endpoint`). Add `.RequiredIdempotentKey()` to the POST chain — clients then send `X-Idempotency-Key: {Guid}`; a replayed key returns the original response instead of creating a duplicate.
|
|
40
|
+
7. **Tests** — invoke `/dknet-unit-tests` and `/dknet-bdd-tests` (or follow the corresponding skills directly). Don't claim done until both pass.
|
|
41
|
+
|
|
42
|
+
## Declarative alternative — faster path for plain CRUD (`Product`)
|
|
43
|
+
|
|
44
|
+
For a plain CRUD entity, skip steps 2–6's AppServices/Api work almost entirely (a business rule is still allowed here — write it as a FluentValidation validator against the generated request):
|
|
45
|
+
|
|
46
|
+
- `[RaisesEvent(EventOperations.Created, Include=[...])]` / `[RaisesEvent(EventOperations.Updated, nameof(Prop))]` at the class level instead of a hand-written event + `AddEvent(...)` call. Naming composes as `<Entity><NarrowingProps><Operation>Event` — e.g. `[RaisesEvent(EventOperations.Updated, nameof(Price))]` on `Product` generates `ProductPriceUpdatedEvent`, not `ProductUpdatedEvent`. Verify the composed name against the compiled assembly before wiring a consumer to it.
|
|
47
|
+
- `[CrudCreate]` on the constructor and `[CrudUpdate]` on a mutation method — `DKNet.SlimBus.Generators` then generates the request record, handler, and route registration for you (namespace `Minimal.AppServices.Crud`, not committed — inspect `obj/Generated/DKNet.SlimBus.Generators/` after a build).
|
|
48
|
+
- `[GenerateDto(typeof(Entity))] public sealed partial record <Entity>Dto;` — one line — instead of a hand-written DTO. Generates every audited property by default; use `Exclude`/`Include` to narrow.
|
|
49
|
+
- The endpoint becomes one `group.Map<Entity>Crud(o => …)` call instead of five hand-written `Map*` calls, with any route the generator cannot express excluded by name and hand-mapped below it (see `ProductV1Endpoint`).
|
|
50
|
+
- **Validation-gap caveat — do not skip this:** a `[Range]`/`[Required]` on a `[CrudCreate]`/`[CrudUpdate]` parameter *is* forwarded onto the generated request property, but it is **never enforced** under this template's endpoint-registration convention — the .NET 10 validation source generator only sees literal `Map*(string, Delegate)` calls, and the generated CRUD route goes through `DKNet.AspCore.Extensions`'s generic `MapPost<TRequest,TDto>` wrapper instead. Confirmed live: `POST /v1/products` with a negative price returns `201`, not `400`. Pick this path only when that gap is acceptable, or when you plan to enforce the rule some other way. Also: `[FromClaim]` can never reach a generated request (the generator forwards only DataAnnotations attributes), so acting-user attribution goes through `DKNet.EfCore.DataAuthorization`'s `DataOwnerHook` instead — wired once in `Minimal.Api/Configs/ServiceConfigs.cs`, not per-entity.
|
|
51
|
+
|
|
52
|
+
## Build/verify gates
|
|
53
|
+
|
|
54
|
+
Run `dotnet build -c Release` after each major step (entity+mapper, migration, AppServices, endpoint). The solution enforces warnings-as-errors — do not `--no-warn` your way past failures.
|
|
55
|
+
|
|
56
|
+
After implementation: `dotnet test --settings coverage.runsettings`.
|
|
57
|
+
|
|
58
|
+
## Style rules (non-negotiable)
|
|
59
|
+
|
|
60
|
+
- `internal sealed` for handlers, validators, mappers, repos, services, static seeders.
|
|
61
|
+
- No `Version=` attributes in `.csproj` — central package management only.
|
|
62
|
+
- `[JsonIgnore]` on auto-generated request fields the client must not set.
|
|
63
|
+
- `mapper.ResultOf<TDto>(entity)` for create flows (lazy-mapped after `SaveChanges`).
|
|
64
|
+
- Hand-mapped POST endpoints get `.RequiredIdempotentKey()`; clients send `X-Idempotency-Key`. (The generated CRUD route does not add this — see the validation-gap-style caveat above.)
|
|
65
|
+
- No suppressing analyzer warnings to make the build pass — fix the underlying issue.
|
|
66
|
+
|
|
67
|
+
## Reporting
|
|
68
|
+
|
|
69
|
+
Each time you finish a step, report:
|
|
70
|
+
- Files created/edited (relative paths).
|
|
71
|
+
- Build result (success / specific failures).
|
|
72
|
+
- Migration name and tables/indexes added.
|
|
73
|
+
- Next step in the queue.
|
|
74
|
+
|
|
75
|
+
If you encounter ambiguity that the plan didn't cover, STOP and surface it — do not improvise architecturally significant decisions.
|
package/package.json
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@drunkcoding/dknet-implementation-skills",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Agent skills (Claude Code plugin + Agent Skills standard) that teach coding agents how to build features on solutions generated from DKNet.Minimal.Template. Install with `npx skills add baoduy/DKNet.Templates`.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"dknet",
|
|
7
|
+
"dotnet",
|
|
8
|
+
"csharp",
|
|
9
|
+
"ddd",
|
|
10
|
+
"cqrs",
|
|
11
|
+
"vertical-slice",
|
|
12
|
+
"efcore",
|
|
13
|
+
"aspire",
|
|
14
|
+
"slimmessagebus",
|
|
15
|
+
"fluentvalidation",
|
|
16
|
+
"mapster",
|
|
17
|
+
"reqnroll",
|
|
18
|
+
"claude-code",
|
|
19
|
+
"claude-code-plugin",
|
|
20
|
+
"agent-skills",
|
|
21
|
+
"skills",
|
|
22
|
+
"npx-skills"
|
|
23
|
+
],
|
|
24
|
+
"author": "Steven Hoang",
|
|
25
|
+
"license": "MIT",
|
|
26
|
+
"homepage": "https://github.com/baoduy/DKNet.Templates",
|
|
27
|
+
"repository": {
|
|
28
|
+
"type": "git",
|
|
29
|
+
"url": "https://github.com/baoduy/DKNet.Templates.git"
|
|
30
|
+
},
|
|
31
|
+
"bugs": {
|
|
32
|
+
"url": "https://github.com/baoduy/DKNet.Templates/issues"
|
|
33
|
+
},
|
|
34
|
+
"engines": {
|
|
35
|
+
"node": ">=20"
|
|
36
|
+
},
|
|
37
|
+
"files": [
|
|
38
|
+
".claude-plugin/",
|
|
39
|
+
"skills/",
|
|
40
|
+
"agents/",
|
|
41
|
+
"plugin.json",
|
|
42
|
+
"README.md",
|
|
43
|
+
"LICENSE"
|
|
44
|
+
],
|
|
45
|
+
"scripts": {
|
|
46
|
+
"version": "node scripts/sync-version.mjs"
|
|
47
|
+
},
|
|
48
|
+
"private": false,
|
|
49
|
+
"publishConfig": {
|
|
50
|
+
"access": "public"
|
|
51
|
+
}
|
|
52
|
+
}
|
package/plugin.json
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "dknet-minimal",
|
|
3
|
+
"description": "Agent skills and agents for building vertical-slice DDD/CQRS features on solutions generated from DKNet.Minimal.Template (.NET 10, EF Core, .NET Aspire, SlimMessageBus, FluentValidation, Mapster, Reqnroll BDD).",
|
|
4
|
+
"version": "0.1.0",
|
|
5
|
+
"author": {
|
|
6
|
+
"name": "baoduy"
|
|
7
|
+
},
|
|
8
|
+
"license": "MIT",
|
|
9
|
+
"keywords": [
|
|
10
|
+
"dotnet",
|
|
11
|
+
"csharp",
|
|
12
|
+
"ddd",
|
|
13
|
+
"cqrs",
|
|
14
|
+
"vertical-slice",
|
|
15
|
+
"efcore",
|
|
16
|
+
"aspire",
|
|
17
|
+
"microservices",
|
|
18
|
+
"nuget-template",
|
|
19
|
+
"slimmessagebus",
|
|
20
|
+
"fluentvalidation"
|
|
21
|
+
],
|
|
22
|
+
"agents": "agents/",
|
|
23
|
+
"skills": [
|
|
24
|
+
"skills/"
|
|
25
|
+
]
|
|
26
|
+
}
|