fix(backend): survive un-migrated databases and cap prompt-bound fields
Two backend hardenings from the PR #365 review, both in user.ts. ── 1. Profile reads on databases without the 20260821 migrations ── WHY THIS MATTERS Replicated live by dropping the six new user_profiles columns (the state of any deployment that updates the backend before running migrations): GET /user/profile returned 200 but the user's saved legal_research_us=false and quick_actions_visible=false came back as true, model preferences fell back to defaults, and PATCH /user/profile returned a raw 500 leaking PostgREST internals. Settings appeared to reset themselves. WHAT IS THE FALLBACK-TIER CASCADE selectProfile tolerates older databases by retrying with smaller column lists. Each tier is entered by matching the NAME of its newly added column inside the Postgres 42703 (undefined column) error. Postgres reports only the FIRST unknown column - after this PR that is "jurisdiction" - so none of the existing tiers matched and the code fell through to a select that predates the model/research/quick-action columns, then papered over the gap with defaults. HOW THE FIX WORKS A new first tier keys on any of the six 20260821 columns and retries with PROFILE_SELECT_NO_ONBOARDING - the exact pre-PR column list - so every previously saved preference survives. serializeProfile already treats the absent onboarding fields as "legacy exempt" (version 0), which matches what the migration's backfill would write, so existing users are not funneled into onboarding by a missing migration either. getUserModelSettings gets the same treatment: on 42703 it retries with the pre-migration three-column select instead of silently switching every chat to default models and re-enabling US legal research. The test harness's per-table stub now accepts a queue of results so a test can express "first select fails with 42703, the retry succeeds", and a regression test pins the preserved preferences. ── 2. 200-character cap on displayName / organisation ── WHY THIS MATTERS This PR starts injecting both fields into the system prompt of every chat, project chat, and Word chat turn. Every other personalisation field is bounded (jurisdiction <= 100, practice areas <= 20 x 100, titles allowlisted), but these two only had a cap inside the signup trigger - PATCH /user/profile accepted arbitrary sizes, letting one oversized value inflate token cost on every message thereafter. HOW THE FIX WORKS validateProfilePayload rejects values over 200 characters (the same limit handle_new_user applies via left(..., 200)), with tests for both fields. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RuPCULDYgVsiCanRgbEy6W
| Repository | open-legal-products/mike |
|---|---|
| Author | Amal <mamalanand3@gmail.com> |
| Authored | |
| Parents | 64f2e625 |
| Stats | 3 files changed , +153 , -6 |
| Part of | Add Google sign-in and personalised onboarding |
Capture this commit into my fork
Download a Markdown prompt that tells Claude how to port this
exact commit into your working tree. Run it via
claude -p < capture-commit-3f9b9b9d.md
from inside the repo you want the change in.