@atlashub/smartstack-cli 1.13.2 → 1.14.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/.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 +231 -236
- package/.documentation/hooks.html +1 -1
- package/.documentation/index.html +1 -1
- package/.documentation/init.html +3 -3
- package/.documentation/installation.html +1075 -351
- package/.documentation/ralph-loop.html +1 -1
- package/.documentation/test-web.html +1 -1
- package/README.md +88 -20
- package/config/default-config.json +10 -1
- 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 +70 -20
- 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 +31 -2
- package/templates/commands/efcore/db-reset.md +18 -6
- package/templates/commands/efcore/migration.md +1 -1
- package/templates/commands/efcore/rebase-snapshot.md +1 -1
- package/templates/commands/efcore/squash.md +1 -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 +334 -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
- package/templates/gitflow/config.json +0 -138
|
@@ -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
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
using Microsoft.EntityFrameworkCore;
|
|
2
|
+
|
|
3
|
+
namespace {{ProjectName}}.Application.Common.Interfaces;
|
|
4
|
+
|
|
5
|
+
/// <summary>
|
|
6
|
+
/// Interface for Extensions DbContext (client-specific entities).
|
|
7
|
+
///
|
|
8
|
+
/// This interface provides access to all entities specific to your project.
|
|
9
|
+
/// For Core entities (User, Role, Permission, etc.), use ICoreDataService.
|
|
10
|
+
/// </summary>
|
|
11
|
+
public interface IExtensionsDbContext
|
|
12
|
+
{
|
|
13
|
+
// === YOUR ENTITIES ===
|
|
14
|
+
// Add DbSet properties for your entities here. Example:
|
|
15
|
+
// DbSet<Order> Orders { get; }
|
|
16
|
+
// DbSet<Product> Products { get; }
|
|
17
|
+
|
|
18
|
+
/// <summary>
|
|
19
|
+
/// Saves all changes made in this context to the database.
|
|
20
|
+
/// </summary>
|
|
21
|
+
Task<int> SaveChangesAsync(CancellationToken cancellationToken = default);
|
|
22
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
using Microsoft.EntityFrameworkCore;
|
|
2
|
+
using SmartStack.Api.Extensions;
|
|
3
|
+
using {{ProjectName}}.Infrastructure;
|
|
4
|
+
using {{ProjectName}}.Infrastructure.Persistence;
|
|
5
|
+
using {{ProjectName}}.Application;
|
|
6
|
+
|
|
7
|
+
var builder = WebApplication.CreateBuilder(args);
|
|
8
|
+
|
|
9
|
+
// ===================================================================
|
|
10
|
+
// 1. Add SmartStack Core services (from NuGet package)
|
|
11
|
+
// ===================================================================
|
|
12
|
+
builder.Services.AddSmartStack(builder.Configuration, options =>
|
|
13
|
+
{
|
|
14
|
+
options.EnableDevSeeding = builder.Environment.IsDevelopment();
|
|
15
|
+
options.EnableSwagger = builder.Environment.IsDevelopment();
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
// ===================================================================
|
|
19
|
+
// 2. Add client-specific services (Dual-DbContext pattern)
|
|
20
|
+
// ===================================================================
|
|
21
|
+
builder.Services.Add{{ProjectName}}Infrastructure(builder.Configuration);
|
|
22
|
+
builder.Services.Add{{ProjectName}}Application();
|
|
23
|
+
|
|
24
|
+
var app = builder.Build();
|
|
25
|
+
|
|
26
|
+
// ===================================================================
|
|
27
|
+
// 3. Initialize SmartStack + apply migrations (in correct order!)
|
|
28
|
+
// ===================================================================
|
|
29
|
+
// This initializes SmartStack and applies Core migrations automatically
|
|
30
|
+
await app.InitializeSmartStackAsync();
|
|
31
|
+
|
|
32
|
+
// Apply Extensions migrations AFTER Core migrations
|
|
33
|
+
// Your client-specific tables may have FK references to Core tables
|
|
34
|
+
if (app.Environment.IsDevelopment())
|
|
35
|
+
{
|
|
36
|
+
using var scope = app.Services.CreateScope();
|
|
37
|
+
var extDb = scope.ServiceProvider.GetRequiredService<ExtensionsDbContext>();
|
|
38
|
+
await extDb.Database.MigrateAsync();
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// ===================================================================
|
|
42
|
+
// 4. SmartStack middleware & endpoints
|
|
43
|
+
// ===================================================================
|
|
44
|
+
app.UseSmartStack();
|
|
45
|
+
app.MapSmartStack();
|
|
46
|
+
|
|
47
|
+
app.Run();
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# SmartStack Client Project Templates
|
|
2
|
+
|
|
3
|
+
These templates are used by the SmartStack CLI to generate new client projects.
|
|
4
|
+
|
|
5
|
+
## Template Files
|
|
6
|
+
|
|
7
|
+
| File | Description | Destination |
|
|
8
|
+
|------|-------------|-------------|
|
|
9
|
+
| `ExtensionsDbContext.cs.template` | DbContext for client entities | `{ProjectName}.Infrastructure/Persistence/` |
|
|
10
|
+
| `IExtensionsDbContext.cs.template` | Interface for ExtensionsDbContext | `{ProjectName}.Application/Common/Interfaces/` |
|
|
11
|
+
| `DependencyInjection.Infrastructure.cs.template` | DI configuration for Infrastructure | `{ProjectName}.Infrastructure/` |
|
|
12
|
+
| `Program.cs.template` | API entry point with migration order | `{ProjectName}.Api/` |
|
|
13
|
+
| `DesignTimeExtensionsDbContextFactory.cs.template` | Factory for EF Core CLI tools | `{ProjectName}.Infrastructure/Persistence/` |
|
|
14
|
+
| `ExampleEntity.cs.template` | Example entity with FK to Core | `{ProjectName}.Domain/Entities/` (optional) |
|
|
15
|
+
| `ExampleService.cs.template` | Example service using ICoreDataService | `{ProjectName}.Infrastructure/Services/` (optional) |
|
|
16
|
+
| `ExampleEntityConfiguration.cs.template` | Example EF Core configuration | `{ProjectName}.Infrastructure/Persistence/Configurations/` (optional) |
|
|
17
|
+
|
|
18
|
+
## Placeholders
|
|
19
|
+
|
|
20
|
+
The following placeholders are replaced during project generation:
|
|
21
|
+
|
|
22
|
+
| Placeholder | Description | Example |
|
|
23
|
+
|-------------|-------------|---------|
|
|
24
|
+
| `{{ProjectName}}` | PascalCase project name | `MyCompany` |
|
|
25
|
+
|
|
26
|
+
## Architecture Overview
|
|
27
|
+
|
|
28
|
+
### Dual DbContext Pattern
|
|
29
|
+
|
|
30
|
+
SmartStack uses two separate DbContexts:
|
|
31
|
+
|
|
32
|
+
1. **CoreDbContext** (from SmartStack NuGet package)
|
|
33
|
+
- Schema: `core`
|
|
34
|
+
- Manages: Users, Roles, Permissions, Navigation, etc.
|
|
35
|
+
- Migrations: `core.__EFMigrationsHistory`
|
|
36
|
+
|
|
37
|
+
2. **ExtensionsDbContext** (client project)
|
|
38
|
+
- Schema: `extensions`
|
|
39
|
+
- Manages: Client-specific entities
|
|
40
|
+
- Migrations: `extensions.__EFMigrationsHistory`
|
|
41
|
+
|
|
42
|
+
### FK References to Core Entities
|
|
43
|
+
|
|
44
|
+
When your entities need to reference Core entities (User, Role, etc.):
|
|
45
|
+
|
|
46
|
+
```csharp
|
|
47
|
+
// IN YOUR ENTITY - Store GUID only
|
|
48
|
+
public Guid CustomerId { get; private set; } // FK to User
|
|
49
|
+
|
|
50
|
+
// IN YOUR SERVICE - Use ICoreDataService
|
|
51
|
+
var user = await _coreDataService.GetUserByIdAsync(entity.CustomerId);
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
**DO NOT** create navigation properties to Core entities, as ExtensionsDbContext doesn't know about them.
|
|
55
|
+
|
|
56
|
+
### Migration Order
|
|
57
|
+
|
|
58
|
+
Migrations must be applied in order:
|
|
59
|
+
|
|
60
|
+
1. Core migrations first (SmartStack platform tables)
|
|
61
|
+
2. Extensions migrations second (client tables that may reference Core)
|
|
62
|
+
|
|
63
|
+
This is handled automatically in `Program.cs.template`.
|
|
64
|
+
|
|
65
|
+
## Usage
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
# Create new project
|
|
69
|
+
smartstack init MyProject
|
|
70
|
+
|
|
71
|
+
# Add entity to Extensions
|
|
72
|
+
smartstack scaffold entity Order --context extensions
|
|
73
|
+
|
|
74
|
+
# Create migration
|
|
75
|
+
dotnet ef migrations add ext_v1.0.0_001_AddOrders --context ExtensionsDbContext
|
|
76
|
+
|
|
77
|
+
# Apply migrations
|
|
78
|
+
dotnet ef database update
|
|
79
|
+
```
|
|
@@ -27,15 +27,17 @@ Edit `ralph.config.yaml` to customize:
|
|
|
27
27
|
|
|
28
28
|
Ralph **requires** these MCP servers to function:
|
|
29
29
|
|
|
30
|
-
1.
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
30
|
+
### 1. Download MCP packages
|
|
31
|
+
```bash
|
|
32
|
+
npm install -g @atlashub/smartstack-mcp
|
|
33
|
+
npm install -g @upstash/context7-mcp
|
|
34
|
+
```
|
|
34
35
|
|
|
35
|
-
2.
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
36
|
+
### 2. Register in Claude Code
|
|
37
|
+
```bash
|
|
38
|
+
claude mcp add smartstack -- npx @atlashub/smartstack-mcp
|
|
39
|
+
claude mcp add context7 -- npx @upstash/context7-mcp
|
|
40
|
+
```
|
|
39
41
|
|
|
40
42
|
## Usage
|
|
41
43
|
|
|
@@ -9,12 +9,12 @@ mcp:
|
|
|
9
9
|
required:
|
|
10
10
|
- name: context7
|
|
11
11
|
description: "Library documentation and code examples"
|
|
12
|
-
install_command: "claude mcp add context7"
|
|
12
|
+
install_command: "npm install -g @upstash/context7-mcp && claude mcp add context7 -- npx @upstash/context7-mcp"
|
|
13
13
|
health_check: true
|
|
14
14
|
|
|
15
15
|
- name: smartstack
|
|
16
16
|
description: "SmartStack validation and scaffolding"
|
|
17
|
-
install_command: "claude mcp add smartstack"
|
|
17
|
+
install_command: "npm install -g @atlashub/smartstack-mcp && claude mcp add smartstack -- npx @atlashub/smartstack-mcp"
|
|
18
18
|
health_check: true
|
|
19
19
|
|
|
20
20
|
# Behavior when MCP is unavailable
|