@atlashub/smartstack-cli 1.37.0 → 2.0.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.
Files changed (99) hide show
  1. package/config/mcp-defaults.json +62 -0
  2. package/dist/index.js +57 -4
  3. package/dist/index.js.map +1 -1
  4. package/dist/mcp-entry.mjs +16984 -0
  5. package/dist/mcp-entry.mjs.map +1 -0
  6. package/package.json +14 -5
  7. package/templates/agents/gitflow/start.md +5 -4
  8. package/templates/agents/mcp-healthcheck.md +15 -13
  9. package/templates/mcp-scaffolding/component.tsx.hbs +298 -0
  10. package/templates/mcp-scaffolding/controller.cs.hbs +184 -0
  11. package/templates/mcp-scaffolding/entity-extension.cs.hbs +231 -0
  12. package/templates/mcp-scaffolding/frontend/api-client.ts.hbs +116 -0
  13. package/templates/mcp-scaffolding/frontend/nav-routes.ts.hbs +133 -0
  14. package/templates/mcp-scaffolding/frontend/routes.tsx.hbs +134 -0
  15. package/templates/mcp-scaffolding/migrations/seed-roles.cs.hbs +261 -0
  16. package/templates/mcp-scaffolding/service-extension.cs.hbs +53 -0
  17. package/templates/mcp-scaffolding/tests/controller.test.cs.hbs +413 -0
  18. package/templates/mcp-scaffolding/tests/entity.test.cs.hbs +239 -0
  19. package/templates/mcp-scaffolding/tests/repository.test.cs.hbs +441 -0
  20. package/templates/mcp-scaffolding/tests/security.test.cs.hbs +442 -0
  21. package/templates/mcp-scaffolding/tests/service.test.cs.hbs +390 -0
  22. package/templates/mcp-scaffolding/tests/validator.test.cs.hbs +428 -0
  23. package/templates/ralph/README.md +3 -3
  24. package/templates/ralph/ralph.config.yaml +2 -2
  25. package/templates/skills/admin/SKILL.md +42 -0
  26. package/templates/skills/business-analyse/_shared.md +24 -1
  27. package/templates/skills/business-analyse/questionnaire/01-context.md +4 -4
  28. package/templates/skills/business-analyse/questionnaire/02-stakeholders.md +3 -3
  29. package/templates/skills/business-analyse/questionnaire/03-scope.md +4 -4
  30. package/templates/skills/business-analyse/questionnaire/04-data.md +7 -7
  31. package/templates/skills/business-analyse/questionnaire/05-integrations.md +1 -1
  32. package/templates/skills/business-analyse/questionnaire/06-security.md +3 -3
  33. package/templates/skills/business-analyse/questionnaire/07-ui.md +1 -1
  34. package/templates/skills/business-analyse/questionnaire/08-performance.md +3 -3
  35. package/templates/skills/business-analyse/questionnaire/09-constraints.md +4 -4
  36. package/templates/skills/business-analyse/questionnaire/10-documentation.md +2 -2
  37. package/templates/skills/business-analyse/questionnaire/11-data-lifecycle.md +2 -2
  38. package/templates/skills/business-analyse/questionnaire/12-migration.md +1 -1
  39. package/templates/skills/business-analyse/questionnaire/13-cross-module.md +2 -2
  40. package/templates/skills/business-analyse/steps/step-01-discover.md +50 -25
  41. package/templates/skills/business-analyse/steps/step-05-handoff.md +133 -34
  42. package/templates/skills/cc-agent/SKILL.md +129 -0
  43. package/templates/skills/cc-agent/references/agent-frontmatter.md +213 -0
  44. package/templates/skills/cc-agent/references/permission-modes.md +102 -0
  45. package/templates/skills/cc-agent/references/tools-reference.md +144 -0
  46. package/templates/skills/cc-agent/steps/step-00-init.md +134 -0
  47. package/templates/skills/cc-agent/steps/step-01-design.md +186 -0
  48. package/templates/skills/cc-agent/steps/step-02-generate.md +204 -0
  49. package/templates/skills/cc-agent/steps/step-03-validate.md +130 -0
  50. package/templates/skills/cc-agent/templates/agent-categorized.md +67 -0
  51. package/templates/skills/cc-agent/templates/agent-standalone.md +56 -0
  52. package/templates/skills/cc-agent/templates/agent-with-skills.md +94 -0
  53. package/templates/skills/cc-audit/SKILL.md +108 -0
  54. package/templates/skills/cc-audit/references/agent-checklist.md +91 -0
  55. package/templates/skills/cc-audit/references/hook-checklist.md +110 -0
  56. package/templates/skills/cc-audit/references/skill-checklist.md +70 -0
  57. package/templates/skills/cc-audit/steps/step-00-init.md +98 -0
  58. package/templates/skills/cc-audit/steps/step-01-scan.md +142 -0
  59. package/templates/skills/cc-audit/steps/step-02-analyze.md +158 -0
  60. package/templates/skills/cc-audit/steps/step-03-report.md +142 -0
  61. package/templates/skills/cc-skill/SKILL.md +134 -0
  62. package/templates/skills/cc-skill/references/best-practices.md +167 -0
  63. package/templates/skills/cc-skill/references/frontmatter-reference.md +182 -0
  64. package/templates/skills/cc-skill/references/skill-patterns.md +199 -0
  65. package/templates/skills/cc-skill/steps/step-00-init.md +119 -0
  66. package/templates/skills/cc-skill/steps/step-01-design.md +199 -0
  67. package/templates/skills/cc-skill/steps/step-02-generate.md +145 -0
  68. package/templates/skills/cc-skill/steps/step-03-steps.md +151 -0
  69. package/templates/skills/cc-skill/steps/step-04-validate.md +124 -0
  70. package/templates/skills/cc-skill/templates/skill-forked.md +85 -0
  71. package/templates/skills/cc-skill/templates/skill-progressive.md +102 -0
  72. package/templates/skills/cc-skill/templates/skill-simple.md +75 -0
  73. package/templates/skills/cc-skill/templates/step-template.md +82 -0
  74. package/templates/skills/check-version/SKILL.md +6 -0
  75. package/templates/skills/debug/SKILL.md +4 -0
  76. package/templates/skills/documentation/SKILL.md +1 -0
  77. package/templates/skills/efcore/SKILL.md +5 -0
  78. package/templates/skills/efcore/steps/db/step-deploy.md +26 -5
  79. package/templates/skills/efcore/steps/shared/step-00-init.md +21 -7
  80. package/templates/skills/explore/SKILL.md +28 -32
  81. package/templates/skills/feature-full/SKILL.md +1 -0
  82. package/templates/skills/gitflow/SKILL.md +8 -0
  83. package/templates/skills/gitflow/steps/step-start.md +45 -10
  84. package/templates/skills/mcp/SKILL.md +38 -18
  85. package/templates/skills/quick-search/SKILL.md +8 -1
  86. package/templates/skills/ralph-loop/SKILL.md +1 -1
  87. package/templates/skills/ralph-loop/steps/step-00-init.md +8 -68
  88. package/templates/skills/ralph-loop/steps/step-04-check.md +1 -1
  89. package/templates/skills/refactor/SKILL.md +1 -0
  90. package/templates/skills/review-code/SKILL.md +7 -1
  91. package/templates/skills/ui-components/SKILL.md +31 -438
  92. package/templates/skills/ui-components/accessibility.md +170 -0
  93. package/templates/skills/ui-components/patterns/data-table.md +39 -0
  94. package/templates/skills/ui-components/patterns/entity-card.md +77 -0
  95. package/templates/skills/ui-components/patterns/grid-layout.md +91 -0
  96. package/templates/skills/ui-components/patterns/kanban.md +43 -0
  97. package/templates/skills/ui-components/style-guide.md +86 -0
  98. package/templates/skills/utils/SKILL.md +1 -0
  99. package/templates/skills/validate/SKILL.md +1 -0
