assessment-model/src/app/api/postcode
Khalim Conn-Kowlessar 8a0ad0c0dc feat(postcode-search): routes, add-properties page, PropertyTable entry point
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>
2026-07-06 14:33:22 +00:00
..
[postcode] added lpi as additional dataset for ordnance survey to retrieve full results 2025-11-07 14:03:35 +00:00
FormatOsResults.ts missing files 2025-10-23 11:49:04 +01:00
LookupOsPlaces.ts feat(postcode-search): routes, add-properties page, PropertyTable entry point 2026-07-06 14:33:22 +00:00
LookupPostcode.ts feat(postcode-search): routes, add-properties page, PropertyTable entry point 2026-07-06 14:33:22 +00:00
OsPlacesToFlat.ts validated postcodes 2025-10-23 18:22:31 +00:00