Browse Source

First version of .cursorrules file added

pull/24563/head
İsmail ÇAĞDAŞ 1 month ago
parent
commit
fe694c3e59
  1. 206
      .cursorrules

206
.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<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…
Cancel
Save