assessment-model/docs/wip/postcode-search-handover.md
Khalim Conn-Kowlessar 302e200ed6 docs: handover for postcode-search build continuation
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 13:38:54 +00:00

58 lines
3.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Handover: Add properties by postcode search
**Branch:** `feature/add-properties-by-postcode` (2 commits pushed, tree clean).
**Context date:** 2026-07-06. **Goal journey:** add properties → create scenarios (done, PR #353) → trigger modelling (soon).
## State
Done and verified (`npx tsc --noEmit` clean, 329 tests pass):
- **Domain core** `src/lib/postcodeSearch/model.ts` + `model.test.ts` (9 tests):
`normalisePostcode`, `classifyOsCode`, `isCacheFresh` (30-day), `toAddressCandidates`
(DPA>LPI, UPRN-dedup, postcode-stripped title-case address), `buildWritePlan`
(property row + 02 override facts).
- **ADR-0007** (`docs/adr/`) — all decisions + rationale. `docs/adr/**` gitignore rule removed
(it had eaten ADRs 00040006; ask team if recoverable).
- **CONTEXT.md** — "Postcode search" entry; VocabularyMapping now has two producers.
- `os_places` added to `OverrideSourceValues` (schema only — **migration not yet generated**).
- **Approved design mockup** (build the page to this): https://claude.ai/code/artifact/d05a3ab0-48ed-41c3-94b4-b13106b7f372
## Remaining work (in order)
1. **Enum migration**: run `./generate_migration.sh` for `override_source` + `os_places`
(no `.sql` migrations live in-repo; script is repo-root).
2. **Routes** under `src/app/api/portfolio/[portfolioId]/properties/`:
- `search/route.ts` GET `?postcode=`: normalise → `postcode_search` cache read
(`isCacheFresh`; row has unique `postcode` + jsonb `resultData`) → on miss/stale call
`lookupPostcode` (`src/app/api/postcode/LookupPostcode.ts`; **add
`parliamentary_constituency` to its result type**) + OS pages fetch
(`LookupOsPlaces.ts`) → upsert cache → return `toAddressCandidates` + geo +
`alreadyInPortfolio` flags (one query: uprns in portfolio) + cache age.
- `route.ts` POST submit `{candidates, geo}` (re-validate server-side): transaction over
`buildWritePlan` rows — insert `property` `ON CONFLICT DO NOTHING` (partial unique
`uq_property_portfolio_uprn`), upsert `landlord_property_type_overrides` /
`landlord_built_form_type_overrides` (`(portfolio_id, description)` unique,
description = OS code, source `os_places`), insert `property_overrides` snapshots
(`building_part=0`, `original_spreadsheet_description` = OS code). Return
`{added, skipped}`. Next-15 rules: `await params`, `{ error }` shape.
3. **Page** `/portfolio/[slug]/properties/add` + **"Add properties" dropdown** beside Export
in `src/app/portfolio/[slug]/components/PropertyTable.tsx` ("Search by postcode" +
"Bulk excel import — Soon"). Then retire toolbar `AddNew` dropdown. TanStack Query v4
mutations; no useEffect/useMemo (CLAUDE.md).
## How to verify (patterns proven this session)
- DB: `.env.local` creds; NODE_PATH node scripts with `pg` (`ssl:{rejectUnauthorized:false}`).
- Live app: `./node_modules/.bin/next dev -p 3111`; mint a session cookie with
`next-auth/jwt` `encode` + `NEXTAUTH_SECRET` from `.env.local`, email `@domna.homes`,
cookie `next-auth.session-token`. Server-rendered data is greppable in the RSC payload.
- Test portfolio: **814** (new-approach). Searched-in properties will render blank/awaiting
modelling — that's by design (ADR-0007), not a bug.
- `OS_API_KEY` env var powers OS Places.
## Gotchas
- Properties inserted now are "new approach" (`updated_at >= 2026-06-01`, `epcSources.ts`) —
every read path expects an EPC graph that won't exist until modelling. Expected.
- Never per-scenario/per-property probe loops on `plan` (1.6M rows) — grouped/scoped queries
only (see `docs/wip/new-modelling-ui-handover.md` perf notes).
- PR #353 (Scenarios tab) is separate, open; its ADR is numbered 0003.