# 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.
