diff --git a/Directory.Packages.props b/Directory.Packages.props index 21fe0d38bf..5b6839ec30 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -122,7 +122,7 @@ - + diff --git a/docs/en/images/abp-overall-diagram-1600.png b/docs/en/images/abp-overall-diagram-1600.png index 16d397466a..3b02dd66dc 100644 Binary files a/docs/en/images/abp-overall-diagram-1600.png and b/docs/en/images/abp-overall-diagram-1600.png differ diff --git a/docs/en/images/db-options.png b/docs/en/images/db-options.png index 91d2b51ce7..d25811c49b 100644 Binary files a/docs/en/images/db-options.png and b/docs/en/images/db-options.png differ diff --git a/docs/en/images/ui-options.png b/docs/en/images/ui-options.png index 6affab9d21..3c30cd16d7 100644 Binary files a/docs/en/images/ui-options.png and b/docs/en/images/ui-options.png differ diff --git a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionChecker.cs b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionChecker.cs index 7e7457b753..4a5e48c220 100644 --- a/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionChecker.cs +++ b/framework/src/Volo.Abp.Authorization/Volo/Abp/Authorization/Permissions/PermissionChecker.cs @@ -48,7 +48,7 @@ public class PermissionChecker : IPermissionChecker, ITransientDependency { return false; } - + if (!permission.IsEnabled) { return false; @@ -92,12 +92,12 @@ public class PermissionChecker : IPermissionChecker, ITransientDependency return isGranted; } - public async Task IsGrantedAsync(string[] names) + public virtual async Task IsGrantedAsync(string[] names) { return await IsGrantedAsync(PrincipalAccessor.Principal, names); } - public async Task IsGrantedAsync(ClaimsPrincipal? claimsPrincipal, string[] names) + public virtual async Task IsGrantedAsync(ClaimsPrincipal? claimsPrincipal, string[] names) { Check.NotNull(names, nameof(names)); @@ -146,16 +146,27 @@ public class PermissionChecker : IPermissionChecker, ITransientDependency claimsPrincipal); var multipleResult = await provider.CheckAsync(context); - foreach (var grantResult in multipleResult.Result.Where(grantResult => - result.Result.ContainsKey(grantResult.Key) && - result.Result[grantResult.Key] == PermissionGrantResult.Undefined && - grantResult.Value != PermissionGrantResult.Undefined)) + + foreach (var grantResult in multipleResult.Result.Where(x => result.Result.ContainsKey(x.Key))) { - result.Result[grantResult.Key] = grantResult.Value; - permissionDefinitions.RemoveAll(x => x.Name == grantResult.Key); + switch (grantResult.Value) + { + case PermissionGrantResult.Granted: + { + if (result.Result[grantResult.Key] != PermissionGrantResult.Prohibited) + { + result.Result[grantResult.Key] = PermissionGrantResult.Granted; + } + break; + } + case PermissionGrantResult.Prohibited: + result.Result[grantResult.Key] = PermissionGrantResult.Prohibited; + permissionDefinitions.RemoveAll(x => x.Name == grantResult.Key); + break; + } } - if (result.AllGranted || result.AllProhibited) + if (result.AllProhibited) { break; } diff --git a/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/AbpAuthorizationTestModule.cs b/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/AbpAuthorizationTestModule.cs index a4980a58ec..fca3d209b0 100644 --- a/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/AbpAuthorizationTestModule.cs +++ b/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/AbpAuthorizationTestModule.cs @@ -31,6 +31,8 @@ public class AbpAuthorizationTestModule : AbpModule { options.ValueProviders.Add(); options.ValueProviders.Add(); + options.ValueProviders.Add(); + options.ValueProviders.Add(); }); } } diff --git a/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/PermissionChecker_Tests.cs b/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/PermissionChecker_Tests.cs index f39c48e435..c641f21e92 100644 --- a/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/PermissionChecker_Tests.cs +++ b/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/PermissionChecker_Tests.cs @@ -8,7 +8,7 @@ namespace Volo.Abp.Authorization; public class PermissionChecker_Tests: AuthorizationTestBase { private readonly IPermissionChecker _permissionChecker; - + public PermissionChecker_Tests() { _permissionChecker = GetRequiredService(); @@ -21,6 +21,13 @@ public class PermissionChecker_Tests: AuthorizationTestBase (await _permissionChecker.IsGrantedAsync("UndefinedPermission")).ShouldBe(false); } + [Fact] + public async Task IsGranted_ProhibitedAsync() + { + (await _permissionChecker.IsGrantedAsync("MyPermission8")).ShouldBe(false); + (await _permissionChecker.IsGrantedAsync("MyPermission9")).ShouldBe(false); + } + [Fact] public async Task IsGranted_Multiple_Result_Async() { @@ -35,7 +42,7 @@ public class PermissionChecker_Tests: AuthorizationTestBase "MyPermission6", "MyPermission7" }); - + result.Result["MyPermission1"].ShouldBe(PermissionGrantResult.Undefined); result.Result["MyPermission2"].ShouldBe(PermissionGrantResult.Prohibited); result.Result["UndefinedPermission"].ShouldBe(PermissionGrantResult.Prohibited); @@ -44,6 +51,18 @@ public class PermissionChecker_Tests: AuthorizationTestBase result.Result["MyPermission5"].ShouldBe(PermissionGrantResult.Granted); result.Result["MyPermission6"].ShouldBe(PermissionGrantResult.Granted); result.Result["MyPermission7"].ShouldBe(PermissionGrantResult.Granted); - } -} \ No newline at end of file + + [Fact] + public async Task IsGranted_Multiple_Result_ProhibitedAsync() + { + var result = await _permissionChecker.IsGrantedAsync(new [] + { + "MyPermission8", + "MyPermission9" + }); + + result.Result["MyPermission8"].ShouldBe(PermissionGrantResult.Prohibited); + result.Result["MyPermission9"].ShouldBe(PermissionGrantResult.Prohibited); + } +} diff --git a/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/TestServices/AuthorizationTestPermissionDefinitionProvider.cs b/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/TestServices/AuthorizationTestPermissionDefinitionProvider.cs index b2a9179415..7e8ed5e949 100644 --- a/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/TestServices/AuthorizationTestPermissionDefinitionProvider.cs +++ b/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/TestServices/AuthorizationTestPermissionDefinitionProvider.cs @@ -16,11 +16,11 @@ public class AuthorizationTestPermissionDefinitionProvider : PermissionDefinitio var group = context.AddGroup("TestGroup"); group[PermissionDefinitionContext.KnownPropertyNames.CurrentProviderName].ShouldBe(typeof(AuthorizationTestPermissionDefinitionProvider).FullName); - + var permission1 = group.AddPermission("MyAuthorizedService1"); permission1[PermissionDefinitionContext.KnownPropertyNames.CurrentProviderName].ShouldBe(typeof(AuthorizationTestPermissionDefinitionProvider).FullName); - + group.AddPermission("MyPermission1").StateCheckers.Add(new TestRequireEditionPermissionSimpleStateChecker()); group.AddPermission("MyPermission2"); group.AddPermission("MyPermission3"); @@ -28,6 +28,8 @@ public class AuthorizationTestPermissionDefinitionProvider : PermissionDefinitio group.AddPermission("MyPermission5"); group.AddPermission("MyPermission6").WithProviders(nameof(TestPermissionValueProvider1)); group.AddPermission("MyPermission7").WithProviders(nameof(TestPermissionValueProvider2)); + group.AddPermission("MyPermission8"); + group.AddPermission("MyPermission9"); group.GetPermissionOrNull("MyAuthorizedService1").ShouldNotBeNull(); diff --git a/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/TestServices/TestProhibitedPermissionValueProvider1.cs b/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/TestServices/TestProhibitedPermissionValueProvider1.cs new file mode 100644 index 0000000000..2f667cb791 --- /dev/null +++ b/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/TestServices/TestProhibitedPermissionValueProvider1.cs @@ -0,0 +1,38 @@ +using System.Linq; +using System.Threading.Tasks; +using Volo.Abp.Authorization.Permissions; + +namespace Volo.Abp.Authorization.TestServices; + +public class TestProhibitedPermissionValueProvider1 : PermissionValueProvider +{ + public TestProhibitedPermissionValueProvider1(IPermissionStore permissionStore) : base(permissionStore) + { + } + + public override string Name => "TestProhibitedPermissionValueProvider1"; + + public override Task CheckAsync(PermissionValueCheckContext context) + { + var result = PermissionGrantResult.Undefined; + if (context.Permission.Name == "MyPermission8" || context.Permission.Name == "MyPermission9") + { + result = PermissionGrantResult.Granted; + } + + return Task.FromResult(result); + } + + public override Task CheckAsync(PermissionValuesCheckContext context) + { + var result = new MultiplePermissionGrantResult(); + foreach (var name in context.Permissions.Select(x => x.Name)) + { + result.Result.Add(name, name == "MyPermission8" || name == "MyPermission9" + ? PermissionGrantResult.Granted + : PermissionGrantResult.Undefined); + } + + return Task.FromResult(result); + } +} diff --git a/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/TestServices/TestProhibitedPermissionValueProvider2.cs b/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/TestServices/TestProhibitedPermissionValueProvider2.cs new file mode 100644 index 0000000000..0311c19a65 --- /dev/null +++ b/framework/test/Volo.Abp.Authorization.Tests/Volo/Abp/Authorization/TestServices/TestProhibitedPermissionValueProvider2.cs @@ -0,0 +1,38 @@ +using System.Linq; +using System.Threading.Tasks; +using Volo.Abp.Authorization.Permissions; + +namespace Volo.Abp.Authorization.TestServices; + +public class TestProhibitedPermissionValueProvider2 : PermissionValueProvider +{ + public TestProhibitedPermissionValueProvider2(IPermissionStore permissionStore) : base(permissionStore) + { + } + + public override string Name => "TestProhibitedPermissionValueProvider2"; + + public override Task CheckAsync(PermissionValueCheckContext context) + { + var result = PermissionGrantResult.Undefined; + if (context.Permission.Name == "MyPermission8" || context.Permission.Name == "MyPermission9") + { + result = PermissionGrantResult.Prohibited; + } + + return Task.FromResult(result); + } + + public override Task CheckAsync(PermissionValuesCheckContext context) + { + var result = new MultiplePermissionGrantResult(); + foreach (var name in context.Permissions.Select(x => x.Name)) + { + result.Result.Add(name, name == "MyPermission8" || name == "MyPermission9" + ? PermissionGrantResult.Prohibited + : PermissionGrantResult.Undefined); + } + + return Task.FromResult(result); + } +} diff --git a/npm/ng-packs/packages/core/src/lib/guards/permission.guard.ts b/npm/ng-packs/packages/core/src/lib/guards/permission.guard.ts index 8d1e478864..3b77913d2e 100644 --- a/npm/ng-packs/packages/core/src/lib/guards/permission.guard.ts +++ b/npm/ng-packs/packages/core/src/lib/guards/permission.guard.ts @@ -4,10 +4,11 @@ import { CanActivateFn, Router, RouterStateSnapshot, + UrlTree, } from '@angular/router'; import { HttpErrorResponse } from '@angular/common/http'; import { Observable, of } from 'rxjs'; -import { filter, take, tap } from 'rxjs/operators'; +import { map, take } from 'rxjs/operators'; import { AuthService, IAbpGuard } from '../abstracts'; import { findRoute, getRoutePath } from '../utils/route-utils'; import { RoutesService, PermissionService, HttpErrorReporterService } from '../services'; @@ -25,7 +26,7 @@ export class PermissionGuard implements IAbpGuard { protected readonly permissionService = inject(PermissionService); protected readonly httpErrorReporter = inject(HttpErrorReporterService); - canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable { + canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable { let { requiredPolicy } = route.data || {}; if (!requiredPolicy) { @@ -38,12 +39,19 @@ export class PermissionGuard implements IAbpGuard { } return this.permissionService.getGrantedPolicy$(requiredPolicy).pipe( - filter(Boolean), take(1), - tap(access => { - if (!access && this.authService.isAuthenticated) { + map(access => { + if (access) return true; + + if (route.data?.['redirectUrl']) { + return this.router.parseUrl(route.data['redirectUrl']); + } + + if (this.authService.isAuthenticated) { this.httpErrorReporter.reportError({ status: 403 } as HttpErrorResponse); } + + return false; }), ); } @@ -77,12 +85,19 @@ export const permissionGuard: CanActivateFn = ( } return permissionService.getGrantedPolicy$(requiredPolicy).pipe( - filter(Boolean), take(1), - tap(access => { - if (!access && authService.isAuthenticated) { + map(access => { + if (access) return true; + + if (route.data?.['redirectUrl']) { + return router.parseUrl(route.data['redirectUrl']); + } + + if (authService.isAuthenticated) { httpErrorReporter.reportError({ status: 403 } as HttpErrorResponse); } + + return false; }), ); }; diff --git a/npm/ng-packs/packages/core/src/lib/tests/permission.guard.spec.ts b/npm/ng-packs/packages/core/src/lib/tests/permission.guard.spec.ts index 1a0ae3e147..45f3b46d80 100644 --- a/npm/ng-packs/packages/core/src/lib/tests/permission.guard.spec.ts +++ b/npm/ng-packs/packages/core/src/lib/tests/permission.guard.spec.ts @@ -39,6 +39,15 @@ describe('authGuard', () => { component: DummyComponent, canActivate: [permissionGuard], }, + { + path: 'redirect-test', + component: DummyComponent, + canActivate: [permissionGuard], + data: { + requiredPolicy: 'TestPolicy', + redirectUrl: '/zibzib', + }, + }, ]; beforeEach(() => { @@ -103,4 +112,12 @@ describe('authGuard', () => { await RouterTestingHarness.create('/zibzib'); expect(TestBed.inject(Router).url).toEqual('/zibzib'); }); + + it('should redirect to redirectUrl when the grantedPolicy is false and redirectUrl is provided', async () => { + permissionService.getGrantedPolicy$.andReturn(of(false)); + await RouterTestingHarness.create('/redirect-test'); + + expect(TestBed.inject(Router).url).toEqual('/zibzib'); + expect(httpErrorReporter.reportError).not.toHaveBeenCalled(); + }); }); diff --git a/npm/ng-packs/packages/schematics/src/collection.json b/npm/ng-packs/packages/schematics/src/collection.json index b84de19733..1116a7e15a 100644 --- a/npm/ng-packs/packages/schematics/src/collection.json +++ b/npm/ng-packs/packages/schematics/src/collection.json @@ -35,6 +35,11 @@ "factory": "./commands/change-theme", "schema": "./commands/change-theme/schema.json" }, + "ai-config": { + "description": "Generates AI configuration files for Angular projects", + "factory": "./commands/ai-config", + "schema": "./commands/ai-config/schema.json" + }, "server": { "factory": "./commands/ssr-add/server", "description": "Create an Angular server app.", diff --git a/npm/ng-packs/packages/schematics/src/commands/ai-config/files/claude/.claude/CLAUDE.md b/npm/ng-packs/packages/schematics/src/commands/ai-config/files/claude/.claude/CLAUDE.md new file mode 100644 index 0000000000..32dfab0275 --- /dev/null +++ b/npm/ng-packs/packages/schematics/src/commands/ai-config/files/claude/.claude/CLAUDE.md @@ -0,0 +1,186 @@ +# 💻 ABP Full-Stack Development Rules +_Expert Guidelines for .NET Backend (ABP) and Angular Frontend Development_ + +You are a **senior full-stack developer** specializing in **ABP Framework (.NET)** and **Angular (TypeScript)**. +You write **clean, maintainable, and modular** code following **ABP, ASP.NET Core, and Angular best practices**. + +--- + +## 🧩 1. General Principles +- Maintain a clear separation between backend (ABP/.NET) and frontend (Angular) layers. +- Follow **modular architecture** — each layer or feature should be independently testable and reusable. +- Always adhere to **official ABP documentation** ([docs.abp.io](https://docs.abp.io)) and **Angular official guides**. +- Prioritize **readability, maintainability, and performance**. +- Write **idiomatic** and **self-documenting** code. + +--- + +## ⚙️ 2. ABP / .NET Development Rules + +### Code Style and Structure +- Follow ABP’s standard folder structure: + - `*.Application`, `*.Domain`, `*.EntityFrameworkCore`, `*.HttpApi` +- Write concise, idiomatic C# code using modern language features. +- Apply **modular and layered design** (Domain, Application, Infrastructure, UI). +- Prefer **LINQ** and **lambda expressions** for collection operations. +- Use **descriptive method and variable names** (`GetActiveUsers`, `CalculateTotalAmount`). + +### Naming Conventions +- **PascalCase** → Classes, Methods, Properties +- **camelCase** → Local variables and private fields +- **UPPER_CASE** → Constants +- Prefix interfaces with **`I`** (e.g., `IUserRepository`). + +### C# and .NET Usage +- Use **C# 10+ features** (records, pattern matching, null-coalescing assignment). +- Utilize **ABP modules** (Permission Management, Setting Management, Audit Logging). +- Integrate **Entity Framework Core** with ABP’s repository abstractions. + +### Syntax and Formatting +- Follow [Microsoft C# Coding Conventions](https://learn.microsoft.com/dotnet/csharp/fundamentals/coding-style/coding-conventions). +- Use `var` when the type is clear. +- Use `string interpolation` and null-conditional operators. +- Keep code consistent and well-formatted. + +### Error Handling and Validation +- Use exceptions only for exceptional cases. +- Log errors via ABP’s built-in logging or a compatible provider. +- Validate models with **DataAnnotations** or **FluentValidation**. +- Rely on ABP’s global exception middleware for unified responses. +- Return consistent HTTP status codes and error DTOs. + +### API Design +- Build RESTful APIs via `HttpApi` layer and **ABP conventional controllers**. +- Use **attribute-based routing** and versioning when needed. +- Apply **action filters/middleware** for cross-cutting concerns (auditing, authorization). + +### Performance Optimization +- Use `async/await` for I/O operations. +- Use `IDistributedCache` over `IMemoryCache`. +- Avoid N+1 queries — include relations explicitly. +- Implement pagination with `PagedResultDto`. + +### Key Conventions +- Use **Dependency Injection** via ABP’s DI system. +- Apply **repository pattern** or EF Core directly as needed. +- Use **AutoMapper** or ABP object mapping for DTOs. +- Implement **background jobs** with ABP’s job system or `IHostedService`. +- Follow **domain-driven design (DDD)** principles: + - Business rules in Domain layer. + - Use `AuditedAggregateRoot`, `FullAuditedEntity`, etc. +- Avoid unnecessary dependencies between layers. + +### Testing +- Use **xUnit**, **Shouldly**, and **NSubstitute** for testing. +- Write **unit and integration tests** per module (`Application.Tests`, `Domain.Tests`). +- Mock dependencies properly and use ABP’s test base classes. + +### Security +- Use **OpenIddict** for authentication & authorization. +- Implement permission checks through ABP’s infrastructure. +- Enforce **HTTPS** and properly configure **CORS**. + +### API Documentation +- Use **Swagger / OpenAPI** (Swashbuckle or NSwag). +- Add XML comments to controllers and DTOs. +- Follow ABP’s documentation conventions for module APIs. + +**Reference Best Practices:** +- [Domain Services](https://abp.io/docs/latest/framework/architecture/best-practices/domain-services) +- [Repositories](https://abp.io/docs/latest/framework/architecture/best-practices/repositories) +- [Entities](https://abp.io/docs/latest/framework/architecture/best-practices/entities) +- [Application Services](https://abp.io/docs/latest/framework/architecture/best-practices/application-services) +- [DTOs](https://abp.io/docs/latest/framework/architecture/best-practices/data-transfer-objects) +- [Entity Framework Integration](https://abp.io/docs/latest/framework/architecture/best-practices/entity-framework-core-integration) + +--- + +## 🌐 3. Angular / TypeScript Development Rules + +### TypeScript Best Practices +- Enable **strict type checking** in `tsconfig.json`. +- Use **type inference** when the type is obvious. +- Avoid `any`; use `unknown` or generics instead. +- Use interfaces and types for clarity and structure. + +### Angular Best Practices +- Prefer **standalone components** (no `NgModules`). +- Do **NOT** set `standalone: true` manually — it’s default. +- Use **signals** for state management. +- Implement **lazy loading** for feature routes. +- Avoid `@HostBinding` / `@HostListener`; use `host` object in decorators. +- Use **`NgOptimizedImage`** for static images (not base64). + +### Components +- Keep components small, focused, and reusable. +- Use `input()` and `output()` functions instead of decorators. +- Use `computed()` for derived state. +- Always set `changeDetection: ChangeDetectionStrategy.OnPush`. +- Use **inline templates** for small components. +- Prefer **Reactive Forms** over template-driven forms. +- Avoid `ngClass` → use `[class]` bindings. +- Avoid `ngStyle` → use `[style]` bindings. + +### State Management +- Manage **local component state** with signals. +- Use **`computed()`** for derived data. +- Keep state transformations **pure and predictable**. +- Avoid `mutate()` on signals — use `update()` or `set()`. + +### Templates +- Use **native control flow** (`@if`, `@for`, `@switch`) instead of structural directives. +- Keep templates minimal and declarative. +- Use the **async pipe** for observable bindings. + +### Services +- Design services for **single responsibility**. +- Provide services using `providedIn: 'root'`. +- Use the **`inject()` function** instead of constructor injection. + +### Component Replacement +ABP Angular provides a powerful **component replacement** system via `ReplaceableComponentsService`: + +**Key Features:** +- Replace ABP default components (Roles, Users, Tenants, etc.) with custom implementations +- Replace layouts (Application, Account, Empty) +- Replace UI elements (Logo, Routes, NavItems) + +**Basic Usage:** +```typescript +import { ReplaceableComponentsService } from '@abp/ng.core'; +import { eIdentityComponents } from '@abp/ng.identity'; + +constructor(private replaceableComponents: ReplaceableComponentsService) { + this.replaceableComponents.add({ + component: YourCustomComponent, + key: eIdentityComponents.Roles, + }); +} +``` + +**Important Notes:** +- Component templates must include `` for layouts +- Use the second parameter as `true` for runtime replacement (refreshes route) +- Runtime replacement clears component state and re-runs initialization logic + +**📚 Full Documentation:** +For detailed examples, layout replacement, and advanced scenarios: +[Component Replacement Guide](https://abp.io/docs/latest/framework/ui/angular/customization-user-interface) + +--- + +## 🔒 4. Combined Full-Stack Practices +- Ensure backend and frontend follow consistent **DTO contracts** and **naming conventions**. +- Maintain shared models (e.g., via a `contracts` package or OpenAPI generation). +- Version APIs carefully and handle changes in Angular clients. +- Use ABP’s **CORS**, **Swagger**, and **Identity** modules to simplify frontend integration. +- Apply **global error handling** and consistent response wrappers in both layers. +- Monitor performance with tools like **Application Insights**, **ABP auditing**, or **Angular profiler**. + +--- + +## ✅ Summary +This document defines a unified standard for developing **ABP + Angular full-stack applications**, ensuring: +- Code is **modular**, **performant**, and **maintainable**. +- Teams follow **consistent conventions** across backend and frontend. +- Every layer (Domain, Application, UI) is **clean, testable, and scalable**. diff --git a/npm/ng-packs/packages/schematics/src/commands/ai-config/files/copilot/.github/copilot-instructions.md b/npm/ng-packs/packages/schematics/src/commands/ai-config/files/copilot/.github/copilot-instructions.md new file mode 100644 index 0000000000..32dfab0275 --- /dev/null +++ b/npm/ng-packs/packages/schematics/src/commands/ai-config/files/copilot/.github/copilot-instructions.md @@ -0,0 +1,186 @@ +# 💻 ABP Full-Stack Development Rules +_Expert Guidelines for .NET Backend (ABP) and Angular Frontend Development_ + +You are a **senior full-stack developer** specializing in **ABP Framework (.NET)** and **Angular (TypeScript)**. +You write **clean, maintainable, and modular** code following **ABP, ASP.NET Core, and Angular best practices**. + +--- + +## 🧩 1. General Principles +- Maintain a clear separation between backend (ABP/.NET) and frontend (Angular) layers. +- Follow **modular architecture** — each layer or feature should be independently testable and reusable. +- Always adhere to **official ABP documentation** ([docs.abp.io](https://docs.abp.io)) and **Angular official guides**. +- Prioritize **readability, maintainability, and performance**. +- Write **idiomatic** and **self-documenting** code. + +--- + +## ⚙️ 2. ABP / .NET Development Rules + +### Code Style and Structure +- Follow ABP’s standard folder structure: + - `*.Application`, `*.Domain`, `*.EntityFrameworkCore`, `*.HttpApi` +- Write concise, idiomatic C# code using modern language features. +- Apply **modular and layered design** (Domain, Application, Infrastructure, UI). +- Prefer **LINQ** and **lambda expressions** for collection operations. +- Use **descriptive method and variable names** (`GetActiveUsers`, `CalculateTotalAmount`). + +### Naming Conventions +- **PascalCase** → Classes, Methods, Properties +- **camelCase** → Local variables and private fields +- **UPPER_CASE** → Constants +- Prefix interfaces with **`I`** (e.g., `IUserRepository`). + +### C# and .NET Usage +- Use **C# 10+ features** (records, pattern matching, null-coalescing assignment). +- Utilize **ABP modules** (Permission Management, Setting Management, Audit Logging). +- Integrate **Entity Framework Core** with ABP’s repository abstractions. + +### Syntax and Formatting +- Follow [Microsoft C# Coding Conventions](https://learn.microsoft.com/dotnet/csharp/fundamentals/coding-style/coding-conventions). +- Use `var` when the type is clear. +- Use `string interpolation` and null-conditional operators. +- Keep code consistent and well-formatted. + +### Error Handling and Validation +- Use exceptions only for exceptional cases. +- Log errors via ABP’s built-in logging or a compatible provider. +- Validate models with **DataAnnotations** or **FluentValidation**. +- Rely on ABP’s global exception middleware for unified responses. +- Return consistent HTTP status codes and error DTOs. + +### API Design +- Build RESTful APIs via `HttpApi` layer and **ABP conventional controllers**. +- Use **attribute-based routing** and versioning when needed. +- Apply **action filters/middleware** for cross-cutting concerns (auditing, authorization). + +### Performance Optimization +- Use `async/await` for I/O operations. +- Use `IDistributedCache` over `IMemoryCache`. +- Avoid N+1 queries — include relations explicitly. +- Implement pagination with `PagedResultDto`. + +### Key Conventions +- Use **Dependency Injection** via ABP’s DI system. +- Apply **repository pattern** or EF Core directly as needed. +- Use **AutoMapper** or ABP object mapping for DTOs. +- Implement **background jobs** with ABP’s job system or `IHostedService`. +- Follow **domain-driven design (DDD)** principles: + - Business rules in Domain layer. + - Use `AuditedAggregateRoot`, `FullAuditedEntity`, etc. +- Avoid unnecessary dependencies between layers. + +### Testing +- Use **xUnit**, **Shouldly**, and **NSubstitute** for testing. +- Write **unit and integration tests** per module (`Application.Tests`, `Domain.Tests`). +- Mock dependencies properly and use ABP’s test base classes. + +### Security +- Use **OpenIddict** for authentication & authorization. +- Implement permission checks through ABP’s infrastructure. +- Enforce **HTTPS** and properly configure **CORS**. + +### API Documentation +- Use **Swagger / OpenAPI** (Swashbuckle or NSwag). +- Add XML comments to controllers and DTOs. +- Follow ABP’s documentation conventions for module APIs. + +**Reference Best Practices:** +- [Domain Services](https://abp.io/docs/latest/framework/architecture/best-practices/domain-services) +- [Repositories](https://abp.io/docs/latest/framework/architecture/best-practices/repositories) +- [Entities](https://abp.io/docs/latest/framework/architecture/best-practices/entities) +- [Application Services](https://abp.io/docs/latest/framework/architecture/best-practices/application-services) +- [DTOs](https://abp.io/docs/latest/framework/architecture/best-practices/data-transfer-objects) +- [Entity Framework Integration](https://abp.io/docs/latest/framework/architecture/best-practices/entity-framework-core-integration) + +--- + +## 🌐 3. Angular / TypeScript Development Rules + +### TypeScript Best Practices +- Enable **strict type checking** in `tsconfig.json`. +- Use **type inference** when the type is obvious. +- Avoid `any`; use `unknown` or generics instead. +- Use interfaces and types for clarity and structure. + +### Angular Best Practices +- Prefer **standalone components** (no `NgModules`). +- Do **NOT** set `standalone: true` manually — it’s default. +- Use **signals** for state management. +- Implement **lazy loading** for feature routes. +- Avoid `@HostBinding` / `@HostListener`; use `host` object in decorators. +- Use **`NgOptimizedImage`** for static images (not base64). + +### Components +- Keep components small, focused, and reusable. +- Use `input()` and `output()` functions instead of decorators. +- Use `computed()` for derived state. +- Always set `changeDetection: ChangeDetectionStrategy.OnPush`. +- Use **inline templates** for small components. +- Prefer **Reactive Forms** over template-driven forms. +- Avoid `ngClass` → use `[class]` bindings. +- Avoid `ngStyle` → use `[style]` bindings. + +### State Management +- Manage **local component state** with signals. +- Use **`computed()`** for derived data. +- Keep state transformations **pure and predictable**. +- Avoid `mutate()` on signals — use `update()` or `set()`. + +### Templates +- Use **native control flow** (`@if`, `@for`, `@switch`) instead of structural directives. +- Keep templates minimal and declarative. +- Use the **async pipe** for observable bindings. + +### Services +- Design services for **single responsibility**. +- Provide services using `providedIn: 'root'`. +- Use the **`inject()` function** instead of constructor injection. + +### Component Replacement +ABP Angular provides a powerful **component replacement** system via `ReplaceableComponentsService`: + +**Key Features:** +- Replace ABP default components (Roles, Users, Tenants, etc.) with custom implementations +- Replace layouts (Application, Account, Empty) +- Replace UI elements (Logo, Routes, NavItems) + +**Basic Usage:** +```typescript +import { ReplaceableComponentsService } from '@abp/ng.core'; +import { eIdentityComponents } from '@abp/ng.identity'; + +constructor(private replaceableComponents: ReplaceableComponentsService) { + this.replaceableComponents.add({ + component: YourCustomComponent, + key: eIdentityComponents.Roles, + }); +} +``` + +**Important Notes:** +- Component templates must include `` for layouts +- Use the second parameter as `true` for runtime replacement (refreshes route) +- Runtime replacement clears component state and re-runs initialization logic + +**📚 Full Documentation:** +For detailed examples, layout replacement, and advanced scenarios: +[Component Replacement Guide](https://abp.io/docs/latest/framework/ui/angular/customization-user-interface) + +--- + +## 🔒 4. Combined Full-Stack Practices +- Ensure backend and frontend follow consistent **DTO contracts** and **naming conventions**. +- Maintain shared models (e.g., via a `contracts` package or OpenAPI generation). +- Version APIs carefully and handle changes in Angular clients. +- Use ABP’s **CORS**, **Swagger**, and **Identity** modules to simplify frontend integration. +- Apply **global error handling** and consistent response wrappers in both layers. +- Monitor performance with tools like **Application Insights**, **ABP auditing**, or **Angular profiler**. + +--- + +## ✅ Summary +This document defines a unified standard for developing **ABP + Angular full-stack applications**, ensuring: +- Code is **modular**, **performant**, and **maintainable**. +- Teams follow **consistent conventions** across backend and frontend. +- Every layer (Domain, Application, UI) is **clean, testable, and scalable**. diff --git a/npm/ng-packs/packages/schematics/src/commands/ai-config/files/cursor/.cursor/rules/cursor.mdc b/npm/ng-packs/packages/schematics/src/commands/ai-config/files/cursor/.cursor/rules/cursor.mdc new file mode 100644 index 0000000000..32dfab0275 --- /dev/null +++ b/npm/ng-packs/packages/schematics/src/commands/ai-config/files/cursor/.cursor/rules/cursor.mdc @@ -0,0 +1,186 @@ +# 💻 ABP Full-Stack Development Rules +_Expert Guidelines for .NET Backend (ABP) and Angular Frontend Development_ + +You are a **senior full-stack developer** specializing in **ABP Framework (.NET)** and **Angular (TypeScript)**. +You write **clean, maintainable, and modular** code following **ABP, ASP.NET Core, and Angular best practices**. + +--- + +## 🧩 1. General Principles +- Maintain a clear separation between backend (ABP/.NET) and frontend (Angular) layers. +- Follow **modular architecture** — each layer or feature should be independently testable and reusable. +- Always adhere to **official ABP documentation** ([docs.abp.io](https://docs.abp.io)) and **Angular official guides**. +- Prioritize **readability, maintainability, and performance**. +- Write **idiomatic** and **self-documenting** code. + +--- + +## ⚙️ 2. ABP / .NET Development Rules + +### Code Style and Structure +- Follow ABP’s standard folder structure: + - `*.Application`, `*.Domain`, `*.EntityFrameworkCore`, `*.HttpApi` +- Write concise, idiomatic C# code using modern language features. +- Apply **modular and layered design** (Domain, Application, Infrastructure, UI). +- Prefer **LINQ** and **lambda expressions** for collection operations. +- Use **descriptive method and variable names** (`GetActiveUsers`, `CalculateTotalAmount`). + +### Naming Conventions +- **PascalCase** → Classes, Methods, Properties +- **camelCase** → Local variables and private fields +- **UPPER_CASE** → Constants +- Prefix interfaces with **`I`** (e.g., `IUserRepository`). + +### C# and .NET Usage +- Use **C# 10+ features** (records, pattern matching, null-coalescing assignment). +- Utilize **ABP modules** (Permission Management, Setting Management, Audit Logging). +- Integrate **Entity Framework Core** with ABP’s repository abstractions. + +### Syntax and Formatting +- Follow [Microsoft C# Coding Conventions](https://learn.microsoft.com/dotnet/csharp/fundamentals/coding-style/coding-conventions). +- Use `var` when the type is clear. +- Use `string interpolation` and null-conditional operators. +- Keep code consistent and well-formatted. + +### Error Handling and Validation +- Use exceptions only for exceptional cases. +- Log errors via ABP’s built-in logging or a compatible provider. +- Validate models with **DataAnnotations** or **FluentValidation**. +- Rely on ABP’s global exception middleware for unified responses. +- Return consistent HTTP status codes and error DTOs. + +### API Design +- Build RESTful APIs via `HttpApi` layer and **ABP conventional controllers**. +- Use **attribute-based routing** and versioning when needed. +- Apply **action filters/middleware** for cross-cutting concerns (auditing, authorization). + +### Performance Optimization +- Use `async/await` for I/O operations. +- Use `IDistributedCache` over `IMemoryCache`. +- Avoid N+1 queries — include relations explicitly. +- Implement pagination with `PagedResultDto`. + +### Key Conventions +- Use **Dependency Injection** via ABP’s DI system. +- Apply **repository pattern** or EF Core directly as needed. +- Use **AutoMapper** or ABP object mapping for DTOs. +- Implement **background jobs** with ABP’s job system or `IHostedService`. +- Follow **domain-driven design (DDD)** principles: + - Business rules in Domain layer. + - Use `AuditedAggregateRoot`, `FullAuditedEntity`, etc. +- Avoid unnecessary dependencies between layers. + +### Testing +- Use **xUnit**, **Shouldly**, and **NSubstitute** for testing. +- Write **unit and integration tests** per module (`Application.Tests`, `Domain.Tests`). +- Mock dependencies properly and use ABP’s test base classes. + +### Security +- Use **OpenIddict** for authentication & authorization. +- Implement permission checks through ABP’s infrastructure. +- Enforce **HTTPS** and properly configure **CORS**. + +### API Documentation +- Use **Swagger / OpenAPI** (Swashbuckle or NSwag). +- Add XML comments to controllers and DTOs. +- Follow ABP’s documentation conventions for module APIs. + +**Reference Best Practices:** +- [Domain Services](https://abp.io/docs/latest/framework/architecture/best-practices/domain-services) +- [Repositories](https://abp.io/docs/latest/framework/architecture/best-practices/repositories) +- [Entities](https://abp.io/docs/latest/framework/architecture/best-practices/entities) +- [Application Services](https://abp.io/docs/latest/framework/architecture/best-practices/application-services) +- [DTOs](https://abp.io/docs/latest/framework/architecture/best-practices/data-transfer-objects) +- [Entity Framework Integration](https://abp.io/docs/latest/framework/architecture/best-practices/entity-framework-core-integration) + +--- + +## 🌐 3. Angular / TypeScript Development Rules + +### TypeScript Best Practices +- Enable **strict type checking** in `tsconfig.json`. +- Use **type inference** when the type is obvious. +- Avoid `any`; use `unknown` or generics instead. +- Use interfaces and types for clarity and structure. + +### Angular Best Practices +- Prefer **standalone components** (no `NgModules`). +- Do **NOT** set `standalone: true` manually — it’s default. +- Use **signals** for state management. +- Implement **lazy loading** for feature routes. +- Avoid `@HostBinding` / `@HostListener`; use `host` object in decorators. +- Use **`NgOptimizedImage`** for static images (not base64). + +### Components +- Keep components small, focused, and reusable. +- Use `input()` and `output()` functions instead of decorators. +- Use `computed()` for derived state. +- Always set `changeDetection: ChangeDetectionStrategy.OnPush`. +- Use **inline templates** for small components. +- Prefer **Reactive Forms** over template-driven forms. +- Avoid `ngClass` → use `[class]` bindings. +- Avoid `ngStyle` → use `[style]` bindings. + +### State Management +- Manage **local component state** with signals. +- Use **`computed()`** for derived data. +- Keep state transformations **pure and predictable**. +- Avoid `mutate()` on signals — use `update()` or `set()`. + +### Templates +- Use **native control flow** (`@if`, `@for`, `@switch`) instead of structural directives. +- Keep templates minimal and declarative. +- Use the **async pipe** for observable bindings. + +### Services +- Design services for **single responsibility**. +- Provide services using `providedIn: 'root'`. +- Use the **`inject()` function** instead of constructor injection. + +### Component Replacement +ABP Angular provides a powerful **component replacement** system via `ReplaceableComponentsService`: + +**Key Features:** +- Replace ABP default components (Roles, Users, Tenants, etc.) with custom implementations +- Replace layouts (Application, Account, Empty) +- Replace UI elements (Logo, Routes, NavItems) + +**Basic Usage:** +```typescript +import { ReplaceableComponentsService } from '@abp/ng.core'; +import { eIdentityComponents } from '@abp/ng.identity'; + +constructor(private replaceableComponents: ReplaceableComponentsService) { + this.replaceableComponents.add({ + component: YourCustomComponent, + key: eIdentityComponents.Roles, + }); +} +``` + +**Important Notes:** +- Component templates must include `` for layouts +- Use the second parameter as `true` for runtime replacement (refreshes route) +- Runtime replacement clears component state and re-runs initialization logic + +**📚 Full Documentation:** +For detailed examples, layout replacement, and advanced scenarios: +[Component Replacement Guide](https://abp.io/docs/latest/framework/ui/angular/customization-user-interface) + +--- + +## 🔒 4. Combined Full-Stack Practices +- Ensure backend and frontend follow consistent **DTO contracts** and **naming conventions**. +- Maintain shared models (e.g., via a `contracts` package or OpenAPI generation). +- Version APIs carefully and handle changes in Angular clients. +- Use ABP’s **CORS**, **Swagger**, and **Identity** modules to simplify frontend integration. +- Apply **global error handling** and consistent response wrappers in both layers. +- Monitor performance with tools like **Application Insights**, **ABP auditing**, or **Angular profiler**. + +--- + +## ✅ Summary +This document defines a unified standard for developing **ABP + Angular full-stack applications**, ensuring: +- Code is **modular**, **performant**, and **maintainable**. +- Teams follow **consistent conventions** across backend and frontend. +- Every layer (Domain, Application, UI) is **clean, testable, and scalable**. diff --git a/npm/ng-packs/packages/schematics/src/commands/ai-config/files/gemini/.gemini/GEMINI.md b/npm/ng-packs/packages/schematics/src/commands/ai-config/files/gemini/.gemini/GEMINI.md new file mode 100644 index 0000000000..32dfab0275 --- /dev/null +++ b/npm/ng-packs/packages/schematics/src/commands/ai-config/files/gemini/.gemini/GEMINI.md @@ -0,0 +1,186 @@ +# 💻 ABP Full-Stack Development Rules +_Expert Guidelines for .NET Backend (ABP) and Angular Frontend Development_ + +You are a **senior full-stack developer** specializing in **ABP Framework (.NET)** and **Angular (TypeScript)**. +You write **clean, maintainable, and modular** code following **ABP, ASP.NET Core, and Angular best practices**. + +--- + +## 🧩 1. General Principles +- Maintain a clear separation between backend (ABP/.NET) and frontend (Angular) layers. +- Follow **modular architecture** — each layer or feature should be independently testable and reusable. +- Always adhere to **official ABP documentation** ([docs.abp.io](https://docs.abp.io)) and **Angular official guides**. +- Prioritize **readability, maintainability, and performance**. +- Write **idiomatic** and **self-documenting** code. + +--- + +## ⚙️ 2. ABP / .NET Development Rules + +### Code Style and Structure +- Follow ABP’s standard folder structure: + - `*.Application`, `*.Domain`, `*.EntityFrameworkCore`, `*.HttpApi` +- Write concise, idiomatic C# code using modern language features. +- Apply **modular and layered design** (Domain, Application, Infrastructure, UI). +- Prefer **LINQ** and **lambda expressions** for collection operations. +- Use **descriptive method and variable names** (`GetActiveUsers`, `CalculateTotalAmount`). + +### Naming Conventions +- **PascalCase** → Classes, Methods, Properties +- **camelCase** → Local variables and private fields +- **UPPER_CASE** → Constants +- Prefix interfaces with **`I`** (e.g., `IUserRepository`). + +### C# and .NET Usage +- Use **C# 10+ features** (records, pattern matching, null-coalescing assignment). +- Utilize **ABP modules** (Permission Management, Setting Management, Audit Logging). +- Integrate **Entity Framework Core** with ABP’s repository abstractions. + +### Syntax and Formatting +- Follow [Microsoft C# Coding Conventions](https://learn.microsoft.com/dotnet/csharp/fundamentals/coding-style/coding-conventions). +- Use `var` when the type is clear. +- Use `string interpolation` and null-conditional operators. +- Keep code consistent and well-formatted. + +### Error Handling and Validation +- Use exceptions only for exceptional cases. +- Log errors via ABP’s built-in logging or a compatible provider. +- Validate models with **DataAnnotations** or **FluentValidation**. +- Rely on ABP’s global exception middleware for unified responses. +- Return consistent HTTP status codes and error DTOs. + +### API Design +- Build RESTful APIs via `HttpApi` layer and **ABP conventional controllers**. +- Use **attribute-based routing** and versioning when needed. +- Apply **action filters/middleware** for cross-cutting concerns (auditing, authorization). + +### Performance Optimization +- Use `async/await` for I/O operations. +- Use `IDistributedCache` over `IMemoryCache`. +- Avoid N+1 queries — include relations explicitly. +- Implement pagination with `PagedResultDto`. + +### Key Conventions +- Use **Dependency Injection** via ABP’s DI system. +- Apply **repository pattern** or EF Core directly as needed. +- Use **AutoMapper** or ABP object mapping for DTOs. +- Implement **background jobs** with ABP’s job system or `IHostedService`. +- Follow **domain-driven design (DDD)** principles: + - Business rules in Domain layer. + - Use `AuditedAggregateRoot`, `FullAuditedEntity`, etc. +- Avoid unnecessary dependencies between layers. + +### Testing +- Use **xUnit**, **Shouldly**, and **NSubstitute** for testing. +- Write **unit and integration tests** per module (`Application.Tests`, `Domain.Tests`). +- Mock dependencies properly and use ABP’s test base classes. + +### Security +- Use **OpenIddict** for authentication & authorization. +- Implement permission checks through ABP’s infrastructure. +- Enforce **HTTPS** and properly configure **CORS**. + +### API Documentation +- Use **Swagger / OpenAPI** (Swashbuckle or NSwag). +- Add XML comments to controllers and DTOs. +- Follow ABP’s documentation conventions for module APIs. + +**Reference Best Practices:** +- [Domain Services](https://abp.io/docs/latest/framework/architecture/best-practices/domain-services) +- [Repositories](https://abp.io/docs/latest/framework/architecture/best-practices/repositories) +- [Entities](https://abp.io/docs/latest/framework/architecture/best-practices/entities) +- [Application Services](https://abp.io/docs/latest/framework/architecture/best-practices/application-services) +- [DTOs](https://abp.io/docs/latest/framework/architecture/best-practices/data-transfer-objects) +- [Entity Framework Integration](https://abp.io/docs/latest/framework/architecture/best-practices/entity-framework-core-integration) + +--- + +## 🌐 3. Angular / TypeScript Development Rules + +### TypeScript Best Practices +- Enable **strict type checking** in `tsconfig.json`. +- Use **type inference** when the type is obvious. +- Avoid `any`; use `unknown` or generics instead. +- Use interfaces and types for clarity and structure. + +### Angular Best Practices +- Prefer **standalone components** (no `NgModules`). +- Do **NOT** set `standalone: true` manually — it’s default. +- Use **signals** for state management. +- Implement **lazy loading** for feature routes. +- Avoid `@HostBinding` / `@HostListener`; use `host` object in decorators. +- Use **`NgOptimizedImage`** for static images (not base64). + +### Components +- Keep components small, focused, and reusable. +- Use `input()` and `output()` functions instead of decorators. +- Use `computed()` for derived state. +- Always set `changeDetection: ChangeDetectionStrategy.OnPush`. +- Use **inline templates** for small components. +- Prefer **Reactive Forms** over template-driven forms. +- Avoid `ngClass` → use `[class]` bindings. +- Avoid `ngStyle` → use `[style]` bindings. + +### State Management +- Manage **local component state** with signals. +- Use **`computed()`** for derived data. +- Keep state transformations **pure and predictable**. +- Avoid `mutate()` on signals — use `update()` or `set()`. + +### Templates +- Use **native control flow** (`@if`, `@for`, `@switch`) instead of structural directives. +- Keep templates minimal and declarative. +- Use the **async pipe** for observable bindings. + +### Services +- Design services for **single responsibility**. +- Provide services using `providedIn: 'root'`. +- Use the **`inject()` function** instead of constructor injection. + +### Component Replacement +ABP Angular provides a powerful **component replacement** system via `ReplaceableComponentsService`: + +**Key Features:** +- Replace ABP default components (Roles, Users, Tenants, etc.) with custom implementations +- Replace layouts (Application, Account, Empty) +- Replace UI elements (Logo, Routes, NavItems) + +**Basic Usage:** +```typescript +import { ReplaceableComponentsService } from '@abp/ng.core'; +import { eIdentityComponents } from '@abp/ng.identity'; + +constructor(private replaceableComponents: ReplaceableComponentsService) { + this.replaceableComponents.add({ + component: YourCustomComponent, + key: eIdentityComponents.Roles, + }); +} +``` + +**Important Notes:** +- Component templates must include `` for layouts +- Use the second parameter as `true` for runtime replacement (refreshes route) +- Runtime replacement clears component state and re-runs initialization logic + +**📚 Full Documentation:** +For detailed examples, layout replacement, and advanced scenarios: +[Component Replacement Guide](https://abp.io/docs/latest/framework/ui/angular/customization-user-interface) + +--- + +## 🔒 4. Combined Full-Stack Practices +- Ensure backend and frontend follow consistent **DTO contracts** and **naming conventions**. +- Maintain shared models (e.g., via a `contracts` package or OpenAPI generation). +- Version APIs carefully and handle changes in Angular clients. +- Use ABP’s **CORS**, **Swagger**, and **Identity** modules to simplify frontend integration. +- Apply **global error handling** and consistent response wrappers in both layers. +- Monitor performance with tools like **Application Insights**, **ABP auditing**, or **Angular profiler**. + +--- + +## ✅ Summary +This document defines a unified standard for developing **ABP + Angular full-stack applications**, ensuring: +- Code is **modular**, **performant**, and **maintainable**. +- Teams follow **consistent conventions** across backend and frontend. +- Every layer (Domain, Application, UI) is **clean, testable, and scalable**. diff --git a/npm/ng-packs/packages/schematics/src/commands/ai-config/files/junie/.junie/guidelines.md b/npm/ng-packs/packages/schematics/src/commands/ai-config/files/junie/.junie/guidelines.md new file mode 100644 index 0000000000..32dfab0275 --- /dev/null +++ b/npm/ng-packs/packages/schematics/src/commands/ai-config/files/junie/.junie/guidelines.md @@ -0,0 +1,186 @@ +# 💻 ABP Full-Stack Development Rules +_Expert Guidelines for .NET Backend (ABP) and Angular Frontend Development_ + +You are a **senior full-stack developer** specializing in **ABP Framework (.NET)** and **Angular (TypeScript)**. +You write **clean, maintainable, and modular** code following **ABP, ASP.NET Core, and Angular best practices**. + +--- + +## 🧩 1. General Principles +- Maintain a clear separation between backend (ABP/.NET) and frontend (Angular) layers. +- Follow **modular architecture** — each layer or feature should be independently testable and reusable. +- Always adhere to **official ABP documentation** ([docs.abp.io](https://docs.abp.io)) and **Angular official guides**. +- Prioritize **readability, maintainability, and performance**. +- Write **idiomatic** and **self-documenting** code. + +--- + +## ⚙️ 2. ABP / .NET Development Rules + +### Code Style and Structure +- Follow ABP’s standard folder structure: + - `*.Application`, `*.Domain`, `*.EntityFrameworkCore`, `*.HttpApi` +- Write concise, idiomatic C# code using modern language features. +- Apply **modular and layered design** (Domain, Application, Infrastructure, UI). +- Prefer **LINQ** and **lambda expressions** for collection operations. +- Use **descriptive method and variable names** (`GetActiveUsers`, `CalculateTotalAmount`). + +### Naming Conventions +- **PascalCase** → Classes, Methods, Properties +- **camelCase** → Local variables and private fields +- **UPPER_CASE** → Constants +- Prefix interfaces with **`I`** (e.g., `IUserRepository`). + +### C# and .NET Usage +- Use **C# 10+ features** (records, pattern matching, null-coalescing assignment). +- Utilize **ABP modules** (Permission Management, Setting Management, Audit Logging). +- Integrate **Entity Framework Core** with ABP’s repository abstractions. + +### Syntax and Formatting +- Follow [Microsoft C# Coding Conventions](https://learn.microsoft.com/dotnet/csharp/fundamentals/coding-style/coding-conventions). +- Use `var` when the type is clear. +- Use `string interpolation` and null-conditional operators. +- Keep code consistent and well-formatted. + +### Error Handling and Validation +- Use exceptions only for exceptional cases. +- Log errors via ABP’s built-in logging or a compatible provider. +- Validate models with **DataAnnotations** or **FluentValidation**. +- Rely on ABP’s global exception middleware for unified responses. +- Return consistent HTTP status codes and error DTOs. + +### API Design +- Build RESTful APIs via `HttpApi` layer and **ABP conventional controllers**. +- Use **attribute-based routing** and versioning when needed. +- Apply **action filters/middleware** for cross-cutting concerns (auditing, authorization). + +### Performance Optimization +- Use `async/await` for I/O operations. +- Use `IDistributedCache` over `IMemoryCache`. +- Avoid N+1 queries — include relations explicitly. +- Implement pagination with `PagedResultDto`. + +### Key Conventions +- Use **Dependency Injection** via ABP’s DI system. +- Apply **repository pattern** or EF Core directly as needed. +- Use **AutoMapper** or ABP object mapping for DTOs. +- Implement **background jobs** with ABP’s job system or `IHostedService`. +- Follow **domain-driven design (DDD)** principles: + - Business rules in Domain layer. + - Use `AuditedAggregateRoot`, `FullAuditedEntity`, etc. +- Avoid unnecessary dependencies between layers. + +### Testing +- Use **xUnit**, **Shouldly**, and **NSubstitute** for testing. +- Write **unit and integration tests** per module (`Application.Tests`, `Domain.Tests`). +- Mock dependencies properly and use ABP’s test base classes. + +### Security +- Use **OpenIddict** for authentication & authorization. +- Implement permission checks through ABP’s infrastructure. +- Enforce **HTTPS** and properly configure **CORS**. + +### API Documentation +- Use **Swagger / OpenAPI** (Swashbuckle or NSwag). +- Add XML comments to controllers and DTOs. +- Follow ABP’s documentation conventions for module APIs. + +**Reference Best Practices:** +- [Domain Services](https://abp.io/docs/latest/framework/architecture/best-practices/domain-services) +- [Repositories](https://abp.io/docs/latest/framework/architecture/best-practices/repositories) +- [Entities](https://abp.io/docs/latest/framework/architecture/best-practices/entities) +- [Application Services](https://abp.io/docs/latest/framework/architecture/best-practices/application-services) +- [DTOs](https://abp.io/docs/latest/framework/architecture/best-practices/data-transfer-objects) +- [Entity Framework Integration](https://abp.io/docs/latest/framework/architecture/best-practices/entity-framework-core-integration) + +--- + +## 🌐 3. Angular / TypeScript Development Rules + +### TypeScript Best Practices +- Enable **strict type checking** in `tsconfig.json`. +- Use **type inference** when the type is obvious. +- Avoid `any`; use `unknown` or generics instead. +- Use interfaces and types for clarity and structure. + +### Angular Best Practices +- Prefer **standalone components** (no `NgModules`). +- Do **NOT** set `standalone: true` manually — it’s default. +- Use **signals** for state management. +- Implement **lazy loading** for feature routes. +- Avoid `@HostBinding` / `@HostListener`; use `host` object in decorators. +- Use **`NgOptimizedImage`** for static images (not base64). + +### Components +- Keep components small, focused, and reusable. +- Use `input()` and `output()` functions instead of decorators. +- Use `computed()` for derived state. +- Always set `changeDetection: ChangeDetectionStrategy.OnPush`. +- Use **inline templates** for small components. +- Prefer **Reactive Forms** over template-driven forms. +- Avoid `ngClass` → use `[class]` bindings. +- Avoid `ngStyle` → use `[style]` bindings. + +### State Management +- Manage **local component state** with signals. +- Use **`computed()`** for derived data. +- Keep state transformations **pure and predictable**. +- Avoid `mutate()` on signals — use `update()` or `set()`. + +### Templates +- Use **native control flow** (`@if`, `@for`, `@switch`) instead of structural directives. +- Keep templates minimal and declarative. +- Use the **async pipe** for observable bindings. + +### Services +- Design services for **single responsibility**. +- Provide services using `providedIn: 'root'`. +- Use the **`inject()` function** instead of constructor injection. + +### Component Replacement +ABP Angular provides a powerful **component replacement** system via `ReplaceableComponentsService`: + +**Key Features:** +- Replace ABP default components (Roles, Users, Tenants, etc.) with custom implementations +- Replace layouts (Application, Account, Empty) +- Replace UI elements (Logo, Routes, NavItems) + +**Basic Usage:** +```typescript +import { ReplaceableComponentsService } from '@abp/ng.core'; +import { eIdentityComponents } from '@abp/ng.identity'; + +constructor(private replaceableComponents: ReplaceableComponentsService) { + this.replaceableComponents.add({ + component: YourCustomComponent, + key: eIdentityComponents.Roles, + }); +} +``` + +**Important Notes:** +- Component templates must include `` for layouts +- Use the second parameter as `true` for runtime replacement (refreshes route) +- Runtime replacement clears component state and re-runs initialization logic + +**📚 Full Documentation:** +For detailed examples, layout replacement, and advanced scenarios: +[Component Replacement Guide](https://abp.io/docs/latest/framework/ui/angular/customization-user-interface) + +--- + +## 🔒 4. Combined Full-Stack Practices +- Ensure backend and frontend follow consistent **DTO contracts** and **naming conventions**. +- Maintain shared models (e.g., via a `contracts` package or OpenAPI generation). +- Version APIs carefully and handle changes in Angular clients. +- Use ABP’s **CORS**, **Swagger**, and **Identity** modules to simplify frontend integration. +- Apply **global error handling** and consistent response wrappers in both layers. +- Monitor performance with tools like **Application Insights**, **ABP auditing**, or **Angular profiler**. + +--- + +## ✅ Summary +This document defines a unified standard for developing **ABP + Angular full-stack applications**, ensuring: +- Code is **modular**, **performant**, and **maintainable**. +- Teams follow **consistent conventions** across backend and frontend. +- Every layer (Domain, Application, UI) is **clean, testable, and scalable**. diff --git a/npm/ng-packs/packages/schematics/src/commands/ai-config/files/windsurf/.windsurf/rules/guidelines.md b/npm/ng-packs/packages/schematics/src/commands/ai-config/files/windsurf/.windsurf/rules/guidelines.md new file mode 100644 index 0000000000..32dfab0275 --- /dev/null +++ b/npm/ng-packs/packages/schematics/src/commands/ai-config/files/windsurf/.windsurf/rules/guidelines.md @@ -0,0 +1,186 @@ +# 💻 ABP Full-Stack Development Rules +_Expert Guidelines for .NET Backend (ABP) and Angular Frontend Development_ + +You are a **senior full-stack developer** specializing in **ABP Framework (.NET)** and **Angular (TypeScript)**. +You write **clean, maintainable, and modular** code following **ABP, ASP.NET Core, and Angular best practices**. + +--- + +## 🧩 1. General Principles +- Maintain a clear separation between backend (ABP/.NET) and frontend (Angular) layers. +- Follow **modular architecture** — each layer or feature should be independently testable and reusable. +- Always adhere to **official ABP documentation** ([docs.abp.io](https://docs.abp.io)) and **Angular official guides**. +- Prioritize **readability, maintainability, and performance**. +- Write **idiomatic** and **self-documenting** code. + +--- + +## ⚙️ 2. ABP / .NET Development Rules + +### Code Style and Structure +- Follow ABP’s standard folder structure: + - `*.Application`, `*.Domain`, `*.EntityFrameworkCore`, `*.HttpApi` +- Write concise, idiomatic C# code using modern language features. +- Apply **modular and layered design** (Domain, Application, Infrastructure, UI). +- Prefer **LINQ** and **lambda expressions** for collection operations. +- Use **descriptive method and variable names** (`GetActiveUsers`, `CalculateTotalAmount`). + +### Naming Conventions +- **PascalCase** → Classes, Methods, Properties +- **camelCase** → Local variables and private fields +- **UPPER_CASE** → Constants +- Prefix interfaces with **`I`** (e.g., `IUserRepository`). + +### C# and .NET Usage +- Use **C# 10+ features** (records, pattern matching, null-coalescing assignment). +- Utilize **ABP modules** (Permission Management, Setting Management, Audit Logging). +- Integrate **Entity Framework Core** with ABP’s repository abstractions. + +### Syntax and Formatting +- Follow [Microsoft C# Coding Conventions](https://learn.microsoft.com/dotnet/csharp/fundamentals/coding-style/coding-conventions). +- Use `var` when the type is clear. +- Use `string interpolation` and null-conditional operators. +- Keep code consistent and well-formatted. + +### Error Handling and Validation +- Use exceptions only for exceptional cases. +- Log errors via ABP’s built-in logging or a compatible provider. +- Validate models with **DataAnnotations** or **FluentValidation**. +- Rely on ABP’s global exception middleware for unified responses. +- Return consistent HTTP status codes and error DTOs. + +### API Design +- Build RESTful APIs via `HttpApi` layer and **ABP conventional controllers**. +- Use **attribute-based routing** and versioning when needed. +- Apply **action filters/middleware** for cross-cutting concerns (auditing, authorization). + +### Performance Optimization +- Use `async/await` for I/O operations. +- Use `IDistributedCache` over `IMemoryCache`. +- Avoid N+1 queries — include relations explicitly. +- Implement pagination with `PagedResultDto`. + +### Key Conventions +- Use **Dependency Injection** via ABP’s DI system. +- Apply **repository pattern** or EF Core directly as needed. +- Use **AutoMapper** or ABP object mapping for DTOs. +- Implement **background jobs** with ABP’s job system or `IHostedService`. +- Follow **domain-driven design (DDD)** principles: + - Business rules in Domain layer. + - Use `AuditedAggregateRoot`, `FullAuditedEntity`, etc. +- Avoid unnecessary dependencies between layers. + +### Testing +- Use **xUnit**, **Shouldly**, and **NSubstitute** for testing. +- Write **unit and integration tests** per module (`Application.Tests`, `Domain.Tests`). +- Mock dependencies properly and use ABP’s test base classes. + +### Security +- Use **OpenIddict** for authentication & authorization. +- Implement permission checks through ABP’s infrastructure. +- Enforce **HTTPS** and properly configure **CORS**. + +### API Documentation +- Use **Swagger / OpenAPI** (Swashbuckle or NSwag). +- Add XML comments to controllers and DTOs. +- Follow ABP’s documentation conventions for module APIs. + +**Reference Best Practices:** +- [Domain Services](https://abp.io/docs/latest/framework/architecture/best-practices/domain-services) +- [Repositories](https://abp.io/docs/latest/framework/architecture/best-practices/repositories) +- [Entities](https://abp.io/docs/latest/framework/architecture/best-practices/entities) +- [Application Services](https://abp.io/docs/latest/framework/architecture/best-practices/application-services) +- [DTOs](https://abp.io/docs/latest/framework/architecture/best-practices/data-transfer-objects) +- [Entity Framework Integration](https://abp.io/docs/latest/framework/architecture/best-practices/entity-framework-core-integration) + +--- + +## 🌐 3. Angular / TypeScript Development Rules + +### TypeScript Best Practices +- Enable **strict type checking** in `tsconfig.json`. +- Use **type inference** when the type is obvious. +- Avoid `any`; use `unknown` or generics instead. +- Use interfaces and types for clarity and structure. + +### Angular Best Practices +- Prefer **standalone components** (no `NgModules`). +- Do **NOT** set `standalone: true` manually — it’s default. +- Use **signals** for state management. +- Implement **lazy loading** for feature routes. +- Avoid `@HostBinding` / `@HostListener`; use `host` object in decorators. +- Use **`NgOptimizedImage`** for static images (not base64). + +### Components +- Keep components small, focused, and reusable. +- Use `input()` and `output()` functions instead of decorators. +- Use `computed()` for derived state. +- Always set `changeDetection: ChangeDetectionStrategy.OnPush`. +- Use **inline templates** for small components. +- Prefer **Reactive Forms** over template-driven forms. +- Avoid `ngClass` → use `[class]` bindings. +- Avoid `ngStyle` → use `[style]` bindings. + +### State Management +- Manage **local component state** with signals. +- Use **`computed()`** for derived data. +- Keep state transformations **pure and predictable**. +- Avoid `mutate()` on signals — use `update()` or `set()`. + +### Templates +- Use **native control flow** (`@if`, `@for`, `@switch`) instead of structural directives. +- Keep templates minimal and declarative. +- Use the **async pipe** for observable bindings. + +### Services +- Design services for **single responsibility**. +- Provide services using `providedIn: 'root'`. +- Use the **`inject()` function** instead of constructor injection. + +### Component Replacement +ABP Angular provides a powerful **component replacement** system via `ReplaceableComponentsService`: + +**Key Features:** +- Replace ABP default components (Roles, Users, Tenants, etc.) with custom implementations +- Replace layouts (Application, Account, Empty) +- Replace UI elements (Logo, Routes, NavItems) + +**Basic Usage:** +```typescript +import { ReplaceableComponentsService } from '@abp/ng.core'; +import { eIdentityComponents } from '@abp/ng.identity'; + +constructor(private replaceableComponents: ReplaceableComponentsService) { + this.replaceableComponents.add({ + component: YourCustomComponent, + key: eIdentityComponents.Roles, + }); +} +``` + +**Important Notes:** +- Component templates must include `` for layouts +- Use the second parameter as `true` for runtime replacement (refreshes route) +- Runtime replacement clears component state and re-runs initialization logic + +**📚 Full Documentation:** +For detailed examples, layout replacement, and advanced scenarios: +[Component Replacement Guide](https://abp.io/docs/latest/framework/ui/angular/customization-user-interface) + +--- + +## 🔒 4. Combined Full-Stack Practices +- Ensure backend and frontend follow consistent **DTO contracts** and **naming conventions**. +- Maintain shared models (e.g., via a `contracts` package or OpenAPI generation). +- Version APIs carefully and handle changes in Angular clients. +- Use ABP’s **CORS**, **Swagger**, and **Identity** modules to simplify frontend integration. +- Apply **global error handling** and consistent response wrappers in both layers. +- Monitor performance with tools like **Application Insights**, **ABP auditing**, or **Angular profiler**. + +--- + +## ✅ Summary +This document defines a unified standard for developing **ABP + Angular full-stack applications**, ensuring: +- Code is **modular**, **performant**, and **maintainable**. +- Teams follow **consistent conventions** across backend and frontend. +- Every layer (Domain, Application, UI) is **clean, testable, and scalable**. diff --git a/npm/ng-packs/packages/schematics/src/commands/ai-config/index.ts b/npm/ng-packs/packages/schematics/src/commands/ai-config/index.ts new file mode 100644 index 0000000000..2cc2da1165 --- /dev/null +++ b/npm/ng-packs/packages/schematics/src/commands/ai-config/index.ts @@ -0,0 +1,118 @@ +import { + Rule, + SchematicsException, + Tree, + apply, + url, + mergeWith, + MergeStrategy, + filter, + chain, +} from '@angular-devkit/schematics'; +import { join, normalize } from '@angular-devkit/core'; +import { AiConfigSchema, AiTool } from './model'; +import { getWorkspace } from '../../utils'; + +export default function (options: AiConfigSchema): Rule { + return async (tree: Tree) => { + if (!options.tool || options.tool.trim() === '') { + console.log('ℹ️ No AI tools selected. Skipping configuration generation.'); + console.log(''); + console.log('💡 Usage examples:'); + console.log(' ng g @abp/ng.schematics:ai-config --tool=claude,cursor'); + console.log(' ng g @abp/ng.schematics:ai-config --tool="claude, cursor"'); + console.log(' ng g @abp/ng.schematics:ai-config --tool=gemini --tool=cursor'); + console.log(' ng g @abp/ng.schematics:ai-config --tool=gemini --target-project=my-app'); + console.log(''); + console.log('Available tools: claude, copilot, cursor, gemini, junie, windsurf'); + return tree; + } + + const tools = options.tool.split(/[\s,]+/).filter(t => t) as AiTool[]; + + const validTools: AiTool[] = ['claude', 'copilot', 'cursor', 'gemini', 'junie', 'windsurf']; + const invalidTools = tools.filter(tool => !validTools.includes(tool)); + if (invalidTools.length > 0) { + throw new SchematicsException( + `Invalid AI tool(s): ${invalidTools.join(', ')}. Valid options are: ${validTools.join(', ')}`, + ); + } + + if (tools.length === 0) { + console.log('ℹ️ No AI tools selected. Skipping configuration generation.'); + return tree; + } + + const workspace = await getWorkspace(tree); + let targetPath = '/'; + + if (options.targetProject) { + const trimmedTargetProject = options.targetProject.trim(); + const project = workspace.projects.get(trimmedTargetProject); + if (!project) { + throw new SchematicsException(`Project "${trimmedTargetProject}" not found in workspace.`); + } + targetPath = normalize(project.root); + } + + console.log('🚀 Generating AI configuration files...'); + console.log(`📁 Target path: ${targetPath}`); + console.log(`🤖 Selected tools: ${tools.join(', ')}`); + + const rules: Rule[] = tools.map(tool => + generateConfigForTool(tool, targetPath, options.overwrite || false), + ); + + return chain([ + ...rules, + (tree: Tree) => { + console.log('✅ AI configuration files generated successfully!'); + console.log('\n📝 Generated files:'); + + tools.forEach(tool => { + const configPath = getConfigPath(tool, targetPath); + console.log(` - ${configPath}`); + }); + + console.log('\n💡 Tip: Restart your IDE or AI tool to apply the new configurations.'); + + return tree; + }, + ]); + }; +} + +function generateConfigForTool(tool: AiTool, targetPath: string, overwrite: boolean): Rule { + return (tree: Tree) => { + const configPath = getConfigPath(tool, targetPath); + + if (tree.exists(configPath) && !overwrite) { + console.log(`⚠️ Configuration file already exists: ${configPath}`); + console.log(` Use --overwrite flag to replace existing files.`); + return tree; + } + + const sourceDir = `./files/${tool}`; + const source = apply(url(sourceDir), [ + filter(path => { + return !path.endsWith('.DS_Store'); + }), + ]); + + return mergeWith(source, overwrite ? MergeStrategy.Overwrite : MergeStrategy.Default); + }; +} + +function getConfigPath(tool: AiTool, basePath: string): string { + const configFiles: Record = { + claude: '.claude/CLAUDE.md', + copilot: '.github/copilot-instructions.md', + cursor: '.cursor/rules/cursor.mdc', + gemini: '.gemini/GEMINI.md', + junie: '.junie/guidelines.md', + windsurf: '.windsurf/rules/guidelines.md', + }; + + const configFile = configFiles[tool]; + return join(normalize(basePath), configFile); +} diff --git a/npm/ng-packs/packages/schematics/src/commands/ai-config/model.ts b/npm/ng-packs/packages/schematics/src/commands/ai-config/model.ts new file mode 100644 index 0000000000..ab871971c2 --- /dev/null +++ b/npm/ng-packs/packages/schematics/src/commands/ai-config/model.ts @@ -0,0 +1,12 @@ +export type AiTool = 'claude' | 'copilot' | 'cursor' | 'gemini' | 'junie' | 'windsurf'; + +export interface AiConfigSchema { + tool?: string; + targetProject?: string; + overwrite?: boolean; +} + +export interface AiConfigFile { + path: string; + content: string; +} diff --git a/npm/ng-packs/packages/schematics/src/commands/ai-config/schema.json b/npm/ng-packs/packages/schematics/src/commands/ai-config/schema.json new file mode 100644 index 0000000000..0d5e0117ed --- /dev/null +++ b/npm/ng-packs/packages/schematics/src/commands/ai-config/schema.json @@ -0,0 +1,30 @@ +{ + "$schema": "http://json-schema.org/schema", + "$id": "SchematicsABPAiConfig", + "title": "ABP AI Configuration Generator Schema", + "type": "object", + "properties": { + "tool": { + "description": "Comma-separated list of AI tools (e.g., claude,cursor,gemini)", + "type": "string", + "x-prompt": { + "message": "Which AI tools would you like to generate configuration files for? (comma-separated)", + "type": "input" + } + }, + "targetProject": { + "description": "The target project name to generate AI configuration files for", + "type": "string", + "x-prompt": { + "message": "Which project would you like to generate AI config for?", + "type": "input" + } + }, + "overwrite": { + "description": "Overwrite existing AI configuration files", + "type": "boolean", + "default": false + } + }, + "required": [] +} diff --git a/npm/ng-packs/scripts/build-schematics.ts b/npm/ng-packs/scripts/build-schematics.ts index c953a362ca..bdf2e66392 100644 --- a/npm/ng-packs/scripts/build-schematics.ts +++ b/npm/ng-packs/scripts/build-schematics.ts @@ -22,6 +22,8 @@ const PACKAGE_TO_BUILD = 'schematics'; const FILES_TO_COPY_AFTER_BUILD: (FileCopy | string)[] = [ { src: 'src/commands/create-lib/schema.json', dest: 'commands/create-lib/schema.json' }, { src: 'src/commands/change-theme/schema.json', dest: 'commands/change-theme/schema.json' }, + { src: 'src/commands/ai-config/schema.json', dest: 'commands/ai-config/schema.json' }, + { src: 'src/commands/ai-config/files', dest: 'commands/ai-config/files' }, { src: 'src/commands/create-lib/files-package', dest: 'commands/create-lib/files-package' }, { src: 'src/commands/create-lib/files-package-standalone', dest: 'commands/create-lib/files-package-standalone' }, { diff --git a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server.Mongo/MyCompanyName.MyProjectName.Blazor.Server.Mongo.csproj b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server.Mongo/MyCompanyName.MyProjectName.Blazor.Server.Mongo.csproj index 7913af7625..037cf42aa2 100644 --- a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server.Mongo/MyCompanyName.MyProjectName.Blazor.Server.Mongo.csproj +++ b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server.Mongo/MyCompanyName.MyProjectName.Blazor.Server.Mongo.csproj @@ -21,8 +21,8 @@ - - + + diff --git a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server/MyCompanyName.MyProjectName.Blazor.Server.csproj b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server/MyCompanyName.MyProjectName.Blazor.Server.csproj index 02ac9eecff..43b1ebfc17 100644 --- a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server/MyCompanyName.MyProjectName.Blazor.Server.csproj +++ b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server/MyCompanyName.MyProjectName.Blazor.Server.csproj @@ -21,8 +21,8 @@ - - + + diff --git a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.WebAssembly/Client/MyCompanyName.MyProjectName.Blazor.WebAssembly.Client.csproj b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.WebAssembly/Client/MyCompanyName.MyProjectName.Blazor.WebAssembly.Client.csproj index e7143cac87..c6d1800bc8 100644 --- a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.WebAssembly/Client/MyCompanyName.MyProjectName.Blazor.WebAssembly.Client.csproj +++ b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.WebAssembly/Client/MyCompanyName.MyProjectName.Blazor.WebAssembly.Client.csproj @@ -21,7 +21,7 @@ - + diff --git a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.WebAssembly/Server.Mongo/MyCompanyName.MyProjectName.Blazor.WebAssembly.Server.Mongo.csproj b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.WebAssembly/Server.Mongo/MyCompanyName.MyProjectName.Blazor.WebAssembly.Server.Mongo.csproj index cf5dc6ab2b..a8bf31d346 100644 --- a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.WebAssembly/Server.Mongo/MyCompanyName.MyProjectName.Blazor.WebAssembly.Server.Mongo.csproj +++ b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.WebAssembly/Server.Mongo/MyCompanyName.MyProjectName.Blazor.WebAssembly.Server.Mongo.csproj @@ -73,8 +73,8 @@ - - + + diff --git a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.WebAssembly/Server/MyCompanyName.MyProjectName.Blazor.WebAssembly.Server.csproj b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.WebAssembly/Server/MyCompanyName.MyProjectName.Blazor.WebAssembly.Server.csproj index f40926e798..06d3ef4d96 100644 --- a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.WebAssembly/Server/MyCompanyName.MyProjectName.Blazor.WebAssembly.Server.csproj +++ b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.WebAssembly/Server/MyCompanyName.MyProjectName.Blazor.WebAssembly.Server.csproj @@ -74,8 +74,8 @@ - - + + diff --git a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host.Mongo/MyCompanyName.MyProjectName.Host.Mongo.csproj b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host.Mongo/MyCompanyName.MyProjectName.Host.Mongo.csproj index f4810d4f58..01791b9243 100644 --- a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host.Mongo/MyCompanyName.MyProjectName.Host.Mongo.csproj +++ b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host.Mongo/MyCompanyName.MyProjectName.Host.Mongo.csproj @@ -69,7 +69,7 @@ - + diff --git a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host/MyCompanyName.MyProjectName.Host.csproj b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host/MyCompanyName.MyProjectName.Host.csproj index 8d1ebead7f..ff10498ccf 100644 --- a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host/MyCompanyName.MyProjectName.Host.csproj +++ b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host/MyCompanyName.MyProjectName.Host.csproj @@ -70,7 +70,7 @@ - + diff --git a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc.Mongo/MyCompanyName.MyProjectName.Mvc.Mongo.csproj b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc.Mongo/MyCompanyName.MyProjectName.Mvc.Mongo.csproj index 10cf94a45d..ddd2eba8a4 100644 --- a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc.Mongo/MyCompanyName.MyProjectName.Mvc.Mongo.csproj +++ b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc.Mongo/MyCompanyName.MyProjectName.Mvc.Mongo.csproj @@ -17,7 +17,7 @@ - + diff --git a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc/MyCompanyName.MyProjectName.Mvc.csproj b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc/MyCompanyName.MyProjectName.Mvc.csproj index 93bae4a676..fb57cc387a 100644 --- a/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc/MyCompanyName.MyProjectName.Mvc.csproj +++ b/templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc/MyCompanyName.MyProjectName.Mvc.csproj @@ -17,7 +17,7 @@ - + diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.AuthServer/MyCompanyName.MyProjectName.AuthServer.csproj b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.AuthServer/MyCompanyName.MyProjectName.AuthServer.csproj index fab200af99..52ce942043 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.AuthServer/MyCompanyName.MyProjectName.AuthServer.csproj +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.AuthServer/MyCompanyName.MyProjectName.AuthServer.csproj @@ -51,7 +51,7 @@ - + diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor.Client/MyCompanyName.MyProjectName.Blazor.Client.csproj b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor.Client/MyCompanyName.MyProjectName.Blazor.Client.csproj index d83f9fb7c6..a05c7e6476 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor.Client/MyCompanyName.MyProjectName.Blazor.Client.csproj +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor.Client/MyCompanyName.MyProjectName.Blazor.Client.csproj @@ -24,7 +24,7 @@ - + diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor.Server.Tiered/MyCompanyName.MyProjectName.Blazor.Server.Tiered.csproj b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor.Server.Tiered/MyCompanyName.MyProjectName.Blazor.Server.Tiered.csproj index f2a3e6563b..03043afdd3 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor.Server.Tiered/MyCompanyName.MyProjectName.Blazor.Server.Tiered.csproj +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor.Server.Tiered/MyCompanyName.MyProjectName.Blazor.Server.Tiered.csproj @@ -30,8 +30,8 @@ - - + + diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor.Server/MyCompanyName.MyProjectName.Blazor.Server.csproj b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor.Server/MyCompanyName.MyProjectName.Blazor.Server.csproj index de809a8924..9c0f3985f8 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor.Server/MyCompanyName.MyProjectName.Blazor.Server.csproj +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor.Server/MyCompanyName.MyProjectName.Blazor.Server.csproj @@ -29,8 +29,8 @@ - - + + diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor.WebApp.Client/MyCompanyName.MyProjectName.Blazor.WebApp.Client.csproj b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor.WebApp.Client/MyCompanyName.MyProjectName.Blazor.WebApp.Client.csproj index 9cad962872..aa6591bcab 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor.WebApp.Client/MyCompanyName.MyProjectName.Blazor.WebApp.Client.csproj +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor.WebApp.Client/MyCompanyName.MyProjectName.Blazor.WebApp.Client.csproj @@ -25,7 +25,7 @@ - + diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor.WebApp.Tiered.Client/MyCompanyName.MyProjectName.Blazor.WebApp.Tiered.Client.csproj b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor.WebApp.Tiered.Client/MyCompanyName.MyProjectName.Blazor.WebApp.Tiered.Client.csproj index 58051e1c8d..f8a19a1921 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor.WebApp.Tiered.Client/MyCompanyName.MyProjectName.Blazor.WebApp.Tiered.Client.csproj +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor.WebApp.Tiered.Client/MyCompanyName.MyProjectName.Blazor.WebApp.Tiered.Client.csproj @@ -25,7 +25,7 @@ - + diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor.WebApp.Tiered/MyCompanyName.MyProjectName.Blazor.WebApp.Tiered.csproj b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor.WebApp.Tiered/MyCompanyName.MyProjectName.Blazor.WebApp.Tiered.csproj index a4208d5f42..55159c4683 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor.WebApp.Tiered/MyCompanyName.MyProjectName.Blazor.WebApp.Tiered.csproj +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor.WebApp.Tiered/MyCompanyName.MyProjectName.Blazor.WebApp.Tiered.csproj @@ -32,8 +32,8 @@ - - + + diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor.WebApp/MyCompanyName.MyProjectName.Blazor.WebApp.csproj b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor.WebApp/MyCompanyName.MyProjectName.Blazor.WebApp.csproj index 2755545498..1aec506594 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor.WebApp/MyCompanyName.MyProjectName.Blazor.WebApp.csproj +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor.WebApp/MyCompanyName.MyProjectName.Blazor.WebApp.csproj @@ -30,9 +30,9 @@ - - - + + + diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor/MyCompanyName.MyProjectName.Blazor.csproj b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor/MyCompanyName.MyProjectName.Blazor.csproj index 813c4e4cf3..ef1012d89d 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor/MyCompanyName.MyProjectName.Blazor.csproj +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor/MyCompanyName.MyProjectName.Blazor.csproj @@ -16,7 +16,7 @@ - + diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.HostWithIds/MyCompanyName.MyProjectName.HttpApi.HostWithIds.csproj b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.HostWithIds/MyCompanyName.MyProjectName.HttpApi.HostWithIds.csproj index 219f63070b..bff7c6c558 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.HostWithIds/MyCompanyName.MyProjectName.HttpApi.HostWithIds.csproj +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.HostWithIds/MyCompanyName.MyProjectName.HttpApi.HostWithIds.csproj @@ -26,7 +26,7 @@ - + diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web.Host/MyCompanyName.MyProjectName.Web.Host.csproj b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web.Host/MyCompanyName.MyProjectName.Web.Host.csproj index 738562b386..fa7d6b10d3 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web.Host/MyCompanyName.MyProjectName.Web.Host.csproj +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web.Host/MyCompanyName.MyProjectName.Web.Host.csproj @@ -28,7 +28,7 @@ - + diff --git a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web/MyCompanyName.MyProjectName.Web.csproj b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web/MyCompanyName.MyProjectName.Web.csproj index 1c67acc87a..cf8dd3d500 100644 --- a/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web/MyCompanyName.MyProjectName.Web.csproj +++ b/templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web/MyCompanyName.MyProjectName.Web.csproj @@ -49,7 +49,7 @@ - +