@atlashub/smartstack-cli 4.32.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.
- package/.documentation/index.html +2 -2
- package/.documentation/init.html +358 -174
- package/dist/index.js +45 -0
- package/dist/index.js.map +1 -1
- 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/project/claude-md/api.CLAUDE.md.template +315 -0
- package/templates/project/claude-md/application.CLAUDE.md.template +181 -0
- package/templates/project/claude-md/domain.CLAUDE.md.template +125 -0
- package/templates/project/claude-md/infrastructure.CLAUDE.md.template +168 -0
- package/templates/project/claude-md/root.CLAUDE.md.template +339 -0
- package/templates/project/claude-md/web.CLAUDE.md.template +339 -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/post-checks.md +124 -2156
- package/templates/skills/apex/references/smartstack-api.md +160 -957
- 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 -752
- 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.
|