@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,144 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: dknet-feature-lifecycle
|
|
3
|
+
description: The add/remove lifecycle of a DKNet vertical-slice business feature — how to choose the manual vs automated flow, the exact file footprint a feature occupies across all six projects, and the out-of-folder touchpoints a delete must clean up. Use before /dknet-feature or /dknet-feature-remove, and whenever you need to enumerate or retire an existing feature.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# DKNet feature lifecycle
|
|
7
|
+
|
|
8
|
+
A **feature** in this template is one business capability delivered as a vertical slice. It is
|
|
9
|
+
addressable by a single PascalCase folder name (`<Feature>`) that appears literally in fixed roots
|
|
10
|
+
across six projects. That is what makes a feature addable and removable as a unit.
|
|
11
|
+
|
|
12
|
+
Two worked examples ship with the template and are the canonical reference for each flow:
|
|
13
|
+
|
|
14
|
+
| Flow | Exemplar feature | Exemplar entity |
|
|
15
|
+
|---|---|---|
|
|
16
|
+
| `manual` | `ManualSample` | `PurchaseOrder` |
|
|
17
|
+
| `auto` | `AutomatedSample` | `Product` |
|
|
18
|
+
|
|
19
|
+
## 1. Choosing the flow
|
|
20
|
+
|
|
21
|
+
Pick **one flow per aggregate** and do not mix them for the same entity. Mixing means some routes
|
|
22
|
+
are generated and some hand-mapped, and the two halves have different validation and idempotency
|
|
23
|
+
behavior — which is exactly the confusion this section exists to prevent.
|
|
24
|
+
|
|
25
|
+
### At a glance: which one should I copy?
|
|
26
|
+
|
|
27
|
+
**Copy `manual` (mirror `PurchaseOrder`)** when the feature needs any of:
|
|
28
|
+
|
|
29
|
+
- Idempotent writes — safe client retries on `POST`.
|
|
30
|
+
- An attribute-declared (`DataAnnotations`) rule that must actually return `400`, not just be
|
|
31
|
+
present on the generated request.
|
|
32
|
+
- An operation that writes more than one aggregate in one transaction.
|
|
33
|
+
- A filtered or customized list/get query beyond the generic list route's `filter`/`search`/`orderBy`
|
|
34
|
+
contract.
|
|
35
|
+
- The acting user must come from a claim on the request itself (`[FromClaim]`).
|
|
36
|
+
|
|
37
|
+
**Copy `auto` (mirror `Product`)** only when the aggregate is genuinely plain CRUD:
|
|
38
|
+
|
|
39
|
+
- Create/update/delete carry no rule a `[Required]`/`[StringLength]`/`[Range]` can't express — and
|
|
40
|
+
you accept those attributes are forwarded but never enforced on a generated route (see the gap
|
|
41
|
+
below).
|
|
42
|
+
- No idempotency requirement on create.
|
|
43
|
+
- The DTO can be every audited property, narrowed at most with `Exclude`/`Include`.
|
|
44
|
+
- Any extra operations fit `[CrudAction]`'s shape (mutate, return `200` + DTO) or can be excluded and
|
|
45
|
+
hand-written when they can't.
|
|
46
|
+
|
|
47
|
+
A rule that must **refuse** an operation is *not* by itself a reason to choose `manual`. A
|
|
48
|
+
FluentValidation validator written against a generated request still runs — `UseEndpointConfigs`
|
|
49
|
+
applies `AddFluentValidationAutoValidation()` to every endpoint group, generated routes included —
|
|
50
|
+
so it can read stored data through `IRepositorySpec` and refuse before the generated handler runs.
|
|
51
|
+
`Product` ships two such rules (`CreateProductRequestValidator`, `DeleteProductRequestValidator`),
|
|
52
|
+
both answering `409` via a `PreconditionCodes`-prefixed error code.
|
|
53
|
+
|
|
54
|
+
| Trade-off | `manual` | `auto` |
|
|
55
|
+
|---|---|---|
|
|
56
|
+
| Attribute-declared validation (`[Range]`, `[Required]` on a `[CrudCreate]`/`[CrudUpdate]` param) | enforced — literal `Map*` calls, seen by the .NET 10 validation source generator | forwarded onto the generated request but **never enforced** — every generated route goes through `DKNet.AspCore.Extensions`'s generic `Map*<TRequest,TDto>` wrapper, which the source generator can't see into |
|
|
57
|
+
| Idempotency on create | `.RequiredIdempotentKey()` — a replayed `X-Idempotency-Key` returns the original response | none — the generated create route has no such call; a duplicate submit creates a duplicate row |
|
|
58
|
+
| DTO default shape | hand-picked fields only (`PurchaseOrderDto` exposes 5) | every audited property by default (`Id`, `CreatedBy/On`, `UpdatedBy/On` + entity props); narrow with `[GenerateDto(..., Exclude=[...])]` |
|
|
59
|
+
| Filtered list / custom get-by-id | a hand-written `Specification<T>` + query handler, any shape | the generic list route only (`filter`/`search`/`orderBy`/paging against the DTO); a bespoke predicate or a "check tenant ownership on get" still forces a hand-written route |
|
|
60
|
+
| Event naming | you choose the record name (`AddEvent(new PurchaseOrderCreatedEvent(...))`) | composed by convention: `<Entity><NarrowingProps><Operation>Event` — e.g. `[RaisesEvent(EventOperations.Updated, nameof(Price))]` on `Product` → `ProductPriceUpdatedEvent`, never `ProductUpdatedEvent`; verify the composed name in the compiled assembly, it has no source file |
|
|
61
|
+
| Acting-user attribution | `[FromClaim(ClaimTypes.Name)]` on the request — visible in the request shape | never a request property (the generator forwards only `DataAnnotations` attributes) — comes from `DKNet.EfCore.DataAuthorization`'s `DataOwnerHook`/audit hook instead, wired once for every entity on `CoreDbContext`; the forgery guarantee is identical, only the visibility differs |
|
|
62
|
+
| External broker (Azure Service Bus) | not wired for `PurchaseOrder` at all — a deliberate scope split | `azb.Produce<T>`/`azb.Consume<T>` in `ServiceBusSetup.cs` works on a declaratively-raised event exactly like a hand-raised one, but only when `EnableServiceBus` is on **and** `ConnectionStrings:AzureBus` is non-empty |
|
|
63
|
+
|
|
64
|
+
A mixed aggregate is a smell, but dropping **one** operation out of `auto` to a hand-written route
|
|
65
|
+
is legitimate when only that operation needs what the generator can't express —
|
|
66
|
+
`CrudMapOptions.Exclude("Discontinue")` plus a literal `MapPut` below it is exactly how `Product`
|
|
67
|
+
handles the one operation that writes two aggregates in one transaction. Say so explicitly when you
|
|
68
|
+
do it.
|
|
69
|
+
|
|
70
|
+
## 2. Feature footprint
|
|
71
|
+
|
|
72
|
+
Every path below is scoped by the feature folder name. `<Feature>` is PascalCase (`Orders`),
|
|
73
|
+
`<Plural>` is the BDD folder (usually the same). Root for the first six: `ApiEndpoints/`. Verified
|
|
74
|
+
against the real tree under both sample features.
|
|
75
|
+
|
|
76
|
+
| # | Path | `manual` | `auto` |
|
|
77
|
+
|---|---|---|---|
|
|
78
|
+
| 1 | `Minimal.Domains/Features/<Feature>/Entities/` | entity + hand-written event record(s) | entity only — `[RaisesEvent]`/`[CrudCreate]`/`[CrudUpdate]`/`[CrudAction]` carry the rest |
|
|
79
|
+
| 2 | `Minimal.Infra/Features/<Feature>/Mappers/` | `IEntityTypeConfiguration<T>` | same — **no generator produces this** |
|
|
80
|
+
| 3 | `Minimal.Infra/Features/<Feature>/StaticData/` | optional `DataSeedingConfiguration<T>` | optional (neither sample ships one for `Product`) |
|
|
81
|
+
| 4 | `Minimal.Infra/Features/<Feature>/ExternalEvents/` | not used by `PurchaseOrder` | optional broker consumer (`ProductCreatedNotificationHandler`) |
|
|
82
|
+
| 5 | `Minimal.AppServices/<Feature>/V1/Actions/` | command requests + handlers | only operations excluded from the generated map (e.g. `Discontinue.cs`) |
|
|
83
|
+
| 6 | `Minimal.AppServices/<Feature>/V1/Queries/` | hand-written read requests + handlers | custom read shapes the generic list can't express (e.g. a price-summary query) |
|
|
84
|
+
| 7 | `Minimal.AppServices/<Feature>/V1/Specs/` | `Specification<T>` filters | specs backing a validator or an excluded query |
|
|
85
|
+
| 8 | `Minimal.AppServices/<Feature>/V1/Events/` | domain event consumers | domain event consumers only — the generator raises, it does not consume |
|
|
86
|
+
| 9 | `Minimal.AppServices/<Feature>/V1/Validators/` | not needed — validation is enforced on literal routes | validators against a **generated** request that must refuse (`CreateXRequestValidator`, `DeleteXRequestValidator`) |
|
|
87
|
+
| 10 | `Minimal.AppServices/<Feature>/V1/<Feature>Dto.cs` (+ optional `<Feature>MappingRegister.cs`) | hand-written DTO record | one `[GenerateDto(typeof(Entity))] public sealed partial record` line; a Mapster `IRegister` only if a response value needs deriving from more than one column |
|
|
88
|
+
| 11 | `Minimal.Api/ApiEndpoints/<Feature>/<Entity>V1Endpoint.cs` | every route a literal `Map*` call | one `group.Map<Entity>Crud(o => …)` call, plus any excluded route mapped literally below it |
|
|
89
|
+
| 12 | `Minimal.App.Tests/Unit/<Feature>/` | entity/validator/spec tests | entity/handler tests |
|
|
90
|
+
| 13 | `Minimal.App.Tests/Integration/<Feature>/V1/` | result-level handler + security tests | same |
|
|
91
|
+
| 14 | `Minimal.App.BDDTests/Features/<Plural>/` | `*.feature` + `Steps/*.cs` | same |
|
|
92
|
+
|
|
93
|
+
Generated code for `auto` lands in `obj/Generated/DKNet.SlimBus.Generators/` (requests, handlers,
|
|
94
|
+
route registration) and `obj/Generated/DKNet.EfCore.DtoGenerator/` (the DTO's generated members) —
|
|
95
|
+
never committed, never deleted by hand, disappears with the attributes.
|
|
96
|
+
|
|
97
|
+
## 3. Out-of-folder touchpoints
|
|
98
|
+
|
|
99
|
+
Deleting the folders above leaves these behind. **Every removal must check all of them** — they are
|
|
100
|
+
the reason a feature delete is a command and not an `rm -rf`.
|
|
101
|
+
|
|
102
|
+
| Touchpoint | File | When it applies |
|
|
103
|
+
|---|---|---|
|
|
104
|
+
| Schema constant | `Minimal.Domains/Share/DomainSchemas.cs` | if the feature added its own `const string` (the samples instead use literal schema strings — `"manual_sample"`/`"sample"` — directly in their mapper's `ToTable` call) |
|
|
105
|
+
| Broker topology | `Minimal.Infra/Extensions/ServiceBusSetup.cs` | the `azb.Produce<T>`/`azb.Consume<T>` pair, e.g. `ProductCreatedEvent` on `product-tp`/`product-sub` |
|
|
106
|
+
| Feature flag | `Minimal.Share/Options/FeatureOptions.cs` + `FeatureManagement` section in every `appsettings*.json` | if the feature gated itself behind a flag |
|
|
107
|
+
| Auth scopes | the feature's own scopes class (e.g. `ProductScopes`) + its `foreach` registration in `Configs/Auth/AuthConfig.cs` | if the feature registered per-route scope policies |
|
|
108
|
+
| Precondition codes | `Minimal.AppServices/Share/PreconditionCodes.cs` | if a validator added a `precondition.`-prefixed code for this feature |
|
|
109
|
+
| Test-support visibility | `InternalsVisibleTo` in the owning project's `.csproj` (e.g. `Minimal.Api.csproj` grants `Minimal.App.TestSupport` and `Minimal.App.Tests` visibility onto `internal` scope classes) | if the feature's `internal` types need to be visible to test doubles |
|
|
110
|
+
| EF migration | `Minimal.Infra/Migrations/` | see §4 — never hand-delete an applied migration |
|
|
111
|
+
|
|
112
|
+
Enumerate existing features at any time — no registry file to keep in sync:
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
ls ApiEndpoints/Minimal.Domains/Features/
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## 4. Migration rules on removal
|
|
119
|
+
|
|
120
|
+
The tables outlive the code. Decide by whether the feature's migration has been applied anywhere:
|
|
121
|
+
|
|
122
|
+
- **Not applied and it is the newest migration** —
|
|
123
|
+
`dotnet ef migrations remove -c CoreDbContext -p Minimal.Infra/Minimal.Infra.csproj` (run from
|
|
124
|
+
`ApiEndpoints/`).
|
|
125
|
+
- **Applied, or newer migrations sit on top of it** — do NOT touch the old migration. Delete the
|
|
126
|
+
entity and mapper, then
|
|
127
|
+
`dotnet ef migrations add Drop<Feature> -c CoreDbContext -p Minimal.Infra/Minimal.Infra.csproj`
|
|
128
|
+
and let EF emit the drop. Rewriting applied history corrupts `__EFMigrationsHistory` for every
|
|
129
|
+
environment already running it.
|
|
130
|
+
|
|
131
|
+
When in doubt, take the second branch — it is always correct, merely more verbose.
|
|
132
|
+
|
|
133
|
+
## 5. Order of operations
|
|
134
|
+
|
|
135
|
+
**Add** (each step builds green before the next): Domains → Infra → AppServices → Api → tests → BDD
|
|
136
|
+
→ docs. The orchestrator is `/dknet-feature <Feature> <Entity> [mode=manual|auto] [props…]`.
|
|
137
|
+
|
|
138
|
+
**Remove** (reverse — drop dependents before dependencies, so the build never sees a dangling
|
|
139
|
+
reference): docs → BDD → tests → Api → AppServices → Infra → Domains → touchpoints → migration. The
|
|
140
|
+
orchestrator is `/dknet-feature-remove <Feature>`.
|
|
141
|
+
|
|
142
|
+
Never remove `ManualSample` or `AutomatedSample` from the template repository itself — they are the
|
|
143
|
+
exemplars every skill and command cites. In a *generated* solution they are the first thing a
|
|
144
|
+
consumer deletes, and `/dknet-feature-remove` is how.
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: dknet-feature-remove
|
|
3
|
+
description: Retire a DKNet vertical-slice business feature end-to-end — deletes its folders across all six projects, cleans the out-of-folder touchpoints, and drops its tables via a new migration.
|
|
4
|
+
metadata:
|
|
5
|
+
kind: workflow
|
|
6
|
+
arguments: "<Feature> [--dry-run] e.g. Orders"
|
|
7
|
+
allowed-tools: Read, Grep, Glob, Edit, Write, Bash, TodoWrite
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
Usage: `/dknet-feature-remove <Feature> [--dry-run] e.g. Orders`
|
|
11
|
+
|
|
12
|
+
You are retiring a complete vertical slice. A feature is addressable by its folder name, but a
|
|
13
|
+
`rm -rf` is **not** a correct removal — schema constants, broker topology, feature flags, docs links,
|
|
14
|
+
and the database tables all live outside the feature folders.
|
|
15
|
+
|
|
16
|
+
## Inputs
|
|
17
|
+
|
|
18
|
+
`$ARGUMENTS` — the feature folder name (PascalCase, as it appears under
|
|
19
|
+
`Minimal.Domains/Features/`), plus optional `--dry-run`.
|
|
20
|
+
|
|
21
|
+
If no feature is named, list the candidates and stop:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
ls ApiEndpoints/Minimal.Domains/Features/
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Required reading
|
|
28
|
+
|
|
29
|
+
1. The `dknet-feature-lifecycle` skill — §2 footprint, §3 touchpoints, §4 migration
|
|
30
|
+
rules, §5 removal order. This command is the executable form of that skill; do not improvise a
|
|
31
|
+
different order.
|
|
32
|
+
|
|
33
|
+
## Phase 0 — Confirm and inventory (always, even under `--dry-run`)
|
|
34
|
+
|
|
35
|
+
1. Resolve the feature: confirm `ApiEndpoints/Minimal.Domains/Features/<Feature>/` exists. If it
|
|
36
|
+
does not, list the candidates and STOP — do not guess at a near-match.
|
|
37
|
+
2. Inventory every path that will be deleted, using the §2 footprint. Report actual matches only:
|
|
38
|
+
```bash
|
|
39
|
+
find ApiEndpoints -path '*<Feature>*' -not -path '*/obj/*' -not -path '*/bin/*' | sort
|
|
40
|
+
find docs -path '*<slug>*' | sort
|
|
41
|
+
```
|
|
42
|
+
3. Grep for references from **outside** the slice — this is what catches the touchpoints and any
|
|
43
|
+
coupling the footprint table doesn't predict:
|
|
44
|
+
```bash
|
|
45
|
+
grep -rn '<Feature>\|<Entity>' ApiEndpoints --include=*.cs --include=*.json \
|
|
46
|
+
-l | grep -v '<Feature>' | sort -u
|
|
47
|
+
```
|
|
48
|
+
Inspect each hit. Anything in a *different* feature's folder is real coupling — surface it and
|
|
49
|
+
STOP; the user decides whether to break it or keep the feature.
|
|
50
|
+
4. Print the inventory: files to delete (grouped by layer), touchpoints to edit, migration decision
|
|
51
|
+
(§4 branch), and the exact table names that will be dropped.
|
|
52
|
+
5. **STOP and ask the user to confirm** before deleting anything. Under `--dry-run`, stop here
|
|
53
|
+
permanently and report.
|
|
54
|
+
|
|
55
|
+
## Phase 1 — Delete, in dependent-first order
|
|
56
|
+
|
|
57
|
+
Do NOT reorder. Each step removes only things that nothing later in the list depends on, so an
|
|
58
|
+
intermediate build failure points at real coupling rather than at the ordering.
|
|
59
|
+
|
|
60
|
+
1. Docs — `docs/features/<slug>/` (or wherever the solution keeps feature docs).
|
|
61
|
+
2. BDD — `ApiEndpoints/Minimal.App.BDDTests/Features/<Plural>/` (both `*.feature` and the
|
|
62
|
+
generated `*.feature.cs`, plus `Steps/`).
|
|
63
|
+
3. Tests — `Minimal.App.Tests/Unit/<Feature>/` and `Minimal.App.Tests/Integration/<Feature>/`.
|
|
64
|
+
Also grep `Minimal.App.Tests/Architecture/` — a convention test may assert on this feature by name.
|
|
65
|
+
4. Api — `Minimal.Api/ApiEndpoints/<Feature>/`.
|
|
66
|
+
5. AppServices — `Minimal.AppServices/<Feature>/`.
|
|
67
|
+
6. Infra — `Minimal.Infra/Features/<Feature>/`.
|
|
68
|
+
7. Domains — `Minimal.Domains/Features/<Feature>/`.
|
|
69
|
+
|
|
70
|
+
## Phase 2 — Out-of-folder touchpoints
|
|
71
|
+
|
|
72
|
+
Work the §3 table. For each, edit surgically — remove the feature's lines, never the whole file:
|
|
73
|
+
|
|
74
|
+
1. `Minimal.Domains/Share/DomainSchemas.cs` — drop the feature's `const string`, if it added one.
|
|
75
|
+
Leave `Migration` and `Profile` alone unless this feature owned one of them.
|
|
76
|
+
2. `Minimal.Infra/Extensions/ServiceBusSetup.cs` — drop the matching `azb.Produce<T>` /
|
|
77
|
+
`azb.Consume<T>` pair and the now-unused `using`.
|
|
78
|
+
3. `Minimal.Share/Options/FeatureOptions.cs` + every `appsettings*.json` `FeatureManagement` section
|
|
79
|
+
— drop the flag property and its JSON key together. A key with no property silently no-ops, so
|
|
80
|
+
an orphan here fails no test; delete both halves or neither.
|
|
81
|
+
4. Docs cross-links — the docs index page and any feature index that linked the slice.
|
|
82
|
+
|
|
83
|
+
## Phase 3 — Migration
|
|
84
|
+
|
|
85
|
+
Apply §4 of the lifecycle skill. State which branch you took and why:
|
|
86
|
+
|
|
87
|
+
- Feature's migration is the newest and unapplied → `cd ApiEndpoints && dotnet ef migrations remove -c CoreDbContext -p Minimal.Infra/Minimal.Infra.csproj`
|
|
88
|
+
- Otherwise → `cd ApiEndpoints && dotnet ef migrations add Drop<Feature> -c CoreDbContext -p Minimal.Infra/Minimal.Infra.csproj` and verify the generated `Up`
|
|
89
|
+
contains the expected `DropTable` calls and nothing else.
|
|
90
|
+
|
|
91
|
+
Read the generated migration before moving on. A drop migration that also touches an unrelated table
|
|
92
|
+
means the model changed underneath you — STOP and report.
|
|
93
|
+
|
|
94
|
+
## Phase 4 — Verify
|
|
95
|
+
|
|
96
|
+
1. `dotnet build -c Release` — must be zero warnings (warnings-as-errors).
|
|
97
|
+
2. `dotnet test --settings coverage.runsettings` — all green.
|
|
98
|
+
3. Final residue sweep — must return nothing:
|
|
99
|
+
```bash
|
|
100
|
+
grep -rn '<Feature>\|<Entity>' ApiEndpoints docs --include=*.cs --include=*.json --include=*.md \
|
|
101
|
+
--include=*.feature | grep -v '/obj/\|/bin/\|Migrations/'
|
|
102
|
+
```
|
|
103
|
+
Hits under `Migrations/` are expected and correct — historical migrations keep the old table
|
|
104
|
+
names and must not be edited.
|
|
105
|
+
|
|
106
|
+
## Report
|
|
107
|
+
|
|
108
|
+
1. Files/folders deleted, grouped by layer.
|
|
109
|
+
2. Touchpoints edited, with the specific lines removed.
|
|
110
|
+
3. Migration branch taken + migration name + tables dropped.
|
|
111
|
+
4. Build + test results.
|
|
112
|
+
5. Anything deliberately left behind, and why (historical migrations, shared types another feature
|
|
113
|
+
uses).
|
|
114
|
+
6. Suggested commit title. Do not commit unless the user asks.
|
|
115
|
+
|
|
116
|
+
## Stop conditions
|
|
117
|
+
|
|
118
|
+
- Feature folder not found → list candidates, STOP.
|
|
119
|
+
- Another feature references this one → report the coupling, STOP.
|
|
120
|
+
- Build or tests fail after deletion and the cause is not an obvious leftover reference → STOP,
|
|
121
|
+
summarize, ask. Do not start deleting unrelated code to make the build pass.
|
|
122
|
+
- Migration branch is ambiguous (unclear whether it was applied) → take the `add-migration` branch,
|
|
123
|
+
say so, and continue. That branch is always safe.
|
|
124
|
+
|
|
125
|
+
## Constraints
|
|
126
|
+
|
|
127
|
+
- Never hand-delete an applied migration or edit migration history.
|
|
128
|
+
- Never delete `ManualSample` or `AutomatedSample` **in the template repo itself** — every skill and
|
|
129
|
+
command cites them as exemplars. In a generated consumer solution, removing them is the expected
|
|
130
|
+
first use of this command.
|
|
131
|
+
- Never widen scope to "cleanup" unrelated code you notice on the way through.
|