@atlashub/smartstack-cli 1.13.2 → 1.14.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 (210) hide show
  1. package/.documentation/agents.html +1 -1
  2. package/.documentation/apex.html +1 -1
  3. package/.documentation/business-analyse.html +1 -1
  4. package/.documentation/cli-commands.html +3 -3
  5. package/.documentation/commands.html +1 -1
  6. package/.documentation/efcore.html +1 -1
  7. package/.documentation/gitflow.html +1 -1
  8. package/.documentation/hooks.html +1 -1
  9. package/.documentation/index.html +1 -1
  10. package/.documentation/init.html +3 -3
  11. package/.documentation/installation.html +1001 -352
  12. package/.documentation/ralph-loop.html +1 -1
  13. package/.documentation/test-web.html +1 -1
  14. package/README.md +88 -20
  15. package/dist/index.js +276 -85
  16. package/dist/index.js.map +1 -1
  17. package/package.json +1 -1
  18. package/templates/agents/code-reviewer.md +163 -0
  19. package/templates/agents/efcore/db-deploy.md +25 -7
  20. package/templates/agents/efcore/db-reset.md +31 -10
  21. package/templates/agents/efcore/db-status.md +22 -5
  22. package/templates/agents/efcore/migration.md +69 -19
  23. package/templates/agents/gitflow/cleanup.md +8 -1
  24. package/templates/agents/gitflow/commit.md +7 -5
  25. package/templates/agents/gitflow/finish.md +6 -4
  26. package/templates/agents/gitflow/pr.md +8 -1
  27. package/templates/agents/gitflow/start.md +1 -1
  28. package/templates/commands/check-version.md +267 -0
  29. package/templates/commands/efcore/_shared.md +30 -1
  30. package/templates/commands/efcore/db-reset.md +18 -6
  31. package/templates/commands/gitflow/OPTIMIZATIONS.md +206 -0
  32. package/templates/commands/refactor.md +164 -0
  33. package/templates/project/DependencyInjection.Application.cs.template +25 -0
  34. package/templates/project/DependencyInjection.Infrastructure.cs.template +61 -0
  35. package/templates/project/DesignTimeExtensionsDbContextFactory.cs.template +70 -0
  36. package/templates/project/ExampleEntity.cs.template +116 -0
  37. package/templates/project/ExampleEntityConfiguration.cs.template +64 -0
  38. package/templates/project/ExampleService.cs.template +146 -0
  39. package/templates/project/ExtensionsDbContext.cs.template +41 -0
  40. package/templates/project/IExtensionsDbContext.cs.template +22 -0
  41. package/templates/project/Program.cs.template +47 -0
  42. package/templates/project/README.md +79 -0
  43. package/templates/ralph/README.md +10 -8
  44. package/templates/ralph/ralph.config.yaml +2 -2
  45. package/templates/skills/_shared.md +44 -44
  46. package/templates/skills/ai-prompt/SKILL.md +55 -55
  47. package/templates/skills/apex/SKILL.md +235 -0
  48. package/templates/skills/apex/steps/step-00-init.md +203 -0
  49. package/templates/skills/apex/steps/step-01-analyze.md +210 -0
  50. package/templates/skills/apex/steps/step-02-plan.md +217 -0
  51. package/templates/skills/apex/steps/step-03-execute.md +178 -0
  52. package/templates/skills/apex/steps/step-04-validate.md +217 -0
  53. package/templates/skills/apex/steps/step-05-examine.md +207 -0
  54. package/templates/skills/apex/steps/step-06-resolve.md +181 -0
  55. package/templates/skills/apex/steps/step-07-tests.md +206 -0
  56. package/templates/skills/apex/steps/step-08-run-tests.md +207 -0
  57. package/templates/skills/apex/templates/00-context.md +46 -0
  58. package/templates/skills/apex/templates/01-analyze.md +63 -0
  59. package/templates/skills/apex/templates/02-plan.md +63 -0
  60. package/templates/skills/apex/templates/03-execute.md +34 -0
  61. package/templates/skills/apex/templates/04-validate.md +61 -0
  62. package/templates/skills/apex/templates/05-examine.md +58 -0
  63. package/templates/skills/apex/templates/06-resolve.md +39 -0
  64. package/templates/skills/apex/templates/07-tests.md +56 -0
  65. package/templates/skills/apex/templates/08-run-tests.md +41 -0
  66. package/templates/skills/apex/templates/README.md +69 -0
  67. package/templates/skills/application/SKILL.md +50 -50
  68. package/templates/skills/application/templates-backend.md +25 -25
  69. package/templates/skills/application/templates-frontend.md +43 -43
  70. package/templates/skills/application/templates-i18n.md +29 -29
  71. package/templates/skills/application/templates-seed.md +77 -77
  72. package/templates/skills/business-analyse/SKILL.md +223 -0
  73. package/templates/skills/business-analyse/_shared.md +258 -0
  74. package/templates/skills/business-analyse/questionnaire/01-context.md +33 -0
  75. package/templates/skills/business-analyse/questionnaire/02-stakeholders.md +35 -0
  76. package/templates/skills/business-analyse/questionnaire/03-scope.md +35 -0
  77. package/templates/skills/business-analyse/questionnaire/04-data.md +36 -0
  78. package/templates/skills/business-analyse/questionnaire/05-integrations.md +36 -0
  79. package/templates/skills/business-analyse/questionnaire/06-security.md +40 -0
  80. package/templates/skills/business-analyse/questionnaire/07-ui.md +36 -0
  81. package/templates/skills/business-analyse/questionnaire/08-performance.md +35 -0
  82. package/templates/skills/business-analyse/questionnaire/09-constraints.md +35 -0
  83. package/templates/skills/business-analyse/questionnaire/10-documentation.md +35 -0
  84. package/templates/skills/business-analyse/questionnaire.md +177 -177
  85. package/templates/skills/business-analyse/react/components.md +340 -0
  86. package/templates/skills/business-analyse/react/i18n-template.md +245 -0
  87. package/templates/skills/business-analyse/react/schema.md +151 -0
  88. package/templates/skills/business-analyse/steps/step-00-init.md +293 -0
  89. package/templates/skills/business-analyse/steps/step-01-discover.md +267 -0
  90. package/templates/skills/business-analyse/steps/step-02-analyse.md +243 -0
  91. package/templates/skills/business-analyse/steps/step-03-specify.md +317 -0
  92. package/templates/skills/business-analyse/steps/step-04-validate.md +239 -0
  93. package/templates/skills/business-analyse/steps/step-05-handoff.md +336 -0
  94. package/templates/skills/business-analyse/steps/step-06-doc-html.md +261 -0
  95. package/templates/skills/business-analyse/templates/00-context.md +105 -0
  96. package/templates/skills/business-analyse/templates/frd-brd.md +97 -0
  97. package/templates/skills/business-analyse/templates/frd-discovery.md +78 -0
  98. package/templates/skills/business-analyse/templates/frd-handoff.md +118 -0
  99. package/templates/skills/business-analyse/templates/frd-spec.md +168 -0
  100. package/templates/skills/business-analyse/templates-frd.md +217 -217
  101. package/templates/skills/business-analyse/templates-react.md +26 -26
  102. package/templates/skills/controller/SKILL.md +141 -92
  103. package/templates/skills/controller/postman-templates.md +15 -15
  104. package/templates/skills/controller/steps/step-00-init.md +191 -0
  105. package/templates/skills/controller/steps/step-01-analyze.md +146 -0
  106. package/templates/skills/controller/steps/step-02-plan.md +176 -0
  107. package/templates/skills/controller/steps/step-03-generate.md +219 -0
  108. package/templates/skills/controller/steps/step-04-perms.md +219 -0
  109. package/templates/skills/controller/steps/step-05-validate.md +107 -0
  110. package/templates/skills/controller/templates.md +77 -77
  111. package/templates/skills/documentation/SKILL.md +79 -79
  112. package/templates/skills/feature-full/SKILL.md +38 -38
  113. package/templates/skills/gitflow/SKILL.md +277 -0
  114. package/templates/{commands → skills}/gitflow/_shared.md +20 -20
  115. package/templates/skills/gitflow/phases/abort.md +173 -0
  116. package/templates/skills/gitflow/phases/cleanup.md +226 -0
  117. package/templates/skills/gitflow/phases/status.md +178 -0
  118. package/templates/skills/gitflow/steps/step-commit.md +255 -0
  119. package/templates/skills/gitflow/steps/step-finish.md +255 -0
  120. package/templates/skills/gitflow/steps/step-init.md +209 -0
  121. package/templates/skills/gitflow/steps/step-merge.md +225 -0
  122. package/templates/skills/gitflow/steps/step-plan.md +208 -0
  123. package/templates/skills/gitflow/steps/step-pr.md +235 -0
  124. package/templates/skills/gitflow/steps/step-start.md +234 -0
  125. package/templates/skills/gitflow/steps/step-sync.md +200 -0
  126. package/templates/skills/gitflow/templates/config.json +53 -0
  127. package/templates/skills/notification/SKILL.md +51 -51
  128. package/templates/skills/ralph-loop/SKILL.md +228 -0
  129. package/templates/skills/ralph-loop/steps/step-00-init.md +201 -0
  130. package/templates/skills/ralph-loop/steps/step-01-task.md +169 -0
  131. package/templates/skills/ralph-loop/steps/step-02-execute.md +173 -0
  132. package/templates/skills/ralph-loop/steps/step-03-commit.md +170 -0
  133. package/templates/skills/ralph-loop/steps/step-04-check.md +162 -0
  134. package/templates/skills/ralph-loop/steps/step-05-report.md +181 -0
  135. package/templates/skills/review-code/SKILL.md +219 -0
  136. package/templates/skills/review-code/references/clean-code-principles.md +140 -0
  137. package/templates/skills/review-code/references/code-quality-metrics.md +174 -0
  138. package/templates/skills/review-code/references/feedback-patterns.md +149 -0
  139. package/templates/skills/review-code/references/security-checklist.md +127 -0
  140. package/templates/skills/ui-components/SKILL.md +54 -54
  141. package/templates/skills/workflow/SKILL.md +46 -46
  142. package/templates/commands/ai-prompt.md +0 -315
  143. package/templates/commands/apex/1-analyze.md +0 -100
  144. package/templates/commands/apex/2-plan.md +0 -145
  145. package/templates/commands/apex/3-execute.md +0 -171
  146. package/templates/commands/apex/4-examine.md +0 -116
  147. package/templates/commands/apex/5-tasks.md +0 -209
  148. package/templates/commands/apex.md +0 -76
  149. package/templates/commands/application/create.md +0 -362
  150. package/templates/commands/application/templates-backend.md +0 -463
  151. package/templates/commands/application/templates-frontend.md +0 -517
  152. package/templates/commands/application/templates-i18n.md +0 -478
  153. package/templates/commands/application/templates-seed.md +0 -362
  154. package/templates/commands/application.md +0 -303
  155. package/templates/commands/business-analyse/0-orchestrate.md +0 -156
  156. package/templates/commands/business-analyse/1-init.md +0 -99
  157. package/templates/commands/business-analyse/2-discover.md +0 -143
  158. package/templates/commands/business-analyse/3-analyse.md +0 -106
  159. package/templates/commands/business-analyse/4-specify.md +0 -133
  160. package/templates/commands/business-analyse/5-validate.md +0 -132
  161. package/templates/commands/business-analyse/6-handoff.md +0 -157
  162. package/templates/commands/business-analyse/7-doc-html.md +0 -103
  163. package/templates/commands/business-analyse/_shared.md +0 -176
  164. package/templates/commands/business-analyse/bug.md +0 -118
  165. package/templates/commands/business-analyse/change-request.md +0 -144
  166. package/templates/commands/business-analyse/hotfix.md +0 -116
  167. package/templates/commands/business-analyse.md +0 -121
  168. package/templates/commands/controller/create.md +0 -216
  169. package/templates/commands/controller/postman-templates.md +0 -528
  170. package/templates/commands/controller/templates.md +0 -600
  171. package/templates/commands/controller.md +0 -337
  172. package/templates/commands/create/agent.md +0 -138
  173. package/templates/commands/create/command.md +0 -166
  174. package/templates/commands/create/hook.md +0 -234
  175. package/templates/commands/create/plugin.md +0 -329
  176. package/templates/commands/create/project.md +0 -508
  177. package/templates/commands/create/skill.md +0 -199
  178. package/templates/commands/create.md +0 -220
  179. package/templates/commands/documentation/module.md +0 -202
  180. package/templates/commands/documentation/templates.md +0 -432
  181. package/templates/commands/documentation.md +0 -190
  182. package/templates/commands/epct.md +0 -69
  183. package/templates/commands/explain.md +0 -186
  184. package/templates/commands/feature-full.md +0 -267
  185. package/templates/commands/gitflow/1-init.md +0 -188
  186. package/templates/commands/gitflow/10-start.md +0 -190
  187. package/templates/commands/gitflow/11-finish.md +0 -382
  188. package/templates/commands/gitflow/12-cleanup.md +0 -103
  189. package/templates/commands/gitflow/13-sync.md +0 -216
  190. package/templates/commands/gitflow/14-rebase.md +0 -251
  191. package/templates/commands/gitflow/2-status.md +0 -122
  192. package/templates/commands/gitflow/3-commit.md +0 -209
  193. package/templates/commands/gitflow/4-plan.md +0 -174
  194. package/templates/commands/gitflow/5-exec.md +0 -202
  195. package/templates/commands/gitflow/6-abort.md +0 -121
  196. package/templates/commands/gitflow/7-pull-request.md +0 -176
  197. package/templates/commands/gitflow/8-review.md +0 -113
  198. package/templates/commands/gitflow/9-merge.md +0 -157
  199. package/templates/commands/gitflow.md +0 -128
  200. package/templates/commands/implement.md +0 -663
  201. package/templates/commands/init.md +0 -567
  202. package/templates/commands/mcp-integration.md +0 -330
  203. package/templates/commands/notification.md +0 -129
  204. package/templates/commands/oneshot.md +0 -57
  205. package/templates/commands/quickstart.md +0 -154
  206. package/templates/commands/ralph-loop/cancel-ralph.md +0 -18
  207. package/templates/commands/ralph-loop/help.md +0 -126
  208. package/templates/commands/ralph-loop/ralph-loop.md +0 -120
  209. package/templates/commands/review.md +0 -106
  210. package/templates/commands/workflow.md +0 -193
