dflow-sdd-ddd 0.3.0 → 0.5.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/CHANGELOG.md +118 -0
- package/README.en.md +7 -9
- package/README.md +10 -12
- package/TEMPLATE-COVERAGE.md +1 -1
- package/bin/dflow.js +11 -5
- package/docs/evaluating-dflow.en.md +2 -5
- package/docs/evaluating-dflow.md +1 -3
- package/docs/examples-by-stack.md +516 -0
- package/docs/migrating-to-dflow-v1.md +1 -1
- package/docs/release-versioning-policy.md +13 -0
- package/docs/using-with-claude-code.en.md +38 -8
- package/docs/using-with-claude-code.md +33 -7
- package/docs/using-with-codex.en.md +31 -5
- package/docs/using-with-codex.md +28 -5
- package/docs/using-with-github-copilot.en.md +29 -5
- package/docs/using-with-github-copilot.md +28 -5
- package/lib/init.js +437 -46
- package/package.json +1 -1
- package/templates/brownfield/scaffolding/AI-AGENT-GUIDE.md +42 -3
- package/templates/brownfield/scaffolding/CLAUDE-md-snippet.md +25 -15
- package/templates/brownfield/scaffolding/Git-principles-gitflow.md +1 -1
- package/templates/brownfield/scaffolding/Git-principles-trunk.md +1 -1
- package/templates/brownfield/scaffolding/_conventions.md +1 -1
- package/templates/brownfield/scaffolding/_overview.md +40 -29
- package/templates/brownfield/templates/CLAUDE.md +25 -17
- package/templates/brownfield/templates/context-definition.md +4 -4
- package/templates/brownfield/templates/context-map.md +1 -1
- package/templates/brownfield/templates/lightweight-spec.md +3 -1
- package/templates/brownfield/templates/models.md +1 -1
- package/templates/brownfield/templates/phase-spec.md +10 -8
- package/templates/brownfield/templates/tech-debt.md +2 -2
- package/templates/greenfield/scaffolding/AI-AGENT-GUIDE.md +42 -3
- package/templates/greenfield/scaffolding/CLAUDE-md-snippet.md +7 -6
- package/templates/greenfield/scaffolding/Git-principles-gitflow.md +2 -2
- package/templates/greenfield/scaffolding/Git-principles-trunk.md +2 -2
- package/templates/greenfield/scaffolding/_overview.md +29 -11
- package/templates/greenfield/templates/CLAUDE.md +5 -5
- package/docs/using-with-gemini-cli.en.md +0 -200
- package/docs/using-with-gemini-cli.md +0 -184
|
@@ -0,0 +1,516 @@
|
|
|
1
|
+
# Examples by Stack
|
|
2
|
+
|
|
3
|
+
> A per-stack appendix to Dflow templates. Dflow itself is language- and
|
|
4
|
+
> framework-agnostic; this document shows what canonical placeholders
|
|
5
|
+
> (`{Language}` / `{Framework}` / `{Framework version}` / `{ORM / persistence}`
|
|
6
|
+
> / `{ORM version}` / `{Mediator}` / `{Test framework}`) and stack-neutral
|
|
7
|
+
> prose look like once filled in for common stacks.
|
|
8
|
+
>
|
|
9
|
+
> **How to use this**: after running `dflow init`, open
|
|
10
|
+
> `dflow/specs/shared/_overview.md` and your root `CLAUDE.md`. Replace
|
|
11
|
+
> placeholder rows / directory trees / dependency lists with the snippets
|
|
12
|
+
> from your stack's section below. Adapt as needed — these are starting
|
|
13
|
+
> points, not prescriptions.
|
|
14
|
+
|
|
15
|
+
## Index
|
|
16
|
+
|
|
17
|
+
- [.NET / ASP.NET Core (Greenfield)](#net--aspnet-core-greenfield)
|
|
18
|
+
- [.NET / ASP.NET WebForms (Brownfield)](#net--aspnet-webforms-brownfield)
|
|
19
|
+
- [Java / Spring Boot (Greenfield)](#java--spring-boot-greenfield) — Kotlin/Spring same pattern
|
|
20
|
+
- [Node.js / TypeScript / NestJS (Greenfield)](#nodejs--typescript--nestjs-greenfield)
|
|
21
|
+
- [Python / FastAPI (Greenfield)](#python--fastapi-greenfield) — Django/Flask similar
|
|
22
|
+
- [Go / Gin (Greenfield)](#go--gin-greenfield)
|
|
23
|
+
- [PHP / Laravel (Brownfield migration)](#php--laravel-brownfield-migration)
|
|
24
|
+
|
|
25
|
+
Each section provides:
|
|
26
|
+
|
|
27
|
+
1. **`_overview.md` stack table** — substituted canonical placeholders
|
|
28
|
+
2. **Project layout** — idiomatic directory / package convention
|
|
29
|
+
3. **Domain purity check** — the stack's equivalent of "no delivery-framework references" (used in Git-principles checklist)
|
|
30
|
+
4. **Test framework** — what `{Test framework}` resolves to
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## .NET / ASP.NET Core (Greenfield)
|
|
35
|
+
|
|
36
|
+
### `_overview.md` stack table
|
|
37
|
+
|
|
38
|
+
```markdown
|
|
39
|
+
| Item | Choice |
|
|
40
|
+
|------|--------|
|
|
41
|
+
| Language | C# 12 |
|
|
42
|
+
| Framework | ASP.NET Core 9 |
|
|
43
|
+
| ORM / persistence | Entity Framework Core 9 |
|
|
44
|
+
| Mediator | MediatR 12 |
|
|
45
|
+
| Test framework | xUnit |
|
|
46
|
+
| Database | PostgreSQL 16 |
|
|
47
|
+
| Auth | JWT bearer / OIDC via Azure AD |
|
|
48
|
+
| Hosting | Azure App Service |
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Project layout
|
|
52
|
+
|
|
53
|
+
```
|
|
54
|
+
src/
|
|
55
|
+
├── {Project}.Domain/ # Aggregates, Value Objects, Domain Events
|
|
56
|
+
│ ├── Common/ # Entity, AggregateRoot, ValueObject base classes
|
|
57
|
+
│ ├── {BoundedContext}/
|
|
58
|
+
│ │ ├── Entities/
|
|
59
|
+
│ │ ├── ValueObjects/
|
|
60
|
+
│ │ ├── Events/
|
|
61
|
+
│ │ ├── Services/
|
|
62
|
+
│ │ └── Interfaces/ # Repository / external service interfaces
|
|
63
|
+
│ └── SharedKernel/
|
|
64
|
+
├── {Project}.Application/ # CQRS handlers, validators, DTOs
|
|
65
|
+
│ ├── Common/
|
|
66
|
+
│ └── {BoundedContext}/
|
|
67
|
+
│ ├── Commands/
|
|
68
|
+
│ ├── Queries/
|
|
69
|
+
│ ├── DTOs/
|
|
70
|
+
│ └── EventHandlers/
|
|
71
|
+
├── {Project}.Infrastructure/ # EF Core DbContext, repository impls
|
|
72
|
+
│ ├── Persistence/
|
|
73
|
+
│ ├── Repositories/
|
|
74
|
+
│ └── ExternalServices/
|
|
75
|
+
└── {Project}.WebAPI/ # Presentation: HTTP endpoints
|
|
76
|
+
|
|
77
|
+
tests/
|
|
78
|
+
├── {Project}.Domain.UnitTests/
|
|
79
|
+
├── {Project}.Application.UnitTests/
|
|
80
|
+
└── {Project}.Integration.Tests/
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### Domain purity check
|
|
84
|
+
|
|
85
|
+
The Domain project's `.csproj` should have **zero** package references
|
|
86
|
+
outside the allow-list (typically just the `SharedKernel`). Specifically
|
|
87
|
+
forbid:
|
|
88
|
+
|
|
89
|
+
- `Microsoft.AspNetCore.*`, `System.Web`
|
|
90
|
+
- `Microsoft.EntityFrameworkCore.*` (Domain declares interfaces; Infrastructure references EF Core)
|
|
91
|
+
- `HttpContext`, `HttpRequest`, `ISession`
|
|
92
|
+
- `Newtonsoft.Json` / `System.Text.Json` attributes on Domain entities
|
|
93
|
+
|
|
94
|
+
CI check example: `dotnet list package` on Domain.csproj — fail if any
|
|
95
|
+
disallowed dependency appears.
|
|
96
|
+
|
|
97
|
+
### Test framework
|
|
98
|
+
|
|
99
|
+
`xUnit` + `FluentAssertions` + `NSubstitute`. Run with `dotnet test`.
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
## .NET / ASP.NET WebForms (Brownfield)
|
|
104
|
+
|
|
105
|
+
### `_overview.md` stack table
|
|
106
|
+
|
|
107
|
+
```markdown
|
|
108
|
+
| Item | Current |
|
|
109
|
+
|------|---------|
|
|
110
|
+
| Language | C# 7 (.NET Framework 4.8) |
|
|
111
|
+
| Framework | ASP.NET WebForms 4.8 |
|
|
112
|
+
| ORM / persistence | Entity Framework 6 (or ADO.NET / Dapper) |
|
|
113
|
+
| Test framework | xUnit / NUnit |
|
|
114
|
+
| Database | SQL Server 2019 |
|
|
115
|
+
| UI | WebForms .aspx + Code-Behind + Bootstrap |
|
|
116
|
+
| Auth | Forms authentication / Windows auth |
|
|
117
|
+
| Hosting | IIS on-prem |
|
|
118
|
+
| Target architecture | ASP.NET Core 8 + Clean Architecture |
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### Project layout
|
|
122
|
+
|
|
123
|
+
```
|
|
124
|
+
src/
|
|
125
|
+
├── Domain/ # Extracted domain logic (framework-pure)
|
|
126
|
+
│ ├── {BoundedContext}/
|
|
127
|
+
│ │ ├── Entities/
|
|
128
|
+
│ │ ├── ValueObjects/
|
|
129
|
+
│ │ └── Services/
|
|
130
|
+
│ └── SharedKernel/
|
|
131
|
+
└── WebForms/ # Existing .aspx + .aspx.cs (Code-Behind)
|
|
132
|
+
└── Pages/
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### Domain purity check
|
|
136
|
+
|
|
137
|
+
The Domain assembly must not reference:
|
|
138
|
+
|
|
139
|
+
- `System.Web.*`, `System.Web.UI.*`
|
|
140
|
+
- `HttpContext.Current`, `Session[…]`, `ViewState[…]`
|
|
141
|
+
- Page lifecycle types (`Page`, `Control`)
|
|
142
|
+
- EF6 attributes on Domain entities (use Fluent API in a separate
|
|
143
|
+
configuration class outside Domain)
|
|
144
|
+
|
|
145
|
+
CI check: project reference analyzer on `src/Domain/Domain.csproj`.
|
|
146
|
+
|
|
147
|
+
### Test framework
|
|
148
|
+
|
|
149
|
+
`xUnit` or `NUnit`. Run with `dotnet test` or `nunit3-console`.
|
|
150
|
+
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
## Java / Spring Boot (Greenfield)
|
|
154
|
+
|
|
155
|
+
> Same pattern applies to Kotlin/Spring with minor syntax differences.
|
|
156
|
+
|
|
157
|
+
### `_overview.md` stack table
|
|
158
|
+
|
|
159
|
+
```markdown
|
|
160
|
+
| Item | Choice |
|
|
161
|
+
|------|--------|
|
|
162
|
+
| Language | Java 21 |
|
|
163
|
+
| Framework | Spring Boot 3.3 |
|
|
164
|
+
| ORM / persistence | Spring Data JPA / Hibernate 6.5 |
|
|
165
|
+
| Mediator | (none — direct service injection; optional: Spring Modulith) |
|
|
166
|
+
| Test framework | JUnit 5 + AssertJ + Mockito |
|
|
167
|
+
| Database | PostgreSQL 16 |
|
|
168
|
+
| Auth | Spring Security + OAuth2 / OIDC |
|
|
169
|
+
| Hosting | Kubernetes / managed app platform |
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### Project layout
|
|
173
|
+
|
|
174
|
+
```
|
|
175
|
+
src/
|
|
176
|
+
├── main/
|
|
177
|
+
│ └── java/com/example/{system}/
|
|
178
|
+
│ ├── domain/ # Aggregates, Value Objects, Domain Events
|
|
179
|
+
│ │ ├── common/ # Base classes (Entity, AggregateRoot, ValueObject)
|
|
180
|
+
│ │ ├── {boundedcontext}/
|
|
181
|
+
│ │ │ ├── entity/
|
|
182
|
+
│ │ │ ├── valueobject/
|
|
183
|
+
│ │ │ ├── event/
|
|
184
|
+
│ │ │ ├── service/
|
|
185
|
+
│ │ │ └── repository/ # Repository interfaces (NOT implementations)
|
|
186
|
+
│ │ └── sharedkernel/
|
|
187
|
+
│ ├── application/ # Command/Query handlers, DTOs
|
|
188
|
+
│ │ ├── command/
|
|
189
|
+
│ │ ├── query/
|
|
190
|
+
│ │ └── dto/
|
|
191
|
+
│ ├── infrastructure/ # JPA repositories, external clients
|
|
192
|
+
│ │ ├── persistence/
|
|
193
|
+
│ │ └── client/
|
|
194
|
+
│ └── web/ # Controllers, REST endpoints
|
|
195
|
+
└── test/
|
|
196
|
+
└── java/com/example/{system}/
|
|
197
|
+
├── domain/ # Unit tests
|
|
198
|
+
├── application/
|
|
199
|
+
└── web/ # @SpringBootTest integration
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
Multi-module Maven/Gradle layouts (one module per layer) are also common
|
|
203
|
+
and recommended for stricter dependency enforcement.
|
|
204
|
+
|
|
205
|
+
### Domain purity check
|
|
206
|
+
|
|
207
|
+
The Domain package must not import:
|
|
208
|
+
|
|
209
|
+
- `org.springframework.*` (no Spring annotations on Domain entities)
|
|
210
|
+
- `jakarta.persistence.*` / `javax.persistence.*` (no JPA annotations on
|
|
211
|
+
Domain entities; use a separate JPA mapping class in Infrastructure)
|
|
212
|
+
- `jakarta.servlet.*` (no HTTP types)
|
|
213
|
+
- `com.fasterxml.jackson.*` (no serialization annotations on Domain)
|
|
214
|
+
|
|
215
|
+
CI check: ArchUnit rule `noClasses().that().resideInAPackage("..domain..")
|
|
216
|
+
.should().dependOnClassesThat().resideInAnyPackage("org.springframework..", "jakarta.persistence..")`.
|
|
217
|
+
|
|
218
|
+
### Test framework
|
|
219
|
+
|
|
220
|
+
`JUnit 5` (`org.junit.jupiter`). Run with `./mvnw test` or `./gradlew test`.
|
|
221
|
+
|
|
222
|
+
---
|
|
223
|
+
|
|
224
|
+
## Node.js / TypeScript / NestJS (Greenfield)
|
|
225
|
+
|
|
226
|
+
### `_overview.md` stack table
|
|
227
|
+
|
|
228
|
+
```markdown
|
|
229
|
+
| Item | Choice |
|
|
230
|
+
|------|--------|
|
|
231
|
+
| Language | TypeScript 5.4 |
|
|
232
|
+
| Framework | NestJS 10 |
|
|
233
|
+
| ORM / persistence | Prisma 5 (or TypeORM / MikroORM) |
|
|
234
|
+
| Mediator | (none — NestJS providers; optional: nestjs-cqrs module) |
|
|
235
|
+
| Test framework | Vitest (or Jest) + supertest |
|
|
236
|
+
| Database | PostgreSQL 16 |
|
|
237
|
+
| Auth | Passport (JWT, OAuth2) |
|
|
238
|
+
| Hosting | Containerized (Docker / Kubernetes / Fly.io) |
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
### Project layout
|
|
242
|
+
|
|
243
|
+
```
|
|
244
|
+
src/
|
|
245
|
+
├── domain/ # Aggregates, Value Objects, Domain Events
|
|
246
|
+
│ ├── common/ # Base classes
|
|
247
|
+
│ ├── {bounded-context}/
|
|
248
|
+
│ │ ├── entities/
|
|
249
|
+
│ │ ├── value-objects/
|
|
250
|
+
│ │ ├── events/
|
|
251
|
+
│ │ ├── services/
|
|
252
|
+
│ │ └── repositories/ # Interfaces only
|
|
253
|
+
│ └── shared-kernel/
|
|
254
|
+
├── application/ # Use cases, command/query handlers
|
|
255
|
+
│ ├── commands/
|
|
256
|
+
│ ├── queries/
|
|
257
|
+
│ └── dtos/
|
|
258
|
+
├── infrastructure/ # Prisma client, external API clients
|
|
259
|
+
│ ├── persistence/
|
|
260
|
+
│ └── external/
|
|
261
|
+
└── presentation/ # NestJS controllers, modules
|
|
262
|
+
└── http/
|
|
263
|
+
|
|
264
|
+
test/
|
|
265
|
+
├── domain/
|
|
266
|
+
├── application/
|
|
267
|
+
└── e2e/
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
### Domain purity check
|
|
271
|
+
|
|
272
|
+
`src/domain/` files must not import:
|
|
273
|
+
|
|
274
|
+
- `@nestjs/*` (no `@Injectable`, `@Module`, decorators on Domain)
|
|
275
|
+
- `@prisma/client` (Prisma generated client lives in Infrastructure only)
|
|
276
|
+
- `express` / `fastify` types
|
|
277
|
+
- `class-transformer` / `class-validator` (use plain TS types; validation
|
|
278
|
+
in Application layer)
|
|
279
|
+
|
|
280
|
+
CI check: ESLint rule `no-restricted-imports` scoped to `src/domain/**` or
|
|
281
|
+
`dependency-cruiser` rule forbidding cross-layer imports.
|
|
282
|
+
|
|
283
|
+
### Test framework
|
|
284
|
+
|
|
285
|
+
`Vitest` (or `Jest`). Run with `npm test` or `pnpm test`.
|
|
286
|
+
|
|
287
|
+
---
|
|
288
|
+
|
|
289
|
+
## Python / FastAPI (Greenfield)
|
|
290
|
+
|
|
291
|
+
> Django and Flask follow the same layered pattern with framework-specific
|
|
292
|
+
> presentation conventions. Django: views/templates as presentation;
|
|
293
|
+
> Flask: blueprints; FastAPI: routers.
|
|
294
|
+
|
|
295
|
+
### `_overview.md` stack table
|
|
296
|
+
|
|
297
|
+
```markdown
|
|
298
|
+
| Item | Choice |
|
|
299
|
+
|------|--------|
|
|
300
|
+
| Language | Python 3.12 |
|
|
301
|
+
| Framework | FastAPI 0.115 |
|
|
302
|
+
| ORM / persistence | SQLAlchemy 2.0 + Alembic (or SQLModel) |
|
|
303
|
+
| Mediator | (none — typed dependency injection via FastAPI Depends) |
|
|
304
|
+
| Test framework | pytest + pytest-asyncio |
|
|
305
|
+
| Database | PostgreSQL 16 |
|
|
306
|
+
| Auth | OAuth2 via fastapi.security (PasswordBearer / JWT) |
|
|
307
|
+
| Hosting | Containerized (Docker / Kubernetes / Fly.io) |
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
### Project layout
|
|
311
|
+
|
|
312
|
+
```
|
|
313
|
+
src/
|
|
314
|
+
├── domain/ # Aggregates, Value Objects, Domain Events
|
|
315
|
+
│ ├── common/
|
|
316
|
+
│ ├── {bounded_context}/
|
|
317
|
+
│ │ ├── entities.py
|
|
318
|
+
│ │ ├── value_objects.py
|
|
319
|
+
│ │ ├── events.py
|
|
320
|
+
│ │ ├── services.py
|
|
321
|
+
│ │ └── repositories.py # Protocol / abstract base classes
|
|
322
|
+
│ └── shared_kernel/
|
|
323
|
+
├── application/ # Use cases, DTOs
|
|
324
|
+
│ ├── commands/
|
|
325
|
+
│ ├── queries/
|
|
326
|
+
│ └── dtos/
|
|
327
|
+
├── infrastructure/ # SQLAlchemy models, external clients
|
|
328
|
+
│ ├── persistence/
|
|
329
|
+
│ └── external/
|
|
330
|
+
└── presentation/ # FastAPI routers
|
|
331
|
+
└── api/
|
|
332
|
+
|
|
333
|
+
tests/
|
|
334
|
+
├── domain/
|
|
335
|
+
├── application/
|
|
336
|
+
└── integration/
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
### Domain purity check
|
|
340
|
+
|
|
341
|
+
`src/domain/` modules must not import:
|
|
342
|
+
|
|
343
|
+
- `fastapi` / `starlette`
|
|
344
|
+
- `sqlalchemy.*` (use Protocols / dataclasses in Domain; SQLAlchemy models
|
|
345
|
+
live in Infrastructure as separate mapping classes)
|
|
346
|
+
- `pydantic.BaseModel` for Domain entities (use `dataclass` or plain
|
|
347
|
+
classes; Pydantic models belong in DTO / API layer)
|
|
348
|
+
|
|
349
|
+
CI check: `import-linter` (`importlinter.org`) contract forbidding Domain
|
|
350
|
+
imports of presentation/infrastructure packages.
|
|
351
|
+
|
|
352
|
+
### Test framework
|
|
353
|
+
|
|
354
|
+
`pytest`. Run with `pytest` or `python -m pytest`.
|
|
355
|
+
|
|
356
|
+
---
|
|
357
|
+
|
|
358
|
+
## Go / Gin (Greenfield)
|
|
359
|
+
|
|
360
|
+
### `_overview.md` stack table
|
|
361
|
+
|
|
362
|
+
```markdown
|
|
363
|
+
| Item | Choice |
|
|
364
|
+
|------|--------|
|
|
365
|
+
| Language | Go 1.22 |
|
|
366
|
+
| Framework | Gin 1.10 (or Echo / Chi) |
|
|
367
|
+
| ORM / persistence | GORM v2 (or sqlx / pgx) |
|
|
368
|
+
| Mediator | (none — interface-based dispatch) |
|
|
369
|
+
| Test framework | go test + testify |
|
|
370
|
+
| Database | PostgreSQL 16 |
|
|
371
|
+
| Auth | JWT middleware / OAuth2 |
|
|
372
|
+
| Hosting | Containerized (Docker / Kubernetes / Fly.io) |
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
### Project layout
|
|
376
|
+
|
|
377
|
+
```
|
|
378
|
+
{module-root}/
|
|
379
|
+
├── cmd/
|
|
380
|
+
│ └── api/main.go # Application entrypoint
|
|
381
|
+
├── internal/
|
|
382
|
+
│ ├── domain/ # Aggregates, Value Objects, Domain Events
|
|
383
|
+
│ │ ├── common/
|
|
384
|
+
│ │ ├── {boundedcontext}/
|
|
385
|
+
│ │ │ ├── entity.go
|
|
386
|
+
│ │ │ ├── valueobject.go
|
|
387
|
+
│ │ │ ├── event.go
|
|
388
|
+
│ │ │ ├── service.go
|
|
389
|
+
│ │ │ └── repository.go # Interface only
|
|
390
|
+
│ │ └── sharedkernel/
|
|
391
|
+
│ ├── application/ # Use cases
|
|
392
|
+
│ │ ├── command/
|
|
393
|
+
│ │ └── query/
|
|
394
|
+
│ ├── infrastructure/ # GORM repo impls, external clients
|
|
395
|
+
│ │ ├── persistence/
|
|
396
|
+
│ │ └── external/
|
|
397
|
+
│ └── handler/ # HTTP handlers (Gin routes)
|
|
398
|
+
└── go.mod
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
`internal/` enforces Go's import boundary — packages outside the module
|
|
402
|
+
cannot import from `internal/...`.
|
|
403
|
+
|
|
404
|
+
### Domain purity check
|
|
405
|
+
|
|
406
|
+
`internal/domain/` packages must not import:
|
|
407
|
+
|
|
408
|
+
- `github.com/gin-gonic/gin` or any HTTP router package
|
|
409
|
+
- `gorm.io/gorm` (Domain declares repository interfaces; GORM lives in
|
|
410
|
+
Infrastructure)
|
|
411
|
+
- `net/http` types (`http.Request`, `http.ResponseWriter`)
|
|
412
|
+
- Encoding tags (e.g. `gorm:"primaryKey"`, `json:"..."`) on Domain
|
|
413
|
+
entities — keep tag-free, do encoding via separate Infrastructure
|
|
414
|
+
models
|
|
415
|
+
|
|
416
|
+
CI check: `go vet` plus a custom `go-arch-lint` or `golangci-lint` rule
|
|
417
|
+
forbidding `internal/domain` from importing the above.
|
|
418
|
+
|
|
419
|
+
### Test framework
|
|
420
|
+
|
|
421
|
+
`go test` (standard library) + `stretchr/testify` for assertions.
|
|
422
|
+
Run with `go test ./...`.
|
|
423
|
+
|
|
424
|
+
---
|
|
425
|
+
|
|
426
|
+
## PHP / Laravel (Brownfield migration)
|
|
427
|
+
|
|
428
|
+
> Older PHP monoliths (Symfony 2/3, CodeIgniter, custom) follow similar
|
|
429
|
+
> extraction patterns; the snippets below are for a modern Laravel app
|
|
430
|
+
> already on Laravel 10+ that wants to introduce a Domain layer.
|
|
431
|
+
|
|
432
|
+
### `_overview.md` stack table
|
|
433
|
+
|
|
434
|
+
```markdown
|
|
435
|
+
| Item | Current |
|
|
436
|
+
|------|---------|
|
|
437
|
+
| Language | PHP 8.3 |
|
|
438
|
+
| Framework | Laravel 11 |
|
|
439
|
+
| ORM / persistence | Eloquent ORM (Active Record pattern — see Domain note) |
|
|
440
|
+
| Test framework | PHPUnit 11 (or Pest 2) |
|
|
441
|
+
| Database | MySQL 8 / MariaDB 10 |
|
|
442
|
+
| UI | Blade templates / Inertia + Vue / API-only |
|
|
443
|
+
| Auth | Laravel Breeze / Sanctum / Passport |
|
|
444
|
+
| Hosting | Laravel Forge / shared hosting / containerized |
|
|
445
|
+
| Target architecture | Same Laravel + extracted Domain layer + repository abstractions |
|
|
446
|
+
```
|
|
447
|
+
|
|
448
|
+
### Project layout
|
|
449
|
+
|
|
450
|
+
```
|
|
451
|
+
app/
|
|
452
|
+
├── Domain/ # Extracted domain logic (framework-pure)
|
|
453
|
+
│ ├── Common/
|
|
454
|
+
│ ├── {BoundedContext}/
|
|
455
|
+
│ │ ├── Entities/ # Plain PHP classes (NOT Eloquent models)
|
|
456
|
+
│ │ ├── ValueObjects/
|
|
457
|
+
│ │ ├── Events/
|
|
458
|
+
│ │ ├── Services/
|
|
459
|
+
│ │ └── Repositories/ # Interfaces only
|
|
460
|
+
│ └── SharedKernel/
|
|
461
|
+
├── Application/ # Use cases, command/query handlers
|
|
462
|
+
│ ├── Commands/
|
|
463
|
+
│ └── Queries/
|
|
464
|
+
├── Infrastructure/ # Eloquent repository implementations
|
|
465
|
+
│ ├── Persistence/
|
|
466
|
+
│ │ ├── Eloquent/ # Eloquent models live HERE, not in Domain
|
|
467
|
+
│ │ └── Repositories/
|
|
468
|
+
│ └── External/
|
|
469
|
+
├── Http/ # Controllers, middleware (Laravel-managed)
|
|
470
|
+
│ ├── Controllers/
|
|
471
|
+
│ └── Middleware/
|
|
472
|
+
└── Providers/
|
|
473
|
+
|
|
474
|
+
tests/
|
|
475
|
+
├── Unit/Domain/
|
|
476
|
+
├── Feature/Application/
|
|
477
|
+
└── Feature/Http/
|
|
478
|
+
```
|
|
479
|
+
|
|
480
|
+
### Domain purity check
|
|
481
|
+
|
|
482
|
+
`app/Domain/` classes must not extend / use:
|
|
483
|
+
|
|
484
|
+
- `Illuminate\Database\Eloquent\Model` (Eloquent models are Infrastructure)
|
|
485
|
+
- `Illuminate\Http\Request` / `Response`
|
|
486
|
+
- `Illuminate\Support\Facades\*` (DB, Auth, Cache, etc.)
|
|
487
|
+
- Laravel attribute / trait magic on Domain entities
|
|
488
|
+
|
|
489
|
+
CI check: a Laravel-aware static analysis rule (Larastan / PHPStan with a
|
|
490
|
+
custom architecture rule) forbidding `app/Domain/` from referencing the
|
|
491
|
+
above.
|
|
492
|
+
|
|
493
|
+
### Test framework
|
|
494
|
+
|
|
495
|
+
`PHPUnit` (`phpunit/phpunit`) or `Pest` (`pestphp/pest`). Run with
|
|
496
|
+
`./vendor/bin/phpunit` or `./vendor/bin/pest`.
|
|
497
|
+
|
|
498
|
+
---
|
|
499
|
+
|
|
500
|
+
## Adding your stack
|
|
501
|
+
|
|
502
|
+
If your stack isn't listed (Rust, Ruby/Rails, Kotlin native, Elixir, etc.),
|
|
503
|
+
the pattern is always the same:
|
|
504
|
+
|
|
505
|
+
1. Identify your stack's **domain layer convention** (folder / package /
|
|
506
|
+
namespace where pure business code lives)
|
|
507
|
+
2. Identify the **delivery / entrypoint layer** (controllers, handlers,
|
|
508
|
+
routes, CLI commands, message consumers, job runners)
|
|
509
|
+
3. Identify the **persistence layer** (ORM, query builder, raw driver)
|
|
510
|
+
4. Domain purity check = "no imports / usings / extends from delivery,
|
|
511
|
+
persistence, or framework runtime packages"
|
|
512
|
+
5. Express the layer separation in a CI-enforceable rule appropriate to
|
|
513
|
+
the stack (ArchUnit, ESLint, import-linter, go-arch-lint, Larastan,
|
|
514
|
+
etc.)
|
|
515
|
+
|
|
516
|
+
Contributions of additional stacks via PR are welcome.
|
|
@@ -163,7 +163,7 @@ shell command instead.
|
|
|
163
163
|
V1 separates the canonical project guide from each per-tool
|
|
164
164
|
instruction file (PROPOSAL-020). The canonical guide lives at
|
|
165
165
|
`dflow/specs/shared/AI-AGENT-GUIDE.md`. Per-tool files (`AGENTS.md`,
|
|
166
|
-
`CLAUDE.md`,
|
|
166
|
+
`CLAUDE.md`, `.github/copilot-instructions.md`) are thin
|
|
167
167
|
shims pointing at the canonical guide.
|
|
168
168
|
|
|
169
169
|
If your project's `CLAUDE.md` (or equivalent) was generated by an
|
|
@@ -44,6 +44,19 @@ Examples:
|
|
|
44
44
|
- Changing command behavior in a way that invalidates existing docs.
|
|
45
45
|
- Replacing a workflow contract that AI agents rely on.
|
|
46
46
|
|
|
47
|
+
Counter-examples (NOT breaking):
|
|
48
|
+
|
|
49
|
+
- Replacing stack-specific framing with stack-neutral umbrella terms when
|
|
50
|
+
the architectural meaning is unchanged (e.g., "Code-Behind" →
|
|
51
|
+
"delivery/entrypoint code") — adopter's existing files are not
|
|
52
|
+
rewritten by Dflow.
|
|
53
|
+
- Renaming an init placeholder if the previous name still resolves via a
|
|
54
|
+
backward-compat alias and the substituted value is identical (e.g.,
|
|
55
|
+
`{ASP.NET Core version}` continuing to resolve while `{Framework version}`
|
|
56
|
+
becomes canonical).
|
|
57
|
+
- Adding a new optional placeholder; existing templates that don't use it
|
|
58
|
+
are unaffected.
|
|
59
|
+
|
|
47
60
|
## Release Ownership
|
|
48
61
|
|
|
49
62
|
Dflow currently has four release surfaces:
|
|
@@ -81,9 +81,9 @@ custom project instructions you already had.
|
|
|
81
81
|
|
|
82
82
|
## Using Dflow Slash Commands in Claude Code
|
|
83
83
|
|
|
84
|
-
Dflow's `/dflow:*` slash commands are workflow names
|
|
85
|
-
through the workflow table in `AI-AGENT-GUIDE.md`, not
|
|
86
|
-
built-in slash command system. You type them as plain chat:
|
|
84
|
+
By default, Dflow's canonical `/dflow:*` slash commands are workflow names
|
|
85
|
+
recognized by the AI through the workflow table in `AI-AGENT-GUIDE.md`, not
|
|
86
|
+
Claude Code's built-in slash command system. You type them as plain chat:
|
|
87
87
|
|
|
88
88
|
```text
|
|
89
89
|
/dflow:new-feature
|
|
@@ -131,6 +131,27 @@ If you forget a command name, ask Claude Code "what dflow workflows are
|
|
|
131
131
|
available?" — the answer comes from the workflow table it already has
|
|
132
132
|
loaded.
|
|
133
133
|
|
|
134
|
+
### Optional Command Adapters
|
|
135
|
+
|
|
136
|
+
If you want Claude Code to expose tool-native command entries, run this in an
|
|
137
|
+
initialized project:
|
|
138
|
+
|
|
139
|
+
```bash
|
|
140
|
+
dflow configure-agents --command-adapters
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
After you select Claude Code, Dflow projects thin wrappers from the command
|
|
144
|
+
registry inside the canonical guide:
|
|
145
|
+
|
|
146
|
+
- `.claude/commands/dflow/dflow-<id>.md`
|
|
147
|
+
|
|
148
|
+
These wrappers use adapter-native names, for example `/dflow-new-feature`.
|
|
149
|
+
Their body only points to the canonical `/dflow:new-feature` workflow and
|
|
150
|
+
`dflow/specs/shared/AI-AGENT-GUIDE.md`; it does not copy workflow steps.
|
|
151
|
+
Dflow v1 does not promise that Claude Code's menu will expose the exact
|
|
152
|
+
colon form `/dflow:new-feature`. The canonical name remains in the guide and
|
|
153
|
+
wrapper body.
|
|
154
|
+
|
|
134
155
|
## Differences vs Other AI Tools
|
|
135
156
|
|
|
136
157
|
The canonical guide (`dflow/specs/shared/AI-AGENT-GUIDE.md`) is identical
|
|
@@ -140,7 +161,6 @@ across tools. Only the root-level shim differs:
|
|
|
140
161
|
|---|---|---|
|
|
141
162
|
| Claude Code | `CLAUDE.md` | `@dflow/specs/shared/AI-AGENT-GUIDE.md` Markdown import |
|
|
142
163
|
| Codex / Copilot coding agent | `AGENTS.md` | Reads file content directly when starting |
|
|
143
|
-
| Gemini CLI | `GEMINI.md` | `@dflow/specs/shared/AI-AGENT-GUIDE.md` Markdown import |
|
|
144
164
|
| GitHub Copilot | `.github/copilot-instructions.md` | Reads file content directly |
|
|
145
165
|
|
|
146
166
|
You can run `dflow configure-agents` later to add another tool's shim without
|
|
@@ -158,10 +178,20 @@ spec locations, or SDD constraints to `CLAUDE.md`, those belong in
|
|
|
158
178
|
`dflow/specs/shared/AI-AGENT-GUIDE.md` instead. The shim stays small so
|
|
159
179
|
that other tools' shims don't drift away from it.
|
|
160
180
|
|
|
161
|
-
|
|
162
|
-
install anything into Claude Code's skill system. The slash commands are
|
|
163
|
-
plain text patterns the AI recognizes from the workflow table.
|
|
164
|
-
|
|
181
|
+
**Default `/dflow:*` is not a Claude Code Skill installation.** `init` does
|
|
182
|
+
not install anything into Claude Code's skill system. The slash commands are
|
|
183
|
+
plain text patterns the AI recognizes from the workflow table. If you later
|
|
184
|
+
run `dflow configure-agents --command-adapters`, the added files are thin
|
|
185
|
+
command wrappers, not a second workflow definition.
|
|
186
|
+
|
|
187
|
+
**Choose either legacy Claude skills or the installed adapter.** If the
|
|
188
|
+
project still has legacy `.claude/skills/sdd-ddd-*` skills, choose either
|
|
189
|
+
those skills or `--command-adapters`. If they must temporarily coexist, use
|
|
190
|
+
Claude Code skill override / `disable-model-invocation` settings to prevent
|
|
191
|
+
the legacy skill from auto-triggering. Otherwise the same `/dflow:*` intent
|
|
192
|
+
may trigger both the legacy skill and the installed adapter. Installed
|
|
193
|
+
adapter wrappers must stay thin pointers and should not copy workflow
|
|
194
|
+
semantics.
|
|
165
195
|
|
|
166
196
|
**Permission gates and Dflow workflow gates are separate.** Claude Code may
|
|
167
197
|
ask permission to run a tool (e.g., write a file). Dflow's workflows have
|
|
@@ -73,9 +73,9 @@ source-of-truth 檔案路徑,以及核心 SDD/DDD 規則。`CLAUDE.md` shim
|
|
|
73
73
|
|
|
74
74
|
## 在 Claude Code 中使用 Dflow Slash Commands
|
|
75
75
|
|
|
76
|
-
Dflow 的 `/dflow:*` slash commands 是 AI 透過
|
|
77
|
-
workflow 表識別的 workflow 名稱,不是 Claude Code
|
|
78
|
-
|
|
76
|
+
預設情況下,Dflow 的 canonical `/dflow:*` slash commands 是 AI 透過
|
|
77
|
+
`AI-AGENT-GUIDE.md` 中的 workflow 表識別的 workflow 名稱,不是 Claude Code
|
|
78
|
+
內建的 slash command 系統。你以普通對話方式輸入它們:
|
|
79
79
|
|
|
80
80
|
```text
|
|
81
81
|
/dflow:new-feature
|
|
@@ -120,6 +120,25 @@ skill 檔案來執行它們。
|
|
|
120
120
|
如果你忘了指令名稱,問 Claude Code「what dflow workflows are available?」
|
|
121
121
|
即可 —— 答案會從它已載入的 workflow 表中給出。
|
|
122
122
|
|
|
123
|
+
### 選配 Command Adapters
|
|
124
|
+
|
|
125
|
+
如果想讓 Claude Code 看到工具原生的命令入口,可在已初始化的專案中執行:
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
dflow configure-agents --command-adapters
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
選擇 Claude Code 後,Dflow 會從 canonical guide 內的 command registry
|
|
132
|
+
投影產生薄 wrapper:
|
|
133
|
+
|
|
134
|
+
- `.claude/commands/dflow/dflow-<id>.md`
|
|
135
|
+
|
|
136
|
+
這些 wrapper 使用 adapter-native 命名,例如 `/dflow-new-feature`。Wrapper
|
|
137
|
+
內容只指向 canonical `/dflow:new-feature` workflow 與
|
|
138
|
+
`dflow/specs/shared/AI-AGENT-GUIDE.md`,不複製 workflow 步驟。Dflow v1 不承諾
|
|
139
|
+
Claude Code 選單中一定會出現 exact `/dflow:new-feature` colon 形式;canonical
|
|
140
|
+
名稱仍保留在 guide 與 wrapper body 中。
|
|
141
|
+
|
|
123
142
|
## 與其他 AI 工具的差異
|
|
124
143
|
|
|
125
144
|
canonical 指南(`dflow/specs/shared/AI-AGENT-GUIDE.md`)在各工具之間是相同的。
|
|
@@ -129,7 +148,6 @@ canonical 指南(`dflow/specs/shared/AI-AGENT-GUIDE.md`)在各工具之間
|
|
|
129
148
|
|---|---|---|
|
|
130
149
|
| Claude Code | `CLAUDE.md` | `@dflow/specs/shared/AI-AGENT-GUIDE.md` Markdown import |
|
|
131
150
|
| Codex / Copilot coding agent | `AGENTS.md` | 啟動時直接讀取檔案內容 |
|
|
132
|
-
| Gemini CLI | `GEMINI.md` | `@dflow/specs/shared/AI-AGENT-GUIDE.md` Markdown import |
|
|
133
151
|
| GitHub Copilot | `.github/copilot-instructions.md` | 直接讀取檔案內容 |
|
|
134
152
|
|
|
135
153
|
你可以之後執行 `dflow configure-agents` 來新增另一個工具的 shim,而不需要重跑
|
|
@@ -146,9 +164,17 @@ SDD 約束加入 `CLAUDE.md`,這些內容應該放到
|
|
|
146
164
|
`dflow/specs/shared/AI-AGENT-GUIDE.md`。shim 保持精簡,其他工具的 shim 才不會
|
|
147
165
|
與它產生漂移(drift)。
|
|
148
166
|
|
|
149
|
-
|
|
150
|
-
系統中安裝任何東西。Slash commands 是 AI 從 workflow 表識別的純文字模式。
|
|
151
|
-
|
|
167
|
+
**預設 `/dflow:*` 不是安裝 Claude Code Skill。** `init` 不會在 Claude Code 的
|
|
168
|
+
skill 系統中安裝任何東西。Slash commands 是 AI 從 workflow 表識別的純文字模式。
|
|
169
|
+
若你之後執行 `dflow configure-agents --command-adapters`,新增的是薄 command
|
|
170
|
+
wrapper,不是 workflow 的第二份定義。
|
|
171
|
+
|
|
172
|
+
**legacy Claude skill 與 installed adapter 擇一。** 如果專案仍保留舊的
|
|
173
|
+
`.claude/skills/sdd-ddd-*` skill,請在 legacy skill 與 `--command-adapters`
|
|
174
|
+
之間擇一使用。若必須暫時共存,請用 Claude Code 的 skill override /
|
|
175
|
+
`disable-model-invocation` 設定避免 legacy skill 自動觸發,否則同一個
|
|
176
|
+
`/dflow:*` 意圖可能同時觸發 legacy skill 與 installed adapter。Installed
|
|
177
|
+
adapter wrapper 必須保持薄指標,不應複製 workflow 語義。
|
|
152
178
|
|
|
153
179
|
**Permission gates 與 Dflow workflow gates 是分開的。** Claude Code 可能會詢問
|
|
154
180
|
執行某個工具的權限(例如寫入檔案)。Dflow 的 workflow 有自己的審核關卡(例如
|