@atlashub/smartstack-cli 4.33.0 → 4.34.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.
@@ -0,0 +1,168 @@
1
+ # {{ProjectName}}.Infrastructure - Memory
2
+
3
+ ## Purpose
4
+
5
+ Technical implementations. HOW things work. EF Core, external APIs, file system, email, etc.
6
+
7
+ ## Dependencies
8
+
9
+ - **{{ProjectName}}.Domain** (entities, repository interfaces)
10
+ - **{{ProjectName}}.Application** (IExtensionsDbContext, service interfaces)
11
+ - **Microsoft.EntityFrameworkCore.SqlServer**
12
+ - **Microsoft.EntityFrameworkCore.Design**
13
+
14
+ ## Structure
15
+
16
+ ```
17
+ {{ProjectName}}.Infrastructure/
18
+ ├── Persistence/
19
+ │ ├── ExtensionsDbContext.cs → EF Core DbContext (implements IExtensionsDbContext)
20
+ │ ├── Configurations/ → Entity configurations (Fluent API)
21
+ │ │ ├── {Feature}/ → Feature-specific configs
22
+ │ │ └── SchemaConstants.cs → Extensions="extensions"
23
+ │ ├── Migrations/ → EF Core migrations
24
+ │ └── Seeding/ → Database seeders
25
+ ├── Services/ → Service implementations
26
+ └── DependencyInjection.cs
27
+ ```
28
+
29
+ ## Patterns
30
+
31
+ ### DbContext Template
32
+
33
+ ```csharp
34
+ namespace {{ProjectName}}.Infrastructure.Persistence;
35
+
36
+ public class ExtensionsDbContext : DbContext, IExtensionsDbContext
37
+ {
38
+ public ExtensionsDbContext(DbContextOptions<ExtensionsDbContext> options)
39
+ : base(options) { }
40
+
41
+ public DbSet<Order> Orders => Set<Order>();
42
+
43
+ protected override void OnModelCreating(ModelBuilder modelBuilder)
44
+ {
45
+ base.OnModelCreating(modelBuilder);
46
+ modelBuilder.HasDefaultSchema(SchemaConstants.Extensions);
47
+ modelBuilder.ApplyConfigurationsFromAssembly(typeof(ExtensionsDbContext).Assembly);
48
+ }
49
+
50
+ public override async Task<int> SaveChangesAsync(CancellationToken ct = default)
51
+ {
52
+ return await base.SaveChangesAsync(ct);
53
+ }
54
+ }
55
+ ```
56
+
57
+ ### Entity Configuration Template
58
+
59
+ ```csharp
60
+ namespace {{ProjectName}}.Infrastructure.Persistence.Configurations.{Feature};
61
+
62
+ public class OrderConfiguration : IEntityTypeConfiguration<Order>
63
+ {
64
+ public void Configure(EntityTypeBuilder<Order> builder)
65
+ {
66
+ builder.ToTable("ext_Orders", SchemaConstants.Extensions);
67
+
68
+ builder.HasKey(o => o.Id);
69
+
70
+ builder.Property(o => o.Name)
71
+ .IsRequired()
72
+ .HasMaxLength(200);
73
+
74
+ builder.Property(o => o.Amount)
75
+ .HasPrecision(18, 2);
76
+
77
+ builder.HasIndex(o => o.Name);
78
+ }
79
+ }
80
+ ```
81
+
82
+ ### Repository Implementation Template
83
+
84
+ ```csharp
85
+ namespace {{ProjectName}}.Infrastructure.Persistence.Repositories;
86
+
87
+ public class OrderRepository : IOrderRepository
88
+ {
89
+ private readonly ExtensionsDbContext _context;
90
+
91
+ public OrderRepository(ExtensionsDbContext context)
92
+ {
93
+ _context = context;
94
+ }
95
+
96
+ public async Task<Order?> GetByIdAsync(Guid id, CancellationToken ct = default)
97
+ => await _context.Orders.FindAsync(new object[] { id }, ct);
98
+
99
+ public async Task<IReadOnlyList<Order>> GetAllAsync(CancellationToken ct = default)
100
+ => await _context.Orders.ToListAsync(ct);
101
+
102
+ public async Task AddAsync(Order entity, CancellationToken ct = default)
103
+ => await _context.Orders.AddAsync(entity, ct);
104
+
105
+ public void Update(Order entity)
106
+ => _context.Orders.Update(entity);
107
+
108
+ public void Remove(Order entity)
109
+ => _context.Orders.Remove(entity);
110
+ }
111
+ ```
112
+
113
+ ## DependencyInjection
114
+
115
+ ```csharp
116
+ public static class DependencyInjection
117
+ {
118
+ public static IServiceCollection AddInfrastructure(
119
+ this IServiceCollection services,
120
+ IConfiguration configuration)
121
+ {
122
+ services.AddDbContext<ExtensionsDbContext>(options =>
123
+ options.UseSqlServer(
124
+ configuration.GetConnectionString("DefaultConnection"),
125
+ b => b.MigrationsAssembly(typeof(ExtensionsDbContext).Assembly.FullName)));
126
+
127
+ services.AddScoped<IExtensionsDbContext>(provider =>
128
+ provider.GetRequiredService<ExtensionsDbContext>());
129
+
130
+ return services;
131
+ }
132
+ }
133
+ ```
134
+
135
+ ## EF Core Commands
136
+
137
+ ```bash
138
+ # Create migration (ExtensionsDbContext)
139
+ dotnet ef migrations add <Name> --context ExtensionsDbContext -p src/{{ProjectName}}.Infrastructure -s src/{{ProjectName}}.Api -o Persistence/Migrations
140
+
141
+ # Update database
142
+ dotnet ef database update --context ExtensionsDbContext -p src/{{ProjectName}}.Infrastructure -s src/{{ProjectName}}.Api
143
+
144
+ # Remove last migration
145
+ dotnet ef migrations remove --context ExtensionsDbContext -p src/{{ProjectName}}.Infrastructure -s src/{{ProjectName}}.Api
146
+ ```
147
+
148
+ ## Rules
149
+
150
+ 1. **ALL** EF configurations in `Configurations/` folder, organized by feature
151
+ 2. **NO** data annotations on entities - use Fluent API only
152
+ 3. **Repositories** implement interfaces from Application
153
+ 4. **DbContext** implements `IExtensionsDbContext` from Application
154
+ 5. **Migrations** stay in this project under `Persistence/Migrations/`
155
+ 6. **SQL objects via SqlObjectHelper** - TVFs/views use `SqlObjectHelper.ApplyAll(migrationBuilder)` and embedded `.sql` files
156
+ 7. **NO sequential/deterministic GUIDs in seed data** - All GUIDs must be generated via `[guid]::NewGuid()`
157
+ 8. **Schema prefix pattern** - Table names use format `{prefix}_{EntityName}` with schema `extensions`. Use `SchemaConstants.Extensions` constant.
158
+
159
+ ## When Adding New Entity
160
+
161
+ 1. Create entity in `{{ProjectName}}.Domain` with factory method
162
+ 2. Create repository interface in `{{ProjectName}}.Application/Common/Interfaces/Persistence/`
163
+ 3. Add `DbSet<Entity>` to `ExtensionsDbContext`
164
+ 4. Create configuration in `Persistence/Configurations/{Feature}/{Entity}Configuration.cs`
165
+ 5. Create repository in `Persistence/Repositories/{Entity}Repository.cs` (if needed)
166
+ 6. Register repository in `DependencyInjection.cs`
167
+ 7. Create migration: `/efcore:migration Add{Entity}`
168
+ 8. Run `/efcore:db-deploy` to apply migration
@@ -0,0 +1,339 @@
1
+ # {{ProjectName}} - Claude Instructions
2
+
3
+ > **{{ProjectName}}** is built on the SmartStack platform (NuGet backend + npm frontend).
4
+ > It extends SmartStack via the **Extensions pattern**: own DbContext, own schema, own modules.
5
+ >
6
+ > 1. SmartStack provides the core platform (auth, navigation, multi-tenant, licensing)
7
+ > 2. {{ProjectName}} adds business-specific modules via `ExtensionsDbContext`
8
+ > 3. Pages are registered via `PageRegistry.register()` — DynamicRouter resolves routes automatically
9
+ > 4. Navigation is managed in DB (admin UI or seed data)
10
+
11
+ > **Priority**: Read sections in order. Earlier sections override later ones.
12
+
13
+ ---
14
+
15
+ ## 1. GOLDEN RULES (ALWAYS APPLY)
16
+
17
+ | # | Rule | Enforcement |
18
+ |---|------|-------------|
19
+ | 1 | **Domain layer has ZERO dependencies** | NEVER import from Application/Infrastructure/Api in Domain |
20
+ | 2 | **Route = Permission path** | `/module/section` → `module.section.*` |
21
+ | 3 | **All GUIDs MUST be random** | Generate via `[guid]::NewGuid()` - NEVER invent patterns |
22
+ | 4 | **SQL objects via SqlObjectHelper** | TVFs/views use `SqlObjectHelper` + embedded `.sql` files. No other raw SQL. |
23
+ | 5 | **Tables use domain prefix** | `ext_Orders`, `ext_Products` in `extensions` schema |
24
+ | 6 | **Auto BugFix Issue after /debug** | After completing a `/debug` skill, ALWAYS run `/bugfix-issue` |
25
+ | 7 | **One migration per feature branch** | Use `/efcore:migration` to manage |
26
+ | 8 | **All code MUST have unit tests** | Backend: xUnit + FluentAssertions. Frontend: Vitest. No PR without tests |
27
+
28
+ ---
29
+
30
+ ## 2. GIT RESTRICTIONS
31
+
32
+ ### NEVER Execute Directly (propose to user)
33
+ ```
34
+ git commit | git push | git merge | git rebase | git cherry-pick | git reset | git revert
35
+ ```
36
+
37
+ ### EXCEPTION: GitFlow Skills
38
+ When user invokes `/gitflow:*` commands → **FOLLOW the skill instructions** and execute git commands as defined by that skill.
39
+
40
+ | Context | Action |
41
+ |---------|--------|
42
+ | Manual git commands | **PROPOSE** only |
43
+ | `/gitflow:*` skills | **FOLLOW skill** and execute |
44
+
45
+ **GitFlow Rule**: Skills define a workflow. Execute commands **as specified by the skill**, not as an automatic pipeline.
46
+
47
+ ### Allowed (read-only)
48
+ `git status` | `git log` | `git diff` | `git branch` | `git fetch` | `git worktree list`
49
+
50
+ ---
51
+
52
+ ## 3. ARCHITECTURE
53
+
54
+ ```
55
+ {{ProjectName}}.sln
56
+ ├── src/
57
+ │ ├── {{ProjectName}}.Domain → Business logic (NO dependencies)
58
+ │ ├── {{ProjectName}}.Application → CQRS, use cases (→ Domain)
59
+ │ ├── {{ProjectName}}.Infrastructure → EF Core, repositories, external services (→ Domain, Application)
60
+ │ └── {{ProjectName}}.Api → REST entry point (→ Application, Infrastructure)
61
+ │ └── Controllers/ → Organized by Application/Module
62
+ ├── tests/
63
+ │ └── {{ProjectName}}.Tests.Unit → xUnit + FluentAssertions + Moq
64
+ └── web/{{ProjectNameLower}}-web → React + TypeScript + Vite
65
+ ├── tests/ → Vitest unit tests (NOT in src/)
66
+ └── src/
67
+ ├── pages/ → Organized by Application/Module
68
+ └── components/
69
+ ```
70
+
71
+ **Dependency flow**: `Domain ← Application ← Infrastructure ← Api`
72
+
73
+ > **Note**: Application references `Microsoft.EntityFrameworkCore` for `DbSet<T>` (used by `IExtensionsDbContext`),
74
+ > `IQueryable<T>` async extensions, and `QueryableExtensions`.
75
+ > This is an intentional architectural tradeoff — the `IExtensionsDbContext` interface remains the abstraction boundary.
76
+
77
+ ### Tech Stack
78
+ | Layer | Tech | Version |
79
+ |-------|------|---------|
80
+ | Runtime | .NET | 10.0 |
81
+ | ORM | EF Core | 10.0.1 |
82
+ | Database | SQL Server | Latest |
83
+ | Frontend | React + Vite | 19.x |
84
+ | Language | TypeScript | 5.x |
85
+
86
+ ---
87
+
88
+ ## 4. NAVIGATION HIERARCHY
89
+
90
+ ```
91
+ Application → Module → Section → Resource
92
+ ↓ ↓
93
+ myapp orders
94
+ │ │
95
+ └───────────┴──→ Route: /myapp/orders
96
+ Permission: myapp.orders.{action}
97
+ ```
98
+
99
+ > **Note**: Applications have an `ApplicationZone` property (enum: `Platform`, `Personal`, `Business`) used for UI layout grouping only. It does NOT appear in routes or permissions.
100
+
101
+ ### Permission Actions
102
+ `access` | `read` | `create` | `update` | `delete` | `export` | `import` | `approve` | `reject` | `assign` | `execute`
103
+
104
+ ### Adding Navigation
105
+ 1. Add HasData in `Navigation*Configuration.cs` (include `ComponentKey` for DynamicRouter)
106
+ 2. Run `/efcore:migration AddXxx`
107
+ 3. Register page in `componentRegistry.generated.ts` via `PageRegistry.register()`
108
+ 4. Add i18n in `navigation.json` (fr/en/it/de — all 4 languages)
109
+ 5. Create page component
110
+
111
+ ---
112
+
113
+ ## 5. DATABASE CONVENTIONS
114
+
115
+ ### Table Naming
116
+ Format: `extensions.{prefix}_{TableName}`
117
+
118
+ > **Note**: {{ProjectName}} uses the `extensions` schema, NOT the `core` schema (which belongs to SmartStack platform).
119
+
120
+ ### EF Core Config Pattern
121
+ ```csharp
122
+ builder.ToTable("ext_Orders", SchemaConstants.Extensions); // ✅ CORRECT
123
+ builder.ToTable("Orders", "ext"); // ❌ WRONG
124
+ ```
125
+
126
+ ### Migration Naming
127
+ Format: `extensions_v{version}_{sequence}_{Description}`
128
+
129
+ | Example |
130
+ |---------|
131
+ | `extensions_v1.0.0_001_CreateOrders` |
132
+ | `extensions_v1.0.0_002_AddOrderItems` |
133
+
134
+ > **Note**: Use `/efcore:migration` which calls MCP `suggest_migration` for automatic naming.
135
+
136
+ ---
137
+
138
+ ## 6. CODE CONVENTIONS
139
+
140
+ ### Naming
141
+ | Type | Pattern | Example |
142
+ |------|---------|---------|
143
+ | Entity | Singular PascalCase | `Order`, `Product` |
144
+ | Command | `{Action}{Entity}Command` | `CreateOrderCommand` |
145
+ | Query | `Get{Entity}Query` | `GetOrderByIdQuery` |
146
+ | Handler | `{Command/Query}Handler` | `CreateOrderCommandHandler` |
147
+ | DTO | `{Entity}Dto` | `OrderDto`, `OrderResponseDto` |
148
+
149
+ ### Backend Patterns
150
+ - **CQRS**: Commands/Queries in Application layer
151
+ - **Repository**: Interfaces in Application, impl in Infrastructure
152
+ - **DI**: Register in each layer's `DependencyInjection.cs`
153
+ - **Domain Events**: Raise in Domain, handle in Application
154
+
155
+ ### Frontend Patterns
156
+ - **Feature-based structure**: Group by feature
157
+ - **Custom hooks**: `use*.ts` for logic
158
+ - **API layer**: Centralized in `services/api/`
159
+ - **Placeholder pages**: Use `UnderDevelopment` component for WIP sections
160
+
161
+ ---
162
+
163
+ ## 7. COMMANDS
164
+
165
+ ```bash
166
+ # Build & Run
167
+ dotnet build
168
+ cd src/{{ProjectName}}.Api && dotnet run
169
+ cd web/{{ProjectNameLower}}-web && npm run dev
170
+
171
+ # Tests (MANDATORY before commit)
172
+ dotnet test tests/{{ProjectName}}.Tests.Unit
173
+ cd web/{{ProjectNameLower}}-web && npm test
174
+
175
+ # EF Core
176
+ /efcore:migration <Name> # Create migration (auto -o)
177
+ /efcore:db-deploy # Apply migrations
178
+ /efcore:db-status # Check status
179
+
180
+ # GitFlow
181
+ /gitflow commit # Commit with validation
182
+ /gitflow pr # Create PR
183
+ ```
184
+
185
+ ---
186
+
187
+ ## 8. API MANAGEMENT
188
+
189
+ Claude MAY start/stop API as needed.
190
+
191
+ ```bash
192
+ # Start (background)
193
+ cd src/{{ProjectName}}.Api && dotnet run &
194
+
195
+ # Stop
196
+ taskkill /F /IM {{ProjectName}}.Api.exe 2>nul || pkill -f {{ProjectName}}.Api
197
+ ```
198
+
199
+ **Rules**: Stop API when done. Stop before rebuild if files locked. Restart after code changes.
200
+
201
+ ---
202
+
203
+ ## 9. SECURITY RULES
204
+
205
+ ### GUID Generation (MANDATORY)
206
+ ```powershell
207
+ # ALWAYS generate via PowerShell
208
+ [guid]::NewGuid().ToString()
209
+ 1..10 | ForEach-Object { [guid]::NewGuid().ToString() } # Multiple
210
+ ```
211
+
212
+ **FORBIDDEN patterns**:
213
+ - Repeated: `a1a1a1a1-b1b1-...`
214
+ - Sequential: `00000001-0001-...`
215
+ - Predictable: `a1b2c3d4-1111-2222-...`
216
+
217
+ ### Why
218
+ - Predictable GUIDs enable enumeration attacks
219
+ - OWASP requires cryptographically random identifiers
220
+
221
+ ---
222
+
223
+ ## 10. ENTITY HOOKS
224
+
225
+ | Interface | When | Use Case |
226
+ |-----------|------|----------|
227
+ | `IBeforeCreate<T>` | Pre-create | Validation |
228
+ | `IAfterCreate<T>` | Post-commit | Notifications |
229
+ | `IBeforeUpdate<T>` | Pre-update | Validation |
230
+ | `IAfterUpdate<T>` | Post-commit | Notifications |
231
+ | `IBeforeDelete<T>` | Pre-delete | Can cancel |
232
+ | `IAfterDelete<T>` | Post-commit | Cleanup |
233
+
234
+ ```csharp
235
+ // Register in DependencyInjection.cs
236
+ services.AddScoped<IAfterCreate<Order>, OrderCreatedNotificationHook>();
237
+ ```
238
+
239
+ ---
240
+
241
+ ## 11. LOGGING
242
+
243
+ ### Backend (Serilog)
244
+ | Level | Usage |
245
+ |-------|-------|
246
+ | Critical | Security breaches, unauthorized access |
247
+ | Error | Unhandled exceptions |
248
+ | Warning | Validation failures |
249
+ | Information | HTTP requests, user actions |
250
+ | Debug | SQL queries (dev only) |
251
+
252
+ ### Frontend
253
+ ```typescript
254
+ import { logService } from '@/services/logging/logService';
255
+ logService.logError(error, 'ComponentName');
256
+ logService.logCritical(error, 'ComponentName'); // Immediate send
257
+ ```
258
+
259
+ ---
260
+
261
+ ## 12. TESTING (MANDATORY)
262
+
263
+ ### Rule
264
+ **Every new feature, entity, service, or utility MUST have corresponding unit tests.** No pull request should be merged without tests.
265
+
266
+ ### Backend Tests (xUnit v3 + FluentAssertions 8.x + Moq)
267
+
268
+ | Layer | What to Test | Location |
269
+ |-------|-------------|----------|
270
+ | Domain | Entity creation, validation, state transitions | `tests/{{ProjectName}}.Tests.Unit/Domain/` |
271
+ | Application | Behaviors, mappings, DTOs | `tests/{{ProjectName}}.Tests.Unit/Application/` |
272
+ | Infrastructure | Services (JWT, FileStorage, etc.) | `tests/{{ProjectName}}.Tests.Unit/Services/` |
273
+ | API | Controller responses, authorization | `tests/{{ProjectName}}.Tests.Unit/Controllers/` |
274
+
275
+ ```bash
276
+ dotnet test tests/{{ProjectName}}.Tests.Unit
277
+ ```
278
+
279
+ **Conventions:**
280
+ - Test file naming: `{ClassName}Tests.cs`
281
+ - Use factory methods (private constructors) - NEVER `new Entity { ... }`
282
+ - Use `Guid.NewGuid()` for all Guid parameters - NEVER hardcode or use strings
283
+
284
+ **FluentAssertions 8.x Gotchas:**
285
+ - DateTime: `BeOnOrAfter()` / `BeBefore()` / `BeCloseTo(expected, TimeSpan.FromSeconds(5))` - NOT `BeGreaterThan()`
286
+ - Collections: `HaveCount(n)` - NOT `HaveLength(n)`
287
+ - String length: `content.Length.Should().BeGreaterThan(n)` - NOT `HaveLengthGreaterThan()`
288
+ - Nullable: use `.Value` explicitly
289
+ - `WithMessage("*keyword*")` wildcard OK - but do NOT pass `StringComparison` parameter
290
+
291
+ **Domain Entity Test Pattern:**
292
+ ```csharp
293
+ [Fact]
294
+ public void Create_WithValidData_SetsAllProperties()
295
+ {
296
+ var before = DateTime.UtcNow;
297
+ var entity = Entity.Create("name", "value");
298
+ entity.Name.Should().Be("name");
299
+ entity.CreatedAt.Should().BeOnOrAfter(before);
300
+ entity.Id.Should().NotBeEmpty();
301
+ }
302
+
303
+ [Fact]
304
+ public void Create_WithEmptyName_ThrowsDomainException()
305
+ {
306
+ var act = () => Entity.Create("", "value");
307
+ act.Should().Throw<DomainException>().WithMessage("*name*");
308
+ }
309
+ ```
310
+
311
+ ### Frontend Tests (Vitest + Testing Library)
312
+
313
+ | Category | What to Test | Location |
314
+ |----------|-------------|----------|
315
+ | Utils | Pure functions | `web/{{ProjectNameLower}}-web/tests/utils/` |
316
+ | Services | Business logic | `web/{{ProjectNameLower}}-web/tests/services/` |
317
+ | Hooks | Custom hooks | `web/{{ProjectNameLower}}-web/tests/hooks/` |
318
+ | Components | UI with interactions | `web/{{ProjectNameLower}}-web/tests/components/` |
319
+
320
+ ```bash
321
+ cd web/{{ProjectNameLower}}-web && npm test
322
+ cd web/{{ProjectNameLower}}-web && npm run test:watch
323
+ ```
324
+
325
+ **Conventions:**
326
+ - Test file naming: `{fileName}.test.ts` or `{fileName}.test.tsx`
327
+ - Tests in `web/{{ProjectNameLower}}-web/tests/` (NOT in `src/`)
328
+ - Import with `@/` alias
329
+ - Use `vi.mock()` for external dependencies
330
+
331
+ ### When to Write Tests
332
+
333
+ | Trigger | Action |
334
+ |---------|--------|
335
+ | New domain entity | Add `{Entity}Tests.cs` with factory, validation, state machine tests |
336
+ | New utility function | Add `{util}.test.ts` covering edge cases |
337
+ | New service | Add `{Service}Tests.cs` or `{service}.test.ts` with mocked dependencies |
338
+ | Bug fix | Add regression test that reproduces the bug BEFORE fixing |
339
+ | New API endpoint | Add controller test with auth and response validation |