[AZ-309] Refactor 02-coupling-refactoring Phase 0-2 artifacts

- Baseline metrics, list of changes, and analysis (research findings,
  refactoring roadmap) for the coupling refactor run
- Six task specs AZ-310..AZ-315 covering endpoint routing through
  ITileService, Services csproj split, consumer rewire, DI extension
  methods, and docs sync
- Existing test coverage assessment for Phase 3 safety net gate
- Dependencies table updated with the refactor block

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Oleksandr Bezdieniezhnykh
2026-05-10 05:53:29 +03:00
parent cc0a876168
commit 220277b9c7
13 changed files with 860 additions and 10 deletions
@@ -0,0 +1,63 @@
# Phase 2b — Refactoring Roadmap
**Run**: 02-coupling-refactoring
**Date**: 2026-05-10
## Solution Assessment
Acceptance criteria (`_docs/00_problem/acceptance_criteria.md`) all map to public HTTP behavior. None of the proposed changes alter that behavior — they redistribute internal ownership. The smoke + unit suite remains the gate.
## Gap Analysis
| Acceptance Criterion (paraphrased) | Current State | Post-Refactor State | Verification |
|------------------------------------|---------------|---------------------|--------------|
| AC: download single tile by lat/lon/zoom returns image metadata | Endpoint inlines logic (Program.cs:206) | Endpoint delegates to `ITileService.DownloadAndStoreSingleTileAsync` | Smoke `RunGetTileByLatLonTest` |
| AC: serve tile by z/x/y returns image bytes | Endpoint inlines logic + cache (Program.cs:141) | Endpoint delegates to `ITileService.GetOrDownloadTileAsync` | Manual smoke (no integration test exists for `/tiles/{z}/{x}/{y}` — note as a follow-up coverage gap) |
| AC: region processing pipeline | RegionService in `Services` csproj | RegionService in `Services.RegionProcessing` csproj | Smoke `RunRegionProcessingTest_200m_Zoom18` + unit RegionServiceTests |
| AC: route management pipeline | RouteService in `Services` csproj | RouteService in `Services.RouteManagement` csproj | Smoke `RunRouteWithTilesZipTest` + unit RouteServiceTests |
| AC: zoom validation rejects invalid zoom | GoogleMapsDownloaderV2 in `Services` csproj | Same class in `Services.TileDownloader` csproj | Unit GoogleMapsDownloaderZoomValidationTests |
**Coverage gap noted but out of scope**: there is no integration test exercising the `/tiles/{z}/{x}/{y}` endpoint specifically. The unit-level cache logic in C01 will be tested via new TileService unit tests; integration coverage can be added in a future cycle.
## Phased Roadmap
### Phase A — Endpoint routing (low risk, sequential)
1. **AZ-NEW-1 (refactor C01)**`ITileService.GetOrDownloadTileAsync(z,x,y)` + ServeTile handler thinning.
2. **AZ-NEW-2 (refactor C02)**`ITileService.DownloadAndStoreSingleTileAsync(lat,lon,zoom)` + GetTileByLatLon handler thinning.
After Phase A, F3 from the architecture baseline is resolved. Smoke + unit suite stays green.
### Phase B — Project split (medium risk, sequential due to compiler dependency chain)
3. **AZ-NEW-3 (refactor C03)** — Create `Services.TileDownloader`, `Services.RegionProcessing`, `Services.RouteManagement` csprojs and move the seven files.
4. **AZ-NEW-4 (refactor C04)** — Update `SatelliteProvider.Tests` and `SatelliteProvider.IntegrationTests` to reference the new csprojs.
5. **AZ-NEW-5 (refactor C05)** — Update `SatelliteProvider.Api` csproj, `Program.cs` namespaces, and `Dockerfile` COPY paths.
After Phase B, F4 from the architecture baseline is resolved. The solution builds, smoke + unit suite stays green, the API container still runs.
### Phase C — Documentation (low risk, last)
6. **AZ-NEW-6 (refactor C06)** — Update `module-layout.md`, `architecture.md`, refresh `architecture_compliance_baseline.md` (mark F3, F4 Resolved; correct F5).
After Phase C, doc-code parity is restored.
## Hardening Tracks
User Phase 0 + Phase 1 approvals already excluded hardening. The only optional track that would fit is:
- **Track A — Tech Debt**: pre-existing FluentAssertions community-license warning would belong here, but it's a licensing decision (legal cost vs. switching to `Shouldly` or `xunit.assert`), not a code-structure decision. Surfacing as a follow-up backlog item rather than including in this run.
No hardening tracks added to this run. Pure structural refactor.
## Applicability Gate
Every roadmap item carries `Selected` status from `research_findings.md`. No `Rejected`, `Experimental only`, or `Needs user decision` entries remain. Gate: **passed**.
## Self-Verification
- [x] All ACs mapped to current vs post-refactor state.
- [x] Phased order respects compiler dependencies (endpoint refactor before split).
- [x] Each item has a verification path (smoke or unit suite).
- [x] No item violates the Project Constraint Matrix.
- [x] Hardening track decision recorded.
@@ -0,0 +1,74 @@
# Phase 2a — Research Findings
**Run**: 02-coupling-refactoring
**Date**: 2026-05-10
## Project Constraint Matrix (extracted)
From `_docs/00_problem/problem.md`, `_docs/00_problem/restrictions.md`, `_docs/00_problem/acceptance_criteria.md`, `_docs/02_document/architecture.md`:
| Constraint | Source | Implication for this refactor |
|------------|--------|--------------------------------|
| .NET 8.0 / ASP.NET Core minimal API | `restrictions.md`, `architecture.md` | New code stays on .NET 8 + minimal API. No framework swap. |
| PostgreSQL via Dapper | `restrictions.md` | DataAccess layer unchanged. |
| Public HTTP API surface stable | `acceptance_criteria.md` (AC-1..AC-3) | Routes, query/body shapes, response shapes preserved exactly. |
| No DB schema rename | project `coderule.mdc` | Migrations not touched. |
| Source under `src/` only for new projects; existing layout retained | project `coderule.mdc` | New `Services.*` csprojs sit at the repo root next to existing `SatelliteProvider.*` csprojs (existing layout). |
| Dockerized deploy via `docker-compose.yml` | `architecture.md`, `AGENTS.md` | API + IntegrationTests Dockerfiles must be updated when csproj layout changes. |
| Test environment runs in Docker | `_docs/02_document/tests/environment.md` | Smoke + unit suite must pass under the existing Docker test runner. |
## Current State Analysis
| Aspect | Pattern in code | Strength | Weakness |
|--------|-----------------|----------|----------|
| API layer | ASP.NET minimal API (`MapGet`, `MapPost` in `Program.cs`) | Compact, easy to read | Two endpoints (`ServeTile`, `GetTileByLatLon`) bypass the service layer (baseline F3) |
| Service layer | Single csproj `SatelliteProvider.Services` containing 7 files | Simple to navigate | No compiler-enforced boundary between TileDownloader / RegionProcessing / RouteManagement (baseline F4) |
| Data access | Dapper repositories injected via interfaces | Clean separation | None |
| DI | Built-in `Microsoft.Extensions.DependencyInjection` | Standard, no surprises | None |
| Testing | xUnit + Moq + FluentAssertions (community license warning, pre-existing) | Standard, expressive | FluentAssertions licensing is a pre-existing concern, out of scope |
## Alternative Approaches Considered
This refactor is structural-only. No new library/SDK/framework is being added or replaced. The mandatory **API Capability Verification** flow does not apply because no replacement candidates exist — the proposed changes reuse existing patterns:
- ASP.NET Core minimal API → kept.
- `IMemoryCache` from `Microsoft.Extensions.Caching.Memory` → kept (moves into TileService instead of being injected into the endpoint handler).
- xUnit / Moq / FluentAssertions → kept.
- DbUp / Dapper → not touched.
`context7` lookup is therefore not required for this refactor (no replacement candidates to verify).
### Alternatives explicitly considered and rejected (already in `list-of-changes.md`)
| Alternative | Status | Reason |
|-------------|--------|--------|
| Adopt MediatR / CQRS layering | Rejected | Heavy dependency for a small codebase; conflicts with the "simplest solution" coderule; not required by any AC. |
| Move `ISatelliteDownloader` into the new TileDownloader csproj | Rejected | Forces RegionService/RegionProcessingService to depend on TileDownloader, defeating the boundary the split is supposed to create. |
| Inline `IMemoryCache` into the public `ITileService` interface | Rejected | Leaks an implementation choice (memory vs. distributed cache) into the public abstraction. |
## Constraint-Fit Table
| Recommendation | Pinned Mode | Constraints Checked | Evidence | Mismatches | Status |
|----------------|-------------|---------------------|----------|------------|--------|
| C01 — `ITileService.GetOrDownloadTileAsync(z,x,y)` | New interface method on existing service | HTTP route preserved; ETag/Cache-Control preserved | Smoke `RunGetTileByLatLonTest` will exercise post-refactor; existing TileServiceTests already cover the cache+download logic at unit level | None | Selected |
| C02 — `ITileService.DownloadAndStoreSingleTileAsync(lat,lon,zoom)` | New interface method on existing service | Query string + DownloadTileResponse shape preserved; zoom validation chain unchanged | Smoke + unit | None | Selected |
| C03 — Split Services into 3 csprojs | New `.csproj` files, code MOVE only | No code logic change; namespaces change | Compiler verifies; smoke verifies behavior | None | Selected |
| C04 — Update test projects | Move `using` + `ProjectReference` only | No test logic change | `dotnet test` post-refactor | None | Selected |
| C05 — Update API project + Dockerfiles | Move `using` + `ProjectReference` + Dockerfile COPY paths | API container builds and runs | `docker compose build` + smoke | None | Selected |
| C06 — Update docs | Documentation only | None | Manual review against new csproj layout | None | Selected |
All six recommendations are `Selected`. None require user decision beyond the Phase 0 / Phase 1 scope approval already obtained.
## Quick Wins vs Strategic Improvements
- **Quick wins** (low risk, immediate value): C01, C02, C04, C06.
- **Strategic** (medium risk, foundation for future work): C03, C05.
## Self-Verification
- [x] Project Constraint Matrix extracted.
- [x] Current state vs. alternatives analyzed.
- [x] All recommendations grounded in actual code (file paths, method names verified).
- [x] No replacement libraries → API capability verification is N/A and explicitly noted.
- [x] Rejected alternatives documented.
- [x] No recommendation violates the Project Constraint Matrix.