AGENTS/Architecture.md
Rama main · réplica de lectura del repositorio original.
# Architecture Guidance
This file captures the current runtime architecture so agents can orient quickly before making design or implementation changes.
## Solution Layers
- `BoardOil.Api`
- HTTP transport, endpoint wiring, auth policies, runtime hosting, MCP transport wiring.
- Endpoints stay thin and delegate behaviour to services.
- `BoardOil.Contracts`
- API contracts (`*Request`, `*Dto`, `ApiResult`, `ValidationError`) shared across API/services/tests.
- `BoardOil.Abstractions`
- Cross-cutting service and infrastructure abstractions (service interfaces, db scope abstractions, auth abstractions).
- `BoardOil.Data.Abstractions`
- Persistence-facing contracts and EF entity types (`Entity*`) plus repository interfaces.
- `BoardOil.Ef`
- EF Core implementation (`BoardOilDbContext`), repository implementations, ambient db scope implementation, migrations.
- Infrastructure composition and startup initialisation extensions for EF wiring/migrations/bootstrap.
- `BoardOil.Services`
- Business workflows, invariants, validation orchestration, persistence coordination, mapping to contracts, realtime event publishing.
- Service-layer DI registrations only; no EF registration or migration/bootstrap startup ownership.
- `BoardOil.Web`
- Vue 3 + Pinia frontend, typed API client, route guards, realtime board updates.
## Request and Write Flow
1. Endpoint/controller-equivalent in `BoardOil.Api` invokes a service (`I*Service`).
2. Service opens a db scope (`Create()` for write, `CreateReadOnly()` for read).
3. Service performs validation + repository operations.
4. Service commits with `scope.SaveChangesAsync()`.
5. Service returns `ApiResult`/`ApiResult<T>` and API layer serialises that contract.
Default: one save per service operation unless a specific transactional reason requires otherwise.
## Endpoint Verb Preference
- For update endpoints, generally prefer `PUT` over `PATCH`.
- Use `PATCH` only when the endpoint is intentionally a partial-update contract.
## Contract Design Guidance
- Prefer endpoint-specific DTOs when read and write concerns diverge; do not force one contract shape to serve both equally if that makes either side awkward.
- Do not create multiple DTOs or record types for the same area unless there is a genuine difference to justify them. A naming distinction on its own is not enough; there should be a concrete difference in fields, behaviour, lifecycle, audience, or contract semantics.
- If two DTOs have the same shape and are used the same way, prefer a single contract until a real divergence appears. Avoid speculative semantic types that add naming without adding clarity.
- Full-update (`PUT`) contracts should remain cheap for clients to round-trip. If a client edits one field and keeps the rest unchanged, it should not need complex shape conversion just to resend the untouched fields.
- Denormalised read models are acceptable when they materially improve consumer ergonomics (for example richer one-hit payloads for integrations), but treat that as a convenience projection rather than proof that the denormalised payload is the only source of truth.
- When a read model duplicates data from a catalogue or parent entity, explicitly document the intended authority model:
- which payload/store is authoritative for live updates and mutations
- which payload is convenience/snapshot data for easier reads
- Do not introduce partial-update contracts just to paper over awkward DTO design. Prefer improving the contract shape first; adopt `PATCH` only when partial semantics are genuinely required.
- Periodically remove dead or orphaned contract types when the intended abstraction never materialised. Unused DTO/record layers create noise and make the real architecture harder to read.
## Boundaries
- Repositories:
- Entity-level data access only.
- No orchestration/policy decisions.
- No commit ownership.
- Services:
- Own orchestration, policy, validation coordination, and cross-repository workflows.
## Realtime and Auth Notes
- Realtime notifications are emitted from services through `IBoardEvents`.
- Clients should treat realtime as incremental and resync-safe after reconnects.
- API auth uses JWT/cookies for user sessions.
- MCP-specific auth policy and bearer challenge behavior are composed through `BoardOil.Api/Mcp/McpAuthExtensions.cs`.
- `Program.cs` should remain orchestration-focused; MCP transport/auth wiring should live in `BoardOil.Api/Mcp/*` extension modules.