Browse Source

Merge branch 'dev' into Passkey

pull/24278/head
maliming 10 months ago
parent
commit
1b712c295e
No known key found for this signature in database GPG Key ID: A646B9CB645ECEA4
  1. 2
      Directory.Packages.props
  2. 9
      abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/en.json
  3. 2
      docs/en/Community-Articles/2025-11-15-Announcing-SSR-Support/article.md
  4. 14
      docs/en/cli/index.md
  5. 4
      docs/en/release-info/release-notes.md
  6. 4
      docs/en/tutorials/microservice/part-01.md
  7. 2
      framework/src/Volo.Abp.AspNetCore.Mvc.NewtonsoftJson/Volo/Abp/AspNetCore/Mvc/NewtonsoftJson/AbpAspNetCoreMvcNewtonsoftModule.cs
  8. 2
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcModule.cs
  9. 2
      framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/MvcCoreBuilderExtensions.cs
  10. 10
      framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/ExtensionProperties.razor.cs
  11. 22
      framework/src/Volo.Abp.Core/Microsoft/Extensions/DependencyInjection/ServiceCollectionOptionsExtensions.cs
  12. 9
      framework/src/Volo.Abp.Core/Volo/Abp/AbpApplicationBase.cs
  13. 5
      framework/src/Volo.Abp.Core/Volo/Abp/Internal/Telemetry/Activity/Providers/TelemetrySolutionInfoEnricher.cs
  14. 18
      framework/src/Volo.Abp.Core/Volo/Abp/Internal/Telemetry/Activity/Storage/TelemetryActivityStorage.cs
  15. 1
      framework/src/Volo.Abp.Core/Volo/Abp/Internal/Telemetry/Constants/ActivityPropertyNames.cs
  16. 8
      framework/src/Volo.Abp.Core/Volo/Abp/Internal/Telemetry/Constants/DeviceManager.cs
  17. 10
      framework/src/Volo.Abp.Core/Volo/Abp/Internal/Telemetry/EnvironmentInspection/Detectors/AbpStudioDetector.cs
  18. 10
      framework/src/Volo.Abp.Core/Volo/Abp/Internal/Telemetry/EnvironmentInspection/Detectors/VisualStudioCodeDetector.cs
  19. 6
      framework/src/Volo.Abp.Core/Volo/Abp/Internal/Telemetry/Helpers/AbpPackageMetadataReader.cs
  20. 36
      framework/src/Volo.Abp.Core/Volo/Abp/Internal/Telemetry/TelemetryService.cs
  21. 34
      framework/src/Volo.Abp.Core/Volo/Abp/Options/AbpUnnamedOptionsManager.cs
  22. 2
      framework/src/Volo.Abp.Json.Newtonsoft/Volo/Abp/Json/Newtonsoft/AbpJsonNewtonsoftModule.cs
  23. 2
      framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/AbpJsonSystemTextJsonModule.cs
  24. 5
      framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/Modularity/ExtensionPropertyUiFormConfiguration.cs
  25. 4
      framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/Modularity/ModuleExtensionConfigurationHelper.cs
  26. 18
      framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionPropertyInfo.cs
  27. 39
      framework/src/Volo.Abp.Swashbuckle/Microsoft/Extensions/DependencyInjection/AbpSwaggerGenServiceCollectionExtensions.cs
  28. 20
      framework/src/Volo.Abp.Swashbuckle/Volo/Abp/Swashbuckle/AbpSwashbuckleDocumentFilter.cs
  29. 18
      framework/src/Volo.Abp.Swashbuckle/Volo/Abp/Swashbuckle/AbpSwashbuckleEnumSchemaFilter.cs
  30. 4
      framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpJsonTestModule.cs
  31. 2
      framework/test/Volo.Abp.MemoryDb.Tests/Volo/Abp/MemoryDb/AbpMemoryDbTestModule.cs
  32. 2
      modules/blogging/app/Volo.BloggingTestApp/BloggingTestAppModule.cs
  33. 2
      modules/cms-kit/host/Volo.CmsKit.HttpApi.Host/CmsKitHttpApiHostModule.cs
  34. 2
      modules/cms-kit/host/Volo.CmsKit.IdentityServer/CmsKitIdentityServerModule.cs
  35. 2
      modules/cms-kit/host/Volo.CmsKit.Web.Host/CmsKitWebHostModule.cs
  36. 2
      modules/cms-kit/host/Volo.CmsKit.Web.Unified/CmsKitWebUnifiedModule.cs
  37. 2
      modules/docs/app/VoloDocs.Web/VoloDocsWebModule.cs
  38. 13
      modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Documents/Index.cshtml
  39. 2
      modules/identity/src/Volo.Abp.Identity.AspNetCore/Volo/Abp/Identity/AspNetCore/AbpIdentityAspNetCoreModule.cs
  40. 16
      modules/openiddict/app/OpenIddict.Demo.API/Program.cs
  41. 2
      modules/setting-management/app/Volo.Abp.SettingManagement.DemoApp/DemoAppModule.cs
  42. 31
      npm/ng-packs/packages/core/src/lib/guards/permission.guard.ts
  43. 17
      npm/ng-packs/packages/core/src/lib/tests/permission.guard.spec.ts
  44. 5
      npm/ng-packs/packages/schematics/src/collection.json
  45. 186
      npm/ng-packs/packages/schematics/src/commands/ai-config/files/claude/.claude/CLAUDE.md
  46. 186
      npm/ng-packs/packages/schematics/src/commands/ai-config/files/copilot/.github/copilot-instructions.md
  47. 186
      npm/ng-packs/packages/schematics/src/commands/ai-config/files/cursor/.cursor/rules/cursor.mdc
  48. 186
      npm/ng-packs/packages/schematics/src/commands/ai-config/files/gemini/.gemini/GEMINI.md
  49. 186
      npm/ng-packs/packages/schematics/src/commands/ai-config/files/junie/.junie/guidelines.md
  50. 186
      npm/ng-packs/packages/schematics/src/commands/ai-config/files/windsurf/.windsurf/rules/guidelines.md
  51. 118
      npm/ng-packs/packages/schematics/src/commands/ai-config/index.ts
  52. 12
      npm/ng-packs/packages/schematics/src/commands/ai-config/model.ts
  53. 30
      npm/ng-packs/packages/schematics/src/commands/ai-config/schema.json
  54. 2
      npm/ng-packs/scripts/build-schematics.ts
  55. 2
      templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server.Mongo/MyProjectNameModule.cs
  56. 2
      templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server/MyProjectNameModule.cs
  57. 2
      templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.WebAssembly/Server.Mongo/MyProjectNameHostModule.cs
  58. 2
      templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.WebAssembly/Server/MyProjectNameHostModule.cs
  59. 2
      templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host.Mongo/MyProjectNameModule.cs
  60. 2
      templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host/MyProjectNameModule.cs
  61. 2
      templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc.Mongo/MyProjectNameModule.cs
  62. 2
      templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc/MyProjectNameModule.cs
  63. 2
      templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor.Server.Tiered/MyProjectNameBlazorModule.cs
  64. 2
      templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor.Server/MyProjectNameBlazorModule.cs
  65. 2
      templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor.WebApp.Tiered/MyProjectNameBlazorModule.cs
  66. 2
      templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor.WebApp/MyProjectNameBlazorModule.cs
  67. 2
      templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.Host/MyProjectNameHttpApiHostModule.cs
  68. 2
      templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.HostWithIds/MyProjectNameHttpApiHostModule.cs
  69. 2
      templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web.Host/MyProjectNameWebModule.cs
  70. 2
      templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web/MyProjectNameWebModule.cs
  71. 2
      templates/module/aspnet-core/host/MyCompanyName.MyProjectName.AuthServer/MyProjectNameAuthServerModule.cs
  72. 2
      templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Blazor.Server.Host/MyProjectNameBlazorHostModule.cs
  73. 2
      templates/module/aspnet-core/host/MyCompanyName.MyProjectName.HttpApi.Host/MyProjectNameHttpApiHostModule.cs
  74. 2
      templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Host/MyProjectNameWebHostModule.cs
  75. 2
      templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/MyProjectNameWebUnifiedModule.cs

