mirror of
https://github.com/Hestia-Homes/assessment-model.git
synced 2026-07-19 17:02:59 +00:00
58 lines
3.6 KiB
Markdown
58 lines
3.6 KiB
Markdown
# 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 + 0–2 override facts).
|
||
- **ADR-0007** (`docs/adr/`) — all decisions + rationale. `docs/adr/**` gitignore rule removed
|
||
(it had eaten ADRs 0004–0006; 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.
|