From fe694c3e59f96892ace825dce1afdd2fc1343ce1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C4=B0smail=20=C3=87A=C4=9EDA=C5=9E?= Date: Wed, 7 Jan 2026 08:39:10 +0300 Subject: [PATCH 1/4] First version of .cursorrules file added --- .cursorrules | 206 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 206 insertions(+) create mode 100644 .cursorrules diff --git a/.cursorrules b/.cursorrules new file mode 100644 index 0000000000..5f583f4e01 --- /dev/null +++ b/.cursorrules @@ -0,0 +1,206 @@ +# ABP Framework – Cursor Rules +# Scope: ABP Framework repository (abpframework/abp). Apply to framework + module development. +# Goal: Enforce ABP module architecture best practices (DDD, layering, DB/ORM independence) +# and align contributions with the ABP contribution guide. + +## Global Defaults +- Follow existing patterns in this repository first. Before generating new code, search for similar implementations and mirror their structure, naming, and conventions. +- Prefer minimal, focused diffs. Avoid drive-by refactors and formatting churn. +- Preserve public APIs. Avoid breaking changes unless explicitly requested and justified. +- Keep layers clean. Do not introduce forbidden dependencies between packages. + +## Module / Package Architecture (Layering) +- Use a layered module structure with explicit dependencies: + - *.Domain.Shared: constants, enums, shared types safe for all layers and 3rd-party clients. MUST NOT contain entities, repositories, domain services, or business objects. + - *.Domain: entities/aggregate roots, repository interfaces, domain services. + - *.Application.Contracts: application service interfaces and DTOs. + - *.Application: application service implementations. + - *.EntityFrameworkCore / *.MongoDb: ORM integration packages depend on *.Domain only. MUST NOT depend on other layers. + - *.HttpApi: REST controllers. MUST depend ONLY on *.Application.Contracts (NOT *.Application). + - *.HttpApi.Client: remote client proxies. MUST depend ONLY on *.Application.Contracts. + - *.Web: UI. MUST depend ONLY on *.HttpApi. +- Enforce dependency direction: + - Web -> HttpApi -> Application.Contracts + - Application -> Domain + Application.Contracts + - Domain -> Domain.Shared + - ORM integration -> Domain +- Do not leak web concerns into application/domain. + +## Domain Layer – Entities & Aggregate Roots +- Define entities in the domain layer. +- Entities must be valid at creation: + - Provide a primary constructor that enforces invariants. + - Always include a protected parameterless constructor for ORMs. + - Always initialize sub-collections in the primary constructor. + - Do NOT generate Guid keys inside constructors; accept `id` and generate using `IGuidGenerator` from the calling code. +- Make members `virtual` where appropriate (ORM/proxy compatibility). +- Protect consistency: + - Use non-public setters (private/protected/internal) when needed. + - Provide meaningful domain methods for state transitions; prefer returning `this` from setters when applicable. +- Aggregate roots: + - Always use a single `Id` property. Do NOT use composite keys. + - Prefer `Guid` keys for aggregate roots. + - Inherit from `AggregateRoot` or audited base classes as required. +- Aggregate boundaries: + - Keep aggregates small. Avoid large sub-collections unless necessary. +- References: + - Reference other aggregate roots by Id only. + - Do NOT add navigation properties to other aggregate roots. + +## Repositories +- Define repository interfaces in the domain layer. +- Create one dedicated repository interface per aggregate root (e.g., `IProductRepository`). +- Application code MUST NOT use generic repositories (e.g., `IRepository`). +- Repository interfaces MUST NOT expose `IQueryable` to application/domain layers: + - Prefer inheriting from `IBasicRepository` (or `IReadOnlyRepository<...>` when suitable). + - Do NOT inherit from `IRepository`. +- Do NOT define repositories for non-aggregate-root entities. +- Repository method conventions: + - All methods async. + - Include optional `CancellationToken cancellationToken = default` in every method. + - For single-entity returning methods: include `bool includeDetails = true`. + - For list returning methods: include `bool includeDetails = false`. + - Do NOT return composite projection classes like `UserWithRoles`. Use `includeDetails` for eager-loading. + - Avoid projection-only view models from repositories by default; only allow when performance is critical. + +## Domain Services +- Define domain services in the domain layer. +- Default: do NOT create interfaces for domain services unless necessary (mocking/multiple implementations). +- Naming: use `*Manager` suffix. +- Domain service methods: + - Do NOT define read-only “GET” methods. Querying belongs to repositories and application services. + - Define methods that mutate state and enforce domain rules. + - Use specific, intention-revealing names (avoid generic `UpdateXAsync`). + - Accept valid domain objects as parameters; do NOT accept/return DTOs. + - On rule violations, throw `BusinessException` (or custom business exceptions). + - Use unique, namespaced error codes suitable for localization (e.g., `IssueTracking:ConcurrentOpenIssueLimit`). + - Do NOT depend on authenticated user logic; pass required values from application layer. + +## Application Services (Contracts + Implementation) +### Contracts +- Define one interface per application service in *.Application.Contracts. +- Interfaces must inherit from `IApplicationService`. +- Naming: `I*AppService`. +- Do NOT accept/return entities. Use DTOs and primitive parameters. + +### Method Naming & Shapes +- All service methods async and end with `Async`. +- Do not repeat entity names in method names (use `GetAsync`, not `GetProductAsync`). +- Standard CRUD: + - `GetAsync(Guid id)` returns a detailed DTO. + - `GetListAsync(QueryDto queryDto)` returns a list of detailed DTOs. + - `CreateAsync(CreateDto dto)` returns detailed DTO. + - `UpdateAsync(Guid id, UpdateDto dto)` returns detailed DTO (id MUST NOT be inside update DTO). + - `DeleteAsync(Guid id)` returns void/Task. +- `GetListAsync` query DTO: + - Filtering/sorting/paging fields optional with defaults. + - Enforce a maximum page size for performance. + +### DTO Usage +- Inputs: + - Do not include unused properties. + - Do NOT share input DTOs between methods. + - Do NOT use inheritance between input DTOs (except rare abstract base DTO cases; be very cautious). + +### Implementation +- Application layer must be independent of web. +- Implement interfaces in *.Application, name `ProductAppService` for `IProductAppService`. +- Inherit from `ApplicationService`. +- Make all public methods `virtual`. +- Avoid private helper methods; prefer `protected virtual` helpers for extensibility. +- Data access: + - Use dedicated repositories (e.g., `IProductRepository`). + - Do NOT use generic repositories. + - Do NOT put LINQ/SQL queries inside application service methods; repositories perform queries. +- Entity mutation: + - Load required entities from repositories. + - Mutate using domain methods. + - Call repository `UpdateAsync` after updates (do not assume change tracking). +- Extra properties: + - Use `MapExtraPropertiesTo` or configure object mapper for `MapExtraProperties`. +- Files: + - Do NOT use web types like `IFormFile` or `Stream` in application services. + - Controllers handle upload; pass `byte[]` (or similar) to application services. +- Cross-application-service calls: + - Do NOT call other application services within the same module. + - For reuse, push logic into domain layer or extract shared helpers carefully. + - You MAY call other modules’ application services only via their Application.Contracts. + +## DTO Conventions +- Define DTOs in *.Application.Contracts. +- Prefer ABP base DTO types (`EntityDto`, audited DTOs). +- For aggregate roots, prefer extensible DTO base types so extra properties can map. +- DTO properties: public getters/setters. +- Input DTO validation: + - Use data annotations. + - Reuse constants from Domain.Shared wherever possible. +- Avoid logic in DTOs; only implement `IValidatableObject` when necessary. +- Mark DTOs `[Serializable]`. +- Output DTO strategy: + - Prefer a Basic DTO and a Detailed DTO; avoid many variants. + - Detailed DTOs: include reference details as nested basic DTOs; avoid duplicating raw FK ids unnecessarily. + +## EF Core Integration +- Define a separate DbContext interface + class per module. +- Do NOT rely on lazy loading; do NOT enable lazy loading. +- DbContext interface: + - Inherit from `IEfCoreDbContext`. + - Add `[ConnectionStringName("...")]`. + - Expose `DbSet` ONLY for aggregate roots. + - Do NOT include setters in the interface. +- DbContext class: + - Inherit `AbpDbContext`. + - Add `[ConnectionStringName("...")]` and implement the interface. +- Table prefix/schema: + - Provide static `TablePrefix` and `Schema` defaulted from constants. + - Use short prefixes; `Abp` prefix reserved for ABP core modules. + - Default schema should be `null`. +- Model mapping: + - Do NOT configure entities directly inside `OnModelCreating`. + - Create `ModelBuilder` extension method `ConfigureX()` and call it. + - Call `b.ConfigureByConvention()` for each entity. +- Repository implementations: + - Inherit from `EfCoreRepository`. + - Use DbContext interface as generic parameter. + - Pass cancellation tokens using `GetCancellationToken(cancellationToken)`. + - Implement `IncludeDetails(include)` extension per aggregate root with sub-collections. + - Override `WithDetailsAsync()` where needed. + +## MongoDB Integration +- Define a separate MongoDbContext interface + class per module. +- MongoDbContext interface: + - Inherit from `IAbpMongoDbContext`. + - Add `[ConnectionStringName("...")]`. + - Expose `IMongoCollection` ONLY for aggregate roots. +- MongoDbContext class: + - Inherit `AbpMongoDbContext` and implement the interface. +- Collection prefix: + - Provide static `CollectionPrefix` defaulted from constants. + - Use short prefixes; `Abp` prefix reserved for ABP core modules. +- Mapping: + - Do NOT configure directly inside `CreateModel`. + - Create `IMongoModelBuilder` extension method `ConfigureX()` and call it. +- Repository implementations: + - Inherit from `MongoDbRepository`. + - Pass cancellation tokens using `GetCancellationToken(cancellationToken)`. + - Ignore `includeDetails` for MongoDB in most cases (documents load sub-collections). + - Prefer `GetQueryableAsync()` to ensure ABP data filters are applied. + +## Contribution Discipline (PR / Issues / Tests) +- Before significant changes, align via GitHub issue/discussion. +- PRs: + - Keep changes scoped and reviewable. + - Add/update unit/integration tests relevant to the change. + - Build and run tests for the impacted area when possible. +- Localization: + - Prefer the `abp translate` workflow for adding missing translations (generate `abp-translation.json`, fill, apply, then PR). + +## Review Checklist +- Layer dependencies respected (no forbidden references). +- No `IQueryable` or generic repository usage leaking into application/domain. +- Entities maintain invariants; Guid id generation not inside constructors. +- Repositories follow async + CancellationToken + includeDetails conventions. +- No web types in application services. +- DTOs in contracts, serializable, validated, minimal, no logic. +- EF/Mongo integration follows context + mapping + repository patterns. +- Minimal diff; no unnecessary API surface expansion. From adab0ae387d2c3545729bc025043a1fc3d17e93e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C4=B0smail=20=C3=87A=C4=9EDA=C5=9E?= Date: Wed, 7 Jan 2026 09:45:01 +0300 Subject: [PATCH 2/4] added AI guidelines for ABP Framework itself for Cursor and Copilot --- .cursorrules | 82 ++++++- .github/copilot-instructions.md | 372 ++++++++++++++++++++++++++++++++ 2 files changed, 445 insertions(+), 9 deletions(-) create mode 100644 .github/copilot-instructions.md diff --git a/.cursorrules b/.cursorrules index 5f583f4e01..b88c4e1588 100644 --- a/.cursorrules +++ b/.cursorrules @@ -1,7 +1,7 @@ # ABP Framework – Cursor Rules -# Scope: ABP Framework repository (abpframework/abp). Apply to framework + module development. -# Goal: Enforce ABP module architecture best practices (DDD, layering, DB/ORM independence) -# and align contributions with the ABP contribution guide. +# Scope: ABP Framework repository (abpframework/abp) — for developing ABP itself, not ABP-based applications. +# Goal: Enforce ABP module architecture best practices (DDD, layering, DB/ORM independence), +# maintain backward compatibility, ensure extensibility, and align with ABP contribution guidelines. ## Global Defaults - Follow existing patterns in this repository first. Before generating new code, search for similar implementations and mirror their structure, naming, and conventions. @@ -50,10 +50,10 @@ ## Repositories - Define repository interfaces in the domain layer. - Create one dedicated repository interface per aggregate root (e.g., `IProductRepository`). -- Application code MUST NOT use generic repositories (e.g., `IRepository`). -- Repository interfaces MUST NOT expose `IQueryable` to application/domain layers: - - Prefer inheriting from `IBasicRepository` (or `IReadOnlyRepository<...>` when suitable). - - Do NOT inherit from `IRepository`. +- Public repository interfaces exposed by modules: + - SHOULD inherit from `IBasicRepository` (or `IReadOnlyRepository<...>` when suitable). + - SHOULD NOT expose `IQueryable` in the public contract. + - Internal implementations MAY use `IRepository` and `IQueryable` as needed. - Do NOT define repositories for non-aggregate-root entities. - Repository method conventions: - All methods async. @@ -68,7 +68,8 @@ - Default: do NOT create interfaces for domain services unless necessary (mocking/multiple implementations). - Naming: use `*Manager` suffix. - Domain service methods: - - Do NOT define read-only “GET” methods. Querying belongs to repositories and application services. + - Focus on operations that enforce domain invariants and business rules. + - Query methods are acceptable when they encapsulate domain-specific lookup logic (e.g., normalized lookups, caching, complex resolution). Simple queries belong in repositories. - Define methods that mutate state and enforce domain rules. - Use specific, intention-revealing names (avoid generic `UpdateXAsync`). - Accept valid domain objects as parameters; do NOT accept/return DTOs. @@ -135,7 +136,7 @@ - Use data annotations. - Reuse constants from Domain.Shared wherever possible. - Avoid logic in DTOs; only implement `IValidatableObject` when necessary. -- Mark DTOs `[Serializable]`. +- Do NOT use `[Serializable]` attribute (BinaryFormatter is obsolete); ABP uses JSON serialization. - Output DTO strategy: - Prefer a Basic DTO and a Detailed DTO; avoid many variants. - Detailed DTOs: include reference details as nested basic DTOs; avoid duplicating raw FK ids unnecessarily. @@ -186,6 +187,69 @@ - Ignore `includeDetails` for MongoDB in most cases (documents load sub-collections). - Prefer `GetQueryableAsync()` to ensure ABP data filters are applied. +## ABP Module Classes +- Every package must have exactly one `AbpModule` class. +- Naming: `Abp[ModuleName][Layer]Module` (e.g., `AbpIdentityDomainModule`, `AbpIdentityApplicationModule`). +- Use `[DependsOn(typeof(...))]` to declare module dependencies explicitly. +- Override `ConfigureServices` for DI registration and configuration. +- Override `OnApplicationInitialization` sparingly; prefer `ConfigureServices` when possible. +- Each module must be usable standalone; avoid hidden cross-module coupling. + +## Framework Extensibility +- All public and protected members should be `virtual` for inheritance-based extensibility. +- Prefer `protected virtual` over `private` for helper methods to allow overriding. +- Use `[Dependency(ReplaceServices = true)]` patterns for services intended to be replaceable. +- Provide extension points via interfaces and virtual methods. +- Document extension points with XML comments explaining intended usage. +- Consider providing `*Options` classes for configuration-based extensibility. + +## Backward Compatibility +- Do NOT remove or rename public API members without a deprecation cycle. +- Use `[Obsolete("Message. Use X instead.")]` with clear migration guidance before removal. +- Maintain binary and source compatibility within major versions. +- Add new optional parameters with defaults; do not change existing method signatures. +- When adding new abstract members to base classes, provide default implementations if possible. +- Prefer adding new interfaces over modifying existing ones. + +## Localization Resources +- Define localization resources in Domain.Shared. +- Resource class naming: `[ModuleName]Resource` (e.g., `IdentityResource`, `PermissionManagementResource`). +- JSON files under `/Localization/[ModuleName]/` directory. +- Use `LocalizableString.Create("Key")` for localizable exceptions and messages. +- All user-facing strings must be localized; no hardcoded English text in code. +- Error codes should be namespaced: `ModuleName:ErrorCode` (e.g., `Identity:UserNameAlreadyExists`). + +## Settings & Features +- Define settings in `*SettingDefinitionProvider` in Domain.Shared or Domain. +- Setting names must follow `Abp.[ModuleName].[SettingName]` convention. +- Define features in `*FeatureDefinitionProvider` in Domain.Shared. +- Feature names must follow `[ModuleName].[FeatureName]` convention. +- Use constants for setting/feature names; never hardcode strings. + +## Permissions +- Define permissions in `*PermissionDefinitionProvider` in Application.Contracts. +- Permission names must follow `[ModuleName].[Permission]` convention. +- Use constants for permission names (e.g., `IdentityPermissions.Users.Create`). +- Group related permissions logically. + +## Event Bus & Distributed Events +- Use `ILocalEventBus` for intra-module communication within the same process. +- Use `IDistributedEventBus` for cross-module or cross-service communication. +- Define Event Transfer Objects (ETOs) in Domain.Shared for distributed events. +- ETO naming: `[EntityName][Action]Eto` (e.g., `UserCreatedEto`, `OrderCompletedEto`). +- Event handlers belong in the Application layer. +- ETOs should be simple, serializable, and contain only primitive types or nested ETOs. + +## Testing +- Unit tests: `*.Tests` projects for isolated logic testing with mocked dependencies. +- Integration tests: `*.EntityFrameworkCore.Tests` / `*.MongoDB.Tests` for repository and DB tests. +- Use `AbpIntegratedTest` or `AbpApplicationTestBase` base classes. +- Test modules should use `[DependsOn]` on the module under test. +- Use `Shouldly` assertions (ABP convention). +- Test both EF Core and MongoDB implementations when the module supports both. +- Include tests for permission checks, validation, and edge cases. +- Name test methods: `MethodName_Scenario_ExpectedResult` or `Should_ExpectedBehavior_When_Condition`. + ## Contribution Discipline (PR / Issues / Tests) - Before significant changes, align via GitHub issue/discussion. - PRs: diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md new file mode 100644 index 0000000000..a754a2b5ea --- /dev/null +++ b/.github/copilot-instructions.md @@ -0,0 +1,372 @@ +# ABP Framework – GitHub Copilot Instructions + +> **Scope**: ABP Framework repository (abpframework/abp) — for developing ABP itself, not ABP-based applications. +> +> **Goal**: Enforce ABP module architecture best practices (DDD, layering, DB/ORM independence), maintain backward compatibility, ensure extensibility, and align with ABP contribution guidelines. + +--- + +## Global Defaults + +- Follow existing patterns in this repository first. Before generating new code, search for similar implementations and mirror their structure, naming, and conventions. +- Prefer minimal, focused diffs. Avoid drive-by refactors and formatting churn. +- Preserve public APIs. Avoid breaking changes unless explicitly requested and justified. +- Keep layers clean. Do not introduce forbidden dependencies between packages. + +--- + +## Module / Package Architecture (Layering) + +Use a layered module structure with explicit dependencies: + +| Layer | Purpose | Allowed Dependencies | +|-------|---------|---------------------| +| `*.Domain.Shared` | Constants, enums, shared types safe for all layers and 3rd-party clients. MUST NOT contain entities, repositories, domain services, or business objects. | None | +| `*.Domain` | Entities/aggregate roots, repository interfaces, domain services. | Domain.Shared | +| `*.Application.Contracts` | Application service interfaces and DTOs. | Domain.Shared | +| `*.Application` | Application service implementations. | Domain, Application.Contracts | +| `*.EntityFrameworkCore` / `*.MongoDb` | ORM integration packages. MUST NOT depend on other layers. | Domain only | +| `*.HttpApi` | REST controllers. MUST depend ONLY on Application.Contracts (NOT Application). | Application.Contracts | +| `*.HttpApi.Client` | Remote client proxies. MUST depend ONLY on Application.Contracts. | Application.Contracts | +| `*.Web` | UI layer. MUST depend ONLY on HttpApi. | HttpApi | + +### Dependency Direction +``` +Web -> HttpApi -> Application.Contracts +Application -> Domain + Application.Contracts +Domain -> Domain.Shared +ORM integration -> Domain +``` + +Do not leak web concerns into application/domain. + +--- + +## Domain Layer – Entities & Aggregate Roots + +- Define entities in the domain layer. +- Entities must be valid at creation: + - Provide a primary constructor that enforces invariants. + - Always include a `protected` parameterless constructor for ORMs. + - Always initialize sub-collections in the primary constructor. + - Do NOT generate Guid keys inside constructors; accept `id` and generate using `IGuidGenerator` from the calling code. +- Make members `virtual` where appropriate (ORM/proxy compatibility). +- Protect consistency: + - Use non-public setters (`private`/`protected`/`internal`) when needed. + - Provide meaningful domain methods for state transitions. + +### Aggregate Roots +- Always use a single `Id` property. Do NOT use composite keys. +- Prefer `Guid` keys for aggregate roots. +- Inherit from `AggregateRoot` or audited base classes as required. +- Keep aggregates small. Avoid large sub-collections unless necessary. + +### References +- Reference other aggregate roots by Id only. +- Do NOT add navigation properties to other aggregate roots. + +--- + +## Repositories + +- Define repository interfaces in the domain layer. +- Create one dedicated repository interface per aggregate root (e.g., `IProductRepository`). +- Public repository interfaces exposed by modules: + - SHOULD inherit from `IBasicRepository` (or `IReadOnlyRepository<...>` when suitable). + - SHOULD NOT expose `IQueryable` in the public contract. + - Internal implementations MAY use `IRepository` and `IQueryable` as needed. +- Do NOT define repositories for non-aggregate-root entities. + +### Method Conventions +- All methods async. +- Include optional `CancellationToken cancellationToken = default` in every method. +- For single-entity returning methods: include `bool includeDetails = true`. +- For list returning methods: include `bool includeDetails = false`. +- Do NOT return composite projection classes like `UserWithRoles`. Use `includeDetails` for eager-loading. +- Avoid projection-only view models from repositories by default; only allow when performance is critical. + +--- + +## Domain Services + +- Define domain services in the domain layer. +- Default: do NOT create interfaces for domain services unless necessary (mocking/multiple implementations). +- Naming: use `*Manager` suffix. + +### Method Guidelines +- Focus on operations that enforce domain invariants and business rules. +- Query methods are acceptable when they encapsulate domain-specific lookup logic (e.g., normalized lookups, caching, complex resolution). Simple queries belong in repositories. +- Define methods that mutate state and enforce domain rules. +- Use specific, intention-revealing names (avoid generic `UpdateXAsync`). +- Accept valid domain objects as parameters; do NOT accept/return DTOs. +- On rule violations, throw `BusinessException` (or custom business exceptions). +- Use unique, namespaced error codes suitable for localization (e.g., `IssueTracking:ConcurrentOpenIssueLimit`). +- Do NOT depend on authenticated user logic; pass required values from application layer. + +--- + +## Application Services + +### Contracts +- Define one interface per application service in `*.Application.Contracts`. +- Interfaces must inherit from `IApplicationService`. +- Naming: `I*AppService`. +- Do NOT accept/return entities. Use DTOs and primitive parameters. + +### Method Naming & Shapes +- All service methods async and end with `Async`. +- Do not repeat entity names in method names (use `GetAsync`, not `GetProductAsync`). + +**Standard CRUD:** +```csharp +Task GetAsync(Guid id); +Task> GetListAsync(GetProductListInput input); +Task CreateAsync(CreateProductInput input); +Task UpdateAsync(Guid id, UpdateProductInput input); // id NOT inside DTO +Task DeleteAsync(Guid id); +``` + +### DTO Usage (Inputs) +- Do not include unused properties. +- Do NOT share input DTOs between methods. +- Do NOT use inheritance between input DTOs (except rare abstract base DTO cases; be very cautious). + +### Implementation +- Application layer must be independent of web. +- Implement interfaces in `*.Application`, name `ProductAppService` for `IProductAppService`. +- Inherit from `ApplicationService`. +- Make all public methods `virtual`. +- Avoid private helper methods; prefer `protected virtual` helpers for extensibility. + +### Data Access +- Use dedicated repositories (e.g., `IProductRepository`). +- Do NOT put LINQ/SQL queries inside application service methods; repositories perform queries. + +### Entity Mutation +- Load required entities from repositories. +- Mutate using domain methods. +- Call repository `UpdateAsync` after updates (do not assume change tracking). + +### Files +- Do NOT use web types like `IFormFile` or `Stream` in application services. +- Controllers handle upload; pass `byte[]` (or similar) to application services. + +### Cross-Service Calls +- Do NOT call other application services within the same module. +- For reuse, push logic into domain layer or extract shared helpers carefully. +- You MAY call other modules' application services only via their Application.Contracts. + +--- + +## DTO Conventions + +- Define DTOs in `*.Application.Contracts`. +- Prefer ABP base DTO types (`EntityDto`, audited DTOs). +- For aggregate roots, prefer extensible DTO base types so extra properties can map. +- DTO properties: public getters/setters. + +### Input DTO Validation +- Use data annotations. +- Reuse constants from Domain.Shared wherever possible. + +### General Rules +- Avoid logic in DTOs; only implement `IValidatableObject` when necessary. +- Do NOT use `[Serializable]` attribute (BinaryFormatter is obsolete); ABP uses JSON serialization. + +### Output DTO Strategy +- Prefer a Basic DTO and a Detailed DTO; avoid many variants. +- Detailed DTOs: include reference details as nested basic DTOs; avoid duplicating raw FK ids unnecessarily. + +--- + +## EF Core Integration + +- Define a separate DbContext interface + class per module. +- Do NOT rely on lazy loading; do NOT enable lazy loading. + +### DbContext Interface +```csharp +[ConnectionStringName("ModuleName")] +public interface IModuleNameDbContext : IEfCoreDbContext +{ + DbSet Products { get; } // No setters, aggregate roots only +} +``` + +### DbContext Class +```csharp +[ConnectionStringName("ModuleName")] +public class ModuleNameDbContext : AbpDbContext, IModuleNameDbContext +{ + public static string TablePrefix { get; set; } = ModuleNameConsts.DefaultDbTablePrefix; + public static string? Schema { get; set; } = ModuleNameConsts.DefaultDbSchema; + + public DbSet Products { get; set; } +} +``` + +### Table Prefix/Schema +- Provide static `TablePrefix` and `Schema` defaulted from constants. +- Use short prefixes; `Abp` prefix reserved for ABP core modules. +- Default schema should be `null`. + +### Model Mapping +- Do NOT configure entities directly inside `OnModelCreating`. +- Create `ModelBuilder` extension method `ConfigureX()` and call it. +- Call `b.ConfigureByConvention()` for each entity. + +### Repository Implementations +- Inherit from `EfCoreRepository`. +- Use DbContext interface as generic parameter. +- Pass cancellation tokens using `GetCancellationToken(cancellationToken)`. +- Implement `IncludeDetails(include)` extension per aggregate root with sub-collections. +- Override `WithDetailsAsync()` where needed. + +--- + +## MongoDB Integration + +- Define a separate MongoDbContext interface + class per module. + +### MongoDbContext Interface +```csharp +[ConnectionStringName("ModuleName")] +public interface IModuleNameMongoDbContext : IAbpMongoDbContext +{ + IMongoCollection Products { get; } // Aggregate roots only +} +``` + +### MongoDbContext Class +```csharp +public class ModuleNameMongoDbContext : AbpMongoDbContext, IModuleNameMongoDbContext +{ + public static string CollectionPrefix { get; set; } = ModuleNameConsts.DefaultDbTablePrefix; +} +``` + +### Mapping +- Do NOT configure directly inside `CreateModel`. +- Create `IMongoModelBuilder` extension method `ConfigureX()` and call it. + +### Repository Implementations +- Inherit from `MongoDbRepository`. +- Pass cancellation tokens using `GetCancellationToken(cancellationToken)`. +- Ignore `includeDetails` for MongoDB in most cases (documents load sub-collections). +- Prefer `GetQueryableAsync()` to ensure ABP data filters are applied. + +--- + +## ABP Module Classes + +- Every package must have exactly one `AbpModule` class. +- Naming: `Abp[ModuleName][Layer]Module` (e.g., `AbpIdentityDomainModule`, `AbpIdentityApplicationModule`). +- Use `[DependsOn(typeof(...))]` to declare module dependencies explicitly. +- Override `ConfigureServices` for DI registration and configuration. +- Override `OnApplicationInitialization` sparingly; prefer `ConfigureServices` when possible. +- Each module must be usable standalone; avoid hidden cross-module coupling. + +--- + +## Framework Extensibility + +- All public and protected members should be `virtual` for inheritance-based extensibility. +- Prefer `protected virtual` over `private` for helper methods to allow overriding. +- Use `[Dependency(ReplaceServices = true)]` patterns for services intended to be replaceable. +- Provide extension points via interfaces and virtual methods. +- Document extension points with XML comments explaining intended usage. +- Consider providing `*Options` classes for configuration-based extensibility. + +--- + +## Backward Compatibility + +- Do NOT remove or rename public API members without a deprecation cycle. +- Use `[Obsolete("Message. Use X instead.")]` with clear migration guidance before removal. +- Maintain binary and source compatibility within major versions. +- Add new optional parameters with defaults; do not change existing method signatures. +- When adding new abstract members to base classes, provide default implementations if possible. +- Prefer adding new interfaces over modifying existing ones. + +--- + +## Localization Resources + +- Define localization resources in Domain.Shared. +- Resource class naming: `[ModuleName]Resource` (e.g., `IdentityResource`, `PermissionManagementResource`). +- JSON files under `/Localization/[ModuleName]/` directory. +- Use `LocalizableString.Create("Key")` for localizable exceptions and messages. +- All user-facing strings must be localized; no hardcoded English text in code. +- Error codes should be namespaced: `ModuleName:ErrorCode` (e.g., `Identity:UserNameAlreadyExists`). + +--- + +## Settings & Features + +- Define settings in `*SettingDefinitionProvider` in Domain.Shared or Domain. +- Setting names must follow `Abp.[ModuleName].[SettingName]` convention. +- Define features in `*FeatureDefinitionProvider` in Domain.Shared. +- Feature names must follow `[ModuleName].[FeatureName]` convention. +- Use constants for setting/feature names; never hardcode strings. + +--- + +## Permissions + +- Define permissions in `*PermissionDefinitionProvider` in Application.Contracts. +- Permission names must follow `[ModuleName].[Permission]` convention. +- Use constants for permission names (e.g., `IdentityPermissions.Users.Create`). +- Group related permissions logically. + +--- + +## Event Bus & Distributed Events + +- Use `ILocalEventBus` for intra-module communication within the same process. +- Use `IDistributedEventBus` for cross-module or cross-service communication. +- Define Event Transfer Objects (ETOs) in Domain.Shared for distributed events. +- ETO naming: `[EntityName][Action]Eto` (e.g., `UserCreatedEto`, `OrderCompletedEto`). +- Event handlers belong in the Application layer. +- ETOs should be simple, serializable, and contain only primitive types or nested ETOs. + +--- + +## Testing + +- Unit tests: `*.Tests` projects for isolated logic testing with mocked dependencies. +- Integration tests: `*.EntityFrameworkCore.Tests` / `*.MongoDB.Tests` for repository and DB tests. +- Use `AbpIntegratedTest` or `AbpApplicationTestBase` base classes. +- Test modules should use `[DependsOn]` on the module under test. +- Use `Shouldly` assertions (ABP convention). +- Test both EF Core and MongoDB implementations when the module supports both. +- Include tests for permission checks, validation, and edge cases. +- Name test methods: `MethodName_Scenario_ExpectedResult` or `Should_ExpectedBehavior_When_Condition`. + +--- + +## Contribution Discipline (PR / Issues / Tests) + +- Before significant changes, align via GitHub issue/discussion. + +### PRs +- Keep changes scoped and reviewable. +- Add/update unit/integration tests relevant to the change. +- Build and run tests for the impacted area when possible. + +### Localization +- Prefer the `abp translate` workflow for adding missing translations (generate `abp-translation.json`, fill, apply, then PR). + +--- + +## Review Checklist + +- [ ] Layer dependencies respected (no forbidden references). +- [ ] No `IQueryable` leaking into public repository contracts. +- [ ] Entities maintain invariants; Guid id generation not inside constructors. +- [ ] Repositories follow async + CancellationToken + includeDetails conventions. +- [ ] No web types in application services. +- [ ] DTOs in contracts, validated, minimal, no logic. +- [ ] EF/Mongo integration follows context + mapping + repository patterns. +- [ ] Public members are `virtual` for extensibility. +- [ ] Backward compatibility maintained; no breaking changes without deprecation. +- [ ] Minimal diff; no unnecessary API surface expansion. From 75ec207f889ac0dd4137f0c531bdad5e83cf9bbc Mon Sep 17 00:00:00 2001 From: Ma Liming Date: Wed, 7 Jan 2026 14:50:55 +0800 Subject: [PATCH 3/4] Add instructions for reviewing pull requests --- .github/pr-review.instructions.md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .github/pr-review.instructions.md diff --git a/.github/pr-review.instructions.md b/.github/pr-review.instructions.md new file mode 100644 index 0000000000..6f3045f27d --- /dev/null +++ b/.github/pr-review.instructions.md @@ -0,0 +1,2 @@ +When reviewing pull requests, skip and ignore any pull request whose source branch name starts with "auto-merge/". +Please don't make any comments, suggestions, summaries, or reviews for these pull requests. From ed39030ddb620e22061ba7100339a81be73cef37 Mon Sep 17 00:00:00 2001 From: Ma Liming Date: Wed, 7 Jan 2026 14:54:26 +0800 Subject: [PATCH 4/4] Revise PR review instructions for clarity and scope Updated instructions for reviewing pull requests to clarify the scope and expectations for human-authored changes. --- .github/pr-review.instructions.md | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/.github/pr-review.instructions.md b/.github/pr-review.instructions.md index 6f3045f27d..49abc514c4 100644 --- a/.github/pr-review.instructions.md +++ b/.github/pr-review.instructions.md @@ -1,2 +1,18 @@ -When reviewing pull requests, skip and ignore any pull request whose source branch name starts with "auto-merge/". -Please don't make any comments, suggestions, summaries, or reviews for these pull requests. +# Pull Request Review – GitHub Copilot Instructions + +> **Scope**: Pull request reviews in this repository. +> +> **Goal**: Avoid generating noise on machine-generated or automatically merged pull requests, and focus reviews on human-authored changes that require design or code feedback. + +--- + +## Review Scope Filtering + +- When reviewing pull requests, **skip and ignore any pull request whose source branch name starts with `auto-merge/`**. +- Do **not** generate review comments, suggestions, summaries, or approvals for these pull requests. +- Treat these pull requests as machine-generated and out of scope for AI review. + +## Review Expectations (Applicable PRs Only) + +- Only review pull requests created from human-authored feature, bugfix, or maintenance branches. +- Provide feedback that focuses on correctness, design quality, maintainability, and alignment with existing repository conventions.