fix(customers): personnummer guard + personal_number on v1 + payment terms from settings (#1724)
* fix(customers): stop personnummer landing unmasked as org_number, persist personal_number on v1, default payment terms from settings
Closes #1707. Closes #1708.
Personnummer (#1707, Discord kalletoxic):
- CreateCustomerSchema rejects an org_number shaped like a Swedish
personal identity number on business customer_types. Only
customer_type=individual rows are masked in lists, so accepting one
stored an unmasked personal identifier (GDPR art. 5.1 c). The shape
check uses the month-position rule (legal-entity orgnr always
carries >= 20), so real orgnr can never false-positive.
- The v1 create, v1 PATCH and bulk-create endpoints accepted
personal_number through the shared schema but silently dropped it.
They now store it encrypted, expose it masked (********-1234) on the
single-customer surfaces, and treat the masked form as unchanged,
mirroring the internal routes.
- Route-level guards on both PATCH routes (new 400
CUSTOMER_ORG_NUMBER_IS_PERSONAL) plus a client-side message in
CustomerForm (sv + en).
Payment terms (#1708, Discord kalletoxic):
- New resolveDefaultPaymentTerms: provided value, else
company_settings.invoice_default_days, else 30. Wired into the UI
new-customer dialog, the internal POST, v1 create (incl. dry-run),
bulk-create and the MCP staged create_customer.
apiskill regenerated; no migrations.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* docs: record what the CI build OOM actually was
main raised the build heap to 8192 in parallel with this branch, so the
fix itself is already in and this keeps it untouched. What was missing
is the diagnosis.
Measured with tsc --noEmit --extendedDiagnostics, type-checking the repo
needs 4 192 550 K at 506d030b and 4 187 096 K on this branch, 5 MB less
and 0.26% more instantiations. So the ceiling is the type-check pass at
steady state against Node 20's ~4 GB default old-space, not bundle
growth and not any single PR. Worth writing down so the next person who
sees "Ineffective mark-compacts near heap limit" does not go looking for
it in their own diff.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Jakob Wennberg <311770904+jakobwennberg-oss@users.noreply.github.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
Jakob Wennberg
parent
9fc05c383f
commit
e6c4fe2cf8
@@ -1099,3 +1099,8 @@ One line per decision: `[YYYY-MM-DD] <decision>: <why>`. Appended by agents and
|
||||
[2026-08-19] Notices Option A (contextual AttnLine slot fed by lib/notices) over a global layout notice strip: reuses convention 6 instead of adding a second piece of persistent chrome that could itself stack; Option B stays a founder call.
|
||||
[2026-08-19] notice_dismissals is server-side per (company, user, notice_id): dismissals must work cross-device and stay personal (a colleague still sees the notice), unlike the localStorage pattern SkatteverketPromoCard uses (left as-is here, follow-up).
|
||||
[2026-08-19] Notice ids embed a state discriminator (connection id + status/expiry/error timestamp) instead of a snooze timestamp: a dismissal hides exactly the state the user saw, and a NEW failure mints a new id that surfaces without any clock logic.
|
||||
|
||||
[2026-08-19] Personnummer-shaped org_number is REJECTED (400) for business customer_types instead of silently accepted or soft-warned: masking only exists on individual rows, so accepting it stores an unmasked personal identifier (GDPR art. 5.1 c); the month-position rule (orgnr always >= 20) makes the shape check false-positive-free. Enskild firma customers must be created as customer_type=individual.
|
||||
[2026-08-19] New-customer payment terms fall back to company_settings.invoice_default_days (then 30) in every create path (UI, internal API, v1, bulk, MCP staged op) via lib/customers/resolveDefaultPaymentTerms, rather than adding a separate customer-terms setting: one setting, one meaning, and the invoice flow already reads the same column.
|
||||
|
||||
[2026-08-19] The CI build OOM is the TYPE-CHECK pass, not bundle growth: measured with tsc --extendedDiagnostics the repo needs ~4.19 GB at 506d030b and ~4.19 GB on a branch on top of it, i.e. a steady-state ceiling against Node 20 default old-space (~4 GB), not any one PR's regression. Fixed on main independently by raising the build heap to 8192, which this branch keeps; recording the measurement so the next person does not go hunting in a diff. Vercel builds already run with a larger heap and were never affected.
|
||||
|
||||
Reference in New Issue
Block a user