mirror of https://github.com/abpframework/abp.git
1 changed files with 206 additions and 0 deletions
@ -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<TKey>` 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<TEntity, TKey>`). |
|||
- Repository interfaces MUST NOT expose `IQueryable` to application/domain layers: |
|||
- Prefer inheriting from `IBasicRepository<TEntity, TKey>` (or `IReadOnlyRepository<...>` when suitable). |
|||
- Do NOT inherit from `IRepository<TEntity, TKey>`. |
|||
- 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<TKey>`, 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<TEntity>` ONLY for aggregate roots. |
|||
- Do NOT include setters in the interface. |
|||
- DbContext class: |
|||
- Inherit `AbpDbContext<TDbContext>`. |
|||
- 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<TDbContextInterface, TEntity, TKey>`. |
|||
- 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<TEntity>` 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<TMongoDbContextInterface, TEntity, TKey>`. |
|||
- 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. |
|||
Loading…
Reference in new issue