docs: define repository pattern boundary

This commit is contained in:
AzuTear
2026-06-28 09:48:34 +02:00
parent ed8efda692
commit 170308ba05
8 changed files with 171 additions and 2 deletions
+22
View File
@@ -97,6 +97,28 @@ Domain code should not depend on delivery mechanisms, databases, network
clients, or framework-specific runtime concerns unless the project intentionally clients, or framework-specific runtime concerns unless the project intentionally
uses an architecture where that trade-off is accepted and recorded. uses an architecture where that trade-off is accepted and recorded.
## Persistence Boundary
The default persistence boundary is the repository pattern.
Use repositories to express domain-specific persistence operations without
leaking database, ORM, file-system, or external storage details into application
or domain logic.
Default rules:
- Application or domain-facing code depends on repository interfaces.
- Infrastructure implements repository interfaces.
- Repositories are named around domain concepts, not database tables.
- Repositories expose intention-revealing operations, not generic CRUD by
default.
- Transaction boundaries are explicit at the application service, unit of work,
or framework boundary selected by the project.
If a project intentionally avoids repositories because the framework or
architecture provides a better persistence boundary, record that decision in
[DECISIONS.md](DECISIONS.md).
## Request Flow ## Request Flow
```mermaid ```mermaid
+8 -2
View File
@@ -125,9 +125,15 @@ Project-specific DTO rules:
## Repository Rules ## Repository Rules
Repositories, gateways, or data access abstractions should express persistence Use the repository pattern as the default persistence boundary.
intent without hiding important consistency behavior.
Repositories, gateways, or data access abstractions should express domain
persistence intent without hiding important consistency behavior.
- Define repository interfaces at the application or domain boundary.
- Implement repositories in infrastructure or persistence-specific modules.
- Prefer specific repositories such as `OrderRepository` or
`SupportRequestRepository`.
- Keep query methods specific enough to reveal purpose. - Keep query methods specific enough to reveal purpose.
- Avoid generic repositories when they obscure domain behavior. - Avoid generic repositories when they obscure domain behavior.
- Document transaction boundaries. - Document transaction boundaries.
+60
View File
@@ -25,6 +25,7 @@ For project constraints, see [PROJECT.md](PROJECT.md).
| ADR-001 | Example: Start with a modular monolith | Example | 2026-06-28 | | ADR-001 | Example: Start with a modular monolith | Example | 2026-06-28 |
| ADR-002 | Example: Keep project documentation in the repository | Example | 2026-06-28 | | ADR-002 | Example: Keep project documentation in the repository | Example | 2026-06-28 |
| ADR-003 | Example: Require explicit validation evidence before merge | Example | 2026-06-28 | | ADR-003 | Example: Require explicit validation evidence before merge | Example | 2026-06-28 |
| ADR-004 | Example: Use repository pattern for persistence boundaries | Example | 2026-06-28 |
## ADR-000: ADR Template ## ADR-000: ADR Template
@@ -245,3 +246,62 @@ manual checks, or reasons validation could not be run.
- PR templates should include validation. - PR templates should include validation.
- Reviewers can block merges when risk is high and evidence is missing. - Reviewers can block merges when risk is high and evidence is missing.
- Failed or skipped validation must be explained. - Failed or skipped validation must be explained.
## ADR-004: Example: Use Repository Pattern For Persistence Boundaries
### Title
Use repository pattern for persistence boundaries.
### Status
Example
### Date
2026-06-28
### Context
The project needs domain and application logic to remain independent from the
database engine, ORM, and storage implementation details.
### Problem
Without an explicit persistence boundary, database concerns can leak into
business logic and make testing, refactoring, and future storage changes harder.
### Alternatives
| Alternative | Summary |
| --- | --- |
| Direct ORM access everywhere | Fast initially, but couples business logic to persistence details. |
| Generic repository | Reduces ORM exposure, but often becomes a thin CRUD wrapper. |
| Domain-specific repository pattern | Keeps persistence behind intention-revealing interfaces. |
### Pros
- Keeps application and domain logic focused on use cases and rules.
- Makes persistence behavior easier to test and replace.
- Creates a clear place for query intent and transaction expectations.
- Reduces accidental coupling to ORM-specific APIs.
### Cons
- Adds interfaces and implementation classes.
- Poorly designed repositories can hide important query or transaction costs.
- Generic repositories can obscure domain behavior if used mechanically.
### Decision
Use domain-specific repositories as the default persistence boundary.
### Consequences
- Repository interfaces should live at the application or domain boundary.
- Repository implementations should live in infrastructure or persistence
modules.
- Generic CRUD repositories should be avoided unless the project records a clear
reason.
- Transaction boundaries must be documented where writes span multiple
repositories.
+13
View File
@@ -78,6 +78,19 @@ atlas-desk/
- Domain rules do not depend on HTTP, Vue, or database APIs. - Domain rules do not depend on HTTP, Vue, or database APIs.
- Infrastructure implementations depend inward on application contracts. - Infrastructure implementations depend inward on application contracts.
## Persistence Boundary
Atlas Desk uses the repository pattern for persistence boundaries.
- Repository interfaces live in the owning backend module.
- Repository implementations live in the module's infrastructure or persistence
folder.
- Repositories are domain-specific, such as `RequestRepository` and
`UserRepository`.
- Application services coordinate transactions for workflows that write multiple
records, such as assignment plus audit event creation.
- Generic CRUD repositories are not used because they hide workflow intent.
## Request Flow ## Request Flow
```mermaid ```mermaid
+4
View File
@@ -57,6 +57,10 @@
## Repository Rules ## Repository Rules
- Use the repository pattern for persistence boundaries.
- Keep repository interfaces in the owning backend module.
- Keep repository implementations near persistence infrastructure.
- Use specific repositories such as `RequestRepository` and `UserRepository`.
- Keep queries explicit, such as `FindOpenRequestsForQueue`. - Keep queries explicit, such as `FindOpenRequestsForQueue`.
- Do not add generic repository abstractions over the database context. - Do not add generic repository abstractions over the database context.
- Write operations that can be retried must be idempotent or transactionally protected. - Write operations that can be retried must be idempotent or transactionally protected.
+52
View File
@@ -148,3 +148,55 @@ Enforce authorization in backend policies for all sensitive actions.
- Frontend checks remain usability hints only. - Frontend checks remain usability hints only.
- Authorization tests are required for each protected workflow. - Authorization tests are required for each protected workflow.
- Policy changes must be reviewed as security-sensitive changes. - Policy changes must be reviewed as security-sensitive changes.
## ADR-004: Use Repository Pattern For Persistence Boundaries
### Status
Accepted
### Date
2026-06-28
### Context
Atlas Desk uses PostgreSQL and Entity Framework Core, but request workflow rules
should not depend directly on ORM APIs or database-specific query details.
### Problem
Direct persistence access from application services would make workflow logic
harder to test and increase coupling to storage implementation details.
### Alternatives
| Alternative | Summary |
| --- | --- |
| Direct database context access | Simple, but spreads persistence concerns through application logic. |
| Generic repository | Hides the ORM, but exposes low-value CRUD abstractions. |
| Domain-specific repositories | Keeps persistence behind workflow-focused interfaces. |
### Pros
- Keeps workflow services focused on use cases.
- Makes request assignment and audit behavior easier to test.
- Provides intention-revealing query methods.
- Allows persistence implementation changes without rewriting domain logic.
### Cons
- Adds interface and implementation classes.
- Requires discipline to avoid generic CRUD repositories.
- Complex queries still need explicit performance review.
### Decision
Use domain-specific repositories for persistence boundaries.
### Consequences
- `RequestRepository` owns request persistence operations.
- `UserRepository` owns user lookup persistence operations.
- Reporting uses explicit read queries instead of mutating request data.
- Transaction boundaries remain visible in application services.
+8
View File
@@ -45,6 +45,14 @@ flowchart LR
- {{DEPENDENCY_RULE_2}} - {{DEPENDENCY_RULE_2}}
- {{DEPENDENCY_RULE_3}} - {{DEPENDENCY_RULE_3}}
## Persistence Boundary
- Pattern: Repository pattern
- Repository interfaces: {{REPOSITORY_INTERFACE_LOCATION}}
- Repository implementations: {{REPOSITORY_IMPLEMENTATION_LOCATION}}
- Transaction boundary: {{TRANSACTION_BOUNDARY}}
- Repository rules: {{REPOSITORY_RULES}}
## Request Flow ## Request Flow
{{REQUEST_FLOW}} {{REQUEST_FLOW}}
+4
View File
@@ -34,6 +34,10 @@
## Repository Rules ## Repository Rules
- Use the repository pattern for persistence boundaries.
- Repository interfaces live in {{REPOSITORY_INTERFACE_LOCATION}}.
- Repository implementations live in {{REPOSITORY_IMPLEMENTATION_LOCATION}}.
- Repositories should be domain-specific, not generic CRUD wrappers by default.
- {{REPOSITORY_RULE}} - {{REPOSITORY_RULE}}
## Service Rules ## Service Rules