- Order address candidates naturally so Flat 2 sorts before Flat 10
(TDD'd in the domain core; numeric locale compare).
- Disable spell check / autocomplete / autocorrect on the postcode input.
- Long result lists and the tray's postcode chips now scroll inside
their containers instead of growing the page.
- gitignore docs/wip/** and untrack the postcode-search handover doc.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Completes the add-properties-by-postcode journey (ADR-0007) on top of the
TDD'd domain core:
- GET /api/portfolio/[id]/properties/search?postcode= — postcodes.io for
validation + geography (admin_district, parliamentary_constituency) every
time; OS Places through the 30-day postcode_search read-through cache
(refresh=1 bypasses it). Returns candidates with alreadyInPortfolio flags
from one grouped uprn query. Cache reads accept legacy space-less keys;
writes use the canonical spaced form.
- POST /api/portfolio/[id]/properties — re-derives facts server-side from
classification codes (client propertyType never trusted), then one
transaction: property rows via uq_property_portfolio_uprn ON CONFLICT DO
NOTHING, vocabulary upserts with os_places provenance (DO NOTHING preserves
user rows; snapshots mirror the resolved value), property_overrides
snapshots (building_part 0, original description = OS code), and
property_details_spatial per-property coordinates. Returns {added, skipped}.
- OS Places fetches now request output_srs=EPSG:4326 so records carry
LAT/LNG (no mapper read the BNG X/Y coordinates).
- /portfolio/[slug]/properties/add built to the approved mockup: search card
with cache-age line, per-postcode result cards, cross-postcode selection
tray, done state. TanStack Query v4, no useEffect/useMemo.
- "Add properties" dropdown beside Export in PropertyTable (search by
postcode + bulk excel import "Soon"); toolbar AddNew dropdown retired.
- New display/cache helpers (describeCandidate, postcodeCacheKeys,
cacheAgeDays) TDD'd in the domain core.
Verified live against portfolio 814: search (cache + refresh), submit
(added 2, all four write layers checked in DB), dedup re-submit (skipped 2),
alreadyInPortfolio flags, page + dropdown render.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
TDD'd (9 tests): postcode normalisation to canonical form; the ADR-0007
deterministic OS classification mapping (RD02/03/04/06/07; other
residential codes selectable with no facts, Unknown never written;
RD10 + non-RD unselectable); 30-day cache freshness for postcode_search;
DPA-preferred UPRN-deduped address candidates with postcode-stripped
title-case addresses; buildWritePlan producing the property row
(incl. local_authority/constituency from postcodes.io — closing the
no-source gap) and 0-2 property_overrides facts keyed to the OS code.
Adds 'os_places' to OverrideSourceValues — enum migration still needs
generating via generate_migration.sh before deploy.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>