@@ -0,0 +1,164 @@
1
+ ---
2
+ description: Refactor code by finding files, grouping them, and launching parallel Snipper agents
3
+ argument-hint: <search-pattern-or-description>
4
+ ---
5
+
6
+ <objective>
7
+ Refactor code matching #$ARGUMENTS across the codebase using parallel Snipper agents for maximum speed.
8
+
9
+ This command finds all relevant files, creates ONE instruction file, then launches Snipper agents in parallel with batches of max 3 files each.
10
+ </objective>
11
+
12
+ <process>
13
+
14
+ ## Phase 1: Discovery
15
+
16
+ 1. **Parse the refactor request**: Understand what #$ARGUMENTS means
17
+ - Could be: method name, component name, pattern, code smell, etc.
18
+ - Identify the search strategy (Grep for code patterns, Glob for file patterns)
19
+
20
+ 2. **Find all affected files**:
21
+ - Use Grep to search for the pattern in the codebase
22
+ - Use Glob if searching by file name patterns
23
+ - Exclude node_modules, .git, dist, build directories
24
+ - List all files that need refactoring
25
+
26
+ 3. **Analyze scope**:
27
+ - Count total files found
28
+ - If more than 15 files, ask user to confirm or narrow scope
29
+ - Show preview of files to refactor
30
+
31
+ ## Phase 2: Create Instructions
32
+
33
+ 4. **Create task folder**:
34
+ - Generate unique ID: `refactor-{timestamp}`
35
+ - Create folder: `.claude/tasks/refactor-{timestamp}/`
36
+
37
+ 5. **Create ONE instruction file**:
38
+ Create `.claude/tasks/refactor-{id}/instructions.md` with precise, adaptive instructions:
39
+
40
+ ```markdown
41
+ # Refactor Instructions
42
+
43
+ ## Objective
44
+ {Clear description of what to refactor based on #$ARGUMENTS}
45
+
46
+ ## What to Change
47
+ {Specific patterns/code to find and modify}
48
+
49
+ ## How to Change
50
+ {Step-by-step transformation rules}
51
+
52
+ ## Rules
53
+ - Follow existing codebase patterns
54
+ - No unnecessary comments
55
+ - Preserve functionality
56
+ - Only modify what's necessary for this refactor
57
+ ```
58
+
59
+ **IMPORTANT**: Make instructions adaptive - they should work for ANY file in the list.
60
+
61
+ ## Phase 3: Group and Execute
62
+
63
+ 6. **Group files into batches**:
64
+ - Maximum 3 files per batch
65
+ - Group by related functionality when possible
66
+
67
+ 7. **Launch Snipper agents in parallel**:
68
+ For EACH batch, use Task tool with subagent_type='Snipper':
69
+
70
+ ```
71
+ Using the instructions in .claude/tasks/refactor-{id}/instructions.md, refactor these files:
72
+ - {file_1}
73
+ - {file_2}
74
+ - {file_3}
75
+ ```
76
+
77
+ **CRITICAL**: Launch ALL batches in a SINGLE message with multiple Task calls.
78
+
79
+ 8. **Wait for completion**:
80
+ - All Snipper agents run in parallel
81
+ - Collect results from each
82
+
83
+ ## Phase 4: Verification
84
+
85
+ 9. **Validate changes**:
86
+ - Run `pnpm lint` or `npm run lint` to check for errors
87
+ - Run `pnpm tsc` or `npx tsc` if TypeScript project
88
+ - Report any failures
89
+
90
+ 10. **Summary report**:
91
+ - List all files modified
92
+ - Show any errors encountered
93
+ - Provide next steps if needed
94
+
95
+ </process>
96
+
97
+ <instructions_template>
98
+ Create ONE file at `.claude/tasks/refactor-{id}/instructions.md`:
99
+
100
+ ```markdown
101
+ # Refactor: {title}
102
+
103
+ ## Objective
104
+ {What needs to be refactored - derived from #$ARGUMENTS}
105
+
106
+ ## Pattern to Find
107
+ {Exact code pattern, method name, or structure to locate}
108
+
109
+ ## Transformation
110
+ {How to transform the found pattern - be specific and adaptive}
111
+
112
+ ## Examples
113
+ Before:
114
+ ```
115
+ {example of current code}
116
+ ```
117
+
118
+ After:
119
+ ```
120
+ {example of refactored code}
121
+ ```
122
+
123
+ ## Constraints
124
+ - Only modify code matching the pattern
125
+ - Preserve all existing functionality
126
+ - Follow codebase conventions
127
+ - No comments unless necessary
128
+ ```
129
+ </instructions_template>
130
+
131
+ <snipper_prompt_template>
132
+ For each batch, call Snipper with:
133
+
134
+ ```
135
+ Using the instructions in .claude/tasks/refactor-{id}/instructions.md, refactor these files:
136
+ - {file_path_1}
137
+ - {file_path_2}
138
+ - {file_path_3}
139
+
140
+ Read the instructions file first, then apply the refactor to each file.
141
+ ```
142
+ </snipper_prompt_template>
143
+
144
+ <success_criteria>
145
+ - All target files identified
146
+ - ONE instruction file created in `.claude/tasks/refactor-{id}/instructions.md`
147
+ - Snipper agents launched in parallel (max 3 files per agent)
148
+ - All batches completed successfully
149
+ - Lint/type checks pass
150
+ - Summary provided to user
151
+ </success_criteria>
152
+
153
+ <example>
154
+ User: `/refactor rename getUserData to fetchUserProfile`
155
+
156
+ 1. Grep finds 12 files containing "getUserData"
157
+ 2. Creates `.claude/tasks/refactor-1702489200/`
158
+ 3. Creates ONE file: `instructions.md` with rename rules
159
+ 4. Groups into 4 batches of 3 files
160
+ 5. Launches 4 Snipper agents in parallel, each with:
161
+ "Using instructions in .../instructions.md, refactor: file1, file2, file3"
162
+ 6. Waits for completion, runs lint
163
+ 7. Reports: "Refactored 12 files, renamed getUserData to fetchUserProfile"
164
+ </example>
@@ -0,0 +1,25 @@
1
+ using Microsoft.Extensions.DependencyInjection;
2
+
3
+ namespace {{ProjectName}}.Application;
4
+
5
+ /// <summary>
6
+ /// Dependency injection configuration for client Application layer.
7
+ /// </summary>
8
+ public static class DependencyInjection
9
+ {
10
+ /// <summary>
11
+ /// Adds client-specific application services to the DI container.
12
+ ///
13
+ /// IMPORTANT: This must be called AFTER AddSmartStackApplication()
14
+ /// to ensure all Core services are available.
15
+ /// </summary>
16
+ public static IServiceCollection Add{{ProjectName}}Application(
17
+ this IServiceCollection services)
18
+ {
19
+ // TODO: Register your application services here
20
+ // Example:
21
+ // services.AddMediatR(cfg => cfg.RegisterServicesFromAssembly(typeof(DependencyInjection).Assembly));
22
+
23
+ return services;
24
+ }
25
+ }
@@ -0,0 +1,61 @@
1
+ using Microsoft.EntityFrameworkCore;
2
+ using Microsoft.EntityFrameworkCore.Diagnostics;
3
+ using Microsoft.Extensions.Configuration;
4
+ using Microsoft.Extensions.DependencyInjection;
5
+ using {{ProjectName}}.Application.Common.Interfaces;
6
+ using {{ProjectName}}.Infrastructure.Persistence;
7
+ using SmartStack.Infrastructure.Persistence.Configurations;
8
+
9
+ namespace {{ProjectName}}.Infrastructure;
10
+
11
+ /// <summary>
12
+ /// Dependency injection configuration for client Infrastructure layer.
13
+ /// </summary>
14
+ public static class DependencyInjection
15
+ {
16
+ /// <summary>
17
+ /// Adds client-specific infrastructure services to the DI container.
18
+ ///
19
+ /// IMPORTANT: This must be called AFTER AddSmartStackInfrastructure()
20
+ /// to ensure CoreDbContext is registered first.
21
+ /// </summary>
22
+ public static IServiceCollection Add{{ProjectName}}Infrastructure(
23
+ this IServiceCollection services,
24
+ IConfiguration configuration)
25
+ {
26
+ // ExtensionsDbContext with migrations in 'extensions' schema
27
+ services.AddDbContext<ExtensionsDbContext>(options =>
28
+ {
29
+ options.UseSqlServer(
30
+ configuration.GetConnectionString("DefaultConnection"),
31
+ sqlOptions =>
32
+ {
33
+ sqlOptions.MigrationsAssembly(typeof(ExtensionsDbContext).Assembly.FullName);
34
+
35
+ // Store migrations history in extensions schema (separate from Core)
36
+ sqlOptions.MigrationsHistoryTable("__EFMigrationsHistory", SchemaConstants.Extensions);
37
+
38
+ // Enable retry policy for transient failures
39
+ sqlOptions.EnableRetryOnFailure(
40
+ maxRetryCount: 5,
41
+ maxRetryDelay: TimeSpan.FromSeconds(10),
42
+ errorNumbersToAdd: null);
43
+
44
+ // Set command timeout
45
+ sqlOptions.CommandTimeout(60);
46
+ });
47
+
48
+ // Suppress false positive warning for static seed data
49
+ options.ConfigureWarnings(w => w.Ignore(RelationalEventId.PendingModelChangesWarning));
50
+ });
51
+
52
+ // Register the interface
53
+ services.AddScoped<IExtensionsDbContext>(provider =>
54
+ provider.GetRequiredService<ExtensionsDbContext>());
55
+
56
+ // TODO: Register your services here
57
+ // services.AddScoped<IOrderService, OrderService>();
58
+
59
+ return services;
60
+ }
61
+ }
@@ -0,0 +1,70 @@
1
+ using Microsoft.EntityFrameworkCore;
2
+ using Microsoft.EntityFrameworkCore.Design;
3
+ using Microsoft.Extensions.Configuration;
4
+ using SmartStack.Infrastructure.Persistence.Configurations;
5
+
6
+ namespace {{ProjectName}}.Infrastructure.Persistence;
7
+
8
+ /// <summary>
9
+ /// Factory for creating ExtensionsDbContext at design time (for EF Core CLI tools).
10
+ ///
11
+ /// This enables running migrations from the command line:
12
+ /// <code>
13
+ /// dotnet ef migrations add MyMigration --context ExtensionsDbContext
14
+ /// dotnet ef database update --context ExtensionsDbContext
15
+ /// dotnet ef migrations list --context ExtensionsDbContext
16
+ /// dotnet ef migrations script --context ExtensionsDbContext -o deploy.sql
17
+ /// </code>
18
+ ///
19
+ /// IMPORTANT: Migrations are stored in the 'extensions' schema, separate from
20
+ /// SmartStack Core migrations in the 'core' schema.
21
+ /// </summary>
22
+ public class DesignTimeExtensionsDbContextFactory : IDesignTimeDbContextFactory<ExtensionsDbContext>
23
+ {
24
+ public ExtensionsDbContext CreateDbContext(string[] args)
25
+ {
26
+ // Try to find appsettings.json in various locations
27
+ var basePath = Directory.GetCurrentDirectory();
28
+
29
+ // Look for appsettings.json in common locations
30
+ var configPaths = new[]
31
+ {
32
+ basePath,
33
+ Path.Combine(basePath, "..", "{{ProjectName}}.Api"),
34
+ Path.Combine(basePath, "..", "..", "src", "{{ProjectName}}.Api"),
35
+ };
36
+
37
+ IConfigurationRoot? configuration = null;
38
+
39
+ foreach (var path in configPaths)
40
+ {
41
+ var configPath = Path.Combine(path, "appsettings.json");
42
+ if (File.Exists(configPath))
43
+ {
44
+ configuration = new ConfigurationBuilder()
45
+ .SetBasePath(path)
46
+ .AddJsonFile("appsettings.json", optional: false)
47
+ .AddJsonFile("appsettings.Development.json", optional: true)
48
+ .AddJsonFile("appsettings.Local.json", optional: true)
49
+ .Build();
50
+ break;
51
+ }
52
+ }
53
+
54
+ // Fallback: use a default connection string for design-time operations
55
+ var connectionString = configuration?.GetConnectionString("DefaultConnection")
56
+ ?? "Server=(localdb)\\mssqllocaldb;Database={{ProjectName}}_DesignTime;Trusted_Connection=True;MultipleActiveResultSets=true;TrustServerCertificate=True";
57
+
58
+ var optionsBuilder = new DbContextOptionsBuilder<ExtensionsDbContext>();
59
+ optionsBuilder.UseSqlServer(connectionString, b =>
60
+ {
61
+ b.MigrationsAssembly(typeof(ExtensionsDbContext).Assembly.FullName);
62
+
63
+ // IMPORTANT: Store migrations history in 'extensions' schema
64
+ // This keeps client migrations separate from Core migrations
65
+ b.MigrationsHistoryTable("__EFMigrationsHistory", SchemaConstants.Extensions);
66
+ });
67
+
68
+ return new ExtensionsDbContext(optionsBuilder.Options);
69
+ }
70
+ }
@@ -0,0 +1,116 @@
1
+ using SmartStack.Domain.Common;
2
+
3
+ namespace {{ProjectName}}.Domain.Entities;
4
+
5
+ /// <summary>
6
+ /// Example entity demonstrating FK reference to Core entities.
7
+ ///
8
+ /// IMPORTANT: Notice that we store only the UserId (GUID), NOT a navigation property.
9
+ /// This is because ExtensionsDbContext doesn't know about Core entities.
10
+ /// Use ICoreDataService to fetch the User data when needed.
11
+ /// </summary>
12
+ public class Order : BaseAuditableEntity
13
+ {
14
+ /// <summary>
15
+ /// Order number (auto-generated or custom format).
16
+ /// </summary>
17
+ public string OrderNumber { get; private set; } = null!;
18
+
19
+ /// <summary>
20
+ /// Foreign key to the User who created this order.
21
+ ///
22
+ /// IMPORTANT: This is a GUID reference only, NOT a navigation property!
23
+ /// Use ICoreDataService.GetUserByIdAsync() to fetch user details.
24
+ /// </summary>
25
+ public Guid CustomerId { get; private set; }
26
+
27
+ /// <summary>
28
+ /// Order status.
29
+ /// </summary>
30
+ public OrderStatus Status { get; private set; }
31
+
32
+ /// <summary>
33
+ /// Total amount.
34
+ /// </summary>
35
+ public decimal TotalAmount { get; private set; }
36
+
37
+ /// <summary>
38
+ /// Order date.
39
+ /// </summary>
40
+ public DateTime OrderDate { get; private set; }
41
+
42
+ /// <summary>
43
+ /// Optional notes.
44
+ /// </summary>
45
+ public string? Notes { get; private set; }
46
+
47
+ // Private constructor for EF Core
48
+ private Order() { }
49
+
50
+ /// <summary>
51
+ /// Creates a new order.
52
+ /// </summary>
53
+ /// <param name="orderNumber">Order number</param>
54
+ /// <param name="customerId">ID of the user placing the order (from Core)</param>
55
+ /// <param name="totalAmount">Total amount</param>
56
+ public static Order Create(string orderNumber, Guid customerId, decimal totalAmount)
57
+ {
58
+ return new Order
59
+ {
60
+ OrderNumber = orderNumber,
61
+ CustomerId = customerId,
62
+ Status = OrderStatus.Pending,
63
+ TotalAmount = totalAmount,
64
+ OrderDate = DateTime.UtcNow
65
+ };
66
+ }
67
+
68
+ public void Confirm()
69
+ {
70
+ if (Status != OrderStatus.Pending)
71
+ throw new InvalidOperationException("Only pending orders can be confirmed.");
72
+
73
+ Status = OrderStatus.Confirmed;
74
+ }
75
+
76
+ public void Ship()
77
+ {
78
+ if (Status != OrderStatus.Confirmed)
79
+ throw new InvalidOperationException("Only confirmed orders can be shipped.");
80
+
81
+ Status = OrderStatus.Shipped;
82
+ }
83
+
84
+ public void Complete()
85
+ {
86
+ if (Status != OrderStatus.Shipped)
87
+ throw new InvalidOperationException("Only shipped orders can be completed.");
88
+
89
+ Status = OrderStatus.Completed;
90
+ }
91
+
92
+ public void Cancel()
93
+ {
94
+ if (Status == OrderStatus.Completed)
95
+ throw new InvalidOperationException("Completed orders cannot be cancelled.");
96
+
97
+ Status = OrderStatus.Cancelled;
98
+ }
99
+
100
+ public void AddNotes(string notes)
101
+ {
102
+ Notes = notes;
103
+ }
104
+ }
105
+
106
+ /// <summary>
107
+ /// Order status enum.
108
+ /// </summary>
109
+ public enum OrderStatus
110
+ {
111
+ Pending = 0,
112
+ Confirmed = 1,
113
+ Shipped = 2,
114
+ Completed = 3,
115
+ Cancelled = 4
116
+ }
@@ -0,0 +1,64 @@
1
+ using Microsoft.EntityFrameworkCore;
2
+ using Microsoft.EntityFrameworkCore.Metadata.Builders;
3
+ using {{ProjectName}}.Domain.Entities;
4
+ using SmartStack.Infrastructure.Persistence.Configurations;
5
+
6
+ namespace {{ProjectName}}.Infrastructure.Persistence.Configurations;
7
+
8
+ /// <summary>
9
+ /// EF Core configuration for the Order entity.
10
+ ///
11
+ /// NOTE: The table is created in the 'extensions' schema as defined by
12
+ /// ExtensionsDbContext.HasDefaultSchema(SchemaConstants.Extensions).
13
+ /// </summary>
14
+ public class OrderConfiguration : IEntityTypeConfiguration<Order>
15
+ {
16
+ public void Configure(EntityTypeBuilder<Order> builder)
17
+ {
18
+ // Table name with domain prefix (following SmartStack conventions)
19
+ // Use a prefix that makes sense for your domain
20
+ builder.ToTable("biz_Orders", SchemaConstants.Extensions);
21
+
22
+ // Primary key
23
+ builder.HasKey(e => e.Id);
24
+
25
+ // Properties
26
+ builder.Property(e => e.OrderNumber)
27
+ .IsRequired()
28
+ .HasMaxLength(50);
29
+
30
+ builder.Property(e => e.Status)
31
+ .IsRequired();
32
+
33
+ builder.Property(e => e.TotalAmount)
34
+ .HasPrecision(18, 2);
35
+
36
+ builder.Property(e => e.OrderDate)
37
+ .IsRequired();
38
+
39
+ builder.Property(e => e.Notes)
40
+ .HasMaxLength(1000);
41
+
42
+ // CustomerId is a GUID FK to Core.auth_Users
43
+ // IMPORTANT: We do NOT create a navigation property or FK constraint
44
+ // because the User table is in a different DbContext (CoreDbContext)
45
+ builder.Property(e => e.CustomerId)
46
+ .IsRequired();
47
+
48
+ // NOTE: No .HasOne() or navigation property to User!
49
+ // Use ICoreDataService.GetUserByIdAsync() to fetch user data
50
+
51
+ // Indexes
52
+ builder.HasIndex(e => e.OrderNumber)
53
+ .IsUnique();
54
+
55
+ builder.HasIndex(e => e.CustomerId);
56
+
57
+ builder.HasIndex(e => e.Status);
58
+
59
+ builder.HasIndex(e => e.OrderDate);
60
+
61
+ // Query filter for soft delete (if using BaseAuditableEntity)
62
+ builder.HasQueryFilter(e => !e.IsDeleted);
63
+ }
64
+ }
@@ -0,0 +1,146 @@
1
+ using Microsoft.EntityFrameworkCore;
2
+ using SmartStack.Application.Common.Interfaces;
3
+ using {{ProjectName}}.Application.Common.Interfaces;
4
+ using {{ProjectName}}.Domain.Entities;
5
+
6
+ namespace {{ProjectName}}.Infrastructure.Services;
7
+
8
+ /// <summary>
9
+ /// Example service demonstrating how to use ICoreDataService
10
+ /// to fetch Core entity data (User, Role, etc.) from Extensions context.
11
+ /// </summary>
12
+ public class OrderService : IOrderService
13
+ {
14
+ private readonly IExtensionsDbContext _context;
15
+ private readonly ICoreDataService _coreDataService;
16
+
17
+ public OrderService(
18
+ IExtensionsDbContext context,
19
+ ICoreDataService coreDataService)
20
+ {
21
+ _context = context;
22
+ _coreDataService = coreDataService;
23
+ }
24
+
25
+ /// <summary>
26
+ /// Gets an order by ID, including customer information from Core.
27
+ /// </summary>
28
+ public async Task<OrderWithCustomerDto?> GetOrderWithCustomerAsync(
29
+ Guid orderId,
30
+ CancellationToken cancellationToken = default)
31
+ {
32
+ // 1. Get the order from Extensions context
33
+ var order = await _context.Orders
34
+ .AsNoTracking()
35
+ .FirstOrDefaultAsync(o => o.Id == orderId, cancellationToken);
36
+
37
+ if (order == null)
38
+ return null;
39
+
40
+ // 2. Use ICoreDataService to fetch customer info from Core context
41
+ // This is the correct way to access Core entities from Extensions!
42
+ var customer = await _coreDataService.GetUserBasicInfoAsync(
43
+ order.CustomerId,
44
+ cancellationToken);
45
+
46
+ // 3. Combine the data
47
+ return new OrderWithCustomerDto
48
+ {
49
+ Id = order.Id,
50
+ OrderNumber = order.OrderNumber,
51
+ Status = order.Status.ToString(),
52
+ TotalAmount = order.TotalAmount,
53
+ OrderDate = order.OrderDate,
54
+ CustomerId = order.CustomerId,
55
+ CustomerEmail = customer?.Email ?? "Unknown",
56
+ CustomerName = customer?.DisplayName ?? "Unknown"
57
+ };
58
+ }
59
+
60
+ /// <summary>
61
+ /// Gets all orders for a customer.
62
+ /// </summary>
63
+ public async Task<IReadOnlyList<OrderDto>> GetOrdersByCustomerAsync(
64
+ Guid customerId,
65
+ CancellationToken cancellationToken = default)
66
+ {
67
+ // First verify the customer exists in Core
68
+ var customer = await _coreDataService.GetUserBasicInfoAsync(
69
+ customerId,
70
+ cancellationToken);
71
+
72
+ if (customer == null)
73
+ throw new InvalidOperationException($"Customer {customerId} not found.");
74
+
75
+ // Get orders from Extensions context
76
+ return await _context.Orders
77
+ .AsNoTracking()
78
+ .Where(o => o.CustomerId == customerId)
79
+ .OrderByDescending(o => o.OrderDate)
80
+ .Select(o => new OrderDto
81
+ {
82
+ Id = o.Id,
83
+ OrderNumber = o.OrderNumber,
84
+ Status = o.Status.ToString(),
85
+ TotalAmount = o.TotalAmount,
86
+ OrderDate = o.OrderDate
87
+ })
88
+ .ToListAsync(cancellationToken);
89
+ }
90
+
91
+ /// <summary>
92
+ /// Creates a new order.
93
+ /// </summary>
94
+ public async Task<Guid> CreateOrderAsync(
95
+ string orderNumber,
96
+ Guid customerId,
97
+ decimal totalAmount,
98
+ CancellationToken cancellationToken = default)
99
+ {
100
+ // Validate that the customer exists in Core before creating order
101
+ var customer = await _coreDataService.GetUserByIdAsync(
102
+ customerId,
103
+ cancellationToken);
104
+
105
+ if (customer == null)
106
+ throw new InvalidOperationException($"Customer {customerId} not found.");
107
+
108
+ if (!customer.IsActive)
109
+ throw new InvalidOperationException("Cannot create order for inactive customer.");
110
+
111
+ // Create the order in Extensions context
112
+ var order = Order.Create(orderNumber, customerId, totalAmount);
113
+
114
+ _context.Orders.Add(order);
115
+ await _context.SaveChangesAsync(cancellationToken);
116
+
117
+ return order.Id;
118
+ }
119
+ }
120
+
121
+ // === DTOs ===
122
+
123
+ public record OrderDto
124
+ {
125
+ public Guid Id { get; init; }
126
+ public string OrderNumber { get; init; } = null!;
127
+ public string Status { get; init; } = null!;
128
+ public decimal TotalAmount { get; init; }
129
+ public DateTime OrderDate { get; init; }
130
+ }
131
+
132
+ public record OrderWithCustomerDto : OrderDto
133
+ {
134
+ public Guid CustomerId { get; init; }
135
+ public string CustomerEmail { get; init; } = null!;
136
+ public string CustomerName { get; init; } = null!;
137
+ }
138
+
139
+ // === Interface ===
140
+
141
+ public interface IOrderService
142
+ {
143
+ Task<OrderWithCustomerDto?> GetOrderWithCustomerAsync(Guid orderId, CancellationToken cancellationToken = default);
144
+ Task<IReadOnlyList<OrderDto>> GetOrdersByCustomerAsync(Guid customerId, CancellationToken cancellationToken = default);
145
+ Task<Guid> CreateOrderAsync(string orderNumber, Guid customerId, decimal totalAmount, CancellationToken cancellationToken = default);
146
+ }
@@ -0,0 +1,41 @@
1
+ using Microsoft.EntityFrameworkCore;
2
+ using {{ProjectName}}.Application.Common.Interfaces;
3
+ using SmartStack.Infrastructure.Persistence.Configurations;
4
+
5
+ namespace {{ProjectName}}.Infrastructure.Persistence;
6
+
7
+ /// <summary>
8
+ /// DbContext for client-specific entities (schema: extensions).
9
+ ///
10
+ /// This context manages all entities specific to your project.
11
+ /// SmartStack Core entities (User, Role, etc.) are managed separately
12
+ /// by CoreDbContext from the SmartStack NuGet package.
13
+ ///
14
+ /// IMPORTANT: To reference Core entities (User, Role, etc.):
15
+ /// - Store only the GUID foreign key (e.g., CreatedByUserId)
16
+ /// - Use ICoreDataService to fetch the related entity data
17
+ /// - Do NOT create navigation properties to Core entities
18
+ /// </summary>
19
+ public class ExtensionsDbContext : DbContext, IExtensionsDbContext
20
+ {
21
+ public ExtensionsDbContext(DbContextOptions<ExtensionsDbContext> options)
22
+ : base(options)
23
+ {
24
+ }
25
+
26
+ // === YOUR ENTITIES ===
27
+ // Add your DbSet properties here. Example:
28
+ // public DbSet<Order> Orders => Set<Order>();
29
+ // public DbSet<Product> Products => Set<Product>();
30
+
31
+ protected override void OnModelCreating(ModelBuilder modelBuilder)
32
+ {
33
+ base.OnModelCreating(modelBuilder);
34
+
35
+ // All client entities go into the 'extensions' schema
36
+ modelBuilder.HasDefaultSchema(SchemaConstants.Extensions);
37
+
38
+ // Load entity configurations from this assembly
39
+ modelBuilder.ApplyConfigurationsFromAssembly(typeof(ExtensionsDbContext).Assembly);
40
+ }
41
+ }