* fix(bookkeeping): verifikat views show company account names for off-catalog accounts
Verifikat views (entry detail, JournalEntryList, StrikeLinesDialog,
CorrectionPreview) rendered AccountNumber without a name source, so
accounts outside the BAS 2026 catalog (typically SIE-imported, e.g. a
legacy 1580) showed a blank Benamning even though the company's
kontoplan has the name.
AccountNumber now falls back to a session-cached map of the company's
own chart-of-accounts names (one fetch per page load, inactive accounts
included for historical verifikat). Precedence: explicit name prop,
then the company map, then the BAS reference name, keeping the
PR #1968 rule that user-editable chart rows win over hardcoded copy.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N1rcRYRM8DyVp48mp5NNVc
* refactor(bookkeeping): read company account names via the shared reference-data cache
The check:guards raw-reference-fetch ratchet rightly rejected the
hand-rolled session cache: lib/reference-data/hooks.ts already provides
useAccounts with a per-company SWR cache seeded by the dashboard layout.
AccountNumber now derives the company name from useAccounts(false)
instead, and the bespoke hook and its tests are removed.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N1rcRYRM8DyVp48mp5NNVc
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
The hardcoded ACCOUNT_DESCRIPTIONS entry labeled 1580 'Fordran for skatt'
with a Skatteverket explanation. That is wrong on both counts: tax
receivables are 1640 (skattefordringar) / 1650 (momsfordran), and 1580
was traditionally 'Fordringar for kontokort och kuponger', which BAS has
since moved to 1686 (why 1580 is excluded from our BAS 2026 catalog).
Reported by a user who books card/Swish settlements there.
Also flip AccountNumber display precedence to the company's own
account_name over the hardcoded reference name: chart rows are
user-editable data and must not be visually overridden by our copy.
The tooltip keeps showing the BAS reference info.
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* perf(bundle): drop the BAS chart and the Node crypto polyfill from the shared client baseline
Two chunks rode along in the first-load JS of almost every dashboard route:
the full BAS 2026 chart (315 KB uncompressed, in 81 route manifests) and
the browser polyfill for Node's crypto/vm/Buffer (327 KB, in 26 routes
incl. login and register). Neither was needed on first paint; both got
there through static imports of helpers that happen to live next to code
that needs the data or the builtin.
Node polyfill (4 pure splits, behaviour unchanged, re-exported from the
original modules for server callers):
- lib/auth/bankid-flags.ts: isBankIdEnabled (login, register, security
settings imported it from bankid.ts, which imports crypto).
- lib/import/bank-file/formats.ts: the format registry + detection (the
import history imported getFormat from parser.ts, which hashes).
- lib/salary/personnummer-format.ts: parsing/validation/formatting (the
employee forms reached the encrypting personnummer.ts via tax-column).
- lib/auth/api-key-scopes.ts: scope catalogue, groups, tool map, helpers
(the API key panel imported STAGING_SCOPES from the key generator).
BAS chart:
- lib/bookkeeping/bas-lazy.ts + use-bas-reference.ts: the chart becomes a
dynamic import, fetched once per session after first paint; components
that show BAS names/descriptions call useBasReference() and re-render
when it lands. Until then (and on the server) only the hardcoded
account-descriptions answer, so SSR and hydration agree.
- lib/bookkeeping/bas-labels.ts: class/group labels out of bas-reference.ts
(account-descriptions needed a label and paid for the whole chart).
- lib/bookkeeping/bas-account-numbers.ts (generated, ~11 KB) +
scripts/generate-bas-account-numbers.ts (--check) + parity test:
isStandardBASAccountNumber for AddAccountDialog/ChartOfAccountsManager.
- lib/bookkeeping/account-classifier-{heuristic,client}.ts: the BAS-aligned
heuristic shared by the server classifier and a client variant that uses
the lazy chart.
- lib/bookkeeping/invoice-accounts.ts: INVOICE_FX_RATE_MISSING,
InvoiceFxRateMissingError, getRevenueAccount, getOutputVatAccount out of
invoice-entries.ts, whose engine import pulled account-backfill and the
chart into SendInvoiceDialog/PaymentBookingDialog.
- CorrectOpeningBalanceDialog re-seeds names when the chart lands;
OpeningBalanceRowEditor builds its Fuse indexes lazily; the
ChartOfAccountsManager BAS-katalog tab awaits the chunk.
Tooling:
- scripts/perf/client-import-closure.mjs: static import closure of every
'use client' module with the shortest chain to a target (file or bare
specifier); found every path above without a build.
- scripts/checks/client-node-builtin.mjs wired into check:guards: a client
module reaching a Node builtin is a hard failure (0 today).
Left as is: invoices/[id], its credit page and SendInvoiceDialog still
reach the chart through lib/invoices/issue-credit-note -> invoice-entries
-> engine -> account-backfill; splitting the engine is out of scope here.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(perf): unambiguous import-edge regex in the closure walker (CodeQL js/redos)
One quantifier per span: a greedy [^'"]* up to the specifier quote, which it
cannot cross, so a run of whitespace has a single parse. Same edges as
before (multi-line named imports, re-exports, side-effect imports; type-only
imports still skipped).
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>
Raw palette: SalaryCalendar was the only file in the salary cluster still
on bg-red-100 / text-amber-800 style classes, with zero dark: variants, so
every absence pill rendered paper-white on a near-black page. All 30 are
now alpha-over-token on the semantic scale, which needs no dark: variant
(the approach badge.tsx already takes). Eight absence types share four
tones, so fill carries a second axis: filled vs outlined separates the
types whose Lucide icon is identical (Heart is parental, pregnancy and
care_relative; Activity is study and other_leave).
Primitives:
- select and dropdown-menu now scale from their trigger via the Radix
transform-origin variables instead of from their own middle. Dialog stays
centred: modals are not anchored to a trigger.
- toast used fade-out-80, the one animate-* class with no @utility in
globals.css, so --tw-exit-opacity fell back to 1 and the toast slid away
at full opacity. Enter and exit now also share one path per breakpoint
(top on mobile where the viewport is a full-width bar, right on desktop
where it is a corner card) using max-sm:/sm: rather than stacking both,
which would have produced a diagonal.
- slide-over exited on ease-in, which delays the moment the user has
already decided to leave; it enters on the drawer curve and now leaves
on it too.
- progress animated transition-all where only transform changes.
- One app-wide TooltipProvider in the root layout. skipDelayDuration is
provider-scoped, so a provider per instance meant the grace window could
never fire and every account number in a huvudbok re-paid the full 200ms.
Also: nine hand-rolled animate-pulse placeholders in three different greys
to the Skeleton primitive, 25 CardTitle text-lg to the locked text-base,
two always-on chips to muted text (a chip on every row is not an
exception), the three extensions titles onto the display face, the help
filter chips onto pill geometry, and the dead border-border/60 on the
/import row.
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Add LICENSE (AGPL-3.0-or-later), CONTRIBUTING.md, SECURITY.md, DCO, and NOTICE files.
Rewrite README for open-source audience with self-hosting instructions.
Redesign color palette to grayscale chrome theme across all components.
Add transaction uncategorize API route with tests.
Fix VAT account name mismatches in migration 052.
Improve import page with SIE file support and loading skeleton.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Expand BAS reference from ~180 to ~1,276 accounts (full BAS Kontoplan 2026)
with K2 exclusion flags, per-class data files, and computed SRU codes
- Evolve invoice inbox into unified document inbox handling invoices, receipts,
and government letters with AI-powered classification (Claude Haiku Vision)
- Add multi-pass document-to-transaction matching engine with greedy assignment
for both supplier invoices (reference/amount/date/name) and receipts
(weighted amount/merchant/date scoring)
- Add supplier invoice matching in transaction ingest pipeline
- Inject booking template suggestions into AI extraction prompts
- Surface matched documents in swipe categorization UI with one-tap booking
- Auto-activate missing BAS accounts during SIE import against full reference
- Add K2 filter toggle in Chart of Accounts manager
- Add receipt confirmation route with BFNAR representation fields
- Add database migrations for K2 support and document matching columns
- Remove obsolete extension migration scripts
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add modal review/confirmation dialogs before submitting invoices, supplier
invoices, and journal entries. Since journal entries are legally immutable
once posted, users now see a full summary with an amber warning before
confirming. Add AccountNumber component with rich tooltips showing account
name, class, type, and plain-language Swedish explanation for ~45 key BAS
accounts across all report views.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>