guardian-framework 0.1.22 → 0.1.23
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/dist/cli.js +28 -2
- package/dist/exports.js +28 -2
- package/package.json +1 -1
- package/templates/languages/angular-patterns.md +38 -0
- package/templates/languages/nextjs-patterns.md +39 -0
- package/templates/pi/extensions/architect-lib/helpers.ts +2 -0
- package/templates/pi/preflight_report.json +1 -1
- package/templates/pi/scripts/ci/check_ddd_structure.sh +3 -1
- package/templates/pi/skills/agents/angular-codegen.md +36 -0
- package/templates/pi/skills/agents/nextjs-codegen.md +34 -0
- package/templates/pi/skills/angular-enterprise-codegen.md +158 -0
- package/templates/pi/skills/nextjs-enterprise-codegen.md +138 -0
package/dist/cli.js
CHANGED
|
@@ -1335,7 +1335,7 @@ __export(exports_package, {
|
|
|
1335
1335
|
bin: () => bin,
|
|
1336
1336
|
author: () => author
|
|
1337
1337
|
});
|
|
1338
|
-
var name = "guardian-framework", version = "0.1.
|
|
1338
|
+
var name = "guardian-framework", version = "0.1.23", description = "Token-optimized agentic framework scaffolder with pi-first architecture", type = "module", main = "dist/exports.js", exports, types = "dist/exports.d.ts", bin, files, engines, scripts, publishConfig, pi, repository, homepage = "https://github.com/arman-jalili/guardian-framework#readme", bugs, dependencies, devDependencies, keywords, author = "Arman Wolkensteiner-Jalili", license = "MIT", package_default;
|
|
1339
1339
|
var init_package = __esm(() => {
|
|
1340
1340
|
exports = {
|
|
1341
1341
|
".": {
|
|
@@ -1571,7 +1571,7 @@ var init_templates = __esm(() => {
|
|
|
1571
1571
|
TEMPLATE_DIR = findTemplateDir();
|
|
1572
1572
|
PI_TEMPLATE_DIR = path4.join(TEMPLATE_DIR, "pi");
|
|
1573
1573
|
LANGUAGES_DIR = path4.join(TEMPLATE_DIR, "languages");
|
|
1574
|
-
SUPPORTED_LANGUAGES = ["typescript", "rust", "python", "go", "java"];
|
|
1574
|
+
SUPPORTED_LANGUAGES = ["typescript", "rust", "python", "go", "java", "nextjs", "angular"];
|
|
1575
1575
|
AVAILABLE_VALIDATORS = [
|
|
1576
1576
|
"ci",
|
|
1577
1577
|
"tests",
|
|
@@ -1677,6 +1677,30 @@ var init_templates = __esm(() => {
|
|
|
1677
1677
|
tracingPattern: "Micrometer Observation / SLF4j MDC",
|
|
1678
1678
|
cancellationPattern: "Reactive Streams cancellation / @Async CompletableFuture",
|
|
1679
1679
|
atomicWritePattern: "Spring Data CrudRepository.save()"
|
|
1680
|
+
},
|
|
1681
|
+
nextjs: {
|
|
1682
|
+
buildCommand: "npm run build",
|
|
1683
|
+
testCommand: "npm test",
|
|
1684
|
+
lintCommand: "next lint",
|
|
1685
|
+
formatCommand: "prettier --write .",
|
|
1686
|
+
formatCheckCommand: "prettier --check .",
|
|
1687
|
+
securityAuditCommand: "npm audit",
|
|
1688
|
+
errorHandlingPattern: "Result type pattern (ok/error)",
|
|
1689
|
+
tracingPattern: "Structured JSON logging with pino",
|
|
1690
|
+
cancellationPattern: "AbortController pattern",
|
|
1691
|
+
atomicWritePattern: "Write-rename with .tmp file"
|
|
1692
|
+
},
|
|
1693
|
+
angular: {
|
|
1694
|
+
buildCommand: "ng build",
|
|
1695
|
+
testCommand: "ng test --browsers ChromeHeadless --watch=false",
|
|
1696
|
+
lintCommand: "ng lint",
|
|
1697
|
+
formatCommand: "npx prettier --write .",
|
|
1698
|
+
formatCheckCommand: "npx prettier --check .",
|
|
1699
|
+
securityAuditCommand: "npm audit",
|
|
1700
|
+
errorHandlingPattern: "HttpErrorResponse with typed error classes",
|
|
1701
|
+
tracingPattern: "Angular HttpInterceptor with structured logging",
|
|
1702
|
+
cancellationPattern: "RxJS Subscription.unsubscribe() / takeUntil",
|
|
1703
|
+
atomicWritePattern: "Write-rename with .tmp file"
|
|
1680
1704
|
}
|
|
1681
1705
|
};
|
|
1682
1706
|
GRADLE_COMMANDS = {
|
|
@@ -11030,6 +11054,8 @@ async function runInitPrompts() {
|
|
|
11030
11054
|
message: "Select programming language",
|
|
11031
11055
|
options: [
|
|
11032
11056
|
{ value: "typescript", label: "TypeScript/JavaScript (Bun)" },
|
|
11057
|
+
{ value: "nextjs", label: "Next.js (React)" },
|
|
11058
|
+
{ value: "angular", label: "Angular" },
|
|
11033
11059
|
{ value: "rust", label: "Rust" },
|
|
11034
11060
|
{ value: "python", label: "Python" },
|
|
11035
11061
|
{ value: "go", label: "Go" },
|
package/dist/exports.js
CHANGED
|
@@ -995,7 +995,7 @@ __export(exports_package, {
|
|
|
995
995
|
bin: () => bin,
|
|
996
996
|
author: () => author
|
|
997
997
|
});
|
|
998
|
-
var name = "guardian-framework", version = "0.1.
|
|
998
|
+
var name = "guardian-framework", version = "0.1.23", description = "Token-optimized agentic framework scaffolder with pi-first architecture", type = "module", main = "dist/exports.js", exports, types = "dist/exports.d.ts", bin, files, engines, scripts, publishConfig, pi, repository, homepage = "https://github.com/arman-jalili/guardian-framework#readme", bugs, dependencies, devDependencies, keywords, author = "Arman Wolkensteiner-Jalili", license = "MIT", package_default;
|
|
999
999
|
var init_package = __esm(() => {
|
|
1000
1000
|
exports = {
|
|
1001
1001
|
".": {
|
|
@@ -1231,7 +1231,7 @@ var init_templates = __esm(() => {
|
|
|
1231
1231
|
TEMPLATE_DIR = findTemplateDir();
|
|
1232
1232
|
PI_TEMPLATE_DIR = path2.join(TEMPLATE_DIR, "pi");
|
|
1233
1233
|
LANGUAGES_DIR = path2.join(TEMPLATE_DIR, "languages");
|
|
1234
|
-
SUPPORTED_LANGUAGES = ["typescript", "rust", "python", "go", "java"];
|
|
1234
|
+
SUPPORTED_LANGUAGES = ["typescript", "rust", "python", "go", "java", "nextjs", "angular"];
|
|
1235
1235
|
AVAILABLE_VALIDATORS = [
|
|
1236
1236
|
"ci",
|
|
1237
1237
|
"tests",
|
|
@@ -1337,6 +1337,30 @@ var init_templates = __esm(() => {
|
|
|
1337
1337
|
tracingPattern: "Micrometer Observation / SLF4j MDC",
|
|
1338
1338
|
cancellationPattern: "Reactive Streams cancellation / @Async CompletableFuture",
|
|
1339
1339
|
atomicWritePattern: "Spring Data CrudRepository.save()"
|
|
1340
|
+
},
|
|
1341
|
+
nextjs: {
|
|
1342
|
+
buildCommand: "npm run build",
|
|
1343
|
+
testCommand: "npm test",
|
|
1344
|
+
lintCommand: "next lint",
|
|
1345
|
+
formatCommand: "prettier --write .",
|
|
1346
|
+
formatCheckCommand: "prettier --check .",
|
|
1347
|
+
securityAuditCommand: "npm audit",
|
|
1348
|
+
errorHandlingPattern: "Result type pattern (ok/error)",
|
|
1349
|
+
tracingPattern: "Structured JSON logging with pino",
|
|
1350
|
+
cancellationPattern: "AbortController pattern",
|
|
1351
|
+
atomicWritePattern: "Write-rename with .tmp file"
|
|
1352
|
+
},
|
|
1353
|
+
angular: {
|
|
1354
|
+
buildCommand: "ng build",
|
|
1355
|
+
testCommand: "ng test --browsers ChromeHeadless --watch=false",
|
|
1356
|
+
lintCommand: "ng lint",
|
|
1357
|
+
formatCommand: "npx prettier --write .",
|
|
1358
|
+
formatCheckCommand: "npx prettier --check .",
|
|
1359
|
+
securityAuditCommand: "npm audit",
|
|
1360
|
+
errorHandlingPattern: "HttpErrorResponse with typed error classes",
|
|
1361
|
+
tracingPattern: "Angular HttpInterceptor with structured logging",
|
|
1362
|
+
cancellationPattern: "RxJS Subscription.unsubscribe() / takeUntil",
|
|
1363
|
+
atomicWritePattern: "Write-rename with .tmp file"
|
|
1340
1364
|
}
|
|
1341
1365
|
};
|
|
1342
1366
|
GRADLE_COMMANDS = {
|
|
@@ -9793,6 +9817,8 @@ async function runInitPrompts() {
|
|
|
9793
9817
|
message: "Select programming language",
|
|
9794
9818
|
options: [
|
|
9795
9819
|
{ value: "typescript", label: "TypeScript/JavaScript (Bun)" },
|
|
9820
|
+
{ value: "nextjs", label: "Next.js (React)" },
|
|
9821
|
+
{ value: "angular", label: "Angular" },
|
|
9796
9822
|
{ value: "rust", label: "Rust" },
|
|
9797
9823
|
{ value: "python", label: "Python" },
|
|
9798
9824
|
{ value: "go", label: "Go" },
|
package/package.json
CHANGED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Angular Code Patterns
|
|
2
|
+
|
|
3
|
+
> **Purpose:** Reusable Angular patterns for Guardian projects.
|
|
4
|
+
> **Source:** Guardian DDD + Angular 18+ conventions.
|
|
5
|
+
> **Framework:** Angular 18+ with standalone components.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## DDD Module Structure
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
module/
|
|
13
|
+
├── domain/ # Pure business logic (framework-free)
|
|
14
|
+
│ ├── entity.ts
|
|
15
|
+
│ ├── value.ts
|
|
16
|
+
│ └── errors.ts
|
|
17
|
+
├── application/ # State stores, services, use cases
|
|
18
|
+
│ ├── store.ts # Signal-based store
|
|
19
|
+
│ ├── service.ts # Injectable service
|
|
20
|
+
│ └── dto.ts
|
|
21
|
+
├── infrastructure/ # External adapters
|
|
22
|
+
│ ├── api-client.ts # HTTP client wrapper
|
|
23
|
+
│ └── storage.ts # localStorage wrapper
|
|
24
|
+
└── interfaces/ # UI Components
|
|
25
|
+
├── component.ts # Standalone component
|
|
26
|
+
└── page.component.ts
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Commands
|
|
30
|
+
|
|
31
|
+
| Command | Purpose |
|
|
32
|
+
|---------|---------|
|
|
33
|
+
| `ng serve` | Dev server |
|
|
34
|
+
| `ng build` | Production build |
|
|
35
|
+
| `ng test --watch=false` | Run tests (headless) |
|
|
36
|
+
| `ng lint` | Lint |
|
|
37
|
+
| `prettier --write .` | Format |
|
|
38
|
+
| `npm audit` | Security audit |
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Next.js Code Patterns
|
|
2
|
+
|
|
3
|
+
> **Purpose:** Reusable Next.js patterns for Guardian projects.
|
|
4
|
+
> **Source:** Guardian DDD + Next.js App Router conventions.
|
|
5
|
+
> **Framework:** Next.js 14+ with App Router.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## DDD Module Structure
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
module/
|
|
13
|
+
├── domain/ # Pure business logic (framework-free)
|
|
14
|
+
│ ├── entity.ts
|
|
15
|
+
│ ├── value.ts
|
|
16
|
+
│ └── errors.ts
|
|
17
|
+
├── application/ # Server actions, state stores
|
|
18
|
+
│ ├── store.ts # Zustand store
|
|
19
|
+
│ ├── actions.ts # Server actions
|
|
20
|
+
│ └── dto.ts
|
|
21
|
+
├── infrastructure/ # External adapters
|
|
22
|
+
│ ├── api-client.ts # API calls (fetch, tRPC)
|
|
23
|
+
│ └── storage.ts # localStorage / cookies
|
|
24
|
+
└── interfaces/ # UI Components
|
|
25
|
+
├── page.tsx # Next.js page
|
|
26
|
+
├── component.tsx # React component
|
|
27
|
+
└── layout.tsx # Layout wrapper
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Commands
|
|
31
|
+
|
|
32
|
+
| Command | Purpose |
|
|
33
|
+
|---------|---------|
|
|
34
|
+
| `npm run dev` | Dev server |
|
|
35
|
+
| `npm run build` | Production build |
|
|
36
|
+
| `npm test` | Run tests |
|
|
37
|
+
| `next lint` | Lint |
|
|
38
|
+
| `prettier --write .` | Format |
|
|
39
|
+
| `npm audit` | Security audit |
|
|
@@ -238,6 +238,8 @@ export function codegenSkillName(language: string): string {
|
|
|
238
238
|
"python": "python-codegen",
|
|
239
239
|
"typescript": "typescript-codegen",
|
|
240
240
|
"java": "java-codegen",
|
|
241
|
+
"nextjs": "nextjs-codegen",
|
|
242
|
+
"angular": "angular-codegen",
|
|
241
243
|
};
|
|
242
244
|
return map[language] || "typescript-codegen";
|
|
243
245
|
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: angular-codegen
|
|
3
|
+
description: Minimal skill for Angular code generation with DDD + Clean Architecture. References full patterns on demand — never loads inline. Use when implementing Angular modules following enterprise patterns.
|
|
4
|
+
model: inherit
|
|
5
|
+
tools: [Read, Grep]
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Angular Code Generation — DDD + Clean Architecture Patterns
|
|
9
|
+
|
|
10
|
+
> Full reference: `.pi/skills/angular-enterprise-codegen.md`
|
|
11
|
+
|
|
12
|
+
## Quick Reference
|
|
13
|
+
|
|
14
|
+
| When you need... | Read this section |
|
|
15
|
+
|-----------------|-------------------|
|
|
16
|
+
| Module structure | Section 1 — 4-layer DDD for Angular |
|
|
17
|
+
| Domain entities | Section 2 — Pure business logic, no Angular |
|
|
18
|
+
| Application layer | Section 3 — Injectable services, Signal stores |
|
|
19
|
+
| Infrastructure | Section 4 — HttpClient wrappers |
|
|
20
|
+
| UI Components | Section 5 — Standalone components, control flow |
|
|
21
|
+
| Testing | Section 6 — TestBed patterns |
|
|
22
|
+
|
|
23
|
+
## DDD Layer Contract
|
|
24
|
+
|
|
25
|
+
| Layer | Purpose | Dependencies |
|
|
26
|
+
|-------|---------|-------------|
|
|
27
|
+
| `domain/` | Pure business logic | None (no Angular imports) |
|
|
28
|
+
| `application/` | Services, stores | `domain/` |
|
|
29
|
+
| `infrastructure/` | HTTP clients, adapters | `domain/` + `application/` |
|
|
30
|
+
| `interfaces/` | Components, pages | `application/` |
|
|
31
|
+
|
|
32
|
+
## Rules
|
|
33
|
+
- NEVER read full reference — read specific sections
|
|
34
|
+
- Domain layer has ZERO Angular imports
|
|
35
|
+
- Use `inject()` for DI, never constructor injection
|
|
36
|
+
- Use `signal()` over BehaviorSubject for state
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: nextjs-codegen
|
|
3
|
+
description: Minimal skill for Next.js code generation with DDD + Clean Architecture. References full patterns on demand — never loads inline. Use when implementing Next.js modules following enterprise patterns.
|
|
4
|
+
model: inherit
|
|
5
|
+
tools: [Read, Grep]
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Next.js Code Generation — DDD + Clean Architecture Patterns
|
|
9
|
+
|
|
10
|
+
> Full reference: `.pi/skills/nextjs-enterprise-codegen.md`
|
|
11
|
+
|
|
12
|
+
## Quick Reference
|
|
13
|
+
|
|
14
|
+
| When you need... | Read this section |
|
|
15
|
+
|-----------------|-------------------|
|
|
16
|
+
| Module structure | Section 1 — 4-layer DDD for Next.js |
|
|
17
|
+
| Domain entities | Section 2 — Pure business logic, no framework |
|
|
18
|
+
| Application layer | Section 3 — Server actions, Zustand stores |
|
|
19
|
+
| Infrastructure | Section 4 — API clients, storage adapters |
|
|
20
|
+
| UI Components | Section 5 — App Router pages, client components |
|
|
21
|
+
|
|
22
|
+
## DDD Layer Contract
|
|
23
|
+
|
|
24
|
+
| Layer | Purpose | Dependencies |
|
|
25
|
+
|-------|---------|-------------|
|
|
26
|
+
| `domain/` | Pure business logic | None (no Next.js imports) |
|
|
27
|
+
| `application/` | Server actions, stores | `domain/` |
|
|
28
|
+
| `infrastructure/` | API clients, adapters | `domain/` + `application/` |
|
|
29
|
+
| `interfaces/` | Pages, components | `application/` |
|
|
30
|
+
|
|
31
|
+
## Rules
|
|
32
|
+
- NEVER read full reference — read specific sections
|
|
33
|
+
- Domain layer has ZERO Next.js/React imports
|
|
34
|
+
- Use `'use client'` only in interfaces/ layer
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: angular-enterprise-codegen
|
|
3
|
+
description: Full reference for Angular enterprise code generation with DDD + Clean Architecture. Covers module structure, services, Signal stores, standalone components, RxJS patterns, and testing. Loaded on-demand via agents/angular-codegen.md skill.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Angular Enterprise Code Generation — DDD + Clean Architecture
|
|
7
|
+
|
|
8
|
+
> Canonical skill for generating production-grade Angular code with DDD patterns.
|
|
9
|
+
> All code MUST follow these patterns. Validators enforce compliance.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## 1. Project Structure
|
|
14
|
+
|
|
15
|
+
```
|
|
16
|
+
module/
|
|
17
|
+
├── domain/ # Pure business logic, no Angular imports
|
|
18
|
+
│ ├── entity.ts
|
|
19
|
+
│ ├── value.ts
|
|
20
|
+
│ └── errors.ts
|
|
21
|
+
├── application/ # Injectable services, Signal stores
|
|
22
|
+
│ ├── store.ts # Signal-based state
|
|
23
|
+
│ ├── service.ts # @Injectable use case service
|
|
24
|
+
│ └── dto.ts
|
|
25
|
+
├── infrastructure/ # HTTP clients, localStorage adapters
|
|
26
|
+
│ ├── api-client.ts # HttpClient wrapper
|
|
27
|
+
│ └── storage.ts
|
|
28
|
+
└── interfaces/ # UI Components (standalone)
|
|
29
|
+
├── component.ts
|
|
30
|
+
└── page.component.ts
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### Dependency Rule
|
|
34
|
+
```
|
|
35
|
+
domain → application → infrastructure → interfaces
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## 2. Domain Layer
|
|
41
|
+
|
|
42
|
+
```typescript
|
|
43
|
+
// domain/entity.ts — No Angular imports
|
|
44
|
+
export class Order {
|
|
45
|
+
private readonly _id: string;
|
|
46
|
+
private _status: OrderStatus = OrderStatus.PENDING;
|
|
47
|
+
|
|
48
|
+
constructor(id?: string) {
|
|
49
|
+
this._id = id ?? crypto.randomUUID();
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
get id(): string { return this._id; }
|
|
53
|
+
get status(): OrderStatus { return this._status; }
|
|
54
|
+
|
|
55
|
+
confirm(): void {
|
|
56
|
+
if (this._status !== OrderStatus.PENDING) {
|
|
57
|
+
throw new DomainError('INVALID_STATE', 'Only pending orders can be confirmed');
|
|
58
|
+
}
|
|
59
|
+
this._status = OrderStatus.CONFIRMED;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## 3. Application Layer
|
|
67
|
+
|
|
68
|
+
```typescript
|
|
69
|
+
// application/service.ts
|
|
70
|
+
import { Injectable, signal } from '@angular/core';
|
|
71
|
+
import { Order } from '../domain/entity';
|
|
72
|
+
|
|
73
|
+
@Injectable({ providedIn: 'root' })
|
|
74
|
+
export class OrderService {
|
|
75
|
+
private readonly orders = signal<Order[]>([]);
|
|
76
|
+
readonly orders$ = this.orders.asReadonly();
|
|
77
|
+
|
|
78
|
+
confirmOrder(id: string): void {
|
|
79
|
+
this.orders.update(items => {
|
|
80
|
+
const order = items.find(o => o.id === id);
|
|
81
|
+
if (!order) throw new DomainError('NOT_FOUND', 'Order not found');
|
|
82
|
+
order.confirm();
|
|
83
|
+
return [...items];
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
## 4. Infrastructure Layer
|
|
92
|
+
|
|
93
|
+
```typescript
|
|
94
|
+
// infrastructure/api-client.ts
|
|
95
|
+
import { HttpClient } from '@angular/common/http';
|
|
96
|
+
import { Injectable, inject } from '@angular/core';
|
|
97
|
+
|
|
98
|
+
@Injectable({ providedIn: 'root' })
|
|
99
|
+
export class OrderApiClient {
|
|
100
|
+
private readonly http = inject(HttpClient);
|
|
101
|
+
|
|
102
|
+
fetchOrders() {
|
|
103
|
+
return this.http.get<Order[]>('/api/orders');
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
## 5. Interfaces Layer (Components)
|
|
111
|
+
|
|
112
|
+
```typescript
|
|
113
|
+
// interfaces/order-list.component.ts
|
|
114
|
+
import { Component, inject } from '@angular/core';
|
|
115
|
+
import { OrderService } from '../application/service';
|
|
116
|
+
|
|
117
|
+
@Component({
|
|
118
|
+
selector: 'app-order-list',
|
|
119
|
+
standalone: true,
|
|
120
|
+
template: `
|
|
121
|
+
<div>
|
|
122
|
+
@for (order of service.orders$(); track order.id) {
|
|
123
|
+
<div>{{ order.id }} - {{ order.status }}</div>
|
|
124
|
+
}
|
|
125
|
+
</div>
|
|
126
|
+
`,
|
|
127
|
+
})
|
|
128
|
+
export class OrderListComponent {
|
|
129
|
+
readonly service = inject(OrderService);
|
|
130
|
+
}
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
## 6. Testing
|
|
136
|
+
|
|
137
|
+
```typescript
|
|
138
|
+
import { TestBed } from '@angular/core/testing';
|
|
139
|
+
import { OrderService } from './service';
|
|
140
|
+
|
|
141
|
+
describe('OrderService', () => {
|
|
142
|
+
let service: OrderService;
|
|
143
|
+
|
|
144
|
+
beforeEach(() => {
|
|
145
|
+
TestBed.configureTestingModule({});
|
|
146
|
+
service = TestBed.inject(OrderService);
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
it('should confirm order', () => {
|
|
150
|
+
// ... test using service.orders$()
|
|
151
|
+
});
|
|
152
|
+
});
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
|
|
157
|
+
*Version: 1.0.0*
|
|
158
|
+
*Last updated: 2026-07-03*
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: nextjs-enterprise-codegen
|
|
3
|
+
description: Full reference for Next.js enterprise code generation with DDD + Clean Architecture. Covers module structure, server actions, Zustand stores, React components, and testing patterns. Loaded on-demand via agents/nextjs-codegen.md skill.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Next.js Enterprise Code Generation — DDD + Clean Architecture
|
|
7
|
+
|
|
8
|
+
> Canonical skill for generating production-grade Next.js code with DDD patterns.
|
|
9
|
+
> All code MUST follow these patterns. Validators enforce compliance.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## 1. Project Structure
|
|
14
|
+
|
|
15
|
+
```
|
|
16
|
+
module/
|
|
17
|
+
├── domain/ # Pure business logic, no framework dependencies
|
|
18
|
+
│ ├── entity.ts
|
|
19
|
+
│ ├── value.ts
|
|
20
|
+
│ └── errors.ts
|
|
21
|
+
├── application/ # Server actions, state stores, use cases
|
|
22
|
+
│ ├── store.ts # Zustand store (client state)
|
|
23
|
+
│ ├── actions.ts # Server Actions (Next.js 14+)
|
|
24
|
+
│ └── dto.ts
|
|
25
|
+
├── infrastructure/ # API clients, localStorage adapters
|
|
26
|
+
│ ├── api-client.ts
|
|
27
|
+
│ └── storage.ts
|
|
28
|
+
└── interfaces/ # UI Components (Next.js App Router)
|
|
29
|
+
├── page.tsx
|
|
30
|
+
├── component.tsx
|
|
31
|
+
└── layout.tsx
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### Dependency Rule
|
|
35
|
+
```
|
|
36
|
+
domain → application → infrastructure → interfaces
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## 2. Domain Layer
|
|
42
|
+
|
|
43
|
+
```typescript
|
|
44
|
+
// domain/entity.ts — Pure business logic, no React/Next.js imports
|
|
45
|
+
export class Cart {
|
|
46
|
+
private readonly _id: string;
|
|
47
|
+
private _items: CartItem[] = [];
|
|
48
|
+
|
|
49
|
+
constructor(id?: string) {
|
|
50
|
+
this._id = id ?? crypto.randomUUID();
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
get id(): string { return this._id; }
|
|
54
|
+
get items(): readonly CartItem[] { return this._items; }
|
|
55
|
+
get total(): Money { return this._items.reduce((sum, i) => sum.add(i.subtotal), Money.ZERO); }
|
|
56
|
+
|
|
57
|
+
addItem(product: Product, quantity: number): void {
|
|
58
|
+
const existing = this._items.find(i => i.productId === product.id);
|
|
59
|
+
if (existing) {
|
|
60
|
+
existing.increaseQuantity(quantity);
|
|
61
|
+
} else {
|
|
62
|
+
this._items.push(new CartItem(product, quantity));
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## 3. Application Layer
|
|
71
|
+
|
|
72
|
+
```typescript
|
|
73
|
+
// application/store.ts — Zustand store
|
|
74
|
+
import { create } from 'zustand';
|
|
75
|
+
import { Cart } from '../domain/entity';
|
|
76
|
+
|
|
77
|
+
interface CartStore {
|
|
78
|
+
cart: Cart | null;
|
|
79
|
+
isLoading: boolean;
|
|
80
|
+
addItem: (productId: string, quantity: number) => Promise<void>;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export const useCartStore = create<CartStore>((set) => ({
|
|
84
|
+
cart: null,
|
|
85
|
+
isLoading: false,
|
|
86
|
+
addItem: async (productId, quantity) => {
|
|
87
|
+
set({ isLoading: true });
|
|
88
|
+
// ... domain logic
|
|
89
|
+
set({ isLoading: false });
|
|
90
|
+
},
|
|
91
|
+
}));
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## 4. Infrastructure Layer
|
|
97
|
+
|
|
98
|
+
```typescript
|
|
99
|
+
// infrastructure/api-client.ts
|
|
100
|
+
export class CartApiClient {
|
|
101
|
+
async fetchCart(cartId: string): Promise<Cart> {
|
|
102
|
+
const res = await fetch(`/api/cart/${cartId}`);
|
|
103
|
+
if (!res.ok) throw new ApiError('Failed to fetch cart', res.status);
|
|
104
|
+
return res.json();
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
## 5. Interfaces Layer (Components)
|
|
112
|
+
|
|
113
|
+
```typescript
|
|
114
|
+
// interfaces/cart-page.tsx
|
|
115
|
+
'use client';
|
|
116
|
+
import { useCartStore } from '../application/store';
|
|
117
|
+
|
|
118
|
+
export default function CartPage() {
|
|
119
|
+
const { cart, isLoading } = useCartStore();
|
|
120
|
+
|
|
121
|
+
if (isLoading) return <div>Loading...</div>;
|
|
122
|
+
if (!cart) return <div>Cart is empty</div>;
|
|
123
|
+
|
|
124
|
+
return (
|
|
125
|
+
<div>
|
|
126
|
+
<h1>Shopping Cart</h1>
|
|
127
|
+
{cart.items.map(item => (
|
|
128
|
+
<CartItem key={item.id} item={item} />
|
|
129
|
+
))}
|
|
130
|
+
</div>
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
---
|
|
136
|
+
|
|
137
|
+
*Version: 1.0.0*
|
|
138
|
+
*Last updated: 2026-07-03*
|