@atlashub/smartstack-cli 4.5.0 → 4.7.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlashub/smartstack-cli",
3
- "version": "4.5.0",
3
+ "version": "4.7.0",
4
4
  "description": "SmartStack Claude Code automation toolkit - GitFlow, EF Core migrations, prompts and more",
5
5
  "author": {
6
6
  "name": "SmartStack",
@@ -17,8 +17,8 @@ public static class DependencyInjection
17
17
  this IServiceCollection services)
18
18
  {
19
19
  // TODO: Register your application services here
20
- // Example:
21
- // services.AddMediatR(cfg => cfg.RegisterServicesFromAssembly(typeof(DependencyInjection).Assembly));
20
+ // NOTE: MediatR is already registered by AddSmartStack() — do NOT register it again here.
21
+ // Only add client-specific services (e.g., custom validators, domain services).
22
22
 
23
23
  return services;
24
24
  }
@@ -1,46 +1,101 @@
1
+ using Serilog;
2
+ using Serilog.Events;
1
3
  using Microsoft.EntityFrameworkCore;
2
4
  using SmartStack.Api.Extensions;
3
5
  using {{ProjectName}}.Infrastructure;
4
6
  using {{ProjectName}}.Infrastructure.Persistence;
5
7
  using {{ProjectName}}.Application;
6
8
 
7
- var builder = WebApplication.CreateBuilder(args);
9
+ // Bootstrap logger for startup errors
10
+ Log.Logger = new LoggerConfiguration()
11
+ .MinimumLevel.Override("Microsoft", LogEventLevel.Information)
12
+ .Enrich.FromLogContext()
13
+ .WriteTo.Console()
14
+ .CreateBootstrapLogger();
8
15
 
9
- // ===================================================================
10
- // 1. Add SmartStack Core services (from NuGet package)
11
- // ===================================================================
12
- builder.Services.AddSmartStack(builder.Configuration, options =>
16
+ try
13
17
  {
14
- options.EnableDevSeeding = builder.Environment.IsDevelopment();
15
- });
16
-
17
- // ===================================================================
18
- // 2. Add client-specific services (Dual-DbContext pattern)
19
- // ===================================================================
20
- builder.Services.Add{{ProjectName}}Infrastructure(builder.Configuration);
21
- builder.Services.Add{{ProjectName}}Application();
22
-
23
- var app = builder.Build();
24
-
25
- // ===================================================================
26
- // 3. Initialize SmartStack + apply migrations (in correct order!)
27
- // ===================================================================
28
- // This initializes SmartStack and applies Core migrations automatically
29
- await app.InitializeSmartStackAsync();
30
-
31
- // Apply Extensions migrations AFTER Core migrations
32
- // Your client-specific tables may have FK references to Core tables
33
- if (app.Environment.IsDevelopment())
34
- {
35
- using var scope = app.Services.CreateScope();
36
- var extDb = scope.ServiceProvider.GetRequiredService<ExtensionsDbContext>();
37
- await extDb.Database.MigrateAsync();
38
- }
18
+ Log.Information("Starting {{ProjectName}} API");
19
+
20
+ var builder = WebApplication.CreateBuilder(args);
21
+
22
+ // Configure Kestrel to use HTTP/1.1 on all configured endpoints
23
+ builder.WebHost.ConfigureKestrel((context, options) =>
24
+ {
25
+ options.ConfigureEndpointDefaults(listenOptions =>
26
+ {
27
+ listenOptions.Protocols = Microsoft.AspNetCore.Server.Kestrel.Core.HttpProtocols.Http1;
28
+ });
29
+ });
30
+
31
+ // Load appsettings.Local.json if it exists (for local development overrides)
32
+ builder.Configuration.AddJsonFile("appsettings.Local.json", optional: true, reloadOnChange: true);
33
+
34
+ // Serilog configuration from appsettings
35
+ builder.Host.UseSmartStackSerilog();
36
+
37
+ // Application Insights SDK (must be added before Serilog runs)
38
+ var aiConnectionString = builder.Configuration["Logging:Sinks:ApplicationInsights:ConnectionString"];
39
+ var aiEnabled = builder.Configuration.GetValue<bool>("Logging:Sinks:ApplicationInsights:Enabled");
40
+ if (!string.IsNullOrEmpty(aiConnectionString) && aiEnabled)
41
+ {
42
+ builder.Services.AddApplicationInsightsTelemetry(options =>
43
+ {
44
+ options.ConnectionString = aiConnectionString;
45
+ });
46
+ }
47
+
48
+ // ===================================================================
49
+ // 1. Add SmartStack Core services (from NuGet package)
50
+ // ===================================================================
51
+ builder.Services.AddSmartStack(builder.Configuration, options =>
52
+ {
53
+ options.EnableDevSeeding = builder.Environment.IsDevelopment();
54
+ });
55
+
56
+ // ===================================================================
57
+ // 2. Add client-specific services (Dual-DbContext pattern)
58
+ // ===================================================================
59
+ builder.Services.Add{{ProjectName}}Infrastructure(builder.Configuration);
60
+ builder.Services.Add{{ProjectName}}Application();
61
+
62
+ var app = builder.Build();
39
63
 
