@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.
Files changed (36) hide show
  1. package/.claude-plugin/marketplace.json +22 -0
  2. package/.claude-plugin/plugin.json +38 -0
  3. package/LICENSE +21 -0
  4. package/README.md +261 -0
  5. package/agents/dknet-architect.md +49 -0
  6. package/agents/dknet-bdd-engineer.md +62 -0
  7. package/agents/dknet-implementer.md +75 -0
  8. package/package.json +52 -0
  9. package/plugin.json +26 -0
  10. package/skills/README.md +47 -0
  11. package/skills/dknet-auth-and-ownership/SKILL.md +418 -0
  12. package/skills/dknet-bdd-tests/SKILL.md +355 -0
  13. package/skills/dknet-bdd-tests/checklist.md +39 -0
  14. package/skills/dknet-crud/SKILL.md +483 -0
  15. package/skills/dknet-ddd-principles/SKILL.md +87 -0
  16. package/skills/dknet-docs/SKILL.md +296 -0
  17. package/skills/dknet-docs/checklist.md +58 -0
  18. package/skills/dknet-docs/templates/README-template.md +68 -0
  19. package/skills/dknet-docs/templates/api-reference-template.md +275 -0
  20. package/skills/dknet-docs/templates/architecture-template.md +166 -0
  21. package/skills/dknet-docs/templates/data-model-template.md +99 -0
  22. package/skills/dknet-docs/templates/events-template.md +155 -0
  23. package/skills/dknet-dto-mapping/SKILL.md +278 -0
  24. package/skills/dknet-efcore-config/SKILL.md +379 -0
  25. package/skills/dknet-endpoint/SKILL.md +458 -0
  26. package/skills/dknet-entity/SKILL.md +483 -0
  27. package/skills/dknet-feature/SKILL.md +139 -0
  28. package/skills/dknet-feature-lifecycle/SKILL.md +144 -0
  29. package/skills/dknet-feature-remove/SKILL.md +131 -0
  30. package/skills/dknet-messaging-events/SKILL.md +395 -0
  31. package/skills/dknet-package-adoption/SKILL.md +252 -0
  32. package/skills/dknet-platform-config/SKILL.md +342 -0
  33. package/skills/dknet-project-structure/SKILL.md +148 -0
  34. package/skills/dknet-queries-specs/SKILL.md +330 -0
  35. package/skills/dknet-scaffold/SKILL.md +209 -0
  36. package/skills/dknet-unit-tests/SKILL.md +382 -0
