* fix(analytics): mask session replays by default, chrome-only unmask
Invert PostHog session-replay masking from visible-by-default with pattern
masking to deny-by-default: every input value is masked wholesale (rrweb
maskAllInputs, no maskInputFn) and every text node is masked unless it sits
under data-ph-unmask chrome or a table column header (th). Chrome tags live
on the shared UI primitives (PageHeader, Label, Button except combobox
triggers, TabsTrigger, Badge, Card/Dialog/Sheet titles, tooltips, help
popovers, empty states, settings labels), and tagged chrome is still
pattern-scrubbed for amounts and person-/organisationsnummer. data-ph-mask
beats data-ph-unmask, so call sites that interpolate user data into chrome
stay masked; a very-thorough audit swept every unmasked primitive and each
found site got a call-site mask. Confirm-dialog wrappers and toasts stay
masked centrally: their copy describes user objects by design. Untagged new
UI over-masks instead of leaking. Privacy policy, RoPA and decision log
updated in the same change.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(analytics): tag detail-section chrome merged from main
The register-detail primitives landed on main after the replay-masking
audit ran: kickers and DefRow labels are static i18n chrome, values stay
masked.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(analytics): close skeptic and review findings on replay masking
Explicit data-ph tags now resolve before the th chrome fallback, so a th
nested inside a data-ph-mask container masks correctly (regression test
added). Seven missed text-leak sites get call-site masks: delete-invoice
and credit-page invoice numbers, IB-correction voucher reference, TIC
orgnr (served unnormalized, so the separator-based scrub cannot be relied
on), articles search-term empty state, dimension segment labels, and
activate-account buttons. The attribute channel is closed with rrweb's
blockClass: inputs whose placeholder carries an effective user value
(salary overrides, correction description, danger-zone confirms, credit
confirm) get ph-no-capture, removing the element from recordings while
the prefill UX stays intact; the pivot-th title attribute is dropped.
Privacy-policy effective date bumped to 2026-08-17.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Seven radii were in circulation (4/5/6/8/12/16px + pill) with no rule for
which went where; one toolbar row on /transactions mixed four shape
languages. This locks a 4-tier ladder (design.md convention 16):
- pill: interactive toolbar controls (buttons, chips, pickers, segmented
controls, toolbar search, count nubs)
- rounded-xl (12px): overlay tier: page panel, dialogs, slide-overs
- rounded-lg (8px): cards, form fields, popover/menu content, boxes
- rounded-sm (4px): nested leaves (menu items, checkboxes, kbd/code nubs)
Changes:
- New SegmentedControl primitive (pill-in-pill tablist, h-8) replaces the
hand-rolled bg-muted/70 tablist copied across 11 files
- New ToolbarSearch primitive (pill, h-8) adopted on 9 page toolbars;
dialog/picker searches keep the rounded-lg Input
- dialog.tsx 8px -> 12px, matching SettingsModal/slide-over/CommandPalette
- ContextPicker chips at the shared h-8 toolbar height
- ~300 rounded-md / bare rounded call sites remapped by role; auth icon
tiles and the mobile nav sheet come down from 16px to 12px
- rounded-md, bare rounded, rounded-2xl and rounded-[Npx] are dead
vocabulary, enforced by a new off-ladder-radius check in check:guards
Verified: lint 0 errors, 14422 unit tests pass, check:guards green, tsc
clean on all changed files, sandbox screenshots of transactions/
bookkeeping/granskning toolbars and the Ny verifikation dialog.
Co-authored-by: Jakob Wennberg <311770904+jakobwennberg-oss@users.noreply.github.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
The founder flagged the app as bloated with standing instructional text.
Ny verifikation: the what's-missing lines (Ange en beskrivning, Minst
två rader...) rendered from the first frame because their only gate was
form validity, which an empty form fails: instructions dressed as
validation. The submit buttons now stay enabled and an attempt on an
incomplete form is what surfaces the lines, in destructive red, per the
error-on-submit idiom. The Enter-to-advance flow keeps the old
completeness predicate so navigation is untouched.
Matcha mot befintlig verifikation: the two-sentence explainer moved
behind a ? (HelpPopover, convention 7), the N:1 note tightened, the
Visa även matchade switch became a quiet link (switches are settings
idiom), and Stark träff, the normal auto-selected case, renders as
muted text instead of a chip (chips mark exceptions, convention 5).
Deleted always-visible paraphrase lines and their orphaned keys:
items_card_description, picker_description, references_subtitle,
sort_stack_hint, dimensions hints, document_help, and the dead
fill_balance_hint key that had no render site at all.
Co-authored-by: Jakob Wennberg <311770904+jakobwennberg-oss@users.noreply.github.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Em dashes (—) and en dashes (–) had spread across comments, docs, tests,
and a few UI strings, reading as AI-generated boilerplate rather than
house style. Replaced each with punctuation matching its context: colon
for explanatory clauses, comma for asides, plain hyphen for numeric/legal
ranges (e.g. "21-23§"), "to"/"till" for date ranges, parentheses for
paired-dash asides. messages/en.json and messages/sv.json were fixed by
hand together to keep sv/en in sync.
Left untouched where the dash is the functional subject rather than
decorative punctuation: date-range-parser.ts's separator regex,
charset-repair.ts's CP1252 byte-mapping table (and its test), the SIE
encoding mojibake docs, generic-csv.ts's minus-sign normalizer, the
agent system-prompt files that already instruct against em dashes, and
a golden iXBRL test fixture compared byte-for-byte.
Also fixes two bugs surfaced along the way: an off-by-one in
ApiKeysPanel's scope-label split (a leftover from an earlier partial
pass), and a charset-repair test that had lost the literal en-dash it
exists to verify.
Regenerated the agent atom seed migration (skills:generate) since 27
SKILL.md files changed. Added a CLAUDE.md rule against em/en dashes,
with an explicit carve-out for the functional-dash cases above.
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
Bundles three separable concerns:
- style(ui): badge audit + cleanup across 45 files — real-status chips use Badge variants (raw Tailwind colors dropped), non-status count/type/label chips demoted to muted text, clustered badges consolidated; 20 unused imports removed.
- feat(bookkeeping): Kontoplan moved to a dedicated /chart-of-accounts route (nav + command palette wired); /bookkeeping shows the journal list only.
- chore(skills): loop-* automation skills + design-scan workflow under .claude/.
fix(reports): restored the destructive count badge on blocking errors in the periodisk sammanställning (EC Sales List) — a genuine status cue the audit had wrongly flattened; flagged by the PR reviewer and Swedish compliance bot, now clean.
All CI green; compliance bots report no findings.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(inbox): re-add Bokför manuellt on unmatched documents
Pilot feedback: a document in Dokumentinkorg could not be booked
without first matching it to a bank transaction, which is impossible
for cash expenses and other entries with no bank movement. The
backend (/items/:id/book-direct) and BookDirectlyDialog already
support standalone booking — re-expose the button in the unmatched
state. The dialog still offers optional transaction selection inside.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat(transactions): pick existing inbox document when booking manually
Pilot feedback: "Bokför manuellt" from a transaction only allowed
uploading new files — an already-uploaded underlag from the inbox
could not be attached. Add a select mode to InboxDocumentPicker
(onSelect prop; journalEntryId now optional) and mount it in
TransactionBookingDialog: picked documents are linked after the
journal entry is created via /api/documents/{id}/link with
inbox_item_id, which also stamps the inbox item as consumed so it
drops out of every pending surface. Non-ok link responses now count
toward the failure toast (previously only network errors did).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(documents): address PR #670 review — stale preview dialog, JE tenancy check
Review findings:
- InboxDocumentPicker left the preview dialog floating open when a pick
was confirmed from inside it (previewItem was never cleared before
onClose; the component stays mounted, so the on-open reset never ran).
Clear it in both select and link mode. (greptile)
- linkToJournalEntry verified the document's company but trusted the
client-supplied journal_entry_id (FK only requires existence). Add an
explicit company-scoped journal entry lookup; misses map to the
existing DOC_LINK_ENTRY_NOT_FOUND envelope. RLS prevented any data
leak either way — this makes the rejection explicit. New regression
test covers the cross-tenant case. (compliance-swarm A.8.28)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat: implement inbox document picker and linking functionality
* feat: implement self-billing invoice functionality
- Added support for registering self-billed invoices received from customers.
- Updated the invoice schema to include fields for self-billing metadata such as `is_self_billed`, `external_invoice_number`, `self_billing_agreement_ref`, and `received_date`.
- Created API route for handling self-billed invoice submissions, including validation and error handling.
- Implemented database migrations to add necessary columns and constraints for self-billing invoices.
- Developed tests to ensure correct behavior of self-billing invoice creation and validation rules.
- Updated Swedish localization files to include new terms related to self-billing.
* feat: enforce SIE import requirement for non-Fortnox providers in migration process
* feat: streamline invoice processing and enhance error logging across APIs