@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.
- package/.documentation/agents.html +1 -1
- package/.documentation/apex.html +1 -1
- package/.documentation/business-analyse.html +1 -1
- package/.documentation/cli-commands.html +3 -3
- package/.documentation/commands.html +1 -1
- package/.documentation/efcore.html +1 -1
- package/.documentation/gitflow.html +1 -1
- package/.documentation/hooks.html +1 -1
- package/.documentation/index.html +1 -1
- package/.documentation/init.html +3 -3
- package/.documentation/installation.html +1001 -352
- package/.documentation/ralph-loop.html +1 -1
- package/.documentation/test-web.html +1 -1
- package/README.md +88 -20
- package/dist/index.js +276 -85
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/templates/agents/code-reviewer.md +163 -0
- package/templates/agents/efcore/db-deploy.md +25 -7
- package/templates/agents/efcore/db-reset.md +31 -10
- package/templates/agents/efcore/db-status.md +22 -5
- package/templates/agents/efcore/migration.md +69 -19
- package/templates/agents/gitflow/cleanup.md +8 -1
- package/templates/agents/gitflow/commit.md +7 -5
- package/templates/agents/gitflow/finish.md +6 -4
- package/templates/agents/gitflow/pr.md +8 -1
- package/templates/agents/gitflow/start.md +1 -1
- package/templates/commands/check-version.md +267 -0
- package/templates/commands/efcore/_shared.md +30 -1
- package/templates/commands/efcore/db-reset.md +18 -6
- package/templates/commands/gitflow/OPTIMIZATIONS.md +206 -0
- package/templates/commands/refactor.md +164 -0
- package/templates/project/DependencyInjection.Application.cs.template +25 -0
- package/templates/project/DependencyInjection.Infrastructure.cs.template +61 -0
- package/templates/project/DesignTimeExtensionsDbContextFactory.cs.template +70 -0
- package/templates/project/ExampleEntity.cs.template +116 -0
- package/templates/project/ExampleEntityConfiguration.cs.template +64 -0
- package/templates/project/ExampleService.cs.template +146 -0
- package/templates/project/ExtensionsDbContext.cs.template +41 -0
- package/templates/project/IExtensionsDbContext.cs.template +22 -0
- package/templates/project/Program.cs.template +47 -0
- package/templates/project/README.md +79 -0
- package/templates/ralph/README.md +10 -8
- package/templates/ralph/ralph.config.yaml +2 -2
- package/templates/skills/_shared.md +44 -44
- package/templates/skills/ai-prompt/SKILL.md +55 -55
- package/templates/skills/apex/SKILL.md +235 -0
- package/templates/skills/apex/steps/step-00-init.md +203 -0
- package/templates/skills/apex/steps/step-01-analyze.md +210 -0
- package/templates/skills/apex/steps/step-02-plan.md +217 -0
- package/templates/skills/apex/steps/step-03-execute.md +178 -0
- package/templates/skills/apex/steps/step-04-validate.md +217 -0
- package/templates/skills/apex/steps/step-05-examine.md +207 -0
- package/templates/skills/apex/steps/step-06-resolve.md +181 -0
- package/templates/skills/apex/steps/step-07-tests.md +206 -0
- package/templates/skills/apex/steps/step-08-run-tests.md +207 -0
- package/templates/skills/apex/templates/00-context.md +46 -0
- package/templates/skills/apex/templates/01-analyze.md +63 -0
- package/templates/skills/apex/templates/02-plan.md +63 -0
- package/templates/skills/apex/templates/03-execute.md +34 -0
- package/templates/skills/apex/templates/04-validate.md +61 -0
- package/templates/skills/apex/templates/05-examine.md +58 -0
- package/templates/skills/apex/templates/06-resolve.md +39 -0
- package/templates/skills/apex/templates/07-tests.md +56 -0
- package/templates/skills/apex/templates/08-run-tests.md +41 -0
- package/templates/skills/apex/templates/README.md +69 -0
- package/templates/skills/application/SKILL.md +50 -50
- package/templates/skills/application/templates-backend.md +25 -25
- package/templates/skills/application/templates-frontend.md +43 -43
- package/templates/skills/application/templates-i18n.md +29 -29
- package/templates/skills/application/templates-seed.md +77 -77
- package/templates/skills/business-analyse/SKILL.md +223 -0
- package/templates/skills/business-analyse/_shared.md +258 -0
- package/templates/skills/business-analyse/questionnaire/01-context.md +33 -0
- package/templates/skills/business-analyse/questionnaire/02-stakeholders.md +35 -0
- package/templates/skills/business-analyse/questionnaire/03-scope.md +35 -0
- package/templates/skills/business-analyse/questionnaire/04-data.md +36 -0
- package/templates/skills/business-analyse/questionnaire/05-integrations.md +36 -0
- package/templates/skills/business-analyse/questionnaire/06-security.md +40 -0
- package/templates/skills/business-analyse/questionnaire/07-ui.md +36 -0
- package/templates/skills/business-analyse/questionnaire/08-performance.md +35 -0
- package/templates/skills/business-analyse/questionnaire/09-constraints.md +35 -0
- package/templates/skills/business-analyse/questionnaire/10-documentation.md +35 -0
- package/templates/skills/business-analyse/questionnaire.md +177 -177
- package/templates/skills/business-analyse/react/components.md +340 -0
- package/templates/skills/business-analyse/react/i18n-template.md +245 -0
- package/templates/skills/business-analyse/react/schema.md +151 -0
- package/templates/skills/business-analyse/steps/step-00-init.md +293 -0
- package/templates/skills/business-analyse/steps/step-01-discover.md +267 -0
- package/templates/skills/business-analyse/steps/step-02-analyse.md +243 -0
- package/templates/skills/business-analyse/steps/step-03-specify.md +317 -0
- package/templates/skills/business-analyse/steps/step-04-validate.md +239 -0
- package/templates/skills/business-analyse/steps/step-05-handoff.md +336 -0
- package/templates/skills/business-analyse/steps/step-06-doc-html.md +261 -0
- package/templates/skills/business-analyse/templates/00-context.md +105 -0
- package/templates/skills/business-analyse/templates/frd-brd.md +97 -0
- package/templates/skills/business-analyse/templates/frd-discovery.md +78 -0
- package/templates/skills/business-analyse/templates/frd-handoff.md +118 -0
- package/templates/skills/business-analyse/templates/frd-spec.md +168 -0
- package/templates/skills/business-analyse/templates-frd.md +217 -217
- package/templates/skills/business-analyse/templates-react.md +26 -26
- package/templates/skills/controller/SKILL.md +141 -92
- package/templates/skills/controller/postman-templates.md +15 -15
- package/templates/skills/controller/steps/step-00-init.md +191 -0
- package/templates/skills/controller/steps/step-01-analyze.md +146 -0
- package/templates/skills/controller/steps/step-02-plan.md +176 -0
- package/templates/skills/controller/steps/step-03-generate.md +219 -0
- package/templates/skills/controller/steps/step-04-perms.md +219 -0
- package/templates/skills/controller/steps/step-05-validate.md +107 -0
- package/templates/skills/controller/templates.md +77 -77
- package/templates/skills/documentation/SKILL.md +79 -79
- package/templates/skills/feature-full/SKILL.md +38 -38
- package/templates/skills/gitflow/SKILL.md +277 -0
- package/templates/{commands → skills}/gitflow/_shared.md +20 -20
- package/templates/skills/gitflow/phases/abort.md +173 -0
- package/templates/skills/gitflow/phases/cleanup.md +226 -0
- package/templates/skills/gitflow/phases/status.md +178 -0
- package/templates/skills/gitflow/steps/step-commit.md +255 -0
- package/templates/skills/gitflow/steps/step-finish.md +255 -0
- package/templates/skills/gitflow/steps/step-init.md +209 -0
- package/templates/skills/gitflow/steps/step-merge.md +225 -0
- package/templates/skills/gitflow/steps/step-plan.md +208 -0
- package/templates/skills/gitflow/steps/step-pr.md +235 -0
- package/templates/skills/gitflow/steps/step-start.md +234 -0
- package/templates/skills/gitflow/steps/step-sync.md +200 -0
- package/templates/skills/gitflow/templates/config.json +53 -0
- package/templates/skills/notification/SKILL.md +51 -51
- package/templates/skills/ralph-loop/SKILL.md +228 -0
- package/templates/skills/ralph-loop/steps/step-00-init.md +201 -0
- package/templates/skills/ralph-loop/steps/step-01-task.md +169 -0
- package/templates/skills/ralph-loop/steps/step-02-execute.md +173 -0
- package/templates/skills/ralph-loop/steps/step-03-commit.md +170 -0
- package/templates/skills/ralph-loop/steps/step-04-check.md +162 -0
- package/templates/skills/ralph-loop/steps/step-05-report.md +181 -0
- package/templates/skills/review-code/SKILL.md +219 -0
- package/templates/skills/review-code/references/clean-code-principles.md +140 -0
- package/templates/skills/review-code/references/code-quality-metrics.md +174 -0
- package/templates/skills/review-code/references/feedback-patterns.md +149 -0
- package/templates/skills/review-code/references/security-checklist.md +127 -0
- package/templates/skills/ui-components/SKILL.md +54 -54
- package/templates/skills/workflow/SKILL.md +46 -46
- package/templates/commands/ai-prompt.md +0 -315
- package/templates/commands/apex/1-analyze.md +0 -100
- package/templates/commands/apex/2-plan.md +0 -145
- package/templates/commands/apex/3-execute.md +0 -171
- package/templates/commands/apex/4-examine.md +0 -116
- package/templates/commands/apex/5-tasks.md +0 -209
- package/templates/commands/apex.md +0 -76
- package/templates/commands/application/create.md +0 -362
- package/templates/commands/application/templates-backend.md +0 -463
- package/templates/commands/application/templates-frontend.md +0 -517
- package/templates/commands/application/templates-i18n.md +0 -478
- package/templates/commands/application/templates-seed.md +0 -362
- package/templates/commands/application.md +0 -303
- package/templates/commands/business-analyse/0-orchestrate.md +0 -156
- package/templates/commands/business-analyse/1-init.md +0 -99
- package/templates/commands/business-analyse/2-discover.md +0 -143
- package/templates/commands/business-analyse/3-analyse.md +0 -106
- package/templates/commands/business-analyse/4-specify.md +0 -133
- package/templates/commands/business-analyse/5-validate.md +0 -132
- package/templates/commands/business-analyse/6-handoff.md +0 -157
- package/templates/commands/business-analyse/7-doc-html.md +0 -103
- package/templates/commands/business-analyse/_shared.md +0 -176
- package/templates/commands/business-analyse/bug.md +0 -118
- package/templates/commands/business-analyse/change-request.md +0 -144
- package/templates/commands/business-analyse/hotfix.md +0 -116
- package/templates/commands/business-analyse.md +0 -121
- package/templates/commands/controller/create.md +0 -216
- package/templates/commands/controller/postman-templates.md +0 -528
- package/templates/commands/controller/templates.md +0 -600
- package/templates/commands/controller.md +0 -337
- package/templates/commands/create/agent.md +0 -138
- package/templates/commands/create/command.md +0 -166
- package/templates/commands/create/hook.md +0 -234
- package/templates/commands/create/plugin.md +0 -329
- package/templates/commands/create/project.md +0 -508
- package/templates/commands/create/skill.md +0 -199
- package/templates/commands/create.md +0 -220
- package/templates/commands/documentation/module.md +0 -202
- package/templates/commands/documentation/templates.md +0 -432
- package/templates/commands/documentation.md +0 -190
- package/templates/commands/epct.md +0 -69
- package/templates/commands/explain.md +0 -186
- package/templates/commands/feature-full.md +0 -267
- package/templates/commands/gitflow/1-init.md +0 -188
- package/templates/commands/gitflow/10-start.md +0 -190
- package/templates/commands/gitflow/11-finish.md +0 -382
- package/templates/commands/gitflow/12-cleanup.md +0 -103
- package/templates/commands/gitflow/13-sync.md +0 -216
- package/templates/commands/gitflow/14-rebase.md +0 -251
- package/templates/commands/gitflow/2-status.md +0 -122
- package/templates/commands/gitflow/3-commit.md +0 -209
- package/templates/commands/gitflow/4-plan.md +0 -174
- package/templates/commands/gitflow/5-exec.md +0 -202
- package/templates/commands/gitflow/6-abort.md +0 -121
- package/templates/commands/gitflow/7-pull-request.md +0 -176
- package/templates/commands/gitflow/8-review.md +0 -113
- package/templates/commands/gitflow/9-merge.md +0 -157
- package/templates/commands/gitflow.md +0 -128
- package/templates/commands/implement.md +0 -663
- package/templates/commands/init.md +0 -567
- package/templates/commands/mcp-integration.md +0 -330
- package/templates/commands/notification.md +0 -129
- package/templates/commands/oneshot.md +0 -57
- package/templates/commands/quickstart.md +0 -154
- package/templates/commands/ralph-loop/cancel-ralph.md +0 -18
- package/templates/commands/ralph-loop/help.md +0 -126
- package/templates/commands/ralph-loop/ralph-loop.md +0 -120
- package/templates/commands/review.md +0 -106
- 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
|
+
}
|