@atlashub/smartstack-cli 3.22.0 → 3.23.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.
@@ -26901,12 +26901,16 @@ async function validateNamespaces(structure, config2, result) {
26901
26901
  if (namespaceMatch) {
26902
26902
  const namespace = namespaceMatch[1];
26903
26903
  if (!namespace.startsWith(layer.expected)) {
26904
+ const lastDot = namespace.lastIndexOf(".");
26905
+ const namespaceSuffix = lastDot > 0 ? namespace.substring(lastDot + 1) : "";
26906
+ const isValidLayerPattern = ["Domain", "Application", "Infrastructure", "Api"].some((l) => namespace.includes(`.${l}`) || namespace.endsWith(`.${l}`));
26907
+ const severity = isValidLayerPattern ? "warning" : "error";
26904
26908
  result.errors.push({
26905
- type: "error",
26909
+ type: severity,
26906
26910
  category: "namespaces",
26907
- message: `${layer.name} file has incorrect namespace "${namespace}"`,
26911
+ message: `${layer.name} file has namespace "${namespace}" (expected prefix: "${layer.expected}")`,
26908
26912
  file: path8.relative(structure.root, file),
26909
- suggestion: `Should start with "${layer.expected}"`
26913
+ suggestion: severity === "warning" ? `Client extension project detected. Namespace "${namespace}" follows Clean Architecture pattern but differs from config.` : `Should start with "${layer.expected}"`
26910
26914
  });
26911
26915
  }
26912
26916
  }
@@ -34497,18 +34501,28 @@ public interface I{{name}}Service
34497
34501
  using System.Threading.Tasks;
34498
34502
  using System.Collections.Generic;
34499
34503
  using Microsoft.Extensions.Logging;
34504
+ using SmartStack.Application.Common.Interfaces.Identity;
34505
+ using SmartStack.Application.Common.Interfaces.Persistence;
34500
34506
 
34501
34507
  namespace {{implNamespace}};
34502
34508
 
34503
34509
  /// <summary>
34504
- /// Service implementation for {{name}} operations
34510
+ /// Service implementation for {{name}} operations.
34511
+ /// IMPORTANT: All queries MUST filter by _currentUser.TenantId for multi-tenant isolation.
34505
34512
  /// </summary>
34506
34513
  public class {{name}}Service : I{{name}}Service
34507
34514
  {
34515
+ private readonly IExtensionsDbContext _db;
34516
+ private readonly ICurrentUser _currentUser;
34508
34517
  private readonly ILogger<{{name}}Service> _logger;
34509
34518
 
34510
- public {{name}}Service(ILogger<{{name}}Service> logger)
34519
+ public {{name}}Service(
34520
+ IExtensionsDbContext db,
34521
+ ICurrentUser currentUser,
34522
+ ILogger<{{name}}Service> logger)
34511
34523
  {
34524
+ _db = db;
34525
+ _currentUser = currentUser;
34512
34526
  _logger = logger;
34513
34527
  }
34514
34528
 
@@ -34516,8 +34530,8 @@ public class {{name}}Service : I{{name}}Service
34516
34530
  /// <inheritdoc />
34517
34531
  public async Task<object> {{this}}(CancellationToken cancellationToken = default)
34518
34532
  {
34519
- _logger.LogInformation("Executing {{this}}");
34520
- // TODO: Implement {{this}}
34533
+ _logger.LogInformation("Executing {{this}} for tenant {TenantId}", _currentUser.TenantId);
34534
+ // TODO: Implement {{this}} \u2014 ALL queries must filter by _currentUser.TenantId
34521
34535
  await Task.CompletedTask;
34522
34536
  throw new NotImplementedException();
34523
34537
  }
@@ -34561,7 +34575,6 @@ async function scaffoldEntity(name, options, structure, config2, result, dryRun
34561
34575
  const schema = options?.schema || config2.conventions.schemas.platform;
34562
34576
  const entityTemplate = `using System;
34563
34577
  using SmartStack.Domain.Common;
34564
- using SmartStack.Domain.Common.Interfaces;
34565
34578
 
34566
34579
  namespace {{namespace}};
34567
34580
 
@@ -34570,14 +34583,10 @@ namespace {{namespace}};
34570
34583
  {{#unless isSystemEntity}}
34571
34584
  /// Tenant-scoped: data is isolated per tenant
34572
34585
  {{else}}
34573
- /// System entity: platform-level, no tenant isolation
34586
+ /// Platform-level entity: no tenant isolation
34574
34587
  {{/unless}}
34575
34588
  /// </summary>
34576
- {{#if isSystemEntity}}
34577
- public class {{name}} : SystemEntity
34578
- {{else}}
34579
- public class {{name}} : BaseEntity, ITenantEntity
34580
- {{/if}}
34589
+ public class {{name}} : BaseEntity{{#unless isSystemEntity}}, ITenantEntity, IAuditableEntity{{else}}, IAuditableEntity{{/unless}}
34581
34590
  {
34582
34591
  {{#unless isSystemEntity}}
34583
34592
  // === MULTI-TENANT ===
@@ -34588,6 +34597,14 @@ public class {{name}} : BaseEntity, ITenantEntity
34588
34597
  public Guid TenantId { get; private set; }
34589
34598
 
34590
34599
  {{/unless}}
34600
+ // === AUDIT ===
34601
+
34602
+ /// <summary>User who created this entity</summary>
34603
+ public string? CreatedBy { get; set; }
34604
+
34605
+ /// <summary>User who last updated this entity</summary>
34606
+ public string? UpdatedBy { get; set; }
34607
+
34591
34608
  {{#if baseEntity}}
34592
34609
  // === RELATIONSHIPS ===
34593
34610
 
@@ -34599,7 +34616,7 @@ public class {{name}} : BaseEntity, ITenantEntity
34599
34616
  /// <summary>
34600
34617
  /// Navigation property to {{baseEntity}}
34601
34618
  /// </summary>
34602
- public virtual {{baseEntity}}? {{baseEntity}} { get; private set; }
34619
+ public {{baseEntity}}? {{baseEntity}} { get; private set; }
34603
34620
 
34604
34621
  {{/if}}
34605
34622
  // === BUSINESS PROPERTIES ===
@@ -34613,71 +34630,38 @@ public class {{name}} : BaseEntity, ITenantEntity
34613
34630
  /// <summary>
34614
34631
  /// Factory method to create a new {{name}}
34615
34632
  /// </summary>
34616
- {{#if isSystemEntity}}
34633
+ {{#unless isSystemEntity}}
34634
+ /// <param name="tenantId">Required tenant identifier</param>
34617
34635
  public static {{name}} Create(
34618
- string code,
34619
- string? createdBy = null)
34636
+ Guid tenantId)
34620
34637
  {
34638
+ if (tenantId == Guid.Empty)
34639
+ throw new ArgumentException("TenantId is required", nameof(tenantId));
34640
+
34621
34641
  return new {{name}}
34622
34642
  {
34623
34643
  Id = Guid.NewGuid(),
34624
- Code = code.ToLowerInvariant(),
34625
- CreatedAt = DateTime.UtcNow,
34626
- CreatedBy = createdBy
34644
+ TenantId = tenantId,
34645
+ CreatedAt = DateTime.UtcNow
34627
34646
  };
34628
34647
  }
34629
34648
  {{else}}
34630
- /// <param name="tenantId">Required tenant identifier</param>
34631
- /// <param name="code">Unique code within tenant (will be lowercased)</param>
34632
- /// <param name="createdBy">User who created this entity</param>
34633
- public static {{name}} Create(
34634
- Guid tenantId,
34635
- string code,
34636
- string? createdBy = null)
34649
+ public static {{name}} Create()
34637
34650
  {
34638
- if (tenantId == Guid.Empty)
34639
- throw new ArgumentException("TenantId is required", nameof(tenantId));
34640
-
34641
34651
  return new {{name}}
34642
34652
  {
34643
34653
  Id = Guid.NewGuid(),
34644
- TenantId = tenantId,
34645
- Code = code.ToLowerInvariant(),
34646
- CreatedAt = DateTime.UtcNow,
34647
- CreatedBy = createdBy
34654
+ CreatedAt = DateTime.UtcNow
34648
34655
  };
34649
34656
  }
34650
- {{/if}}
34657
+ {{/unless}}
34651
34658
 
34652
34659
  /// <summary>
34653
34660
  /// Update the entity
34654
34661
  /// </summary>
34655
- public void Update(string? updatedBy = null)
34662
+ public void Update()
34656
34663
  {
34657
34664
  UpdatedAt = DateTime.UtcNow;
34658
- UpdatedBy = updatedBy;
34659
- }
34660
-
34661
- /// <summary>
34662
- /// Soft delete the entity
34663
- /// </summary>
34664
- public void SoftDelete(string? deletedBy = null)
34665
- {
34666
- IsDeleted = true;
34667
- DeletedAt = DateTime.UtcNow;
34668
- DeletedBy = deletedBy;
34669
- }
34670
-
34671
- /// <summary>
34672
- /// Restore a soft-deleted entity
34673
- /// </summary>
34674
- public void Restore(string? restoredBy = null)
34675
- {
34676
- IsDeleted = false;
34677
- DeletedAt = null;
34678
- DeletedBy = null;
34679
- UpdatedAt = DateTime.UtcNow;
34680
- UpdatedBy = restoredBy;
34681
34665
  }
34682
34666
  }
34683
34667
  `;
@@ -34689,85 +34673,38 @@ namespace {{infrastructureNamespace}}.Persistence.Configurations{{#if configName
34689
34673
 
34690
34674
  /// <summary>
34691
34675
  /// EF Core configuration for {{name}}
34692
- {{#unless isSystemEntity}}
34693
- /// Tenant-aware: includes tenant isolation query filter
34694
- {{else}}
34695
- /// System entity: no tenant isolation
34696
- {{/unless}}
34697
34676
  /// </summary>
34698
34677
  public class {{name}}Configuration : IEntityTypeConfiguration<{{name}}>
34699
34678
  {
34700
34679
  public void Configure(EntityTypeBuilder<{{name}}> builder)
34701
34680
  {
34702
- // Table name with schema and domain prefix
34703
34681
  builder.ToTable("{{tablePrefix}}{{name}}s", "{{schema}}");
34704
34682
 
34705
- // Primary key
34706
34683
  builder.HasKey(e => e.Id);
34707
34684
 
34708
34685
  {{#unless isSystemEntity}}
34709
- // ============================================
34710
- // MULTI-TENANT CONFIGURATION
34711
- // ============================================
34712
-
34713
- // TenantId is required for tenant isolation
34686
+ // Multi-tenant
34714
34687
  builder.Property(e => e.TenantId).IsRequired();
34715
34688
  builder.HasIndex(e => e.TenantId)
34716
34689
  .HasDatabaseName("IX_{{tablePrefix}}{{name}}s_TenantId");
34717
34690
 
34718
- // Tenant relationship (configured in Tenant configuration)
34719
- // builder.HasOne<Tenant>().WithMany().HasForeignKey(e => e.TenantId);
34720
-
34721
- // Code: lowercase, unique per tenant (filtered for soft delete)
34722
- builder.Property(e => e.Code).HasMaxLength(100).IsRequired();
34723
- builder.HasIndex(e => new { e.TenantId, e.Code })
34724
- .IsUnique()
34725
- .HasFilter("[IsDeleted] = 0")
34726
- .HasDatabaseName("IX_{{tablePrefix}}{{name}}s_Tenant_Code_Unique");
34727
- {{else}}
34728
- // Code: lowercase, unique globally (filtered for soft delete)
34729
- builder.Property(e => e.Code).HasMaxLength(100).IsRequired();
34730
- builder.HasIndex(e => e.Code)
34731
- .IsUnique()
34732
- .HasFilter("[IsDeleted] = 0")
34733
- .HasDatabaseName("IX_{{tablePrefix}}{{name}}s_Code_Unique");
34734
34691
  {{/unless}}
34735
-
34736
- // Concurrency token
34737
- builder.Property(e => e.RowVersion).IsRowVersion();
34738
-
34739
- // Audit fields
34692
+ // Audit fields (from IAuditableEntity)
34740
34693
  builder.Property(e => e.CreatedBy).HasMaxLength(256);
34741
34694
  builder.Property(e => e.UpdatedBy).HasMaxLength(256);
34742
- builder.Property(e => e.DeletedBy).HasMaxLength(256);
34743
34695
 
34744
34696
  {{#if baseEntity}}
34745
- // ============================================
34746
- // RELATIONSHIPS
34747
- // ============================================
34748
-
34749
- // Relationship to {{baseEntity}} (1:1)
34697
+ // Relationship to {{baseEntity}}
34750
34698
  builder.HasOne(e => e.{{baseEntity}})
34751
- .WithOne()
34752
- .HasForeignKey<{{name}}>(e => e.{{baseEntity}}Id)
34753
- .OnDelete(DeleteBehavior.Cascade);
34699
+ .WithMany()
34700
+ .HasForeignKey(e => e.{{baseEntity}}Id)
34701
+ .OnDelete(DeleteBehavior.Restrict);
34754
34702
 
34755
- // Index on foreign key
34756
34703
  builder.HasIndex(e => e.{{baseEntity}}Id)
34757
- .IsUnique();
34704
+ .HasDatabaseName("IX_{{tablePrefix}}{{name}}s_{{baseEntity}}Id");
34758
34705
  {{/if}}
34759
34706
 
34760
- // ============================================
34761
- // QUERY FILTERS
34762
- // ============================================
34763
- // Note: Global query filters are applied in DbContext.OnModelCreating
34764
- // - Soft delete: .HasQueryFilter(e => !e.IsDeleted)
34765
- {{#unless isSystemEntity}}
34766
- // - Tenant isolation: .HasQueryFilter(e => e.TenantId == _tenantId)
34767
- // Combined filter applied via ITenantEntity interface check
34768
- {{/unless}}
34769
-
34770
- // TODO: Add additional business-specific configuration
34707
+ // TODO: Add business property configurations (HasMaxLength, IsRequired, indexes)
34771
34708
  }
34772
34709
  }
34773
34710
  `;
@@ -34813,11 +34750,11 @@ public class {{name}}Configuration : IEntityTypeConfiguration<{{name}}>
34813
34750
  result.instructions.push("Create migration:");
34814
34751
  result.instructions.push(`dotnet ef migrations add ${migrationPrefix}_vX.X.X_XXX_Add${name} --context ${dbContextName}`);
34815
34752
  result.instructions.push("");
34816
- result.instructions.push("Required fields from BaseEntity:");
34817
- result.instructions.push(`- Id (Guid), ${isSystemEntity ? "" : "TenantId (Guid), "}Code (string, lowercase)`);
34818
- result.instructions.push("- CreatedAt, UpdatedAt, CreatedBy, UpdatedBy (audit)");
34819
- result.instructions.push("- IsDeleted, DeletedAt, DeletedBy (soft delete)");
34820
- result.instructions.push("- RowVersion (concurrency)");
34753
+ result.instructions.push("BaseEntity fields (inherited):");
34754
+ result.instructions.push(`- Id (Guid), CreatedAt (DateTime), UpdatedAt (DateTime?)`);
34755
+ result.instructions.push(`${isSystemEntity ? "" : "- TenantId (Guid) \u2014 from ITenantEntity"}`);
34756
+ result.instructions.push("- CreatedBy, UpdatedBy (string?) \u2014 from IAuditableEntity");
34757
+ result.instructions.push("- Add your own business properties (Code, Name, etc.) as needed");
34821
34758
  if (options?.withSeedData) {
34822
34759
  result.instructions.push("");
34823
34760
  result.instructions.push("### Seed Data");
@@ -34889,9 +34826,7 @@ public static class {{name}}SeedData
34889
34826
  {{#unless isSystemEntity}}
34890
34827
  TenantId = (Guid?)null, // Seed data systeme sans tenant
34891
34828
  {{/unless}}
34892
- Code = ExampleCode,
34893
34829
  // TODO: Ajouter les proprietes specifiques
34894
- IsDeleted = false,
34895
34830
  CreatedAt = seedDate
34896
34831
  }
34897
34832
  };
@@ -35116,11 +35051,8 @@ async function scaffoldController(name, options, structure, config2, result, dry
35116
35051
  const namespace = options?.namespace || (hierarchy.controllerArea ? `${config2.conventions.namespaces.api}.Controllers.${hierarchy.controllerArea}` : `${config2.conventions.namespaces.api}.Controllers`);
35117
35052
  const navRoute = options?.navRoute;
35118
35053
  const navRouteSuffix = options?.navRouteSuffix;
35119
- const apiRoute = navRoute ? `api/${navRoute.replace(/\./g, "/")}${navRouteSuffix ? `/${navRouteSuffix}` : ""}` : null;
35120
- const routeAttribute = navRoute ? navRouteSuffix ? `[Route("${apiRoute}")]
35121
- [NavRoute("${navRoute}", Suffix = "${navRouteSuffix}")]` : `[Route("${apiRoute}")]
35122
- [NavRoute("${navRoute}")]` : `[Route("api/[controller]")]`;
35123
- const navRouteUsing = navRoute ? "using SmartStack.Api.Core.Routing;\n" : "";
35054
+ const routeAttribute = navRoute ? navRouteSuffix ? `[NavRoute("${navRoute}", Suffix = "${navRouteSuffix}")]` : `[NavRoute("${navRoute}")]` : `[Route("api/[controller]")]`;
35055
+ const navRouteUsing = navRoute ? "using SmartStack.Api.Routing;\n" : "";
35124
35056
  const controllerTemplate = `using Microsoft.AspNetCore.Authorization;
35125
35057
  using Microsoft.AspNetCore.Mvc;
35126
35058
  using Microsoft.Extensions.Logging;
@@ -35128,17 +35060,20 @@ ${navRouteUsing}
35128
35060
  namespace {{namespace}};
35129
35061
 
35130
35062
  /// <summary>
35131
- /// API controller for {{name}} operations
35063
+ /// API controller for {{name}} operations.
35064
+ /// IMPORTANT: Use [RequirePermission] on each endpoint for RBAC enforcement.
35132
35065
  /// </summary>
35133
35066
  [ApiController]
35134
35067
  {{routeAttribute}}
35135
35068
  [Authorize]
35136
35069
  public class {{name}}Controller : ControllerBase
35137
35070
  {
35071
+ private readonly I{{name}}Service _service;
35138
35072
  private readonly ILogger<{{name}}Controller> _logger;
35139
35073
 
35140
- public {{name}}Controller(ILogger<{{name}}Controller> logger)
35074
+ public {{name}}Controller(I{{name}}Service service, ILogger<{{name}}Controller> logger)
35141
35075
  {
35076
+ _service = service;
35142
35077
  _logger = logger;
35143
35078
  }
35144
35079
 
@@ -35146,21 +35081,21 @@ public class {{name}}Controller : ControllerBase
35146
35081
  /// Get all {{nameLower}}s
35147
35082
  /// </summary>
35148
35083
  [HttpGet]
35149
- public async Task<ActionResult<IEnumerable<{{name}}Dto>>> GetAll()
35084
+ // TODO: Add [RequirePermission(Permissions.{Module}.Read)] for RBAC
35085
+ public async Task<ActionResult<IEnumerable<object>>> GetAll(CancellationToken ct)
35150
35086
  {
35151
- _logger.LogInformation("Getting all {{nameLower}}s");
35152
- // TODO: Implement
35153
- return Ok(Array.Empty<{{name}}Dto>());
35087
+ // TODO: Call _service.GetAllAsync(ct)
35088
+ return Ok(Array.Empty<object>());
35154
35089
  }
35155
35090
 
35156
35091
  /// <summary>
35157
35092
  /// Get {{nameLower}} by ID
35158
35093
  /// </summary>
35159
35094
  [HttpGet("{id:guid}")]
35160
- public async Task<ActionResult<{{name}}Dto>> GetById(Guid id)
35095
+ // TODO: Add [RequirePermission(Permissions.{Module}.Read)] for RBAC
35096
+ public async Task<ActionResult<object>> GetById(Guid id, CancellationToken ct)
35161
35097
  {
35162
- _logger.LogInformation("Getting {{nameLower}} {Id}", id);
35163
- // TODO: Implement
35098
+ // TODO: Call _service.GetByIdAsync(id, ct)
35164
35099
  return NotFound();
35165
35100
  }
35166
35101
 
@@ -35168,10 +35103,10 @@ public class {{name}}Controller : ControllerBase
35168
35103
  /// Create new {{nameLower}}
35169
35104
  /// </summary>
35170
35105
  [HttpPost]
35171
- public async Task<ActionResult<{{name}}Dto>> Create([FromBody] Create{{name}}Request request)
35106
+ // TODO: Add [RequirePermission(Permissions.{Module}.Create)] for RBAC
35107
+ public async Task<ActionResult<object>> Create([FromBody] object request, CancellationToken ct)
35172
35108
  {
35173
- _logger.LogInformation("Creating {{nameLower}}");
35174
- // TODO: Implement
35109
+ // TODO: Call _service.CreateAsync(dto, ct)
35175
35110
  return CreatedAtAction(nameof(GetById), new { id = Guid.NewGuid() }, null);
35176
35111
  }
35177
35112
 
@@ -35179,10 +35114,10 @@ public class {{name}}Controller : ControllerBase
35179
35114
  /// Update {{nameLower}}
35180
35115
  /// </summary>
35181
35116
  [HttpPut("{id:guid}")]
35182
- public async Task<ActionResult> Update(Guid id, [FromBody] Update{{name}}Request request)
35117
+ // TODO: Add [RequirePermission(Permissions.{Module}.Update)] for RBAC
35118
+ public async Task<ActionResult> Update(Guid id, [FromBody] object request, CancellationToken ct)
35183
35119
  {
35184
- _logger.LogInformation("Updating {{nameLower}} {Id}", id);
35185
- // TODO: Implement
35120
+ // TODO: Call _service.UpdateAsync(id, dto, ct)
35186
35121
  return NoContent();
35187
35122
  }
35188
35123
 
@@ -35190,18 +35125,13 @@ public class {{name}}Controller : ControllerBase
35190
35125
  /// Delete {{nameLower}}
35191
35126
  /// </summary>
35192
35127
  [HttpDelete("{id:guid}")]
35193
- public async Task<ActionResult> Delete(Guid id)
35128
+ // TODO: Add [RequirePermission(Permissions.{Module}.Delete)] for RBAC
35129
+ public async Task<ActionResult> Delete(Guid id, CancellationToken ct)
35194
35130
  {
35195
- _logger.LogInformation("Deleting {{nameLower}} {Id}", id);
35196
- // TODO: Implement
35131
+ // TODO: Call _service.DeleteAsync(id, ct)
35197
35132
  return NoContent();
35198
35133
  }
35199
35134
  }
35200
-
35201
- // DTOs
35202
- public record {{name}}Dto(Guid Id, DateTime CreatedAt);
35203
- public record Create{{name}}Request();
35204
- public record Update{{name}}Request();
35205
35135
  `;
35206
35136
  const context = {
35207
35137
  namespace,
@@ -35221,14 +35151,12 @@ public record Update{{name}}Request();
35221
35151
  }
35222
35152
  result.files.push({ path: controllerFilePath, content: controllerContent, type: "created" });
35223
35153
  if (navRoute) {
35224
- result.instructions.push("Controller created with NavRoute + explicit Route (deterministic routing).");
35154
+ result.instructions.push("Controller created with NavRoute (route resolved from DB at startup).");
35225
35155
  result.instructions.push(`NavRoute: ${navRoute}${navRouteSuffix ? ` (Suffix: ${navRouteSuffix})` : ""}`);
35226
- result.instructions.push(`API Route: ${apiRoute}`);
35227
35156
  result.instructions.push("");
35228
- result.instructions.push("The [Route] attribute ensures deterministic API routing.");
35229
- result.instructions.push("The [NavRoute] attribute integrates with the navigation/permission system.");
35230
- result.instructions.push("Ensure the navigation path exists in the database:");
35231
- result.instructions.push(` Context > Application > Module > Section matching "${navRoute}"`);
35157
+ result.instructions.push("NavRoute resolves API routes from Navigation entities in the database.");
35158
+ result.instructions.push("Ensure the navigation path exists (seed data required):");
35159
+ result.instructions.push(` Context > Application > Module matching "${navRoute}"`);
35232
35160
  } else {
35233
35161
  result.instructions.push("Controller created with traditional routing.");
35234
35162
  result.instructions.push("");
@@ -35810,7 +35738,7 @@ public interface I{{name}}Repository
35810
35738
  /// <summary>Update entity</summary>
35811
35739
  Task UpdateAsync({{name}} entity, CancellationToken ct = default);
35812
35740
 
35813
- /// <summary>Soft delete entity</summary>
35741
+ /// <summary>Delete entity</summary>
35814
35742
  Task DeleteAsync({{name}} entity, CancellationToken ct = default);
35815
35743
  }
35816
35744
  `;
@@ -35885,8 +35813,8 @@ public class {{name}}Repository : I{{name}}Repository
35885
35813
  /// <inheritdoc />
35886
35814
  public async Task DeleteAsync({{name}} entity, CancellationToken ct = default)
35887
35815
  {
35888
- entity.SoftDelete();
35889
- await UpdateAsync(entity, ct);
35816
+ _context.{{name}}s.Remove(entity);
35817
+ await _context.SaveChangesAsync(ct);
35890
35818
  }
35891
35819
  }
35892
35820
  `;