From a863351eeea78dac27ffa39fd2f05f7109546c69 Mon Sep 17 00:00:00 2001 From: Daniel Roth Date: Mon, 11 May 2026 15:42:53 +0000 Subject: [PATCH] delete temp prd file --- backend/backlog/prd-extract-domain-to-root.md | 114 ------------------ 1 file changed, 114 deletions(-) delete mode 100644 backend/backlog/prd-extract-domain-to-root.md diff --git a/backend/backlog/prd-extract-domain-to-root.md b/backend/backlog/prd-extract-domain-to-root.md deleted file mode 100644 index b4ef2d7e..00000000 --- a/backend/backlog/prd-extract-domain-to-root.md +++ /dev/null @@ -1,114 +0,0 @@ -# PRD: Extract Domain Layer to Root-Level `domain/` Package - -## Problem Statement - -Domain objects (models, enums, mappers) shared across microservices are nested under `datatypes/epc/domain/` and `datatypes/magicplan/domain/`. This creates two problems: - -1. **Misleading location**: "Datatypes" implies low-level type definitions, but these folders contain rich domain models and business logic (mappers, historic EPC matching, property data aggregation). New developers cannot discover the domain layer by inspection. -2. **False coupling**: Domain objects belonging to the whole system are buried inside a folder that also contains source-data representations (versioned RdSAP schemas, Elmhurst/Pashub survey shapes, MagicPlan API responses). The domain has no clear home — it is mixed with external data adapters. - -## Solution - -Extract all domain objects (domain models, domain vocabulary enums, mappers) into a dedicated root-level `domain/` package. The `datatypes/` package is repurposed to hold only external/source data shapes: RdSAP schemas, survey provider types, and third-party API response types. - -The result is a clear, discoverable split: - -- `domain/` — canonical domain models, vocabulary enums, and mappers owned by this system -- `datatypes/` — shapes that mirror external systems (schemas, surveys, API responses) - -## User Stories - -1. As a backend engineer, I want domain models to live in a top-level `domain/` package, so that I can find the canonical representation of an EPC or MagicPlan floor plan without navigating into `datatypes/`. -2. As a backend engineer, I want to import EPC domain models with `from domain.epc import ...`, so that the import path reflects the conceptual ownership of the type. -3. As a backend engineer, I want EPC vocabulary enums (wall descriptions, roof descriptions, fuel types, etc.) to live in `domain/epc/`, so that all domain vocabulary is co-located with domain models. -4. As a backend engineer adding a new microservice, I want a clear pattern for importing shared domain objects, so that I do not accidentally reach into `datatypes/` for domain types. -5. As a backend engineer, I want the `datatypes/` package to contain only source-data representations, so that I understand it as the anti-corruption layer and not as the domain. -6. As a backend engineer, I want mappers (which transform external shapes into domain models) to live alongside domain models in `domain/`, so that the translation between external and domain is easy to find. -7. As a backend engineer running tests, I want the pytest test paths to reflect the new `domain/` location, so that `pytest` discovers and runs all domain tests correctly. -8. As a backend engineer, I want no backwards-compatibility shims or re-export stubs left behind in `datatypes/`, so that there is one canonical import path for each domain type. -9. As a code reviewer, I want imports from `domain.*` to clearly signal "this is a domain concept", so that the distinction from `datatypes.*` (external data) is immediately readable. -10. As a backend engineer, I want internal references within moved files (e.g. mapper.py importing models.py) to be updated to their new paths, so that no moved module has a stale import. - -## Implementation Decisions - -### Package structure - -A root-level `domain/` package is created alongside `datatypes/`. It contains two sub-packages mirroring the existing subdomain split: - -- `domain/epc/` — all EPC domain objects -- `domain/magicplan/` — all MagicPlan domain objects - -### What moves into `domain/epc/` - -All of the following move from their current `datatypes/epc/` locations: - -- EPC vocabulary enums: `construction_age_band`, `efficiency`, `floor`, `fuel`, `heating_controls`, `hotwater`, `main_heating`, `property_type_built_form`, `roof`, `walls`, `windows` -- EPC domain models and logic: `epc`, `epc_property_data`, `field_mappings`, `historic_epc`, `historic_epc_matching`, `mapper` -- Domain tests (currently under `datatypes/epc/domain/tests/`) - -`domain/epc/__init__.py` re-exports all vocabulary enums (matching the current `datatypes/epc/__init__.py` interface) so call-sites using the package-level import continue to work after the path change. - -### What moves into `domain/magicplan/` - -- Domain models: `models` (Window, Door, Room, Floor, Plan dataclasses) -- Domain mapper: `mapper` (transforms MagicPlan API response into domain models) -- Domain tests (currently under `datatypes/magicplan/domain/tests/`) - -### What stays in `datatypes/` - -- `datatypes/epc/schema/` — versioned RdSAP XML schemas (17.0 through 21.0.1) -- `datatypes/epc/surveys/` — Elmhurst and Pashub site notes shapes -- `datatypes/epc/loaders/` — historic EPC loading logic -- `datatypes/magicplan/api/` — MagicPlan API response types -- `datatypes/datatypes.py` and `datatypes/enums.py` — pre-existing shared primitives (out of scope for this change) - -### Mapper placement - -Mappers live in `domain/` alongside the models they produce. This reflects the view that a mapper is the domain's intake port — the boundary at which external data becomes domain data — and belongs with the domain, not with the external shapes. - -### Import path changes - -| Old import | New import | -|---|---| -| `from datatypes.epc.domain.X import Y` | `from domain.epc.X import Y` | -| `from datatypes.epc.walls import Y` | `from domain.epc.walls import Y` | -| `from datatypes.epc import EpcWallDescriptions` | `from domain.epc import EpcWallDescriptions` | -| `from datatypes.magicplan.domain.models import Y` | `from domain.magicplan.models import Y` | -| `from datatypes.magicplan.domain.mapper import Y` | `from domain.magicplan.mapper import Y` | - -Imports from `datatypes.epc.schema.*`, `datatypes.epc.surveys.*`, and `datatypes.magicplan.api.*` are unchanged. - -### pytest.ini update - -`testpaths` entries for `datatypes/epc/domain/tests` and `datatypes/magicplan/domain/tests` are replaced with `domain/epc/tests` and `domain/magicplan/tests`. - -### No backwards-compatibility shims - -`datatypes/epc/` enum files and `datatypes/epc/domain/` files are deleted after the move. No re-export stubs are left behind. All consumers are updated in the same change. - -## Testing Decisions - -A good test for this change verifies that the domain objects behave identically under their new import paths — not that the files were moved. - -**Modules to test:** - -- `domain/epc/` — existing tests from `datatypes/epc/domain/tests/` cover mapper (`test_from_rdsap_schema`, `test_from_site_notes`) and historic EPC matching (`test_historic_epc_matching`). These tests are moved verbatim; passing them confirms the domain logic is intact. -- `domain/magicplan/` — existing tests from `datatypes/magicplan/domain/tests/test_mapper.py` are moved verbatim. - -**Prior art:** `datatypes/epc/domain/tests/` and `datatypes/magicplan/domain/tests/` are the direct prior art — same test patterns, same fixtures, relocated. - -**Verification grep:** After the change, `grep -r "from datatypes.epc.domain" . --include="*.py"` and `grep -r "from datatypes.magicplan.domain" . --include="*.py"` should return zero results (excluding `__pycache__`). - -## Out of Scope - -- Moving `datatypes/datatypes.py` (`OpenUprnCoordinateData`) or `datatypes/enums.py` (`QuantityUnits`) — these are pre-existing and will be addressed in a future refactor. -- Renaming `datatypes/` to `external/` or any other name — out of scope for this change. -- Moving `datatypes/epc/schema/`, `datatypes/epc/surveys/`, `datatypes/epc/loaders/`, or `datatypes/magicplan/api/` — these are source-data shapes and stay in `datatypes/`. -- Adding new domain objects or changing domain logic — this is a structural move only. -- Introducing Python packaging (`setup.py`, `pyproject.toml`) changes beyond `pytest.ini`. - -## Further Notes - -- `pytest.ini` sets `pythonpath = .`, so `domain/` at the repo root will be importable immediately without additional configuration. -- `datatypes/epc/__init__.py` currently aggregates enum exports via `__all__`. The equivalent `domain/epc/__init__.py` should preserve this interface so call-sites using `from datatypes.epc import EpcWallDescriptions`-style imports need only a path change, not a restructuring. -- ~40 files across `backend/`, `etl/`, and `scripts/` import from `datatypes.epc.*` domain paths. ~10 files import from `datatypes.magicplan.domain.*`. A single `sed` pass or IDE rename refactor covers the bulk; the verification grep confirms completeness.