2
Directory.Packages.props

@ -168,7 +168,7 @@
<PackageVersion Include="Slugify.Core" Version="5.1.1" />
<PackageVersion Include="Spectre.Console" Version="0.51.1" />
<PackageVersion Include="StackExchange.Redis" Version="2.9.17" />
<PackageVersion Include="Swashbuckle.AspNetCore" Version="9.0.4" />
<PackageVersion Include="Swashbuckle.AspNetCore" Version="10.0.1" />
<PackageVersion Include="System.Collections.Immutable" Version="10.0.0" />
<PackageVersion Include="System.ComponentModel.Annotations" Version="5.0.0" />
<PackageVersion Include="System.Linq.Dynamic.Core" Version="1.6.7" />

9
abp_io/AbpIoLocalization/AbpIoLocalization/Www/Localization/Resources/en.json

@ -1553,6 +1553,15 @@
"IntegrateToYourKubernetesCluster_Description1": "<span class=\"text-highlight-white\">Connect your local development environment to a local or remote Kubernetes cluster</span>, where that cluster already runs your microservice solution.",
"IntegrateToYourKubernetesCluster_Description2": "Access any service in Kubernetes with their service name as DNS, just like they are running in your local computer.",
"IntegrateToYourKubernetesCluster_Description3": "<span class=\"text-highlight-white\">Intercept any service</span> in that cluster, so all the <span class=\"text-highlight-white\">traffic to the intercepted service is automatically redirected to your service </span>that is running in your local machine. When your service needs to use any service in Kubernetes, the traffic is redirected back to the cluster, just like your local service is running inside the Kubernetes.",
"AskOurAiAssistant": "Ask Our AI Assistant",
"AskOurAiAssistant_Description1": "Build faster with an AI that actually understands your ABP project. The ABP AI Assistant answers your technical questions, explains your code, and helps you solve problems directly inside ABP Studio — with full awareness of your project’s structure. You can even send screenshots or code files to get precise, context-based guidance.",
"AskOurAiAssistant_Description2": "What It Helps You Do",
"AskOurAiAssistant_Description3": "Ask anything about your ABP project — domain layer, modules, configuration, entities, services, or UI.",
"AskOurAiAssistant_Description4": "Get smart, code-aware explanations tailored to your solution.",
"AskOurAiAssistant_Description5": "Generate snippets and scaffolding suggestions instantly.",
"AskOurAiAssistant_Description6": "Fix errors faster with context-aware debugging support.",
"AskOurAiAssistant_Description7": "Learn ABP best practices as you build.",
"AskOurAiAssistant_Description8": "Whether you're generating new features, debugging an issue, or exploring a module, the AI Assistant gives you actionable, project-specific answers — right when you need them.",
"GetInformed": "Get Informed",
"Studio_GetInformed_Description1": "Leave your contact information to <span class=\"text-highlight-white\">get informed</span> and <span class=\"text-highlight-white\">try it first</span> when ABP Studio has been launched.",
"Studio_GetInformed_Description2": "Planned preview release date: Q3 of 2023.",

2
docs/en/Community-Articles/2025-11-15-Announcing-SSR-Support/article.md

