@atlashub/smartstack-mcp 1.2.0 → 1.2.1
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/README.md +96 -140
- package/dist/index.js +88 -60
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,198 +1,154 @@
|
|
|
1
|
-
# @smartstack
|
|
1
|
+
# @atlashub/smartstack-mcp
|
|
2
2
|
|
|
3
3
|
MCP (Model Context Protocol) server for SmartStack/AtlasHub platform development.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Installation
|
|
6
6
|
|
|
7
|
-
###
|
|
7
|
+
### Option 1: Claude Code CLI (Recommended)
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
| `check_migrations` | Analyze EF Core migrations for conflicts and ordering issues |
|
|
13
|
-
| `scaffold_extension` | Generate code for services, entities, controllers, or React components |
|
|
14
|
-
| `api_docs` | Get API endpoint documentation from Swagger or code analysis |
|
|
9
|
+
```bash
|
|
10
|
+
# Add SmartStack MCP (user-level, available in all projects)
|
|
11
|
+
claude mcp add smartstack -s user -e SMARTSTACK_PROJECT_PATH=C:/path/to/your/SmartStack.app -- npx -y @atlashub/smartstack-mcp
|
|
15
12
|
|
|
16
|
-
|
|
13
|
+
# Or project-level (only for current project)
|
|
14
|
+
claude mcp add smartstack -e SMARTSTACK_PROJECT_PATH=C:/path/to/your/SmartStack.app -- npx -y @atlashub/smartstack-mcp
|
|
17
15
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
| `smartstack://api/{endpoint}` | API endpoint documentation |
|
|
23
|
-
| `smartstack://schema/{table}` | Database schema information |
|
|
24
|
-
|
|
25
|
-
## Installation
|
|
16
|
+
# With global install (faster startup)
|
|
17
|
+
npm install -g @atlashub/smartstack-mcp
|
|
18
|
+
claude mcp add smartstack -s user -e SMARTSTACK_PROJECT_PATH=C:/path/to/your/SmartStack.app -- smartstack-mcp
|
|
19
|
+
```
|
|
26
20
|
|
|
21
|
+
**Verify installation:**
|
|
27
22
|
```bash
|
|
28
|
-
|
|
29
|
-
cd "D:\01 - projets\SmartStack.mcp\02-Develop"
|
|
30
|
-
npm install
|
|
31
|
-
|
|
32
|
-
# Build
|
|
33
|
-
npm run build
|
|
23
|
+
claude mcp list
|
|
34
24
|
```
|
|
35
25
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
### Environment Variables
|
|
26
|
+
### Option 2: Visual Studio Code (Extension Claude Code)
|
|
39
27
|
|
|
40
|
-
|
|
41
|
-
|----------|-------------|---------|
|
|
42
|
-
| `SMARTSTACK_PROJECT_PATH` | Path to SmartStack.app project | `D:/SmartStack.app/features/Rework-to-package` |
|
|
43
|
-
| `SMARTSTACK_API_URL` | SmartStack API URL | `https://localhost:7055` |
|
|
44
|
-
| `SMARTSTACK_API_ENABLED` | Enable API integration | `true` |
|
|
45
|
-
| `LOG_LEVEL` | Logging level (debug, info, warn, error) | `info` |
|
|
46
|
-
|
|
47
|
-
### Claude Desktop Configuration
|
|
48
|
-
|
|
49
|
-
Add to your Claude Desktop config file (`claude_desktop_config.json`):
|
|
28
|
+
Create a `.mcp.json` file at the root of your project:
|
|
50
29
|
|
|
51
30
|
```json
|
|
52
31
|
{
|
|
53
32
|
"mcpServers": {
|
|
54
33
|
"smartstack": {
|
|
55
|
-
"command": "
|
|
56
|
-
"args": ["
|
|
34
|
+
"command": "npx",
|
|
35
|
+
"args": ["-y", "@atlashub/smartstack-mcp"],
|
|
57
36
|
"env": {
|
|
58
|
-
"SMARTSTACK_PROJECT_PATH": "
|
|
59
|
-
"SMARTSTACK_API_URL": "https://localhost:7055"
|
|
37
|
+
"SMARTSTACK_PROJECT_PATH": "C:/path/to/your/SmartStack.app"
|
|
60
38
|
}
|
|
61
39
|
}
|
|
62
40
|
}
|
|
63
41
|
}
|
|
64
42
|
```
|
|
65
43
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
Add to your `.claude/settings.json`:
|
|
44
|
+
Or with global install (faster startup):
|
|
69
45
|
|
|
70
46
|
```json
|
|
71
47
|
{
|
|
72
48
|
"mcpServers": {
|
|
73
49
|
"smartstack": {
|
|
74
|
-
"command": "
|
|
75
|
-
"args": ["D:/01 - projets/SmartStack.mcp/02-Develop/dist/index.js"],
|
|
50
|
+
"command": "smartstack-mcp",
|
|
76
51
|
"env": {
|
|
77
|
-
"SMARTSTACK_PROJECT_PATH": "
|
|
52
|
+
"SMARTSTACK_PROJECT_PATH": "C:/path/to/your/SmartStack.app"
|
|
78
53
|
}
|
|
79
54
|
}
|
|
80
55
|
}
|
|
81
56
|
}
|
|
82
57
|
```
|
|
83
58
|
|
|
84
|
-
|
|
59
|
+
**Steps:**
|
|
60
|
+
1. Install the Claude Code extension in VS Code
|
|
61
|
+
2. Create the `.mcp.json` file at project root
|
|
62
|
+
3. Reload VS Code or the extension
|
|
63
|
+
4. The MCP server will be available in Claude Code panel
|
|
85
64
|
|
|
86
|
-
###
|
|
65
|
+
### Option 3: Claude Desktop
|
|
87
66
|
|
|
88
|
-
|
|
89
|
-
Use validate_conventions tool with checks: ["tables", "migrations", "services"]
|
|
90
|
-
```
|
|
67
|
+
Add to `claude_desktop_config.json`:
|
|
91
68
|
|
|
92
|
-
|
|
69
|
+
- **Windows**: `%APPDATA%\Claude\claude_desktop_config.json`
|
|
70
|
+
- **macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
|
|
93
71
|
|
|
94
|
-
```
|
|
95
|
-
|
|
72
|
+
```json
|
|
73
|
+
{
|
|
74
|
+
"mcpServers": {
|
|
75
|
+
"smartstack": {
|
|
76
|
+
"command": "npx",
|
|
77
|
+
"args": ["-y", "@atlashub/smartstack-mcp"],
|
|
78
|
+
"env": {
|
|
79
|
+
"SMARTSTACK_PROJECT_PATH": "C:/path/to/your/SmartStack.app"
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
96
84
|
```
|
|
97
85
|
|
|
98
|
-
###
|
|
86
|
+
### Option 4: Manual Execution
|
|
99
87
|
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
88
|
+
```bash
|
|
89
|
+
# Using npx (no install required)
|
|
90
|
+
SMARTSTACK_PROJECT_PATH=/path/to/project npx @atlashub/smartstack-mcp
|
|
91
|
+
|
|
92
|
+
# Or if installed globally
|
|
93
|
+
npm install -g @atlashub/smartstack-mcp
|
|
94
|
+
SMARTSTACK_PROJECT_PATH=/path/to/project smartstack-mcp
|
|
105
95
|
```
|
|
106
96
|
|
|
107
|
-
|
|
97
|
+
## Adding Context7 (Optional)
|
|
108
98
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
99
|
+
Context7 provides up-to-date documentation lookups for any library.
|
|
100
|
+
|
|
101
|
+
**Claude Code CLI:**
|
|
102
|
+
```bash
|
|
103
|
+
claude mcp add context7 -s user -- npx -y @upstash/context7-mcp
|
|
113
104
|
```
|
|
114
105
|
|
|
115
|
-
|
|
106
|
+
**VS Code (.mcp.json):**
|
|
107
|
+
```json
|
|
108
|
+
{
|
|
109
|
+
"mcpServers": {
|
|
110
|
+
"smartstack": {
|
|
111
|
+
"command": "npx",
|
|
112
|
+
"args": ["-y", "@atlashub/smartstack-mcp"],
|
|
113
|
+
"env": {
|
|
114
|
+
"SMARTSTACK_PROJECT_PATH": "C:/path/to/your/SmartStack.app"
|
|
115
|
+
}
|
|
116
|
+
},
|
|
117
|
+
"context7": {
|
|
118
|
+
"command": "npx",
|
|
119
|
+
"args": ["-y", "@upstash/context7-mcp"]
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
```
|
|
116
124
|
|
|
117
|
-
|
|
118
|
-
# Watch mode
|
|
119
|
-
npm run dev
|
|
125
|
+
## Configuration
|
|
120
126
|
|
|
121
|
-
|
|
122
|
-
|
|
127
|
+
| Variable | Description | Required |
|
|
128
|
+
|----------|-------------|----------|
|
|
129
|
+
| `SMARTSTACK_PROJECT_PATH` | Path to your SmartStack.app project | Yes |
|
|
130
|
+
| `SMARTSTACK_API_URL` | SmartStack API URL | No |
|
|
131
|
+
| `LOG_LEVEL` | Logging level (debug, info, warn, error) | No |
|
|
123
132
|
|
|
124
|
-
|
|
125
|
-
npm run typecheck
|
|
133
|
+
## Features
|
|
126
134
|
|
|
127
|
-
|
|
128
|
-
npm run lint
|
|
129
|
-
```
|
|
135
|
+
### Tools
|
|
130
136
|
|
|
131
|
-
|
|
137
|
+
| Tool | Description |
|
|
138
|
+
|------|-------------|
|
|
139
|
+
| `validate_conventions` | Validate AtlasHub conventions |
|
|
140
|
+
| `check_migrations` | Analyze EF Core migrations |
|
|
141
|
+
| `scaffold_extension` | Generate code scaffolding |
|
|
142
|
+
| `api_docs` | Get API documentation |
|
|
132
143
|
|
|
133
|
-
|
|
134
|
-
src/
|
|
135
|
-
├── index.ts # Entry point
|
|
136
|
-
├── server.ts # MCP server configuration
|
|
137
|
-
├── config.ts # Configuration management
|
|
138
|
-
├── tools/ # MCP tool implementations
|
|
139
|
-
│ ├── validate-conventions.ts
|
|
140
|
-
│ ├── check-migrations.ts
|
|
141
|
-
│ ├── scaffold-extension.ts
|
|
142
|
-
│ └── api-docs.ts
|
|
143
|
-
├── resources/ # MCP resource implementations
|
|
144
|
-
│ ├── conventions.ts
|
|
145
|
-
│ ├── project-info.ts
|
|
146
|
-
│ ├── api-endpoints.ts
|
|
147
|
-
│ └── db-schema.ts
|
|
148
|
-
├── lib/ # Shared libraries
|
|
149
|
-
│ ├── detector.ts # Project detection
|
|
150
|
-
│ └── logger.ts # Logging utilities
|
|
151
|
-
├── types/ # TypeScript types
|
|
152
|
-
│ └── index.ts
|
|
153
|
-
└── utils/ # Utility functions
|
|
154
|
-
├── fs.ts # File system operations
|
|
155
|
-
├── git.ts # Git commands
|
|
156
|
-
└── dotnet.ts # .NET CLI commands
|
|
157
|
-
```
|
|
144
|
+
### Resources
|
|
158
145
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
- **`extensions`**: Client extension tables
|
|
166
|
-
|
|
167
|
-
### Table Prefixes (by domain)
|
|
168
|
-
Tables use domain-specific prefixes within schemas:
|
|
169
|
-
- `auth_*` - Authorization (Users, Roles, Permissions)
|
|
170
|
-
- `nav_*` - Navigation (Contexts, Applications, Modules)
|
|
171
|
-
- `usr_*` - User profiles (Profiles, Preferences)
|
|
172
|
-
- `ai_*` - AI features (Providers, Models, Prompts)
|
|
173
|
-
- `cfg_*` - Configuration (Settings)
|
|
174
|
-
- `wkf_*` - Workflows (EmailTemplates, Workflows)
|
|
175
|
-
- `support_*` - Support (Tickets, Comments)
|
|
176
|
-
- `entra_*` - Entra sync (Groups, SyncState)
|
|
177
|
-
- `ref_*` - References (Companies, Departments)
|
|
178
|
-
- `loc_*` - Localization (Languages, Translations)
|
|
179
|
-
- `lic_*` - Licensing (Licenses)
|
|
180
|
-
|
|
181
|
-
Example: `.ToTable("auth_Users", "core")`
|
|
182
|
-
|
|
183
|
-
### Migration Naming
|
|
184
|
-
Format: `YYYYMMDD_NNN_Description`
|
|
185
|
-
- Example: `20260115_001_InitialSchema`
|
|
186
|
-
|
|
187
|
-
### Service Pattern
|
|
188
|
-
- Interface: `I{Name}Service`
|
|
189
|
-
- Implementation: `{Name}Service`
|
|
190
|
-
|
|
191
|
-
### Namespace Structure
|
|
192
|
-
- Domain: `SmartStack.Domain`
|
|
193
|
-
- Application: `SmartStack.Application`
|
|
194
|
-
- Infrastructure: `SmartStack.Infrastructure`
|
|
195
|
-
- API: `SmartStack.Api`
|
|
146
|
+
| Resource URI | Description |
|
|
147
|
+
|--------------|-------------|
|
|
148
|
+
| `smartstack://conventions` | Naming conventions |
|
|
149
|
+
| `smartstack://project` | Project information |
|
|
150
|
+
| `smartstack://api/{endpoint}` | API documentation |
|
|
151
|
+
| `smartstack://schema/{table}` | Database schema |
|
|
196
152
|
|
|
197
153
|
## License
|
|
198
154
|
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
#!/usr/bin/env node
|
|
3
2
|
|
|
4
3
|
// src/server.ts
|
|
5
4
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
@@ -149,7 +148,7 @@ var defaultConfig = {
|
|
|
149
148
|
"loc_",
|
|
150
149
|
"lic_"
|
|
151
150
|
],
|
|
152
|
-
migrationFormat: "
|
|
151
|
+
migrationFormat: "{context}_v{version}_{sequence}_{Description}",
|
|
153
152
|
namespaces: {
|
|
154
153
|
domain: "SmartStack.Domain",
|
|
155
154
|
application: "SmartStack.Application",
|
|
@@ -533,7 +532,7 @@ async function findControllerFiles(apiPath) {
|
|
|
533
532
|
import path5 from "path";
|
|
534
533
|
var validateConventionsTool = {
|
|
535
534
|
name: "validate_conventions",
|
|
536
|
-
description: "Validate AtlasHub/SmartStack conventions: SQL schemas (core/extensions), domain table prefixes (auth_, nav_, ai_, etc.), migration naming (
|
|
535
|
+
description: "Validate AtlasHub/SmartStack conventions: SQL schemas (core/extensions), domain table prefixes (auth_, nav_, ai_, etc.), migration naming ({context}_v{version}_{sequence}_*), service interfaces (I*Service), namespace structure",
|
|
537
536
|
inputSchema: {
|
|
538
537
|
type: "object",
|
|
539
538
|
properties: {
|
|
@@ -675,7 +674,7 @@ async function validateMigrationNaming(structure, _config, result) {
|
|
|
675
674
|
return;
|
|
676
675
|
}
|
|
677
676
|
const migrationFiles = await findFiles("*.cs", { cwd: structure.migrations });
|
|
678
|
-
const migrationPattern = /^(\d
|
|
677
|
+
const migrationPattern = /^(\w+)_v(\d+\.\d+\.\d+)_(\d{3})_(.+)\.cs$/;
|
|
679
678
|
const designerPattern = /\.Designer\.cs$/;
|
|
680
679
|
for (const file of migrationFiles) {
|
|
681
680
|
const fileName = path5.basename(file);
|
|
@@ -688,7 +687,7 @@ async function validateMigrationNaming(structure, _config, result) {
|
|
|
688
687
|
category: "migrations",
|
|
689
688
|
message: `Migration "${fileName}" does not follow naming convention`,
|
|
690
689
|
file: path5.relative(structure.root, file),
|
|
691
|
-
suggestion: `Expected format:
|
|
690
|
+
suggestion: `Expected format: {context}_v{version}_{sequence}_{Description}.cs (e.g., core_v1.0.0_001_CreateAuthUsers.cs)`
|
|
692
691
|
});
|
|
693
692
|
}
|
|
694
693
|
}
|
|
@@ -696,14 +695,18 @@ async function validateMigrationNaming(structure, _config, result) {
|
|
|
696
695
|
for (let i = 1; i < orderedMigrations.length; i++) {
|
|
697
696
|
const prev = orderedMigrations[i - 1];
|
|
698
697
|
const curr = orderedMigrations[i];
|
|
699
|
-
const
|
|
700
|
-
const
|
|
701
|
-
if (
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
698
|
+
const prevMatch = migrationPattern.exec(prev);
|
|
699
|
+
const currMatch = migrationPattern.exec(curr);
|
|
700
|
+
if (prevMatch && currMatch) {
|
|
701
|
+
const prevVersion = prevMatch[2];
|
|
702
|
+
const currVersion = currMatch[2];
|
|
703
|
+
if (currVersion < prevVersion) {
|
|
704
|
+
result.warnings.push({
|
|
705
|
+
type: "warning",
|
|
706
|
+
category: "migrations",
|
|
707
|
+
message: `Migration order issue: "${curr}" (v${currVersion}) comes before "${prev}" (v${prevVersion})`
|
|
708
|
+
});
|
|
709
|
+
}
|
|
707
710
|
}
|
|
708
711
|
}
|
|
709
712
|
}
|
|
@@ -871,7 +874,7 @@ async function handleCheckMigrations(args, config) {
|
|
|
871
874
|
async function parseMigrations(migrationsPath, rootPath) {
|
|
872
875
|
const files = await findFiles("*.cs", { cwd: migrationsPath });
|
|
873
876
|
const migrations = [];
|
|
874
|
-
const pattern = /^(\d
|
|
877
|
+
const pattern = /^(\w+)_v(\d+\.\d+\.\d+)_(\d{3})_(.+)\.cs$/;
|
|
875
878
|
for (const file of files) {
|
|
876
879
|
const fileName = path6.basename(file);
|
|
877
880
|
if (fileName.includes(".Designer.") || fileName.includes("ModelSnapshot")) {
|
|
@@ -881,10 +884,13 @@ async function parseMigrations(migrationsPath, rootPath) {
|
|
|
881
884
|
if (match) {
|
|
882
885
|
migrations.push({
|
|
883
886
|
name: fileName.replace(".cs", ""),
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
887
|
+
context: match[1],
|
|
888
|
+
// DbContext (core, extensions, etc.)
|
|
889
|
+
version: match[2],
|
|
890
|
+
// Semver version (1.0.0, 1.2.0, etc.)
|
|
891
|
+
sequence: match[3],
|
|
892
|
+
// Sequence number (001, 002, etc.)
|
|
893
|
+
description: match[4],
|
|
888
894
|
file: path6.relative(rootPath, file),
|
|
889
895
|
applied: true
|
|
890
896
|
// We'd need DB connection to check this
|
|
@@ -892,8 +898,9 @@ async function parseMigrations(migrationsPath, rootPath) {
|
|
|
892
898
|
} else {
|
|
893
899
|
migrations.push({
|
|
894
900
|
name: fileName.replace(".cs", ""),
|
|
895
|
-
|
|
896
|
-
|
|
901
|
+
context: "Unknown",
|
|
902
|
+
version: "0.0.0",
|
|
903
|
+
sequence: "000",
|
|
897
904
|
description: fileName.replace(".cs", ""),
|
|
898
905
|
file: path6.relative(rootPath, file),
|
|
899
906
|
applied: true
|
|
@@ -901,51 +908,63 @@ async function parseMigrations(migrationsPath, rootPath) {
|
|
|
901
908
|
}
|
|
902
909
|
}
|
|
903
910
|
return migrations.sort((a, b) => {
|
|
904
|
-
const
|
|
905
|
-
if (
|
|
906
|
-
return a.
|
|
911
|
+
const versionCompare = compareVersions(a.version, b.version);
|
|
912
|
+
if (versionCompare !== 0) return versionCompare;
|
|
913
|
+
return a.sequence.localeCompare(b.sequence);
|
|
907
914
|
});
|
|
908
915
|
}
|
|
916
|
+
function compareVersions(a, b) {
|
|
917
|
+
const partsA = a.split(".").map(Number);
|
|
918
|
+
const partsB = b.split(".").map(Number);
|
|
919
|
+
for (let i = 0; i < 3; i++) {
|
|
920
|
+
if (partsA[i] > partsB[i]) return 1;
|
|
921
|
+
if (partsA[i] < partsB[i]) return -1;
|
|
922
|
+
}
|
|
923
|
+
return 0;
|
|
924
|
+
}
|
|
909
925
|
function checkNamingConventions(result, _config) {
|
|
910
926
|
for (const migration of result.migrations) {
|
|
911
|
-
if (
|
|
927
|
+
if (migration.context === "Unknown") {
|
|
912
928
|
result.conflicts.push({
|
|
913
929
|
type: "naming",
|
|
914
930
|
description: `Migration "${migration.name}" does not follow naming convention`,
|
|
915
931
|
files: [migration.file],
|
|
916
|
-
resolution: `Rename to format:
|
|
932
|
+
resolution: `Rename to format: {context}_v{version}_{sequence}_{Description} (e.g., core_v1.0.0_001_CreateAuthUsers)`
|
|
917
933
|
});
|
|
918
934
|
}
|
|
919
|
-
if (migration.
|
|
935
|
+
if (migration.version === "0.0.0") {
|
|
920
936
|
result.conflicts.push({
|
|
921
937
|
type: "naming",
|
|
922
|
-
description: `Migration "${migration.name}" missing
|
|
938
|
+
description: `Migration "${migration.name}" missing version number`,
|
|
923
939
|
files: [migration.file],
|
|
924
|
-
resolution: `Use format:
|
|
940
|
+
resolution: `Use format: {context}_v{version}_{sequence}_{Description} where version is semver (1.0.0, 1.2.0, etc.)`
|
|
925
941
|
});
|
|
926
942
|
}
|
|
927
943
|
}
|
|
928
944
|
}
|
|
929
945
|
function checkChronologicalOrder(result) {
|
|
930
|
-
const migrations = result.migrations.filter((m) => m.
|
|
946
|
+
const migrations = result.migrations.filter((m) => m.context !== "Unknown");
|
|
931
947
|
for (let i = 1; i < migrations.length; i++) {
|
|
932
948
|
const prev = migrations[i - 1];
|
|
933
949
|
const curr = migrations[i];
|
|
934
|
-
if (curr.
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
950
|
+
if (curr.context === prev.context) {
|
|
951
|
+
const versionCompare = compareVersions(curr.version, prev.version);
|
|
952
|
+
if (versionCompare < 0) {
|
|
953
|
+
result.conflicts.push({
|
|
954
|
+
type: "order",
|
|
955
|
+
description: `Migration "${curr.name}" (v${curr.version}) is versioned before "${prev.name}" (v${prev.version})`,
|
|
956
|
+
files: [curr.file, prev.file],
|
|
957
|
+
resolution: "Reorder migrations or update version numbers"
|
|
958
|
+
});
|
|
959
|
+
}
|
|
960
|
+
if (curr.version === prev.version && curr.sequence === prev.sequence) {
|
|
961
|
+
result.conflicts.push({
|
|
962
|
+
type: "order",
|
|
963
|
+
description: `Migrations "${curr.name}" and "${prev.name}" have same version and sequence`,
|
|
964
|
+
files: [curr.file, prev.file],
|
|
965
|
+
resolution: "Use different sequence numbers (001, 002, etc.) for migrations in the same version"
|
|
966
|
+
});
|
|
967
|
+
}
|
|
949
968
|
}
|
|
950
969
|
}
|
|
951
970
|
}
|
|
@@ -1000,7 +1019,7 @@ async function checkModelSnapshot(result, structure) {
|
|
|
1000
1019
|
}
|
|
1001
1020
|
const snapshotContent = await readText(snapshotFiles[0]);
|
|
1002
1021
|
for (const migration of result.migrations) {
|
|
1003
|
-
if (migration.
|
|
1022
|
+
if (migration.context !== "Unknown" && !snapshotContent.includes(migration.name)) {
|
|
1004
1023
|
result.conflicts.push({
|
|
1005
1024
|
type: "dependency",
|
|
1006
1025
|
description: `Migration "${migration.name}" not referenced in ModelSnapshot`,
|
|
@@ -1018,12 +1037,12 @@ function generateSuggestions(result) {
|
|
|
1018
1037
|
}
|
|
1019
1038
|
if (result.conflicts.some((c) => c.type === "naming")) {
|
|
1020
1039
|
result.suggestions.push(
|
|
1021
|
-
"Use convention:
|
|
1040
|
+
"Use convention: {context}_v{version}_{sequence}_{Description} for migration naming (e.g., core_v1.0.0_001_CreateAuthUsers)"
|
|
1022
1041
|
);
|
|
1023
1042
|
}
|
|
1024
1043
|
if (result.conflicts.some((c) => c.type === "order")) {
|
|
1025
1044
|
result.suggestions.push(
|
|
1026
|
-
"Ensure migrations are created in
|
|
1045
|
+
"Ensure migrations are created in version order to avoid conflicts"
|
|
1027
1046
|
);
|
|
1028
1047
|
}
|
|
1029
1048
|
if (result.migrations.length > 20) {
|
|
@@ -1047,11 +1066,11 @@ function formatResult2(result, currentBranch, compareBranch) {
|
|
|
1047
1066
|
lines.push("");
|
|
1048
1067
|
lines.push("## Migrations");
|
|
1049
1068
|
lines.push("");
|
|
1050
|
-
lines.push("| Name |
|
|
1051
|
-
lines.push("
|
|
1069
|
+
lines.push("| Name | Context | Version | Sequence | Description |");
|
|
1070
|
+
lines.push("|------|---------|---------|----------|-------------|");
|
|
1052
1071
|
for (const migration of result.migrations) {
|
|
1053
1072
|
lines.push(
|
|
1054
|
-
`| ${migration.name} | ${migration.
|
|
1073
|
+
`| ${migration.name} | ${migration.context} | ${migration.version} | ${migration.sequence} | ${migration.description} |`
|
|
1055
1074
|
);
|
|
1056
1075
|
}
|
|
1057
1076
|
lines.push("");
|
|
@@ -1978,28 +1997,37 @@ Migrations MUST follow this naming pattern:
|
|
|
1978
1997
|
${migrationFormat}
|
|
1979
1998
|
\`\`\`
|
|
1980
1999
|
|
|
2000
|
+
| Part | Description | Example |
|
|
2001
|
+
|------|-------------|---------|
|
|
2002
|
+
| \`{context}\` | DbContext name | \`core\`, \`extensions\` |
|
|
2003
|
+
| \`{version}\` | Semver version | \`v1.0.0\`, \`v1.2.0\` |
|
|
2004
|
+
| \`{sequence}\` | Order in version | \`001\`, \`002\` |
|
|
2005
|
+
| \`{Description}\` | Action (PascalCase) | \`CreateAuthUsers\` |
|
|
2006
|
+
|
|
1981
2007
|
**Examples:**
|
|
1982
|
-
- \`
|
|
1983
|
-
- \`
|
|
1984
|
-
- \`
|
|
2008
|
+
- \`core_v1.0.0_001_InitialSchema.cs\`
|
|
2009
|
+
- \`core_v1.0.0_002_CreateAuthUsers.cs\`
|
|
2010
|
+
- \`core_v1.2.0_001_AddUserProfiles.cs\`
|
|
2011
|
+
- \`extensions_v1.0.0_001_AddClientFeatures.cs\`
|
|
1985
2012
|
|
|
1986
2013
|
### Creating Migrations
|
|
1987
2014
|
|
|
1988
2015
|
\`\`\`bash
|
|
1989
2016
|
# Create a new migration
|
|
1990
|
-
dotnet ef migrations add
|
|
2017
|
+
dotnet ef migrations add core_v1.0.0_001_InitialSchema
|
|
1991
2018
|
|
|
1992
2019
|
# With context specified
|
|
1993
|
-
dotnet ef migrations add
|
|
2020
|
+
dotnet ef migrations add core_v1.2.0_001_AddUserProfiles --context ApplicationDbContext
|
|
1994
2021
|
\`\`\`
|
|
1995
2022
|
|
|
1996
2023
|
### Migration Rules
|
|
1997
2024
|
|
|
1998
2025
|
1. **One migration per feature** - Group related changes in a single migration
|
|
1999
|
-
2. **
|
|
2000
|
-
3. **Sequence numbers** - Use NNN (001, 002, etc.) for migrations
|
|
2001
|
-
4. **
|
|
2002
|
-
5. **
|
|
2026
|
+
2. **Version-based naming** - Use semver (v1.0.0, v1.2.0) to link migrations to releases
|
|
2027
|
+
3. **Sequence numbers** - Use NNN (001, 002, etc.) for migrations in the same version
|
|
2028
|
+
4. **Context prefix** - Use \`core_\` for platform tables, \`extensions_\` for client extensions
|
|
2029
|
+
5. **Descriptive names** - Use clear PascalCase descriptions (CreateAuthUsers, AddUserProfiles, etc.)
|
|
2030
|
+
6. **Schema must be specified** - All tables must specify their schema in ToTable()
|
|
2003
2031
|
|
|
2004
2032
|
---
|
|
2005
2033
|
|
|
@@ -2166,7 +2194,7 @@ public interface IUserServiceHooks
|
|
|
2166
2194
|
| Platform schema | \`${schemas.platform}\` | \`.ToTable("auth_Users", "${schemas.platform}")\` |
|
|
2167
2195
|
| Extensions schema | \`${schemas.extensions}\` | \`.ToTable("client_Custom", "${schemas.extensions}")\` |
|
|
2168
2196
|
| Table prefixes | \`${tablePrefixes.slice(0, 5).join(", ")}\`, etc. | \`auth_Users\`, \`nav_Modules\` |
|
|
2169
|
-
| Migration | \`
|
|
2197
|
+
| Migration | \`{context}_v{version}_{seq}_{Desc}\` | \`core_v1.0.0_001_CreateAuthUsers\` |
|
|
2170
2198
|
| Interface | \`I<Name>Service\` | \`IUserService\` |
|
|
2171
2199
|
| Implementation | \`<Name>Service\` | \`UserService\` |
|
|
2172
2200
|
| Domain namespace | \`${namespaces.domain}\` | - |
|