# Module Layout **Status**: derived-from-code **Language**: csharp **Layout Convention**: single-assembly (`Azaion.Annotations`), vertical slices expressed as **logical components** under flat `src/` folders (`Controllers/`, `Services/`, `DTOs/`). **Root**: `src/` **Last Updated**: 2026-05-14 ## Verification Needed 1. **No per-component physical root** — all components share `src/Controllers/`, `src/Services/`, `src/DTOs/`. File ownership below is **exclusive for implementation planning**; merges touching the same file need explicit batch ordering. 2. **`AnnotationsController.cs` split (user-approved six-component model)** — **REST + static files** belong to **01 Annotations REST**; **SSE** (`Events`) belongs to **02 Annotations realtime & sync**. For `/implement`, treat **`src/Controllers/AnnotationsController.cs` as owned by 01**; tasks that **only** change SSE must still edit this file — flag as **cross-component** (01 + 02) or split into partial classes in a future refactor. 3. **`src/DTOs/`** — no subfolders; each file has a **primary owner** in [Shared: DTO files](#shared-dto-files-primary-ownership) to resolve FORBIDDEN vs OWNED during tasks. 4. **`FailsafeProducer.cs`** contains `RabbitMqConfig` and `FailsafeProducer` — fully owned by **02** (even though `Program.cs` registers the config as singleton). --- ## Layout Rules (adapted for this repo) 1. Components map to **logical** slices from `_docs/02_document/components/*/description.md`, not to separate top-level directories. 2. **Foundation** (`06_platform`) owns schema, enums, auth registration helpers, middleware, path resolution, and **composition** (`Program.cs`, csproj, Dockerfile). 3. **Feature** components own listed **service + controller** files; they **read** foundation public APIs and **shared DTO** types per the DTO table. 4. Tests are **not present** in-repo; future test project should follow `tests/Azaion.Annotations.Tests/` (conventional) — not owned by feature slices until created. --- ## Per-Component Mapping ### Component: `01_annotations-rest` - **Epic**: (assign per change; layout is structural) - **Directory (primary)**: `src/Services/` (partial), `src/Controllers/` (partial) - **Public API** (types other components may reference through DI / same assembly): - `Azaion.Annotations.Services.AnnotationService` - `Azaion.Annotations.Controllers.AnnotationsController` (REST + image/thumbnail actions only — see Verification) - **Internal**: private methods inside owned types; do not reach into other components’ services from new code without updating this layout. - **Owns (exclusive write scope)**: - `src/Services/AnnotationService.cs` - `src/Controllers/AnnotationsController.cs` — **primary file owner** (REST, `GetThumbnail`, `GetImage`; coordinate with 02 for `Events`) - **Imports from**: `06_platform` (Database, Enums, DTOs used here, PathResolver, Middleware indirectly), `02_annotations-realtime-sync` (`AnnotationEventService` for publish) - **Consumed by**: `04_dataset` (read paths share DB entities; no direct `AnnotationService` reference required), external callers ### Component: `02_annotations-realtime-sync` - **Epic**: (assign per change) - **Directory (primary)**: `src/Services/` (partial) - **Public API**: - `Azaion.Annotations.Services.AnnotationEventService` - `Azaion.Annotations.Services.RabbitMqConfig` - `Azaion.Annotations.Services.FailsafeProducer` - `FailsafeProducer.EnqueueAsync` (static helper on same type as producer) - **Owns**: - `src/Services/FailsafeProducer.cs` (includes `RabbitMqConfig` + `FailsafeProducer`) - `src/Services/AnnotationEventService.cs` - **SSE contract**: `AnnotationsController.Events` (same `.cs` as 01 — see Verification) - **Imports from**: `06_platform` (Database, Entities, PathResolver, Enums, `DTOs/QueueMessages.cs`), `DTOs/AnnotationEventDto.cs` (see Shared) - **Consumed by**: `01_annotations-rest` (publishes events), external RabbitMQ consumers ### Component: `03_media` - **Epic**: (assign per change) - **Public API**: `MediaService`, `MediaController` - **Owns**: - `src/Services/MediaService.cs` - `src/Controllers/MediaController.cs` - **Imports from**: `06_platform` - **Consumed by**: `01_annotations-rest` (domain: media rows referenced by annotations), UI ### Component: `04_dataset` - **Epic**: (assign per change) - **Public API**: `DatasetService`, `DatasetController` - **Owns**: - `src/Services/DatasetService.cs` - `src/Controllers/DatasetController.cs` - **Imports from**: `06_platform` - **Consumed by**: Dataset Explorer UI ### Component: `05_settings-metadata` - **Epic**: (assign per change) - **Public API**: `SettingsService`, `SettingsController`, `ClassesController` - **Owns**: - `src/Services/SettingsService.cs` - `src/Controllers/SettingsController.cs` - `src/Controllers/ClassesController.cs` - **Imports from**: `06_platform` - **Consumed by**: UI; `PathResolver` / directory settings (via DB) interact with **06** cache reset when dirs change ### Component: `06_platform` - **Epic**: (assign per change) - **Public API** (representative; all `public` types in these areas are the integration surface): - `Azaion.Annotations.Database.AppDataConnection`, `DatabaseMigrator`, `Azaion.Annotations.Database.Entities.*` - `Azaion.Annotations.Enums.*` - `Azaion.Annotations.Middleware.ErrorHandlingMiddleware` - `Azaion.Annotations.Auth.JwtExtensions` - `Azaion.Annotations.Infrastructure.ConfigurationResolver`, `CorsConfigurationValidator` - `Azaion.Annotations.Services.PathResolver` - `Program` (implicit entry), `src/Program.cs` - **Owns**: - `src/Enums/**` - `src/Database/**` - `src/Middleware/**` - `src/Auth/**` - `src/Infrastructure/**` - `src/Services/PathResolver.cs` - `src/GlobalUsings.cs` - `src/Program.cs` - `src/Azaion.Annotations.csproj` - `src/Dockerfile` - **Imports from**: (none — foundation) - **Consumed by**: all other components --- ## Shared: DTO files (primary ownership) | File under `src/DTOs/` | Primary component | Notes | |------------------------|-------------------|--------| | `PaginatedResponse.cs` | `06_platform` | Generic list wrapper — cross-cutting | | `ErrorResponse.cs` | `06_platform` | Shared error shape | | `CreateAnnotationRequest.cs` | `01_annotations-rest` | | | `UpdateAnnotationRequest.cs` | `01_annotations-rest` | | | `UpdateStatusRequest.cs` | `01_annotations-rest` / `04_dataset` | **Shared type** — **01** owns file edits; `04_dataset` uses for PATCH | | `GetAnnotationsQuery.cs` | `01_annotations-rest` | | | `AnnotationListItem.cs` | `01_annotations-rest` | | | `DetectionDto.cs` | `01_annotations-rest` | | | `AnnotationEventDto.cs` | `02_annotations-realtime-sync` | SSE payload | | `QueueMessages.cs` | `02_annotations-realtime-sync` | MessagePack stream payloads | | `CreateMediaRequest.cs` | `03_media` | | | `GetMediaQuery.cs` | `03_media` | | | `MediaListItem.cs` | `03_media` | | | `GetDatasetQuery.cs` | `04_dataset` | | | `DatasetItem.cs` | `04_dataset` | | | `ClassDistributionItem.cs` | `04_dataset` | | | `BulkStatusRequest.cs` | `04_dataset` | | | `UpdateSystemSettingsRequest.cs` | `05_settings-metadata` | | | `UpdateDirectoriesRequest.cs` | `05_settings-metadata` | | | `UpdateCameraSettingsRequest.cs` | `05_settings-metadata` | | | `UpdateUserSettingsRequest.cs` | `05_settings-metadata` | | --- ## Shared / Cross-Cutting (non-DTO) ### `common-helpers/01_http-error-envelope.md` - **Purpose**: Documents middleware as cross-cutting (see `_docs/02_document/common-helpers/`). - **Owned by**: tasks touching **06_platform** (`ErrorHandlingMiddleware`). - **Consumed by**: all HTTP components. --- ## Allowed Dependencies (layering) Higher layers may depend on lower; **not** the reverse. Same-layer components should not introduce compile-time cycles (current codebase: none detected). | Layer | Components | May import from (namespaces / types from) | |-------|------------|---------------------------------------------| | 1 — Foundation | `06_platform` | *(none)* | | 2 — Realtime infra | `02_annotations-realtime-sync` | `06_platform` | | 3 — Application features | `01_annotations-rest`, `03_media`, `04_dataset`, `05_settings-metadata` | `06_platform`, and **`01` additionally `02`** (`AnnotationEventService`) | **Rules** - `03`, `04`, `05` → **must not** reference `AnnotationService` / `MediaService` across features without an explicit API (today: only via shared `AppDataConnection` in same assembly — acceptable but treat as **tight coupling**; prefer domain services for new code). - `02` → **must not** reference `01` service types (no reverse dependency today). Violations are **Architecture** findings for code-review Phase 7. --- ## Layout Conventions (reference) | Language | Root | This repo | |----------|------|-----------| | C# (.NET) | `src/` | Single web project; vertical slices = **logical** component rows above + DTO table |