diff --git a/docs/wip/landlord-override-frontend-plan.md b/docs/wip/landlord-override-frontend-plan.md new file mode 100644 index 0000000..a26deb4 --- /dev/null +++ b/docs/wip/landlord-override-frontend-plan.md @@ -0,0 +1,107 @@ +# Landlord override frontend — in-flight design notes + +**Status:** Paused mid-grilling (2026-05-27) +**Branch:** `feautre/additional_walltypes` +**Author:** Jun-te (with Claude, via `/grill-me`) + +This is a *design-in-progress* document, not an ADR. It captures decisions made +so far on the landlord-override frontend plan so the conversation can resume +without re-litigating settled questions. Promote to an ADR once the trigger +mechanism (Q4) is resolved — that's the decision worth permanent recording. + +## Goal + +Build the front-end e2e for `landlord_description_override`, starting from the +`bulk_upload` flow. Backend lives at `/workspaces/home/github/Model`. + +## Backstory + +- Four landlord override tables exist in Drizzle + ([src/app/db/schema/landlord_overrides.ts](../../src/app/db/schema/landlord_overrides.ts)): + `landlord_property_type_overrides`, `landlord_built_form_type_overrides`, + `landlord_wall_type_overrides`, `landlord_roof_type_overrides`. Schema + rationale in [ADR-0002](../adr/0002-landlord-override-vocabulary.md). +- Nothing in Next.js reads or writes them yet. +- The Python lambda at + `/workspaces/home/github/Model/applications/landlord_description_overrides/handler.py` + is **not deployed** and **not wired** into the BulkUpload pipeline. It + hardcodes its trigger params (`portfolio_id`, `s3_uri`) and its source column + names (`"Property Type"`, `"Walls"`, `"Roofs"`). +- Note: ADR-0002 says writes come from Next.js POST, but the current backend + writes direct to Postgres. This drift may need to be revisited under Q4. + +## Decided so far + +### Q1 — Scope + +**Trigger + Review/Edit, with classifier non-blocking for address matching.** +Restated by user as: extend the column-mapping UI with optional +landlord-description slots → persist the mapping on the upload → pass mapping +to the lambda → lambda needs edits to work when deployed. + +### Q2 — Categories + +**All four classifier categories** get independent optional slots in +[`INTERNAL_FIELDS`](../../src/app/portfolio/[slug]/(portfolio)/bulk-upload/[uploadId]/map-columns/MapColumnsClient.tsx#L14-L21): +`property_type`, `built_form_type`, `wall_type`, `roof_type`. + +Rejected alternatives: (a) start with only PT+BF — wasted plumbing churn for +the same migration cost; (c) collapse PT+BF into one UI slot — bakes a +backend coincidence (they read the same CSV column today) into the +user-facing model. + +### Q2.1 — No `autoDetect` for the new slots + +The four new slots default to `"skip"`. The user must explicitly map them. +`autoDetect()` regex patterns are for required address-ish fields only. + +**Why:** Address headers are unambiguous and required, so guessing is safe and +useful. Landlord-description columns are ambiguous (a "type" column could be +PropertyType or BuiltFormType or something else) and they are optional — +auto-detecting them would silently opt the landlord into classifier runs they +didn't intend. + +## Open — resume here + +### Q3 (in flight) — Uniqueness validation on the mapping + +Today validation only checks required fields exist +([MapColumnsClient.tsx:67-68](../../src/app/portfolio/[slug]/(portfolio)/bulk-upload/[uploadId]/map-columns/MapColumnsClient.tsx#L67-L68)); +two CSV headers can both map to `address_1` silently. + +- (a) Leave it alone — backend last-wins. +- (b) Enforce uniqueness only on the four new slots. +- (c) Enforce uniqueness everywhere except `skip`. **Recommended.** + +### Q4 (queued — biggest) — Trigger mechanism + +How does Next.js invoke the lambda once mapping is complete? SQS message? +Direct lambda invoke? HTTP endpoint? And what's the state-machine integration — +new `BulkUpload` status, or runs orthogonally to address matching? + +This drives both the deployment work and the lambda edits. Likely worth its +own ADR once decided. + +### Q5 (queued) — Persistence of the extended mapping + +Current `bulkAddressUploads.columnMapping` is a `Record` and +naturally accommodates the new slots. Confirm no separate table is needed. + +### Q6 (queued) — Lambda edits + +Handler hardcodes `source_column="Property Type" / "Walls" / "Roofs"`; needs +to read the mapping from the trigger body. +`LandlordDescriptionOverridesTriggerBody` already exists — check what fields +it has vs needs. + +### Q7 (queued) — Review/Edit UI for classified mappings + +Is the per-row review/edit surface in scope for this iteration, or deferred? +User has not addressed yet. ADR-0002 calls this "the future override +frontend" and treats it as deferred work — but "front end e2e from +bulk_upload" could reasonably include it. + +## Resuming + +Re-read this file, then ask Q3. Don't re-litigate Q1/Q2 unless the user +reopens them.