@atlashub/smartstack-cli 4.31.0 → 4.33.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/.documentation/commands.html +952 -116
- package/.documentation/index.html +2 -2
- package/.documentation/init.html +358 -174
- package/dist/mcp-entry.mjs +271 -44
- package/dist/mcp-entry.mjs.map +1 -1
- package/package.json +1 -1
- package/templates/mcp-scaffolding/controller.cs.hbs +54 -128
- package/templates/project/README.md +19 -0
- package/templates/skills/apex/SKILL.md +16 -10
- package/templates/skills/apex/_shared.md +1 -1
- package/templates/skills/apex/references/checks/architecture-checks.sh +154 -0
- package/templates/skills/apex/references/checks/backend-checks.sh +194 -0
- package/templates/skills/apex/references/checks/frontend-checks.sh +448 -0
- package/templates/skills/apex/references/checks/infrastructure-checks.sh +255 -0
- package/templates/skills/apex/references/checks/security-checks.sh +153 -0
- package/templates/skills/apex/references/checks/seed-checks.sh +536 -0
- package/templates/skills/apex/references/frontend-route-wiring-app-tsx.md +49 -192
- package/templates/skills/apex/references/parallel-execution.md +18 -5
- package/templates/skills/apex/references/post-checks.md +124 -2156
- package/templates/skills/apex/references/smartstack-api.md +160 -957
- package/templates/skills/apex/references/smartstack-frontend-compliance.md +23 -1
- package/templates/skills/apex/references/smartstack-frontend.md +134 -1022
- package/templates/skills/apex/references/smartstack-layers.md +12 -6
- package/templates/skills/apex/steps/step-00-init.md +81 -238
- package/templates/skills/apex/steps/step-03-execute.md +25 -751
- package/templates/skills/apex/steps/step-03a-layer0-domain.md +118 -0
- package/templates/skills/apex/steps/step-03b-layer1-seed.md +91 -0
- package/templates/skills/apex/steps/step-03c-layer2-backend.md +240 -0
- package/templates/skills/apex/steps/step-03d-layer3-frontend.md +300 -0
- package/templates/skills/apex/steps/step-03e-layer4-devdata.md +44 -0
- package/templates/skills/apex/steps/step-04-examine.md +70 -150
- package/templates/skills/application/references/frontend-i18n-and-output.md +2 -2
- package/templates/skills/application/references/frontend-route-naming.md +5 -1
- package/templates/skills/application/references/frontend-route-wiring-app-tsx.md +49 -198
- package/templates/skills/application/references/frontend-verification.md +11 -11
- package/templates/skills/application/steps/step-05-frontend.md +26 -15
- package/templates/skills/application/templates-frontend.md +4 -0
- package/templates/skills/cli-app-sync/SKILL.md +2 -2
- package/templates/skills/cli-app-sync/references/comparison-map.md +1 -1
- package/templates/skills/controller/references/controller-code-templates.md +70 -67
- package/templates/skills/controller/references/mcp-scaffold-workflow.md +5 -1
|
@@ -1,162 +1,70 @@
|
|
|
1
|
-
# Frontend: Route
|
|
1
|
+
# Frontend: Route Registration with PageRegistry + DynamicRouter
|
|
2
2
|
|
|
3
|
-
>
|
|
3
|
+
> **v3.7+** — Replaces the legacy Pattern A (mergeRoutes) and Pattern B (JSX routes) patterns.
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
##
|
|
7
|
+
## How It Works
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
1. **Backend seed data** defines navigation entries with `ComponentKey` values
|
|
10
|
+
(e.g., `administration.users`, `support.tickets.list`)
|
|
11
|
+
2. **`componentRegistry.generated.ts`** registers all page components into `PageRegistry`
|
|
12
|
+
via `PageRegistry.register('key', lazy(() => import(...)))`
|
|
13
|
+
3. **DynamicRouter** fetches the menu API, matches each entry's `componentKey` to a
|
|
14
|
+
`PageRegistry` entry, and generates `<Route>` elements at runtime
|
|
15
|
+
4. **Implicit routes** (detail, create, edit) are resolved by convention:
|
|
16
|
+
- `*.detail` → `.../:id`
|
|
17
|
+
- `*.create` → `.../create`
|
|
18
|
+
- `*.edit` → `.../:id/edit`
|
|
10
19
|
|
|
11
|
-
|
|
20
|
+
No manual App.tsx wiring is needed.
|
|
12
21
|
|
|
13
22
|
---
|
|
14
23
|
|
|
15
|
-
##
|
|
24
|
+
## For SmartStack Core Pages
|
|
16
25
|
|
|
17
|
-
|
|
26
|
+
`componentRegistry.generated.ts` is auto-generated by MCP `scaffold_routes`:
|
|
18
27
|
|
|
19
28
|
```tsx
|
|
20
|
-
//
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
)
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
29
|
+
// Auto-generated — DO NOT EDIT
|
|
30
|
+
import { lazy } from 'react';
|
|
31
|
+
import { PageRegistry } from '@/extensions/PageRegistry';
|
|
32
|
+
|
|
33
|
+
PageRegistry.register('administration.users', lazy(() =>
|
|
34
|
+
import('@/pages/platform/administration/users/UsersPage').then(m => ({ default: m.UsersPage }))
|
|
35
|
+
));
|
|
36
|
+
PageRegistry.register('administration.users.detail', lazy(() =>
|
|
37
|
+
import('@/pages/platform/administration/users/UserDetailPage').then(m => ({ default: m.UserDetailPage }))
|
|
38
|
+
));
|
|
39
|
+
// ... ~100 registrations
|
|
28
40
|
```
|
|
29
41
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
## Step 4a.5: Import Generated Route Extensions (if scaffold_routes was used)
|
|
33
|
-
|
|
34
|
-
If `scaffold_routes` generated `applicationRoutes.generated.tsx`, import and spread:
|
|
35
|
-
|
|
42
|
+
Imported once in `main.tsx`:
|
|
36
43
|
```tsx
|
|
37
|
-
import
|
|
38
|
-
|
|
39
|
-
const applicationRoutes: ApplicationRouteExtensions = {
|
|
40
|
-
...applicationRouteExtensions,
|
|
41
|
-
// additional manual routes if needed...
|
|
42
|
-
};
|
|
44
|
+
import './extensions/componentRegistry.generated';
|
|
43
45
|
```
|
|
44
46
|
|
|
45
|
-
If no generated file exists, add routes directly to the existing `applicationRoutes` object.
|
|
46
|
-
|
|
47
47
|
---
|
|
48
48
|
|
|
49
|
-
##
|
|
50
|
-
|
|
51
|
-
Read App.tsx and detect which pattern is used:
|
|
49
|
+
## For Client SDK Pages
|
|
52
50
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
**If App.tsx contains:** `applicationRoutes: ApplicationRouteExtensions`
|
|
56
|
-
|
|
57
|
-
→ Add routes to `applicationRoutes.{application}[]` with **RELATIVE** paths (no leading `/`)
|
|
58
|
-
|
|
59
|
-
> **CRITICAL — Include Module Segment:** Paths are relative to `/{application}/`.
|
|
60
|
-
> For a 3-level hierarchy (app → module → sections), paths MUST be `{module_kebab}/{section_kebab}`.
|
|
61
|
-
> Using just `{section_kebab}` omits the module segment → route resolves to `/{app}/{section}` instead
|
|
62
|
-
> of `/{app}/{module}/{section}` → mismatch with backend navigation seed data → 404.
|
|
51
|
+
Clients register their own pages directly:
|
|
63
52
|
|
|
64
53
|
```tsx
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
// existing routes...
|
|
68
|
-
// Paths include module segment: employee-management/employees (NOT just employees)
|
|
69
|
-
{ path: '{module_kebab}/{section_kebab}', element: <{EntityName}ListPage /> },
|
|
70
|
-
{ path: '{module_kebab}/{section_kebab}/create', element: <Create{EntityName}Page /> },
|
|
71
|
-
{ path: '{module_kebab}/{section_kebab}/:id', element: <{EntityName}DetailPage /> },
|
|
72
|
-
{ path: '{module_kebab}/{section_kebab}/:id/edit', element: <Edit{EntityName}Page /> },
|
|
73
|
-
|
|
74
|
-
// Parent redirect routes (MANDATORY — prevents /login redirect on parent navigation)
|
|
75
|
-
{ path: '{module_kebab}', element: <Navigate to="{module_kebab}/{first_section_kebab}" replace /> },
|
|
76
|
-
{ path: '', element: <Navigate to="{first_module_kebab}/{first_section_kebab}" replace /> },
|
|
77
|
-
],
|
|
78
|
-
};
|
|
79
|
-
|
|
80
|
-
// Concrete example: app=human-resources, module=employee-management, sections=employees,absences
|
|
81
|
-
const applicationRoutes: ApplicationRouteExtensions = {
|
|
82
|
-
'human-resources': [
|
|
83
|
-
{ path: 'employee-management/employees', element: <EmployeesPage /> }, // ✅
|
|
84
|
-
{ path: 'employee-management/employees/create', element: <CreateEmployeePage /> }, // ✅
|
|
85
|
-
{ path: 'employee-management/employees/:id', element: <EmployeeDetailPage /> }, // ✅
|
|
86
|
-
// ...absences...
|
|
87
|
-
{ path: 'employee-management', element: <Navigate to="employee-management/employees" replace /> },
|
|
88
|
-
{ path: '', element: <Navigate to="employee-management/employees" replace /> },
|
|
89
|
-
],
|
|
90
|
-
};
|
|
91
|
-
|
|
92
|
-
// ❌ WRONG — missing module segment:
|
|
93
|
-
// { path: 'employees', ... } → resolves to /human-resources/employees (backend expects /human-resources/employee-management/employees)
|
|
94
|
-
```
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
Routes are automatically injected into BOTH standard (`/{application}/...`) and tenant-prefixed (`/t/:slug/{application}/...`) route trees by `mergeRoutes()`. No manual duplication needed.
|
|
98
|
-
|
|
99
|
-
#### Custom Applications (Pattern A)
|
|
54
|
+
import { PageRegistry } from '@atlashub/smartstack';
|
|
55
|
+
import { lazy } from 'react';
|
|
100
56
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
2. Injects it into **both** standard (`/{app-key}/...`) and tenant-prefixed (`/t/:slug/{app-key}/...`) trees, inside `TenantRouteWrapper > RouteGuard > LicenseGuard`
|
|
105
|
-
3. Generates automatic parent redirect routes (e.g., `employees` → `employees/management`)
|
|
106
|
-
|
|
107
|
-
No need to use Pattern B for custom applications — Pattern A handles everything automatically.
|
|
108
|
-
|
|
109
|
-
### Pattern B: JSX Routes
|
|
110
|
-
|
|
111
|
-
**If App.tsx contains:** `<Route path="/{application}" element={<{Layout} />}>`
|
|
112
|
-
|
|
113
|
-
→ Insert `<Route>` children inside the Layout wrapper:
|
|
114
|
-
|
|
115
|
-
```tsx
|
|
116
|
-
<Route path="/human-resources" element={<AppLayout />}>
|
|
117
|
-
{/* ... existing routes ... */}
|
|
118
|
-
<Route path="{module_kebab}" element={<{EntityName}Page />} />
|
|
119
|
-
</Route>
|
|
57
|
+
PageRegistry.register('rh.time.dashboard', lazy(() => import('./pages/TimeDashboard')));
|
|
58
|
+
PageRegistry.register('rh.time.list', lazy(() => import('./pages/TimeList')));
|
|
59
|
+
PageRegistry.register('rh.time.detail', lazy(() => import('./pages/TimeDetail')));
|
|
120
60
|
```
|
|
121
61
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
Find `<Route path="/t/:slug">` and add the **same route entries** there.
|
|
62
|
+
Navigation entries are created in DB (via admin UI or seed data).
|
|
63
|
+
DynamicRouter does the junction automatically.
|
|
125
64
|
|
|
126
65
|
---
|
|
127
66
|
|
|
128
|
-
##
|
|
129
|
-
|
|
130
|
-
**Before modifying routes, READ App.tsx and verify the `mergeRoutes()` call has 2 parameters.**
|
|
131
|
-
|
|
132
|
-
✅ Correct:
|
|
133
|
-
```tsx
|
|
134
|
-
const routes = mergeRoutes(clientRoutes, applicationRoutes);
|
|
135
|
-
```
|
|
136
|
-
|
|
137
|
-
❌ If you see only 1 parameter:
|
|
138
|
-
```tsx
|
|
139
|
-
const routes = mergeRoutes(clientRoutes);
|
|
140
|
-
```
|
|
141
|
-
|
|
142
|
-
→ Add the `applicationRoutes` object and pass it as 2nd parameter.
|
|
143
|
-
Without it, all application routes are silently ignored → blank page or /login redirect.
|
|
144
|
-
|
|
145
|
-
**Do not remove the `applicationRoutes` parameter or the `ApplicationRouteExtensions` import.**
|
|
146
|
-
|
|
147
|
-
---
|
|
148
|
-
|
|
149
|
-
## Step 4c: Application-to-Layout Mapping
|
|
150
|
-
|
|
151
|
-
| Application prefix | Layout Component | Route path |
|
|
152
|
-
|---------|------------------|------------|
|
|
153
|
-
| `administration.*` | `AppLayout` | `/administration` |
|
|
154
|
-
| `*` (business apps) | `AppLayout` | `/{application}` |
|
|
155
|
-
| `myspace.*` | `AppLayout` | `/myspace` |
|
|
156
|
-
|
|
157
|
-
---
|
|
158
|
-
|
|
159
|
-
## Step 4d: Verify Wiring
|
|
67
|
+
## Verification
|
|
160
68
|
|
|
161
69
|
```
|
|
162
70
|
Tool: mcp__smartstack__validate_frontend_routes
|
|
@@ -164,68 +72,17 @@ Args:
|
|
|
164
72
|
scope: "routes"
|
|
165
73
|
```
|
|
166
74
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
**Important:** 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.
|
|
174
|
-
|
|
175
|
-
For each application, add:
|
|
176
|
-
|
|
177
|
-
1. **Application root redirect** — redirects `/{application}` to the first module/section:
|
|
178
|
-
```tsx
|
|
179
|
-
{ path: '', element: <Navigate to="{first_module}/{first_section}" replace /> }
|
|
180
|
-
```
|
|
181
|
-
|
|
182
|
-
2. **Module redirect** (if modules have sections) — redirects `/{application}/{module}` to first section:
|
|
183
|
-
```tsx
|
|
184
|
-
{ path: '{module}', element: <Navigate to="{module}/{first_section}" replace /> }
|
|
185
|
-
```
|
|
186
|
-
|
|
187
|
-
**Example:** For NavRoutes `human-resources.employee-management.employees` and `human-resources.employee-management.absences`:
|
|
188
|
-
```tsx
|
|
189
|
-
{ path: 'employee-management', element: <Navigate to="employee-management/employees" replace /> },
|
|
190
|
-
{ path: '', element: <Navigate to="employee-management/employees" replace /> },
|
|
191
|
-
```
|
|
192
|
-
|
|
193
|
-
The `to` prop is resolved relative to the **parent route** (`/{application}`), so always use the full path from the application root.
|
|
194
|
-
|
|
195
|
-
> Note: `scaffold_routes` with `outputFormat: "applicationRoutes"` generates these redirects automatically.
|
|
196
|
-
|
|
197
|
-
---
|
|
198
|
-
|
|
199
|
-
## Patterns to Avoid (BOTH patterns)
|
|
200
|
-
|
|
201
|
-
- Do not add application routes to `clientRoutes[]` with absolute paths — `clientRoutes` is only for routes outside SmartStack applications (e.g., `/about`, `/pricing`)
|
|
202
|
-
- Do not add routes outside the Layout wrapper (shell will not render)
|
|
203
|
-
- Do not use `createBrowserRouter` (SmartStack uses `useRoutes()` + `mergeRoutes()`)
|
|
204
|
-
- Do not add custom application routes to `clientRoutes[]` with absolute paths:
|
|
205
|
-
```tsx
|
|
206
|
-
// ❌ WRONG — bypasses RouteGuard + TenantLayout + AppLayout → /login redirect
|
|
207
|
-
const clientRoutes: RouteConfig[] = [
|
|
208
|
-
{ path: '/human-resources/employees/management', element: <EmployeePage /> },
|
|
209
|
-
];
|
|
210
|
-
```
|
|
211
|
-
Custom application routes go in `applicationRoutes` with RELATIVE paths (including module segment):
|
|
212
|
-
```tsx
|
|
213
|
-
// ✅ CORRECT — module segment included
|
|
214
|
-
const applicationRoutes: ApplicationRouteExtensions = {
|
|
215
|
-
'human-resources': [
|
|
216
|
-
{ path: 'employee-management/employees', element: <EmployeesPage /> },
|
|
217
|
-
],
|
|
218
|
-
};
|
|
219
|
-
```
|
|
220
|
-
- Do not remove the `applicationRoutes` 2nd parameter from `mergeRoutes()` — this silently breaks all custom routes
|
|
75
|
+
Checks:
|
|
76
|
+
- `componentRegistry.generated.ts` exists
|
|
77
|
+
- Each backend NavRoute has a `PageRegistry.register()` call
|
|
78
|
+
- `main.tsx` imports the generated file
|
|
79
|
+
- Implicit route keys (*.detail, *.create, *.edit) exist for CRUD pages
|
|
221
80
|
|
|
222
81
|
---
|
|
223
82
|
|
|
224
|
-
##
|
|
83
|
+
## Legacy Patterns (DEPRECATED)
|
|
225
84
|
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
- [ ] Page components are imported at top of App.tsx
|
|
231
|
-
- [ ] `mcp__smartstack__validate_frontend_routes` returns no issues
|
|
85
|
+
> The Pattern A (`mergeRoutes(clientRoutes, applicationRoutes)`) and Pattern B
|
|
86
|
+
> (JSX `<Route>` in App.tsx) patterns are deprecated since v3.7.
|
|
87
|
+
> They still work but are not recommended for new development.
|
|
88
|
+
> See git history for the legacy documentation.
|
|
@@ -98,14 +98,26 @@ Layer 2 (Backend) — if multiple entities:
|
|
|
98
98
|
# Launched in parallel in a single message
|
|
99
99
|
|
|
100
100
|
Layer 3 (Frontend) — if multiple entities:
|
|
101
|
+
# ⛔ AGENT BOUNDARY: Snipper agents do NOT have access to Skill().
|
|
102
|
+
# Pages (.tsx) MUST be generated by the principal agent via Skill("ui-components").
|
|
103
|
+
# Snipper agents handle ONLY: API clients, routes, wiring, i18n — NOT pages.
|
|
104
|
+
|
|
105
|
+
# PHASE A — Parallel: infrastructure (Snipper agents)
|
|
101
106
|
Agent(subagent_type='Snipper', model='opus',
|
|
102
|
-
prompt='Execute Layer 3
|
|
107
|
+
prompt='Execute Layer 3 INFRASTRUCTURE for {Entity1}: API client, routes, wiring, i18n.
|
|
108
|
+
DO NOT generate any .tsx page files — pages are handled by the principal agent.')
|
|
103
109
|
Agent(subagent_type='Snipper', model='opus',
|
|
104
|
-
prompt='Execute Layer 3
|
|
110
|
+
prompt='Execute Layer 3 INFRASTRUCTURE for {Entity2}: API client, routes, wiring, i18n.
|
|
111
|
+
DO NOT generate any .tsx page files — pages are handled by the principal agent.')
|
|
105
112
|
# Launched in parallel in a single message
|
|
113
|
+
|
|
114
|
+
# PHASE B — Sequential: pages (principal agent only)
|
|
115
|
+
# After all Snipper agents complete, principal generates pages via Skill("ui-components").
|
|
116
|
+
# See step-03-execute.md Layer 3 HARD RULE for full protocol.
|
|
106
117
|
```
|
|
107
118
|
|
|
108
119
|
Each agent has an **isolated scope**: handles one entity end-to-end within the layer.
|
|
120
|
+
**Exception:** Layer 3 pages are NOT delegated — see step-03 HARD RULE.
|
|
109
121
|
|
|
110
122
|
---
|
|
111
123
|
|
|
@@ -129,8 +141,9 @@ Each agent has an **isolated scope**: handles one entity end-to-end within the l
|
|
|
129
141
|
5. Layer 2: launch Snipper agents per entity (if multi-entity) OR agent principal (if single)
|
|
130
142
|
6. Build gate: dotnet build → MUST PASS
|
|
131
143
|
7. Backend tests inline (scaffold + run + fix max 3)
|
|
132
|
-
8. Layer 3: launch Snipper agents
|
|
133
|
-
9.
|
|
144
|
+
8. Layer 3 Phase A: launch Snipper agents for infra (api-client, routes, i18n) — NOT pages
|
|
145
|
+
9. Layer 3 Phase B: principal agent generates ALL pages via Skill("ui-components") — sequential
|
|
146
|
+
10. Compliance gate: 6 frontend checks → MUST PASS
|
|
134
147
|
10. Frontend tests inline (scaffold + run + fix max 3)
|
|
135
148
|
11. Layer 4 (optional): agent principal executes DevData
|
|
136
149
|
```
|
|
@@ -151,6 +164,6 @@ There is no idle state to manage — the agent principal simply waits for result
|
|
|
151
164
|
| economy_mode = true | NO parallel agents, all sequential |
|
|
152
165
|
| Single entity (any layer) | NO parallel agents, agent principal handles all |
|
|
153
166
|
| Multiple entities, Layer 2 | Parallel: one Snipper agent per entity (service + controller) |
|
|
154
|
-
| Multiple entities, Layer 3 | Parallel:
|
|
167
|
+
| Multiple entities, Layer 3 | Parallel: Snipper agents for infra (api-client, routes, i18n) — pages by principal via Skill("ui-components") |
|
|
155
168
|
| Layer 0, Layer 1, Layer 4 | NO parallel agents (sequential by nature) |
|
|
156
169
|
| Analysis phase (step-01) | Parallel: 2-3 Explore agents (backend + frontend + context) |
|