@@ -0,0 +1,231 @@
1
+ using System;
2
+ using System.ComponentModel.DataAnnotations;
3
+ using SmartStack.Domain.Common;
4
+ using SmartStack.Domain.Common.Interfaces;
5
+
6
+ namespace {{namespace}};
7
+
8
+ /// <summary>
9
+ /// {{name}} entity{{#if baseEntity}} extending {{baseEntity}}{{/if}}
10
+ /// </summary>
11
+ {{#if isSystemEntity}}
12
+ public class {{name}} : SystemEntity
13
+ {{else}}
14
+ public class {{name}} : BaseEntity
15
+ {{/if}}
16
+ {
17
+ {{#if baseEntity}}
18
+ /// <summary>
19
+ /// Foreign key to {{baseEntity}}
20
+ /// </summary>
21
+ public Guid {{baseEntity}}Id { get; private set; }
22
+
23
+ /// <summary>
24
+ /// Navigation property to {{baseEntity}}
25
+ /// </summary>
26
+ public virtual {{baseEntity}}? {{baseEntity}} { get; private set; }
27
+
28
+ {{/if}}
29
+ // === BUSINESS PROPERTIES ===
30
+ // TODO: Add {{name}} specific properties here
31
+
32
+ /// <summary>
33
+ /// Private constructor for EF Core
34
+ /// </summary>
35
+ private {{name}}() { }
36
+
37
+ /// <summary>
38
+ /// Factory method to create a new {{name}}
39
+ /// </summary>
40
+ {{#if isSystemEntity}}
41
+ public static {{name}} Create(
42
+ string code,
43
+ string? createdBy = null)
44
+ {
45
+ return new {{name}}
46
+ {
47
+ Id = Guid.NewGuid(),
48
+ Code = code.ToLowerInvariant(),
49
+ CreatedAt = DateTime.UtcNow,
50
+ CreatedBy = createdBy
51
+ };
52
+ }
53
+ {{else}}
54
+ public static {{name}} Create(
55
+ Guid tenantId,
56
+ string code,
57
+ string? createdBy = null)
58
+ {
59
+ return new {{name}}
60
+ {
61
+ Id = Guid.NewGuid(),
62
+ TenantId = tenantId,
63
+ Code = code.ToLowerInvariant(),
64
+ CreatedAt = DateTime.UtcNow,
65
+ CreatedBy = createdBy
66
+ };
67
+ }
68
+ {{/if}}
69
+
70
+ /// <summary>
71
+ /// Update the entity
72
+ /// </summary>
73
+ public void Update(string? updatedBy = null)
74
+ {
75
+ UpdatedAt = DateTime.UtcNow;
76
+ UpdatedBy = updatedBy;
77
+ }
78
+
79
+ /// <summary>
80
+ /// Soft delete the entity
81
+ /// </summary>
82
+ public void SoftDelete(string? deletedBy = null)
83
+ {
84
+ IsDeleted = true;
85
+ DeletedAt = DateTime.UtcNow;
86
+ DeletedBy = deletedBy;
87
+ }
88
+
89
+ /// <summary>
90
+ /// Restore a soft-deleted entity
91
+ /// </summary>
92
+ public void Restore(string? restoredBy = null)
93
+ {
94
+ IsDeleted = false;
95
+ DeletedAt = null;
96
+ DeletedBy = null;
97
+ UpdatedAt = DateTime.UtcNow;
98
+ UpdatedBy = restoredBy;
99
+ }
100
+ }
101
+
102
+ // ============================================================================
103
+ // Base Entity Classes (SmartStack.Domain.Common)
104
+ // ============================================================================
105
+ /*
106
+ /// <summary>
107
+ /// Base entity for tenant-scoped entities (default)
108
+ /// </summary>
109
+ public abstract class BaseEntity : ITenantEntity, IHasCode, ISoftDeletable, IVersioned
110
+ {
111
+ public Guid Id { get; set; } = Guid.NewGuid();
112
+ public Guid TenantId { get; set; }
113
+
114
+ private string _code = string.Empty;
115
+ public string Code
116
+ {
117
+ get => _code;
118
+ set => _code = value?.ToLowerInvariant() ?? string.Empty;
119
+ }
120
+
121
+ public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
122
+ public DateTime? UpdatedAt { get; set; }
123
+ public string? CreatedBy { get; set; }
124
+ public string? UpdatedBy { get; set; }
125
+
126
+ public bool IsDeleted { get; set; }
127
+ public DateTime? DeletedAt { get; set; }
128
+ public string? DeletedBy { get; set; }
129
+
130
+ public byte[] RowVersion { get; set; } = Array.Empty<byte>();
131
+ }
132
+
133
+ /// <summary>
134
+ /// Base entity for system-wide entities (no tenant isolation)
135
+ /// </summary>
136
+ public abstract class SystemEntity : ISystemEntity, IHasCode, ISoftDeletable, IVersioned
137
+ {
138
+ public Guid Id { get; set; } = Guid.NewGuid();
139
+
140
+ private string _code = string.Empty;
141
+ public string Code
142
+ {
143
+ get => _code;
144
+ set => _code = value?.ToLowerInvariant() ?? string.Empty;
145
+ }
146
+
147
+ public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
148
+ public DateTime? UpdatedAt { get; set; }
149
+ public string? CreatedBy { get; set; }
150
+ public string? UpdatedBy { get; set; }
151
+
152
+ public bool IsDeleted { get; set; }
153
+ public DateTime? DeletedAt { get; set; }
154
+ public string? DeletedBy { get; set; }
155
+
156
+ public byte[] RowVersion { get; set; } = Array.Empty<byte>();
157
+ }
158
+ */
159
+
160
+ // ============================================================================
161
+ // EF Core Configuration
162
+ // ============================================================================
163
+ namespace {{infrastructureNamespace}}.Persistence.Configurations;
164
+
165
+ using Microsoft.EntityFrameworkCore;
166
+ using Microsoft.EntityFrameworkCore.Metadata.Builders;
167
+ using {{domainNamespace}};
168
+
169
+ public class {{name}}Configuration : IEntityTypeConfiguration<{{name}}>
170
+ {
171
+ public void Configure(EntityTypeBuilder<{{name}}> builder)
172
+ {
173
+ // Table name with schema and domain prefix
174
+ builder.ToTable("{{tablePrefix}}{{name}}s", "{{schema}}");
175
+
176
+ // Primary key
177
+ builder.HasKey(e => e.Id);
178
+
179
+ {{#unless isSystemEntity}}
180
+ // Multi-tenant
181
+ builder.Property(e => e.TenantId).IsRequired();
182
+ builder.HasIndex(e => e.TenantId);
183
+
184
+ // Code: lowercase, unique per tenant (filtered for soft delete)
185
+ builder.Property(e => e.Code).HasMaxLength(100).IsRequired();
186
+ builder.HasIndex(e => new { e.TenantId, e.Code })
187
+ .IsUnique()
188
+ .HasFilter("[IsDeleted] = 0")
189
+ .HasDatabaseName("IX_{{tablePrefix}}{{name}}s_Tenant_Code_Unique");
190
+ {{else}}
191
+ // Code: lowercase, unique (filtered for soft delete)
192
+ builder.Property(e => e.Code).HasMaxLength(100).IsRequired();
193
+ builder.HasIndex(e => e.Code)
194
+ .IsUnique()
195
+ .HasFilter("[IsDeleted] = 0")
196
+ .HasDatabaseName("IX_{{tablePrefix}}{{name}}s_Code_Unique");
197
+ {{/unless}}
198
+
199
+ // Concurrency token
200
+ builder.Property(e => e.RowVersion).IsRowVersion();
201
+
202
+ // Audit fields
203
+ builder.Property(e => e.CreatedBy).HasMaxLength(256);
204
+ builder.Property(e => e.UpdatedBy).HasMaxLength(256);
205
+ builder.Property(e => e.DeletedBy).HasMaxLength(256);
206
+
207
+ {{#if baseEntity}}
208
+ // Relationship to {{baseEntity}} (1:1)
209
+ builder.HasOne(e => e.{{baseEntity}})
210
+ .WithOne()
211
+ .HasForeignKey<{{name}}>(e => e.{{baseEntity}}Id)
212
+ .OnDelete(DeleteBehavior.Cascade);
213
+
214
+ // Index on foreign key
215
+ builder.HasIndex(e => e.{{baseEntity}}Id)
216
+ .IsUnique();
217
+ {{/if}}
218
+
219
+ // TODO: Add additional configuration
220
+ }
221
+ }
222
+
223
+ // ============================================================================
224
+ // DbContext Update (add to ApplicationDbContext.cs)
225
+ // ============================================================================
226
+ // public DbSet<{{name}}> {{name}}s => Set<{{name}}>();
227
+
228
+ // ============================================================================
229
+ // Migration Command
230
+ // ============================================================================
231
+ // dotnet ef migrations add core_vX.X.X_XXX_Add{{name}} --context ApplicationDbContext
@@ -0,0 +1,116 @@
1
+ {{!-- SmartStack API Client Template --}}
2
+ {{!-- Generates type-safe API client with NavRoute integration --}}
3
+
4
+ /**
5
+ * {{name}} API Client
6
+ *
7
+ * Auto-generated by SmartStack MCP - DO NOT EDIT MANUALLY
8
+ * NavRoute: {{navRoute}}
9
+ * API Path: {{apiPath}}
10
+ */
11
+
12
+ import { getRoute } from '../routes/navRoutes.generated';
13
+ import { apiClient } from '../lib/apiClient';
14
+ import type {
15
+ {{name}},
16
+ {{name}}CreateRequest,
17
+ {{name}}UpdateRequest,
18
+ {{name}}ListResponse,
19
+ PaginatedRequest,
20
+ PaginatedResponse
21
+ } from '../types/{{nameLower}}';
22
+
23
+ const ROUTE = getRoute('{{navRoute}}');
24
+
25
+ export const {{nameLower}}Api = {
26
+ {{#if includeGetAll}}
27
+ /**
28
+ * Get all {{name}}s with pagination
29
+ */
30
+ async getAll(params?: PaginatedRequest): Promise<PaginatedResponse<{{name}}>> {
31
+ const response = await apiClient.get<{{name}}ListResponse>(ROUTE.api, { params });
32
+ return response.data;
33
+ },
34
+
35
+ {{/if}}
36
+ {{#if includeGetById}}
37
+ /**
38
+ * Get {{name}} by ID
39
+ */
40
+ async getById(id: string): Promise<{{name}}> {
41
+ const response = await apiClient.get<{{name}}>(`${ROUTE.api}/${id}`);
42
+ return response.data;
43
+ },
44
+
45
+ {{/if}}
46
+ {{#if includeCreate}}
47
+ /**
48
+ * Create new {{name}}
49
+ */
50
+ async create(data: {{name}}CreateRequest): Promise<{{name}}> {
51
+ const response = await apiClient.post<{{name}}>(ROUTE.api, data);
52
+ return response.data;
53
+ },
54
+
55
+ {{/if}}
56
+ {{#if includeUpdate}}
57
+ /**
58
+ * Update existing {{name}}
59
+ */
60
+ async update(id: string, data: {{name}}UpdateRequest): Promise<{{name}}> {
61
+ const response = await apiClient.put<{{name}}>(`${ROUTE.api}/${id}`, data);
62
+ return response.data;
63
+ },
64
+
65
+ {{/if}}
66
+ {{#if includeDelete}}
67
+ /**
68
+ * Delete {{name}}
69
+ */
70
+ async delete(id: string): Promise<void> {
71
+ await apiClient.delete(`${ROUTE.api}/${id}`);
72
+ },
73
+
74
+ {{/if}}
75
+ {{#if includeSearch}}
76
+ /**
77
+ * Search {{name}}s
78
+ */
79
+ async search(query: string, params?: PaginatedRequest): Promise<PaginatedResponse<{{name}}>> {
80
+ const response = await apiClient.get<{{name}}ListResponse>(`${ROUTE.api}/search`, {
81
+ params: { q: query, ...params }
82
+ });
83
+ return response.data;
84
+ },
85
+
86
+ {{/if}}
87
+ {{#if includeExport}}
88
+ /**
89
+ * Export {{name}}s to file
90
+ */
91
+ async export(format: 'csv' | 'xlsx' | 'pdf' = 'xlsx'): Promise<Blob> {
92
+ const response = await apiClient.get(`${ROUTE.api}/export`, {
93
+ params: { format },
94
+ responseType: 'blob'
95
+ });
96
+ return response.data;
97
+ },
98
+
99
+ {{/if}}
100
+ /**
101
+ * Get the NavRoute configuration for this API
102
+ */
103
+ getRoute() {
104
+ return ROUTE;
105
+ },
106
+
107
+ /**
108
+ * Check if user has permission to access this API
109
+ */
110
+ hasPermission(userPermissions: string[]): boolean {
111
+ if (ROUTE.permissions.length === 0) return true;
112
+ return ROUTE.permissions.some(p => userPermissions.includes(p));
113
+ },
114
+ };
115
+
116
+ export default {{nameLower}}Api;
@@ -0,0 +1,133 @@
1
+ {{!-- SmartStack NavRoute Registry Template --}}
2
+ {{!-- Generates centralized route registry for frontend --}}
3
+
4
+ /**
5
+ * NavRoute Registry
6
+ *
7
+ * Auto-generated by SmartStack MCP - DO NOT EDIT MANUALLY
8
+ * Generated: {{generatedAt}}
9
+ * Source: {{source}}
10
+ * Routes: {{routeCount}}
11
+ */
12
+
13
+ export interface NavRoute {
14
+ /** NavRoute path (e.g., "platform.administration.users") */
15
+ navRoute: string;
16
+ /** API endpoint path (e.g., "/api/platform/administration/users") */
17
+ api: string;
18
+ /** Frontend route path (e.g., "/platform/administration/users") */
19
+ web: string;
20
+ /** Required permissions to access this route */
21
+ permissions: string[];
22
+ /** Backend controller name */
23
+ controller?: string;
24
+ /** Supported HTTP methods */
25
+ methods: string[];
26
+ }
27
+
28
+ /**
29
+ * All registered NavRoutes
30
+ */
31
+ export const ROUTES: Record<string, NavRoute> = {
32
+ {{#each routes}}
33
+ '{{this.navRoute}}': {
34
+ navRoute: '{{this.navRoute}}',
35
+ api: '{{this.apiPath}}',
36
+ web: '{{this.webPath}}',
37
+ permissions: [{{#each this.permissions}}'{{this}}'{{#unless @last}}, {{/unless}}{{/each}}],
38
+ {{#if this.controller}}
39
+ controller: '{{this.controller}}',
40
+ {{/if}}
41
+ methods: [{{#each this.methods}}'{{this}}'{{#unless @last}}, {{/unless}}{{/each}}],
42
+ },
43
+ {{/each}}
44
+ };
45
+
46
+ /**
47
+ * Get route configuration by NavRoute path
48
+ * @throws Error if route not found
49
+ */
50
+ export function getRoute(navRoute: string): NavRoute {
51
+ const route = ROUTES[navRoute];
52
+ if (!route) {
53
+ throw new Error(`Route not found: ${navRoute}. Run scaffold_routes to regenerate.`);
54
+ }
55
+ return route;
56
+ }
57
+
58
+ /**
59
+ * Safely get route configuration, returns undefined if not found
60
+ */
61
+ export function tryGetRoute(navRoute: string): NavRoute | undefined {
62
+ return ROUTES[navRoute];
63
+ }
64
+
65
+ /**
66
+ * Check if user has permission for route
67
+ */
68
+ export function hasRoutePermission(navRoute: string, userPermissions: string[]): boolean {
69
+ const route = ROUTES[navRoute];
70
+ if (!route || route.permissions.length === 0) return true;
71
+ return route.permissions.some(p => userPermissions.includes(p));
72
+ }
73
+
74
+ /**
75
+ * Get all routes for a context (e.g., "platform")
76
+ */
77
+ export function getRoutesByContext(context: string): NavRoute[] {
78
+ return Object.values(ROUTES).filter(r => r.navRoute.startsWith(`${context}.`));
79
+ }
80
+
81
+ /**
82
+ * Get all routes for a context and application (e.g., "platform.administration")
83
+ */
84
+ export function getRoutesByApplication(context: string, application: string): NavRoute[] {
85
+ const prefix = `${context}.${application}`;
86
+ return Object.values(ROUTES).filter(r => r.navRoute.startsWith(`${prefix}.`) || r.navRoute === prefix);
87
+ }
88
+
89
+ /**
90
+ * Get all unique contexts
91
+ */
92
+ export function getContexts(): string[] {
93
+ const contexts = new Set<string>();
94
+ for (const route of Object.values(ROUTES)) {
95
+ contexts.add(route.navRoute.split('.')[0]);
96
+ }
97
+ return Array.from(contexts);
98
+ }
99
+
100
+ /**
101
+ * Get all unique applications within a context
102
+ */
103
+ export function getApplications(context: string): string[] {
104
+ const apps = new Set<string>();
105
+ for (const route of Object.values(ROUTES)) {
106
+ const parts = route.navRoute.split('.');
107
+ if (parts[0] === context && parts.length >= 2) {
108
+ apps.add(parts[1]);
109
+ }
110
+ }
111
+ return Array.from(apps);
112
+ }
113
+
114
+ /**
115
+ * Build API URL from NavRoute with optional path segments
116
+ */
117
+ export function buildApiUrl(navRoute: string, ...segments: string[]): string {
118
+ const route = getRoute(navRoute);
119
+ if (segments.length === 0) return route.api;
120
+ return `${route.api}/${segments.join('/')}`;
121
+ }
122
+
123
+ /**
124
+ * Build frontend URL from NavRoute with optional path segments
125
+ */
126
+ export function buildWebUrl(navRoute: string, ...segments: string[]): string {
127
+ const route = getRoute(navRoute);
128
+ if (segments.length === 0) return route.web;
129
+ return `${route.web}/${segments.join('/')}`;
130
+ }
131
+
132
+ // Route count for debugging
133
+ export const ROUTE_COUNT = {{routeCount}};
@@ -0,0 +1,134 @@
1
+ {{!-- SmartStack React Router Configuration Template --}}
2
+ {{!-- Generates router configuration from NavRoute registry --}}
3
+
4
+ /**
5
+ * React Router Configuration
6
+ *
7
+ * Auto-generated by SmartStack MCP - DO NOT EDIT MANUALLY
8
+ * Generated: {{generatedAt}}
9
+ */
10
+
11
+ import React, { Suspense, lazy } from 'react';
12
+ import { createBrowserRouter, RouteObject, Navigate } from 'react-router-dom';
13
+ import { ROUTES } from './navRoutes.generated';
14
+ {{#if includeGuards}}
15
+ import { ProtectedRoute, PermissionGuard } from './guards';
16
+ {{/if}}
17
+
18
+ // ============================================================================
19
+ // Layouts
20
+ // ============================================================================
21
+
22
+ {{#each contexts}}
23
+ import { {{capitalize this}}Layout } from '../layouts/{{capitalize this}}Layout';
24
+ {{/each}}
25
+
26
+ // ============================================================================
27
+ // Pages (lazy loaded for code splitting)
28
+ // ============================================================================
29
+
30
+ {{#each routes}}
31
+ const {{pageName this.navRoute}}Page = lazy(() => import('../pages/{{pagePath this.navRoute}}'));
32
+ {{/each}}
33
+
34
+ // ============================================================================
35
+ // Loading Component
36
+ // ============================================================================
37
+
38
+ const PageLoader: React.FC = () => (
39
+ <div className="flex items-center justify-center h-64">
40
+ <div className="animate-spin rounded-full h-8 w-8 border-b-2 border-blue-500" />
41
+ </div>
42
+ );
43
+
44
+ // ============================================================================
45
+ // Route Configuration
46
+ // ============================================================================
47
+
48
+ const routes: RouteObject[] = [
49
+ // Root redirect
50
+ {
51
+ path: '/',
52
+ element: <Navigate to="{{defaultPath}}" replace />,
53
+ },
54
+
55
+ {{#each contextTree}}
56
+ // {{uppercase @key}} Context
57
+ {
58
+ path: '{{@key}}',
59
+ element: <{{capitalize @key}}Layout />,
60
+ children: [
61
+ {{#each this}}
62
+ // {{uppercase @key}} Application
63
+ {
64
+ path: '{{@key}}',
65
+ children: [
66
+ {{#each this}}
67
+ {
68
+ path: '{{modulePath this.navRoute}}',
69
+ {{#if this.permissions.length}}
70
+ element: (
71
+ <PermissionGuard permissions={ROUTES['{{this.navRoute}}'].permissions}>
72
+ <Suspense fallback={<PageLoader />}>
73
+ <{{pageName this.navRoute}}Page />
74
+ </Suspense>
75
+ </PermissionGuard>
76
+ ),
77
+ {{else}}
78
+ element: (
79
+ <Suspense fallback={<PageLoader />}>
80
+ <{{pageName this.navRoute}}Page />
81
+ </Suspense>
82
+ ),
83
+ {{/if}}
84
+ },
85
+ {{/each}}
86
+ ],
87
+ },
88
+ {{/each}}
89
+ ],
90
+ },
91
+ {{/each}}
92
+
93
+ // 404 Not Found
94
+ {
95
+ path: '*',
96
+ element: (
97
+ <div className="flex flex-col items-center justify-center h-screen">
98
+ <h1 className="text-4xl font-bold text-gray-900">404</h1>
99
+ <p className="mt-2 text-gray-600">Page not found</p>
100
+ <a href="{{defaultPath}}" className="mt-4 text-blue-600 hover:underline">
101
+ Return to home
102
+ </a>
103
+ </div>
104
+ ),
105
+ },
106
+ ];
107
+
108
+ // ============================================================================
109
+ // Router Export
110
+ // ============================================================================
111
+
112
+ {{#if includeGuards}}
113
+ export const router = createBrowserRouter([
114
+ {
115
+ element: <ProtectedRoute />,
116
+ children: routes,
117
+ },
118
+ ]);
119
+ {{else}}
120
+ export const router = createBrowserRouter(routes);
121
+ {{/if}}
122
+
123
+ export default router;
124
+
125
+ // ============================================================================
126
+ // Type Exports
127
+ // ============================================================================
128
+
129
+ export type { RouteObject };
130
+
131
+ /**
132
+ * Get route configuration by NavRoute path
133
+ */
134
+ export const getRouteConfig = (navRoute: string) => ROUTES[navRoute];