@ -33,7 +33,7 @@ You can easily add SSR support to your existing ABP Angular application using th
# Generate SSR configuration for your project
ng generate @abp/ng.schematics:ssr-add
# Or using the short form
# Alternatively, you can use the short form
ng g @abp/ng.schematics:ssr-add
```

14
docs/en/cli/index.md

@ -7,11 +7,7 @@
# ABP CLI
ABP CLI (Command Line Interface) is a command line tool to perform some common operations for ABP based solutions or ABP Studio features.
> With **v8.2+**, the old/legacy ABP CLI has been replaced with a new CLI system to align with the new templating system and [ABP Studio](../studio/index.md). The new ABP CLI commands are explained in this documentation. However, if you want to learn more about the differences between the old and new CLIs, want to learn the reason for the change, or need guidance to use the old ABP CLI, please refer to the [Old vs New CLI](differences-between-old-and-new-cli.md) documentation.
>
> You may need to remove the Old CLI before installing the New CLI, by running the following command: `dotnet tool uninstall -g Volo.Abp.Cli`
ABP CLI (Command Line Interface) is a command line tool to perform some common operations for ABP based solutions or [ABP Studio](../studio/index.md) features.
## Installation
@ -29,16 +25,16 @@ dotnet tool update -g Volo.Abp.Studio.Cli
## Global Options
While each command may have a set of options, there are some global options that can be used with any command;
While each command may have a set of options, there are some global options that can be used with any command:
* `--skip-cli-version-check` or `-scvc`: Skips to check the latest version of the ABP CLI. If you don't specify, it will check the latest version and shows a warning message if there is a newer version of the ABP CLI.
- `--skip-extension-version-check` or `-sevc`: Skips to check the latest version of the ABP CLI extensions. If you don't specify, it will check the latest version and download the latest version if there is a newer version of the ABP CLI extensions.
* `--skip-cli-version-check` or `-scvc`: Skips checking the latest version of the ABP CLI. If you don't specify, it will check the latest version and shows a warning message if there is a newer version of the ABP CLI.
- `--skip-extension-version-check` or `-sevc`: Skips checking the latest version of the ABP CLI extensions. If you don't specify, it will check the latest version and download the latest version if there is a newer version of the ABP CLI extensions.
* `--old`: ABP CLI has two variations: `Volo.Abp.Studio.Cli` and `Volo.Abp.Cli`. New features/templates are added to the `Volo.Abp.Studio.Cli`. But if you want to use the old version, you can use this option **at the end of your commands**. For example, `abp new Acme.BookStore --old`.
* `--help` or `-h`: Shows help for the specified command.
## Commands
Here, is the list of all available commands before explaining their details:
Here is the list of all available commands before explaining their details:
* **[`help`](../cli#help)**: Shows help on the usage of the ABP CLI.
* **[`cli`](../cli#cli)**: Update or remove ABP CLI.

4
docs/en/release-info/release-notes.md

@ -14,9 +14,9 @@ Also see the following notes about ABP releases:
* [ABP Studio release notes](../studio/release-notes.md)
* [Change logs for ABP pro packages](https://abp.io/pro-releases)
## 10.0 (2025-10-01)
## 10.0 (2025-11-18)
This is currently a RC (release-candidate) and you can see the detailed **[blog post / announcement](https://abp.io/community/announcements/announcing-abp-10-0-release-candidate-86lrnyox)** for the v10.0 release.
See the detailed **[blog post / announcement](https://abp.io/community/announcements/abp.io-platform-10.0-final-has-been-released-spknn925)** for the v10.0 release.
* Upgraded to .NET 10.0
* Upgraded to `Blazorise` **v1.8.6**

4
docs/en/tutorials/microservice/part-01.md

@ -25,7 +25,7 @@
}
````
Follow the *[Get Started](../../get-started/microservice.md)* guide to create a new layered web application with the following configurations:
Follow the *[Get Started](../../get-started/microservice.md)* guide to create a new microservice solution with the following configurations:
* **Solution name**: `CloudCrm`
{{if DB == "EF"}}
@ -82,4 +82,4 @@ You can see the *[Microservice Solution Template](../../solution-templates/micro
## Summary
In this part, you've created the initial microservice solution, which already contains a few infrastructure services. We will create our first business service in the [next part](part-02.md).
In this part, you've created the initial microservice solution, which already contains a few infrastructure services. We will create our first business service in the [next part](part-02.md).

2
framework/src/Volo.Abp.AspNetCore.Mvc.NewtonsoftJson/Volo/Abp/AspNetCore/Mvc/NewtonsoftJson/AbpAspNetCoreMvcNewtonsoftModule.cs

@ -13,7 +13,7 @@ public class AbpAspNetCoreMvcNewtonsoftModule : AbpModule
{
context.Services.AddMvcCore().AddNewtonsoftJson();
context.Services.AddOptions<MvcNewtonsoftJsonOptions>()
context.Services.AddAbpOptions<MvcNewtonsoftJsonOptions>()
.Configure<IServiceProvider>((options, rootServiceProvider) =>
{
options.SerializerSettings.ContractResolver =

2
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/AbpAspNetCoreMvcModule.cs

@ -165,7 +165,7 @@ public class AbpAspNetCoreMvcModule : AbpModule
context.Services.AddSingleton<ValidationAttributeAdapterProvider>();
context.Services.TryAddEnumerable(ServiceDescriptor.Transient<IActionDescriptorProvider, AbpMvcActionDescriptorProvider>());
context.Services.AddOptions<MvcOptions>()
context.Services.AddAbpOptions<MvcOptions>()
.Configure<IServiceProvider>((mvcOptions, serviceProvider) =>
{
mvcOptions.AddAbp(context.Services);

2
framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/Json/MvcCoreBuilderExtensions.cs

@ -13,7 +13,7 @@ public static class MvcCoreBuilderExtensions
{
public static IMvcCoreBuilder AddAbpJson(this IMvcCoreBuilder builder)
{
builder.Services.AddOptions<JsonOptions>()
builder.Services.AddAbpOptions<JsonOptions>()
.Configure<IServiceProvider>((options, rootServiceProvider) =>
{
options.JsonSerializerOptions.ReadCommentHandling = JsonCommentHandling.Skip;

10
framework/src/Volo.Abp.BlazoriseUI/Components/ObjectExtending/ExtensionProperties.razor.cs

@ -1,5 +1,6 @@
using System;
using System.Collections.Immutable;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components;
using Microsoft.Extensions.Localization;
@ -29,8 +30,13 @@ public partial class ExtensionProperties<TEntityType, TResourceType> : Component
public ImmutableList<ObjectExtensionPropertyInfo> Properties { get; set; } = ImmutableList<ObjectExtensionPropertyInfo>.Empty;
protected async override Task OnInitializedAsync()
protected override async Task OnInitializedAsync()
{
Properties = await ObjectExtensionManager.Instance.GetPropertiesAndCheckPolicyAsync<TEntityType>(ServiceProvider);
Properties =
(await ObjectExtensionManager.Instance.GetPropertiesAndCheckPolicyAsync<TEntityType>(ServiceProvider))
.Where(p => ModalType == ExtensionPropertyModalType.CreateModal
? p.UI.CreateModal.IsVisible
: p.UI.EditModal.IsVisible)
.ToImmutableList();
}
}

22
framework/src/Volo.Abp.Core/Microsoft/Extensions/DependencyInjection/ServiceCollectionOptionsExtensions.cs

@ -0,0 +1,22 @@
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Options;
using Volo.Abp.Options;
namespace Microsoft.Extensions.DependencyInjection;
public static class ServiceCollectionOptionsExtensions
{
/// <summary>
/// You should only use this method to register options if you need to continue using the ServiceProvider to get other options in your Options configuration method.
/// Otherwise, please use the default AddOptions method for better performance.
/// </summary>
/// <param name="services"></param>
/// <typeparam name="TOptions"></typeparam>
/// <returns></returns>
public static OptionsBuilder<TOptions> AddAbpOptions<TOptions>(this IServiceCollection services)
where TOptions : class
{
services.TryAddSingleton<IOptions<TOptions>, AbpUnnamedOptionsManager<TOptions>>();
return services.AddOptions<TOptions>();
}
}

9
framework/src/Volo.Abp.Core/Volo/Abp/AbpApplicationBase.cs

@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using JetBrains.Annotations;
using Microsoft.Extensions.Configuration;
@ -200,7 +201,13 @@ public abstract class AbpApplicationBase : IAbpApplication
using var scope = ServiceProvider.CreateScope();
var abpHostEnvironment = scope.ServiceProvider.GetRequiredService<IAbpHostEnvironment>();
var configuration = scope.ServiceProvider.GetRequiredService<IConfiguration>();
return abpHostEnvironment.IsDevelopment() && configuration.GetValue<bool?>("Abp:Telemetry:IsEnabled") != false;
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) || RuntimeInformation.IsOSPlatform(OSPlatform.OSX) || RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
return abpHostEnvironment.IsDevelopment() && configuration.GetValue<bool?>("Abp:Telemetry:IsEnabled") != false;
}
return false;
}
//TODO: We can extract a new class for this

5
framework/src/Volo.Abp.Core/Volo/Abp/Internal/Telemetry/Activity/Providers/TelemetrySolutionInfoEnricher.cs

@ -114,7 +114,10 @@ internal sealed class TelemetrySolutionInfoEnricher : TelemetryActivityEventEnri
}
var moduleJsonFileContent = File.ReadAllText(modulePath);
using var moduleDoc = JsonDocument.Parse(moduleJsonFileContent);
using var moduleDoc = JsonDocument.Parse(moduleJsonFileContent, new JsonDocumentOptions
{
AllowTrailingCommas = true
});
if (!moduleDoc.RootElement.TryGetProperty("imports", out var imports))
{

18
framework/src/Volo.Abp.Core/Volo/Abp/Internal/Telemetry/Activity/Storage/TelemetryActivityStorage.cs

@ -25,6 +25,8 @@ public class TelemetryActivityStorage : ITelemetryActivityStorage, ISingletonDep
public TelemetryActivityStorage()
{
CreateDirectoryIfNotExist();
DeleteExistingOldInformation();
State = LoadState();
}
@ -166,6 +168,22 @@ public class TelemetryActivityStorage : ITelemetryActivityStorage, ISingletonDep
}
}
private static void DeleteExistingOldInformation()
{
try
{
var file = new FileInfo(TelemetryPaths.ActivityStorage);
if (file.Exists && file.CreationTime < new DateTime(2025, 12, 01))
{
file.Delete();
}
}
catch
{
// Ignored
}
}
private static TelemetryActivityStorageState LoadState()
{
try

1
framework/src/Volo.Abp.Core/Volo/Abp/Internal/Telemetry/Constants/ActivityPropertyNames.cs

@ -12,6 +12,7 @@ public static class ActivityPropertyNames
public const string IpAddress = "IpAddress";
public const string IsFirstSession = "IsFirstSession";
public const string DeviceId = "DeviceId";
public const string UserDeviceId = "UserDeviceId";
public const string DeviceLanguage = "DeviceLanguage";
public const string OperatingSystem = "OperatingSystem";
public const string CountryIsoCode = "CountryIsoCode";

8
framework/src/Volo.Abp.Core/Volo/Abp/Internal/Telemetry/Constants/DeviceManager.cs

@ -133,7 +133,7 @@ static internal class DeviceManager
{
try
{
return GetProcessorIdForWindows();
return GetBaseBoardSerialNumberForWindows();
}
catch
{
@ -142,10 +142,10 @@ static internal class DeviceManager
return GetWindowsMachineUniqueId();
}
private static string GetProcessorIdForWindows()
private static string GetBaseBoardSerialNumberForWindows()
{
using (var managementObjectSearcher =
new System.Management.ManagementObjectSearcher("SELECT ProcessorId FROM Win32_Processor"))
new System.Management.ManagementObjectSearcher("SELECT SerialNumber FROM Win32_BaseBoard"))
{
using (var searcherObj = managementObjectSearcher.Get())
{
@ -156,7 +156,7 @@ static internal class DeviceManager
var managementObjectEnumerator = searcherObj.GetEnumerator();
managementObjectEnumerator.MoveNext();
return managementObjectEnumerator.Current.GetPropertyValue("ProcessorId").ToString()!;
return managementObjectEnumerator.Current.GetPropertyValue("SerialNumber").ToString()!;
}
}
}

10
framework/src/Volo.Abp.Core/Volo/Abp/Internal/Telemetry/EnvironmentInspection/Detectors/AbpStudioDetector.cs

@ -40,7 +40,10 @@ internal sealed class AbpStudioDetector : SoftwareDetector
return null;
}
using var fs = new FileStream(ideStateJsonPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
using var doc = JsonDocument.Parse(fs);
using var doc = JsonDocument.Parse(fs, new JsonDocumentOptions
{
AllowTrailingCommas = true
});
return doc.RootElement.TryGetProperty("theme", out var themeElement) ? themeElement.GetString() : null;
}
@ -55,7 +58,10 @@ internal sealed class AbpStudioDetector : SoftwareDetector
}
using var fs = new FileStream(extensionsFilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
using var doc = JsonDocument.Parse(fs);
using var doc = JsonDocument.Parse(fs, new JsonDocumentOptions
{
AllowTrailingCommas = true
});
if (doc.RootElement.TryGetProperty("Extensions", out var extensionsElement) &&
extensionsElement.ValueKind == JsonValueKind.Array)

10
framework/src/Volo.Abp.Core/Volo/Abp/Internal/Telemetry/EnvironmentInspection/Detectors/VisualStudioCodeDetector.cs

@ -77,7 +77,10 @@ internal sealed class VisualStudioCodeDetector : SoftwareDetector
{
try
{
using var jsonDoc = JsonDocument.Parse(File.ReadAllText(productJson));
using var jsonDoc = JsonDocument.Parse(File.ReadAllText(productJson), new JsonDocumentOptions
{
AllowTrailingCommas = true
});
var root = jsonDoc.RootElement;
if (root.TryGetProperty("version", out var versionProp))
{
@ -105,7 +108,10 @@ internal sealed class VisualStudioCodeDetector : SoftwareDetector
{
try
{
using var json = JsonDocument.Parse( File.ReadAllText(settingsPath));
using var json = JsonDocument.Parse( File.ReadAllText(settingsPath), new JsonDocumentOptions
{
AllowTrailingCommas = true
});
var root = json.RootElement;
if (root.TryGetProperty("theme", out var themeProp))
{

6
framework/src/Volo.Abp.Core/Volo/Abp/Internal/Telemetry/Helpers/AbpPackageMetadataReader.cs

@ -49,11 +49,13 @@ static internal class AbpProjectMetadataReader
private static AbpProjectMetaData ReadOrCreateMetadata(string packagePath)
{
var fileContent = File.ReadAllText(packagePath);
var metadata = new AbpProjectMetaData();
using var document = JsonDocument.Parse(fileContent);
using var document = JsonDocument.Parse(fileContent, new JsonDocumentOptions
{
AllowTrailingCommas = true
});
var root = document.RootElement;
if (TryGetProjectId(root,out var projectId))

36
framework/src/Volo.Abp.Core/Volo/Abp/Internal/Telemetry/TelemetryService.cs

@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Internal.Telemetry.Activity.Contracts;
using Volo.Abp.Internal.Telemetry.Constants;
@ -11,17 +12,11 @@ namespace Volo.Abp.Internal.Telemetry;
public class TelemetryService : ITelemetryService, IScopedDependency
{
private readonly ITelemetryActivitySender _telemetryActivitySender;
private readonly ITelemetryActivityEventBuilder _telemetryActivityEventBuilder;
private readonly ITelemetryActivityStorage _telemetryActivityStorage;
private readonly IServiceScopeFactory _serviceScopeFactory;
public TelemetryService(ITelemetryActivitySender telemetryActivitySender,
ITelemetryActivityEventBuilder telemetryActivityEventBuilder,
ITelemetryActivityStorage telemetryActivityStorage)
public TelemetryService(IServiceScopeFactory serviceScopeFactory)
{
_telemetryActivitySender = telemetryActivitySender;
_telemetryActivityEventBuilder = telemetryActivityEventBuilder;
_telemetryActivityStorage = telemetryActivityStorage;
_serviceScopeFactory = serviceScopeFactory;
}
@ -74,24 +69,37 @@ public class TelemetryService : ITelemetryService, IScopedDependency
{
_ = Task.Run(async () =>
{
await BuildAndSendActivityAsync(context);
using var scope = _serviceScopeFactory.CreateScope();
var telemetryActivityEventBuilder = scope.ServiceProvider.GetRequiredService<ITelemetryActivityEventBuilder>();
var telemetryActivityStorage = scope.ServiceProvider.GetRequiredService<ITelemetryActivityStorage>();
var telemetryActivitySender = scope.ServiceProvider.GetRequiredService<ITelemetryActivitySender>();
await BuildAndSendActivityAsync(context,
telemetryActivityEventBuilder,
telemetryActivityStorage,
telemetryActivitySender);
});
return Task.CompletedTask;
}
private async Task BuildAndSendActivityAsync(ActivityContext context)
private static async Task BuildAndSendActivityAsync(
ActivityContext context,
ITelemetryActivityEventBuilder telemetryActivityEventBuilder,
ITelemetryActivityStorage telemetryActivityStorage,
ITelemetryActivitySender telemetryActivitySender)
{
try
{
var activityEvent = await _telemetryActivityEventBuilder.BuildAsync(context);
var activityEvent = await telemetryActivityEventBuilder.BuildAsync(context);
if (activityEvent is null)
{
return;
}
_telemetryActivityStorage.SaveActivity(activityEvent);
await _telemetryActivitySender.TrySendQueuedActivitiesAsync();
telemetryActivityStorage.SaveActivity(activityEvent);
await telemetryActivitySender.TrySendQueuedActivitiesAsync();
}
catch
{

34
framework/src/Volo.Abp.Core/Volo/Abp/Options/AbpUnnamedOptionsManager.cs

@ -0,0 +1,34 @@
using Microsoft.Extensions.Options;
namespace Volo.Abp.Options;
/// <summary>
/// This Options manager is similar to Microsoft UnnamedOptionsManager but without the locking mechanism.
/// Prevent deadlocks when accessing options in multiple threads.
/// </summary>
/// <typeparam name="TOptions"></typeparam>
public class AbpUnnamedOptionsManager<TOptions> : IOptions<TOptions>
where TOptions : class
{
private readonly IOptionsFactory<TOptions> _factory;
private TOptions? _value;
public AbpUnnamedOptionsManager(IOptionsFactory<TOptions> factory)
{
_factory = factory;
}
public TOptions Value
{
get
{
if (_value is { } value)
{
return value;
}
_value = _factory.Create(Microsoft.Extensions.Options.Options.DefaultName);
return _value;
}
}
}

2
framework/src/Volo.Abp.Json.Newtonsoft/Volo/Abp/Json/Newtonsoft/AbpJsonNewtonsoftModule.cs

@ -10,7 +10,7 @@ public class AbpJsonNewtonsoftModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddOptions<AbpNewtonsoftJsonSerializerOptions>()
context.Services.AddAbpOptions<AbpNewtonsoftJsonSerializerOptions>()
.Configure<IServiceProvider>((options, rootServiceProvider) =>
{
options.JsonSerializerSettings.ContractResolver = new AbpCamelCasePropertyNamesContractResolver(

2
framework/src/Volo.Abp.Json.SystemTextJson/Volo/Abp/Json/SystemTextJson/AbpJsonSystemTextJsonModule.cs

@ -15,7 +15,7 @@ public class AbpJsonSystemTextJsonModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddOptions<AbpSystemTextJsonSerializerOptions>()
context.Services.AddAbpOptions<AbpSystemTextJsonSerializerOptions>()
.Configure<IServiceProvider>((options, rootServiceProvider) =>
{
// If the user hasn't explicitly configured the encoder, use the less strict encoder that does not encode all non-ASCII characters.

5
framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/Modularity/ExtensionPropertyUiFormConfiguration.cs

@ -6,4 +6,9 @@ public class ExtensionPropertyUiFormConfiguration
/// Default: true.
/// </summary>
public bool IsVisible { get; set; } = true;
/// <summary>
/// Default: false.
/// </summary>
public bool IsReadOnly { get; set; } = false;
}

4
framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/Modularity/ModuleExtensionConfigurationHelper.cs

@ -175,6 +175,10 @@ public static class ModuleExtensionConfigurationHelper
property.DefaultValueFactory = propertyConfig.DefaultValueFactory;
property.Lookup = propertyConfig.UI.Lookup;
property.UI.Order = propertyConfig.UI.Order;
property.UI.CreateModal.IsVisible = propertyConfig.UI.OnCreateForm.IsVisible;
property.UI.CreateModal.IsReadOnly = propertyConfig.UI.OnCreateForm.IsReadOnly;
property.UI.EditModal.IsVisible = propertyConfig.UI.OnEditForm.IsVisible;
property.UI.EditModal.IsReadOnly = propertyConfig.UI.OnEditForm.IsReadOnly;
property.Policy = propertyConfig.Policy;
foreach (var configuration in propertyConfig.Configuration)
{

18
framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionPropertyInfo.cs

@ -90,16 +90,34 @@ public class ObjectExtensionPropertyInfo : IHasNameWithLocalizableDisplayName, I
{
public int Order { get; set; }
public ExtensionPropertyUICreateModal CreateModal { get; set; }
public ExtensionPropertyUIEditModal EditModal { get; set; }
public ExtensionPropertyUI()
{
CreateModal = new ExtensionPropertyUICreateModal();
EditModal = new ExtensionPropertyUIEditModal();
}
}
public class ExtensionPropertyUICreateModal
{
/// <summary>
/// Default: true.
/// </summary>
public bool IsVisible { get; set; } = true;
public bool IsReadOnly { get; set; }
}
public class ExtensionPropertyUIEditModal
{
/// <summary>
/// Default: true.
/// </summary>
public bool IsVisible { get; set; } = true;
public bool IsReadOnly { get; set; }
}
}

39
framework/src/Volo.Abp.Swashbuckle/Microsoft/Extensions/DependencyInjection/AbpSwaggerGenServiceCollectionExtensions.cs

@ -1,7 +1,7 @@
using System;
using System.Collections.Generic;
using JetBrains.Annotations;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi;
using Swashbuckle.AspNetCore.SwaggerGen;
using Swashbuckle.AspNetCore.SwaggerUI;
using Volo.Abp.Content;
@ -21,7 +21,7 @@ public static class AbpSwaggerGenServiceCollectionExtensions
{
Func<OpenApiSchema> remoteStreamContentSchemaFactory = () => new OpenApiSchema()
{
Type = "string",
Type = JsonSchemaType.String,
Format = "binary"
};
@ -42,7 +42,7 @@ public static class AbpSwaggerGenServiceCollectionExtensions
{
var authorizationUrl = new Uri($"{authority.TrimEnd('/')}{authorizationEndpoint.EnsureStartsWith('/')}");
var tokenUrl = new Uri($"{authority.TrimEnd('/')}{tokenEndpoint.EnsureStartsWith('/')}");
return services
.AddAbpSwaggerGen()
.AddSwaggerGen(
@ -62,19 +62,9 @@ public static class AbpSwaggerGenServiceCollectionExtensions
}
});
options.AddSecurityRequirement(new OpenApiSecurityRequirement
options.AddSecurityRequirement(document => new OpenApiSecurityRequirement()
{
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference
{
Type = ReferenceType.SecurityScheme,
Id = "oauth2"
}
},
Array.Empty<string>()
}
[new OpenApiSecuritySchemeReference("oauth2", document)] = []
});
setupAction?.Invoke(options);
@ -100,7 +90,7 @@ public static class AbpSwaggerGenServiceCollectionExtensions
swaggerUiOptions.ConfigObject.AdditionalItems["oidcSupportedScopes"] = scopes;
swaggerUiOptions.ConfigObject.AdditionalItems["oidcDiscoveryEndpoint"] = discoveryUrl;
});
return services
.AddAbpSwaggerGen()
.AddSwaggerGen(
@ -112,24 +102,15 @@ public static class AbpSwaggerGenServiceCollectionExtensions
OpenIdConnectUrl = new Uri(RemoveTenantPlaceholders(discoveryUrl))
});
options.AddSecurityRequirement(new OpenApiSecurityRequirement
options.AddSecurityRequirement(document => new OpenApiSecurityRequirement()
{
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference
{
Type = ReferenceType.SecurityScheme,
Id = "oidc"
}
},
Array.Empty<string>()
}
[new OpenApiSecuritySchemeReference("oauth2", document)] = []
});
setupAction?.Invoke(options);
});
}
private static string RemoveTenantPlaceholders(string url)
{
return url

20
framework/src/Volo.Abp.Swashbuckle/Volo/Abp/Swashbuckle/AbpSwashbuckleDocumentFilter.cs

@ -3,7 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi;
using Swashbuckle.AspNetCore.SwaggerGen;
namespace Volo.Abp.Swashbuckle;
@ -13,7 +13,7 @@ public class AbpSwashbuckleDocumentFilter : IDocumentFilter
protected virtual string[] ActionUrlPrefixes { get; set; } = new[] { "Volo." };
protected virtual string RegexConstraintPattern => @":regex\(([^()]*)\)";
public virtual void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context)
{
var actionUrls = context.ApiDescriptions
@ -28,6 +28,20 @@ public class AbpSwashbuckleDocumentFilter : IDocumentFilter
swaggerDoc
.Paths
.RemoveAll(path => !actionUrls.Contains(path.Key));
var tags = new List<string>();
foreach (var path in swaggerDoc.Paths)
{
if (path.Value.Operations != null)
{
tags.AddRange(path.Value.Operations.SelectMany(x =>
{
return x.Value.Tags?.Select(t => t.Name ?? string.Empty) ?? Array.Empty<string>();
}));
}
}
tags = tags.Distinct().ToList();
swaggerDoc.Tags?.RemoveAll(tag => tag.Name == null || !tags.Contains(tag.Name));
}
protected virtual string? RemoveRouteParameterConstraints(ActionDescriptor actionDescriptor)
@ -49,7 +63,7 @@ public class AbpSwashbuckleDocumentFilter : IDocumentFilter
{
break;
}
route = route.Remove(startIndex, (endIndex - startIndex));
}

18
framework/src/Volo.Abp.Swashbuckle/Volo/Abp/Swashbuckle/AbpSwashbuckleEnumSchemaFilter.cs

@ -1,22 +1,22 @@
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Models;
using System;
using System.Text.Json.Nodes;
using Microsoft.OpenApi;
using Swashbuckle.AspNetCore.SwaggerGen;
using System;
namespace Volo.Abp.Swashbuckle;
public class AbpSwashbuckleEnumSchemaFilter : ISchemaFilter
{
public void Apply(OpenApiSchema schema, SchemaFilterContext context)
public void Apply(IOpenApiSchema schema, SchemaFilterContext context)
{
if (context.Type.IsEnum)
if (schema is OpenApiSchema openApiScheme && context.Type.IsEnum)
{
schema.Enum.Clear();
schema.Type = "string";
schema.Format = null;
openApiScheme.Enum?.Clear();
openApiScheme.Type = JsonSchemaType.String;
openApiScheme.Format = null;
foreach (var name in Enum.GetNames(context.Type))
{
schema.Enum.Add(new OpenApiString($"{name}"));
openApiScheme.Enum?.Add(JsonNode.Parse($"\"{name}\"")!);
}
}
}

4
framework/test/Volo.Abp.Json.Tests/Volo/Abp/Json/AbpJsonTestModule.cs

@ -19,7 +19,7 @@ public class AbpJsonSystemTextJsonTestModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddOptions<AbpSystemTextJsonSerializerOptions>()
context.Services.AddAbpOptions<AbpSystemTextJsonSerializerOptions>()
.Configure<IServiceProvider>((options, rootServiceProvider) =>
{
if (options.JsonSerializerOptions.TypeInfoResolver != null)
@ -43,7 +43,7 @@ public class AbpJsonNewtonsoftTestModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddOptions<AbpNewtonsoftJsonSerializerOptions>()
context.Services.AddAbpOptions<AbpNewtonsoftJsonSerializerOptions>()
.Configure<IServiceProvider>((options, rootServiceProvider) =>
{
options.JsonSerializerSettings.ContractResolver = new AbpCamelCasePropertyNamesContractResolver(

2
framework/test/Volo.Abp.MemoryDb.Tests/Volo/Abp/MemoryDb/AbpMemoryDbTestModule.cs

@ -34,7 +34,7 @@ public class AbpMemoryDbTestModule : AbpModule
options.AddRepository<City, CityRepository>();
});
context.Services.AddOptions<Utf8JsonMemoryDbSerializerOptions>()
context.Services.AddAbpOptions<Utf8JsonMemoryDbSerializerOptions>()
.Configure<IServiceProvider>((options, rootServiceProvider) =>
{
options.JsonSerializerOptions.Converters.Add(new EntityJsonConverter<EntityWithIntPk, int>());

2
modules/blogging/app/Volo.BloggingTestApp/BloggingTestAppModule.cs

@ -11,7 +11,7 @@ using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Options;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi;
using Swashbuckle.AspNetCore.Swagger;
using Volo.Abp;
using Volo.Abp.Account;

2
modules/cms-kit/host/Volo.CmsKit.HttpApi.Host/CmsKitHttpApiHostModule.cs

@ -13,7 +13,7 @@ using Microsoft.Extensions.Hosting;
using Volo.CmsKit.EntityFrameworkCore;
using Volo.CmsKit.MultiTenancy;
using StackExchange.Redis;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi;
using Swashbuckle.AspNetCore.Swagger;
using Volo.Abp;
using Volo.Abp.AspNetCore.MultiTenancy;

2
modules/cms-kit/host/Volo.CmsKit.IdentityServer/CmsKitIdentityServerModule.cs

@ -8,7 +8,7 @@ using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Volo.CmsKit.MultiTenancy;
using StackExchange.Redis;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi;
using Swashbuckle.AspNetCore.Swagger;
using Volo.Abp;
using Volo.Abp.Account;

2
modules/cms-kit/host/Volo.CmsKit.Web.Host/CmsKitWebHostModule.cs

@ -2,7 +2,7 @@ using System;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi;
using System.IO;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.DataProtection;

2
modules/cms-kit/host/Volo.CmsKit.Web.Unified/CmsKitWebUnifiedModule.cs

@ -3,7 +3,7 @@ using System.IO;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi;
using Volo.Abp;
using Volo.Abp.Account;
using Volo.Abp.Account.Web;

2
modules/docs/app/VoloDocs.Web/VoloDocsWebModule.cs

@ -2,7 +2,7 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi;
using Swashbuckle.AspNetCore.Swagger;
using Volo.Abp;
using Volo.Abp.Account.Web;

13
modules/docs/src/Volo.Docs.Admin.Web/Pages/Docs/Admin/Documents/Index.cshtml

@ -29,7 +29,7 @@
<div id="DocumentsContainer">
<abp-card>
<abp-card-header>
<abp-card-body>
<form autocomplete="off" id="FilterForm">
<abp-row>
@ -86,7 +86,7 @@
</div>
</abp-column>
<abp-column size="Auto">
<abp-button button-type="Primary" icon="search" id="SearchButton" style="line-height: 25px;" text="@L["Search"].Value"></abp-button>
<abp-button button-type="Primary" icon="search" id="SearchButton" text="@L["Search"].Value"></abp-button>
</abp-column>
<abp-row class="mt-3 mb-3">
<abp-column size-md="_12">
@ -149,7 +149,7 @@
</div>
</abp-column>
<abp-column size="_2">
<abp-column size="_3">
<div class="input-group mb-2">
<div class="input-group-text">@L["Format"].Value</div>
@ -161,9 +161,6 @@
</div>
</abp-column>
<abp-column size="_2">
</abp-column>
<abp-column size="Auto">
<div class="input-group mb-2">
<div class="input-group-text">@L["LastSignificantUpdateTime"].Value</div>
@ -185,7 +182,9 @@
</abp-row>
</abp-row>
</form>
</abp-card-header>
</abp-card-body>
</abp-card>
<abp-card>
<abp-card-body>
<abp-table id="DocumentsTable" class="nowrap">
<thead>

2
modules/identity/src/Volo.Abp.Identity.AspNetCore/Volo/Abp/Identity/AspNetCore/AbpIdentityAspNetCoreModule.cs

@ -47,7 +47,7 @@ public class AbpIdentityAspNetCoreModule : AbpModule
public override void PostConfigureServices(ServiceConfigurationContext context)
{
context.Services.AddOptions<SecurityStampValidatorOptions>()
context.Services.AddAbpOptions<SecurityStampValidatorOptions>()
.Configure<IServiceProvider>((securityStampValidatorOptions, serviceProvider) =>
{
var abpRefreshingPrincipalOptions = serviceProvider.GetRequiredService<IOptions<AbpRefreshingPrincipalOptions>>().Value;

16
modules/openiddict/app/OpenIddict.Demo.API/Program.cs

@ -1,6 +1,6 @@
using Microsoft.AspNetCore.Authentication.JwtBearer;
using OpenIddict.Demo.API;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi;
using Swashbuckle.AspNetCore.SwaggerGen;
using Swashbuckle.AspNetCore.SwaggerUI;
@ -42,19 +42,9 @@ builder.Services.AddSwaggerGen(options =>
}
});
options.AddSecurityRequirement(new OpenApiSecurityRequirement
options.AddSecurityRequirement(document => new OpenApiSecurityRequirement()
{
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference
{
Type = ReferenceType.SecurityScheme,
Id = "oauth2"
}
},
Array.Empty<string>()
}
[new OpenApiSecuritySchemeReference("oauth2", document)] = []
});
});

2
modules/setting-management/app/Volo.Abp.SettingManagement.DemoApp/DemoAppModule.cs

@ -3,7 +3,7 @@ using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Hosting;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi;
using Volo.Abp.Account;
using Volo.Abp.Account.Web;
using Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic;

31
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<boolean> {
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean | UrlTree> {
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;
}),
);
};

17
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();
});
});

5
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.",

186
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 `<router-outlet></router-outlet>` 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**.

186
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 `<router-outlet></router-outlet>` 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**.

186
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 `<router-outlet></router-outlet>` 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**.

186
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 `<router-outlet></router-outlet>` 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**.

186
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 `<router-outlet></router-outlet>` 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**.

186
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 `<router-outlet></router-outlet>` 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**.

118
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<AiTool, string> = {
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);
}

12
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;
}

30
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": []
}

2
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' },
{

2
templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server.Mongo/MyProjectNameModule.cs

@ -3,7 +3,7 @@ using Blazorise.Icons.FontAwesome;
using Microsoft.AspNetCore.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Options;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi;
using MyCompanyName.MyProjectName.Blazor.Server.Mongo.Components;
using MyCompanyName.MyProjectName.Data;
using MyCompanyName.MyProjectName.Localization;

2
templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.Server/MyProjectNameModule.cs

@ -3,7 +3,7 @@ using Blazorise.Icons.FontAwesome;
using Microsoft.AspNetCore.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Options;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi;
using MyCompanyName.MyProjectName.Blazor.Server.Components;
using MyCompanyName.MyProjectName.Data;
using MyCompanyName.MyProjectName.Localization;

2
templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.WebAssembly/Server.Mongo/MyProjectNameHostModule.cs

@ -2,7 +2,7 @@
using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi;
using MyCompanyName.MyProjectName.Data;
using MyCompanyName.MyProjectName.Localization;
using MyCompanyName.MyProjectName.Components;

2
templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Blazor.WebAssembly/Server/MyProjectNameHostModule.cs

@ -2,7 +2,7 @@
using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi;
using MyCompanyName.MyProjectName.Data;
using MyCompanyName.MyProjectName.Localization;
using MyCompanyName.MyProjectName.Components;

2
templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host.Mongo/MyProjectNameModule.cs

@ -2,7 +2,7 @@
using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi;
using MyCompanyName.MyProjectName.Data;
using MyCompanyName.MyProjectName.Localization;
using OpenIddict.Validation.AspNetCore;

2
templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Host/MyProjectNameModule.cs

@ -2,7 +2,7 @@
using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi;
using MyCompanyName.MyProjectName.Data;
using MyCompanyName.MyProjectName.Localization;
using OpenIddict.Validation.AspNetCore;

2
templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc.Mongo/MyProjectNameModule.cs

@ -1,6 +1,6 @@
using Microsoft.AspNetCore.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi;
using MyCompanyName.MyProjectName.Data;
using MyCompanyName.MyProjectName.Localization;
using MyCompanyName.MyProjectName.Menus;

2
templates/app-nolayers/aspnet-core/MyCompanyName.MyProjectName.Mvc/MyProjectNameModule.cs

@ -1,6 +1,6 @@
using Microsoft.AspNetCore.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi;
using MyCompanyName.MyProjectName.Data;
using MyCompanyName.MyProjectName.Localization;
using MyCompanyName.MyProjectName.Menus;

2
templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor.Server.Tiered/MyProjectNameBlazorModule.cs

@ -14,7 +14,7 @@ using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi;
using MyCompanyName.MyProjectName.Blazor.Server.Tiered.Components;
using MyCompanyName.MyProjectName.Blazor.Server.Tiered.Menus;
using MyCompanyName.MyProjectName.Localization;

2
templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor.Server/MyProjectNameBlazorModule.cs

@ -9,7 +9,7 @@ using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Options;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi;
using MyCompanyName.MyProjectName.Blazor.Server.Components;
using MyCompanyName.MyProjectName.Blazor.Server.Menus;
using MyCompanyName.MyProjectName.EntityFrameworkCore;

2
templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor.WebApp.Tiered/MyProjectNameBlazorModule.cs

@ -14,7 +14,7 @@ using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi;
using MyCompanyName.MyProjectName.Blazor.WebApp.Tiered.Client;
using MyCompanyName.MyProjectName.Blazor.WebApp.Tiered.Client.Menus;
using MyCompanyName.MyProjectName.Blazor.WebApp.Tiered.Components;

2
templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Blazor.WebApp/MyProjectNameBlazorModule.cs

@ -9,7 +9,7 @@ using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Options;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi;
using MyCompanyName.MyProjectName.Blazor.WebApp.Client;
using MyCompanyName.MyProjectName.Blazor.WebApp.Client.Menus;
using MyCompanyName.MyProjectName.Blazor.WebApp.Components;

2
templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.Host/MyProjectNameHttpApiHostModule.cs

@ -15,7 +15,7 @@ using Microsoft.Extensions.Hosting;
using MyCompanyName.MyProjectName.EntityFrameworkCore;
using MyCompanyName.MyProjectName.MultiTenancy;
using StackExchange.Redis;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi;
using Volo.Abp;
using Volo.Abp.AspNetCore.Authentication.JwtBearer;
using Volo.Abp.AspNetCore.Mvc;

2
templates/app/aspnet-core/src/MyCompanyName.MyProjectName.HttpApi.HostWithIds/MyProjectNameHttpApiHostModule.cs

@ -12,7 +12,7 @@ using MyCompanyName.MyProjectName.EntityFrameworkCore;
using MyCompanyName.MyProjectName.MultiTenancy;
using Volo.Abp.AspNetCore.Mvc.UI.Theme.LeptonXLite;
using Volo.Abp.AspNetCore.Mvc.UI.Theme.LeptonXLite.Bundling;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi;
using OpenIddict.Validation.AspNetCore;
using Volo.Abp;
using Volo.Abp.Account;

2
templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web.Host/MyProjectNameWebModule.cs

@ -14,7 +14,7 @@ using MyCompanyName.MyProjectName.Localization;
using MyCompanyName.MyProjectName.MultiTenancy;
using MyCompanyName.MyProjectName.Web.Menus;
using StackExchange.Redis;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi;
using Volo.Abp;
using Volo.Abp.AspNetCore.Authentication.OpenIdConnect;
using Volo.Abp.AspNetCore.Mvc.Client;

2
templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Web/MyProjectNameWebModule.cs

@ -10,7 +10,7 @@ using MyCompanyName.MyProjectName.EntityFrameworkCore;
using MyCompanyName.MyProjectName.Localization;
using MyCompanyName.MyProjectName.MultiTenancy;
using MyCompanyName.MyProjectName.Web.Menus;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi;
using OpenIddict.Validation.AspNetCore;
using Volo.Abp;
using Volo.Abp.Account.Web;

2
templates/module/aspnet-core/host/MyCompanyName.MyProjectName.AuthServer/MyProjectNameAuthServerModule.cs

@ -10,7 +10,7 @@ using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Hosting;
using MyCompanyName.MyProjectName.MultiTenancy;
using StackExchange.Redis;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi;
using OpenIddict.Validation.AspNetCore;
using Volo.Abp;
using Volo.Abp.Account;

2
templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Blazor.Server.Host/MyProjectNameBlazorHostModule.cs

@ -9,7 +9,7 @@ using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Options;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi;
using MyCompanyName.MyProjectName.Blazor.Server.Host.Components;
using MyCompanyName.MyProjectName.Blazor.Server.Host.Menus;
using MyCompanyName.MyProjectName.EntityFrameworkCore;

2
templates/module/aspnet-core/host/MyCompanyName.MyProjectName.HttpApi.Host/MyProjectNameHttpApiHostModule.cs

@ -13,7 +13,7 @@ using Microsoft.Extensions.Hosting;
using MyCompanyName.MyProjectName.EntityFrameworkCore;
using MyCompanyName.MyProjectName.MultiTenancy;
using StackExchange.Redis;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi;
using Volo.Abp;
using Volo.Abp.AspNetCore.Authentication.JwtBearer;
using Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy;

2
templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Host/MyProjectNameWebHostModule.cs

@ -2,7 +2,7 @@ using System;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi;
using System.IO;
using System.Reflection;
using System.Threading.Tasks;

2
templates/module/aspnet-core/host/MyCompanyName.MyProjectName.Web.Unified/MyProjectNameWebUnifiedModule.cs

@ -8,7 +8,7 @@ using Microsoft.Extensions.Hosting;
using MyCompanyName.MyProjectName.EntityFrameworkCore;
using MyCompanyName.MyProjectName.MultiTenancy;
using MyCompanyName.MyProjectName.Web;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi;
using Swashbuckle.AspNetCore.Swagger;
using Volo.Abp;
using Volo.Abp.Account;

Loading…
Cancel
Save