@@ -0,0 +1,166 @@
1
+ # {FeatureName} — Architecture
2
+
3
+ ## Vertical Slice Overview
4
+
5
+ This feature follows the DKNet vertical slice architecture.
6
+ Each layer has a single, focused responsibility for this feature.
7
+
8
+ ```mermaid
9
+ graph TD
10
+ Client["Client / Browser"]
11
+
12
+ subgraph API["Minimal.Api"]
13
+ EP["{EntityName}V1Endpoint\n(IEndpointConfig)"]
14
+ end
15
+
16
+ subgraph AppServices["Minimal.AppServices"]
17
+ REQ["Request Types\n(Create / Update / Delete\n+ custom actions)"]
18
+ VAL["Validators\n(FluentValidation)"]
19
+ HDL["Command Handlers\n(IHandler)"]
20
+ SPEC["Query Specs\n(Ardalis.Specification)"]
21
+ EVT["Domain Events\n({EntityName}CreatedEvent etc.)"]
22
+ end
23
+
24
+ subgraph Domains["Minimal.Domains"]
25
+ ENT["{EntityName}\n(AggregateRoot)"]
26
+ end
27
+
28
+ subgraph Infra["Minimal.Infra"]
29
+ MAP["{EntityName}Mapper.cs\n(EF Core Config)"]
30
+ REPO["IRepositorySpec\n(EF Core + Spec)"]
31
+ EVH["Event Handlers\n(Azure Bus / In-Memory)"]
32
+ end
33
+
34
+ DB[("SQL Server")]
35
+
36
+ Client -->|HTTP| EP
37
+ EP -->|Message Bus| REQ
38
+ REQ --> VAL
39
+ VAL --> HDL
40
+ HDL -->|Query via Spec| SPEC
41
+ SPEC -->|Reads| REPO
42
+ HDL -->|Mutations| REPO
43
+ HDL -->|Publish| EVT
44
+ REPO --> MAP
45
+ MAP --> DB
46
+ EVT --> EVH
47
+ ```
48
+
49
+ ## Create {EntityName} — Sequence Diagram
50
+
51
+ ```mermaid
52
+ sequenceDiagram
53
+ participant C as Client
54
+ participant EP as {EntityName}Endpoints
55
+ participant BUS as MessageBus
56
+ participant VAL as Validator
57
+ participant HDL as Create{EntityName}Handler
58
+ participant SPEC as Spec{EntityName}GetByEmail
59
+ participant REPO as IRepositorySpec
60
+ participant EVT as EventPublisher
61
+
62
+ C->>EP: POST /api/v1/{feature-route}
63
+ EP->>BUS: bus.Send(Create{EntityName}Request)
64
+ BUS->>VAL: Validate request
65
+ VAL-->>BUS: Valid ✓
66
+
67
+ BUS->>HDL: Handle(request)
68
+ HDL->>SPEC: new Spec{EntityName}GetByEmail(email)
69
+ HDL->>REPO: FirstOrDefaultAsync(spec)
70
+ REPO-->>HDL: null (no duplicate)
71
+
72
+ HDL->>HDL: new {EntityName}(...)
73
+ HDL->>REPO: AddAsync(entity)
74
+ HDL->>REPO: SaveChangesAsync()
75
+ REPO-->>HDL: OK
76
+
77
+ HDL->>EVT: PublishAsync({EntityName}CreatedEvent)
78
+ EVT-->>HDL: OK
79
+
80
+ HDL-->>BUS: Result<{EntityName}Dto>.Success(dto)
81
+ BUS-->>EP: {EntityName}Dto
82
+ EP-->>C: 201 Created + {EntityName}Dto
83
+ ```
84
+
85
+ ## Component Diagram
86
+
87
+ ```mermaid
88
+ classDiagram
89
+ class {EntityName}V1Endpoint {
90
+ +int Version = 1
91
+ +string GroupEndpoint = "/{feature-route}"
92
+ +Map(RouteGroupBuilder group)
93
+ }
94
+
95
+ class Create{EntityName}Request {
96
+ +string Field1
97
+ +string Field2
98
+ }
99
+
100
+ class Create{EntityName}CommandHandler {
101
+ -IMapper _mapper
102
+ -IRepositorySpec _repo
103
+ -IEventPublisher _eventPublisher
104
+ +Handle(request) Result~{EntityName}Dto~
105
+ }
106
+
107
+ class {EntityName} {
108
+ +Guid Id
109
+ +string Field1
110
+ +string Field2
111
+ +string Status
112
+ +Approve(reason)
113
+ +Reject(reason)
114
+ +Update(...)
115
+ }
116
+
117
+ class {EntityName}Mapper {
118
+ +Configure(EntityTypeBuilder)
119
+ }
120
+
121
+ {EntityName}V1Endpoint ..> Create{EntityName}Request : maps request
122
+ Create{EntityName}CommandHandler --> {EntityName} : creates
123
+ Create{EntityName}CommandHandler --> IRepositorySpec : uses
124
+ {EntityName}Mapper --> {EntityName} : configures
125
+ ```
126
+
127
+ ## Status State Machine
128
+
129
+ > Remove this section if the entity has no status/approval workflow.
130
+
131
+ ```mermaid
132
+ stateDiagram-v2
133
+ [*] --> Pending : {EntityName} Created
134
+
135
+ Pending --> Approved : approve() action
136
+ Pending --> Rejected : reject() action
137
+
138
+ Approved --> [*] : (soft-deleted)
139
+ Rejected --> [*] : (soft-deleted)
140
+
141
+ note right of Pending : Default status on creation
142
+ note right of Approved : Entity available for downstream use
143
+ note right of Rejected : Reason stored for audit trail
144
+ ```
145
+
146
+ ## Event Flow
147
+
148
+ ```mermaid
149
+ graph LR
150
+ HDL["Create{EntityName}Handler"] -->|Publish| EVT["{EntityName}CreatedEvent"]
151
+
152
+ EVT --> MEM["In-Memory Bus Handler"]
153
+ EVT --> AZ["Azure Service Bus Handler\n(if AzureBus configured)"]
154
+
155
+ MEM -->|Side effects| LOG["Audit Log / Internal"]
156
+ AZ -->|Message to subscribers| EXT["External Systems\n(Notifications, Billing, etc.)"]
157
+ ```
158
+
159
+ ## Layer Responsibilities
160
+
161
+ | Layer | Responsibility in this feature |
162
+ |-------|-------------------------------|
163
+ | `Minimal.Api` | Route mapping only; zero business logic |
164
+ | `Minimal.AppServices` | Command handling, validation, event publishing |
165
+ | `Minimal.Domains` | Entity state, domain rules, invariants |
166
+ | `Minimal.Infra` | Persistence, EF Core config, message bus setup |
@@ -0,0 +1,99 @@
1
+ # {FeatureName} — Data Model
2
+
3
+ ## Entity Relationship Diagram
4
+
5
+ ```mermaid
6
+ erDiagram
7
+ {ENTITY_TABLE_NAME} {
8
+ uniqueidentifier Id PK "Auto-generated GUID"
9
+ nvarchar(150) Field1 "Not null"
10
+ nvarchar(256) Field2 UK "Unique, not null"
11
+ nvarchar(50) Field3 "Nullable"
12
+ nvarchar(50) Status "Enum: Pending / Approved / Rejected"
13
+ bit IsDeleted "Soft delete flag; default false"
14
+ nvarchar(450) CreatedBy FK "Linked to user"
15
+ datetime2 CreatedAt "UTC, auto-set on insert"
16
+ nvarchar(450) UpdatedBy "Nullable"
17
+ datetime2 UpdatedAt "UTC, auto-updated"
18
+ }
19
+
20
+ RELATED_TABLE {
21
+ uniqueidentifier Id PK
22
+ uniqueidentifier {EntityName}Id FK
23
+ nvarchar(100) SomeField
24
+ }
25
+
26
+ {ENTITY_TABLE_NAME} ||--o{ RELATED_TABLE : "has many"
27
+ ```
28
+
29
+ > Remove the `RELATED_TABLE` block if there are no related entities.
30
+ > Add `UK` (unique key) annotation to columns with unique indexes.
31
+
32
+ ---
33
+
34
+ ## Properties
35
+
36
+ | Property | C# Type | DB Column | Constraints |
37
+ |----------|---------|-----------|-------------|
38
+ | `Id` | `Guid` | `Id` (PK) | Not null, auto-generated |
39
+ | `Field1` | `string` | `Field1` | Not null, max {N} chars |
40
+ | `Field2` | `string` | `Field2` | Not null, max {N} chars, unique index |
41
+ | `Field3` | `string?` | `Field3` | Nullable, max {N} chars |
42
+ | `Status` | `string` | `Status` | Not null, max 50 chars |
43
+ | `IsDeleted` | `bool` | `IsDeleted` | Default: `false` |
44
+ | `CreatedBy` | `string` | `CreatedBy` | Not null (from the request's `[FromClaim(ClaimTypes.Name)]` `ByUser`) |
45
+ | `CreatedAt` | `DateTime` | `CreatedAt` | UTC, auto-set on insert |
46
+ | `UpdatedBy` | `string?` | `UpdatedBy` | Nullable |
47
+ | `UpdatedAt` | `DateTime?` | `UpdatedAt` | UTC, auto-updated |
48
+
49
+ ---
50
+
51
+ ## EF Core Mapping Configuration
52
+
53
+ Source: `ApiEndpoints/Minimal.Infra/Features/{EntityFolder}/Mappers/{EntityName}Mapper.cs`
54
+
55
+ Key mapping decisions:
56
+
57
+ | Configuration | Value | Reason |
58
+ |--------------|-------|--------|
59
+ | Table name | `{EntityTableName}` (schema: `dbo`) | Convention |
60
+ | Unique index | `{Field2}` | Business uniqueness constraint |
61
+ | Unique index | `{Field1}` (if applicable) | {Reason} |
62
+ | Global query filter | `IsDeleted == false` | Automatically excludes soft-deleted records from all queries |
63
+ | Column type | `datetime2(7)` for `UpdatedAt` | Sub-second precision for audit trail |
64
+ | Column precision | `nvarchar({N})` for `Field1` | Max length constraint from business rules |
65
+
66
+ ---
67
+
68
+ ## Validation Rules
69
+
70
+ | Field | Rule | Enforcement |
71
+ |-------|------|-------------|
72
+ | `Field2` (e.g., Email) | Must be unique per entity | DB unique index + FluentValidation Spec check before insert |
73
+ | `Field1` (e.g., Name) | 2–{N} characters | FluentValidation in `Create{EntityName}RequestValidator` |
74
+ | `Field3` (e.g., Phone) | Valid phone format if provided | FluentValidation with `.When()` conditional |
75
+ | `Status` | Valid transition only (`Pending → Approved/Rejected`) | Domain entity method enforces valid transitions |
76
+ | Soft delete | `IsDeleted` flag | EF Core Global Query Filter excludes deleted from all queries |
77
+
78
+ ---
79
+
80
+ ## Status Values
81
+
82
+ > Remove this section if the entity has no status field.
83
+
84
+ | Value | Meaning | Transitions to |
85
+ |-------|---------|----------------|
86
+ | `Pending` | Default on create; awaiting review | `Approved`, `Rejected` |
87
+ | `Approved` | Passed review; active | N/A (terminal for workflow) |
88
+ | `Rejected` | Failed review; inactive | N/A (terminal for workflow) |
89
+
90
+ ---
91
+
92
+ ## Migration History
93
+
94
+ | Migration Name | Description |
95
+ |----------------|-------------|
96
+ | `Initial_{EntityName}` | Create initial `{EntityTableName}` table |
97
+ | `Add_{Field}_To_{EntityName}` | {Reason for the change} |
98
+
99
+ > Keep this table updated when running `dotnet ef migrations add <Name> -c CoreDbContext -p Minimal.Infra/Minimal.Infra.csproj`.
@@ -0,0 +1,155 @@
1
+ # {FeatureName} — Domain Events
2
+
3
+ ## Events Published
4
+
5
+ ### {EntityName}CreatedEvent
6
+
7
+ Raised immediately after a new {entityName} is successfully created and persisted.
8
+
9
+ **Published by**: `Create{EntityName}CommandHandler`
10
+
11
+ **Payload**
12
+
13
+ ```csharp
14
+ public sealed record {EntityName}CreatedEvent(Guid Id, string {KeyField});
15
+ ```
16
+
17
+ | Property | Type | Description |
18
+ |----------|------|-------------|
19
+ | `Id` | `Guid` | The newly created {entityName}'s ID |
20
+ | `{KeyField}` | `string` | {Key identifying property, e.g., Name or Email} |
21
+
22
+ **Current Subscribers**
23
+
24
+ | Handler Class | Bus Type | Action |
25
+ |--------------|----------|--------|
26
+ | `{EntityName}CreatedFromMemoryHandler` | In-Memory | Internal audit / testing |
27
+ | _{Add external handlers as they are added}_ | Azure Service Bus | External notifications |
28
+
29
+ **Code Example** — How to subscribe:
30
+
31
+ ```csharp
32
+ internal sealed class SendWelcomeNotificationHandler :
33
+ Fluents.EventsConsumers.IHandler<{EntityName}CreatedEvent>
34
+ {
35
+ public Task OnHandle(
36
+ {EntityName}CreatedEvent notification,
37
+ CancellationToken cancellationToken)
38
+ {
39
+ // TODO: implement side-effect logic
40
+ return Task.CompletedTask;
41
+ }
42
+ }
43
+ ```
44
+
45
+ ---
46
+
47
+ ### {EntityName}StatusChangedEvent
48
+
49
+ > Add this section if status changes (approve/reject) publish events.
50
+
51
+ Raised when a {entityName}'s status changes (e.g., Approved or Rejected).
52
+
53
+ **Published by**: `Approve{EntityName}CommandHandler`, `Reject{EntityName}CommandHandler`
54
+
55
+ **Payload**
56
+
57
+ ```csharp
58
+ public sealed record {EntityName}StatusChangedEvent(
59
+ Guid Id,
60
+ string OldStatus,
61
+ string NewStatus,
62
+ string? Reason);
63
+ ```
64
+
65
+ | Property | Type | Description |
66
+ |----------|------|-------------|
67
+ | `Id` | `Guid` | The {entityName}'s ID |
68
+ | `OldStatus` | `string` | Status before change |
69
+ | `NewStatus` | `string` | Status after change |
70
+ | `Reason` | `string?` | Reason provided (e.g., rejection reason) |
71
+
72
+ **Current Subscribers**
73
+
74
+ | Handler Class | Bus Type | Action |
75
+ |--------------|----------|--------|
76
+ | _{None yet — add as needed}_ | — | — |
77
+
78
+ ---
79
+
80
+ ### {EntityName}DeletedEvent
81
+
82
+ > Add this section only if deletion publishes an event.
83
+
84
+ Raised when a {entityName} is soft-deleted.
85
+
86
+ **Published by**: `Delete{EntityName}CommandHandler`
87
+
88
+ **Payload**
89
+
90
+ ```csharp
91
+ public sealed record {EntityName}DeletedEvent(Guid Id, string DeletedBy);
92
+ ```
93
+
94
+ ---
95
+
96
+ ## Events Consumed
97
+
98
+ > List any events from OTHER features that this feature subscribes to.
99
+ > If none, keep the statement below.
100
+
101
+ This feature does not currently consume events from other features.
102
+
103
+ ---
104
+
105
+ ## Event Bus Configuration
106
+
107
+ Events are dispatched via the Minimal message bus with two bus types:
108
+
109
+ | Bus Type | When Active | Purpose |
110
+ |----------|-------------|---------|
111
+ | **In-Memory** | Always (all environments) | Same-process handlers; local side effects |
112
+ | **Azure Service Bus** | When `ConnectionStrings:AzureBus` is non-empty | Cross-service/process messaging |
113
+
114
+ See `ApiEndpoints/Minimal.Infra/Extensions/ServiceBusSetup.cs` for wiring configuration.
115
+
116
+ ```mermaid
117
+ graph LR
118
+ HDL["Create{EntityName}Handler"]
119
+ EVT["{EntityName}CreatedEvent"]
120
+ MEM["In-Memory Bus"]
121
+ AZ["Azure Service Bus\n(if configured)"]
122
+ INTL["Internal Handlers\n(same process)"]
123
+ EXT["External Systems\n(notifications, billing...)"]
124
+
125
+ HDL -->|PublishAsync| EVT
126
+ EVT --> MEM
127
+ EVT --> AZ
128
+ MEM --> INTL
129
+ AZ --> EXT
130
+ ```
131
+
132
+ ---
133
+
134
+ ## Adding a New Event Subscriber
135
+
136
+ To subscribe to an event from this feature:
137
+
138
+ 1. Create a handler class in the consuming feature's AppServices project
139
+ 2. Implement `Fluents.EventsConsumers.IHandler<TEvent>`
140
+ 3. The message bus auto-discovers handlers via assembly scan — no manual registration needed
141
+
142
+ ```csharp
143
+ // In the consuming feature's AppServices project:
144
+ internal sealed class On{EntityName}CreatedHandler :
145
+ Fluents.EventsConsumers.IHandler<{EntityName}CreatedEvent>
146
+ {
147
+ public Task OnHandle(
148
+ {EntityName}CreatedEvent notification,
149
+ CancellationToken cancellationToken)
150
+ {
151
+ // React to the event
152
+ return Task.CompletedTask;
153
+ }
154
+ }
155
+ ```