40
- // ===================================================================
41
- // 4. SmartStack middleware & endpoints
42
- // ===================================================================
43
- app.UseSmartStack();
44
- app.MapSmartStack();
64
+ // ===================================================================
65
+ // 3. Initialize SmartStack + apply migrations (in correct order!)
66
+ // ===================================================================
67
+ // This initializes SmartStack and applies Core migrations automatically
68
+ await app.InitializeSmartStackAsync();
45
69
 
46
- app.Run();
70
+ // Apply Extensions migrations AFTER Core migrations
71
+ // Your client-specific tables may have FK references to Core tables
72
+ if (app.Environment.IsDevelopment())
73
+ {
74
+ using var scope = app.Services.CreateScope();
75
+ var extDb = scope.ServiceProvider.GetRequiredService<ExtensionsDbContext>();
76
+ await extDb.Database.MigrateAsync();
77
+ }
78
+
79
+ // ===================================================================
80
+ // 4. SmartStack middleware & endpoints
81
+ // ===================================================================
82
+ // Swagger UI (development only)
83
+ app.UseSmartStackSwagger();
84
+
85
+ // SmartStack middleware pipeline
86
+ app.UseSmartStack();
87
+
88
+ // Map controllers and SignalR hubs
89
+ app.MapSmartStack();
90
+
91
+ Log.Information("{{ProjectName}} API started successfully");
92
+ app.Run();
93
+ }
94
+ catch (Exception ex)
95
+ {
96
+ Log.Fatal(ex, "Application terminated unexpectedly");
97
+ }
98
+ finally
99
+ {
100
+ Log.CloseAndFlush();
101
+ }
@@ -0,0 +1,139 @@
1
+ # Frontend: Route Wiring in App.tsx
2
+
3
+ > Referenced from `steps/step-03-execute.md` — Detailed route wiring patterns and verification.
4
+
5
+ ---
6
+
7
+ ## Step 4: Wire Routes to App.tsx (BLOCKING)
8
+
9
+ **CRITICAL:** This step is MANDATORY. Without it, routes exist as files but are invisible to the React Router. The page will be BLANK.
10
+
11
+ After `scaffold_routes` generates the route files, you MUST manually insert the routes into `App.tsx`.
12
+
13
+ ---
14
+
15
+ ## Step 4a: Import Page Components
16
+
17
+ At the top of App.tsx:
18
+
19
+ ```tsx
20
+ import { {EntityName}Page } from '@/pages/{Application}/{Module}/{EntityName}Page';
21
+ // Or lazy-loaded:
22
+ const {EntityName}Page = lazy(() => import('@/pages/{Application}/{Module}/{EntityName}Page'));
23
+ ```
24
+
25
+ ---
26
+
27
+ ## Step 4b: Detect App.tsx Routing Pattern
28
+
29
+ Read App.tsx and detect which pattern is used:
30
+
31
+ ### Pattern A: applicationRoutes Object
32
+
33
+ **If App.tsx contains:** `applicationRoutes: ApplicationRouteExtensions`
34
+
35
+ → Add routes to `applicationRoutes.{application}[]` with **RELATIVE** paths (no leading `/`)
36
+
37
+ ```tsx
38
+ const applicationRoutes: ApplicationRouteExtensions = {
39
+ 'human-resources': [
40
+ // existing routes...
41
+ { path: '{module_kebab}/{section_kebab}', element: <{EntityName}ListPage /> },
42
+ { path: '{module_kebab}/{section_kebab}/new', element: <Create{EntityName}Page /> },
43
+ { path: '{module_kebab}/{section_kebab}/:id', element: <{EntityName}DetailPage /> },
44
+ { path: '{module_kebab}/{section_kebab}/:id/edit', element: <Create{EntityName}Page /> },
45
+
46
+ // Parent redirect routes (MANDATORY — prevents /login redirect on parent navigation)
47
+ { path: '{module_kebab}', element: <Navigate to="{module_kebab}/{first_section_kebab}" replace /> },
48
+ { path: '', element: <Navigate to="{first_module_kebab}/{first_section_kebab}" replace /> },
49
+ ],
50
+ };
51
+ ```
52
+
53
+ Routes are automatically injected into BOTH standard (`/{application}/...`) and tenant-prefixed (`/t/:slug/{application}/...`) route trees by `mergeRoutes()`. No manual duplication needed.
54
+
55
+ ### Pattern B: JSX Routes
56
+
57
+ **If App.tsx contains:** `<Route path="/{application}" element={<{Layout} />}>`
58
+
59
+ → Insert `<Route>` children inside the Layout wrapper:
60
+
61
+ ```tsx
62
+ <Route path="/human-resources" element={<AppLayout />}>
63
+ {/* ... existing routes ... */}
64
+ <Route path="{module_kebab}" element={<{EntityName}Page />} />
65
+ </Route>
66
+ ```
67
+
68
+ **ALSO add the same routes inside the tenant-prefixed block:**
69
+
70
+ Find `<Route path="/t/:slug">` and add the **same route entries** there.
71
+
72
+ ---
73
+
74
+ ## Step 4c: Application-to-Layout Mapping
75
+
76
+ | Application prefix | Layout Component | Route path |
77
+ |---------|------------------|------------|
78
+ | `administration.*` | `AppLayout` | `/administration` |
79
+ | `*` (business apps) | `AppLayout` | `/{application}` |
80
+ | `myspace.*` | `AppLayout` | `/myspace` |
81
+
82
+ ---
83
+
84
+ ## Step 4d: Verify Wiring
85
+
86
+ ```
87
+ Tool: mcp__smartstack__validate_frontend_routes
88
+ Args:
89
+ scope: "routes"
90
+ ```
91
+
92
+ If `appWiring.issues` is not empty, fix the wiring before proceeding.
93
+
94
+ ---
95
+
96
+ ## Step 4e: Parent Redirect Routes (MANDATORY)
97
+
98
+ **CRITICAL:** Without parent redirects, navigating to an application or module URL (e.g., `/human-resources` or `/human-resources/employees`) will cause a redirect to `/login` because no route matches.
99
+
100
+ For each application, you MUST add:
101
+
102
+ 1. **Application root redirect** — redirects `/{application}` to the first module/section:
103
+ ```tsx
104
+ { path: '', element: <Navigate to="{first_module}/{first_section}" replace /> }
105
+ ```
106
+
107
+ 2. **Module redirect** (if modules have sections) — redirects `/{application}/{module}` to first section:
108
+ ```tsx
109
+ { path: '{module}', element: <Navigate to="{module}/{first_section}" replace /> }
110
+ ```
111
+
112
+ **Example:** For NavRoutes `human-resources.employees.management` and `human-resources.employees.departments`:
113
+ ```tsx
114
+ { path: 'employees', element: <Navigate to="employees/management" replace /> },
115
+ { path: '', element: <Navigate to="employees/management" replace /> },
116
+ ```
117
+
118
+ The `to` prop is resolved relative to the **parent route** (`/{application}`), so always use the full path from the application root.
119
+
120
+ > Note: `scaffold_routes` with `outputFormat: "clientRoutes"` generates these redirects automatically.
121
+
122
+ ---
123
+
124
+ ## Forbidden Patterns (BOTH patterns)
125
+
126
+ - Adding application routes to `clientRoutes[]` with absolute paths — `clientRoutes` is ONLY for routes outside SmartStack applications (e.g., `/about`, `/pricing`)
127
+ - Adding routes OUTSIDE the Layout wrapper (shell will not render)
128
+ - Using `createBrowserRouter` (SmartStack uses `useRoutes()` + `mergeRoutes()`)
129
+
130
+ ---
131
+
132
+ ## Verification Checklist
133
+
134
+ - [ ] Routes are inside the AppLayout wrapper
135
+ - [ ] Routes use NESTED structure (not flat)
136
+ - [ ] Application kebab-case matches navigation seed data
137
+ - [ ] Both standard and tenant-prefixed blocks have routes (if using Pattern B)
138
+ - [ ] Page components are imported at top of App.tsx
139
+ - [ ] `mcp__smartstack__validate_frontend_routes` returns no issues
@@ -542,15 +542,17 @@ public record CustomerResponseDto(
542
542
 
543
543
  ```tsx
544
544
  // Composite columns from response DTO (already resolved by backend)
545
- <SmartTable
545
+ <DataTable
546
546
  columns={[
547
- { key: 'code', label: t('module:columns.code', 'Code') },
548
- { key: 'displayFirstName', label: t('module:columns.firstName', 'First Name') },
549
- { key: 'displayLastName', label: t('module:columns.lastName', 'Last Name') },
550
- { key: 'displayEmail', label: t('module:columns.email', 'Email') },
547
+ { key: 'code', label: t('module:columns.code', 'Code'), sortable: true },
548
+ { key: 'displayFirstName', label: t('module:columns.firstName', 'First Name'), sortable: true },
549
+ { key: 'displayLastName', label: t('module:columns.lastName', 'Last Name'), sortable: true },
550
+ { key: 'displayEmail', label: t('module:columns.email', 'Email'), sortable: true },
551
551
  { key: 'status', label: t('module:columns.status', 'Status') },
552
552
  ]}
553
553
  data={items}
554
+ searchable
555
+ pagination={{ pageSize: 10 }}
554
556
  />
555
557
  ```
556
558