* fix: add rounding tolerance to INK2 balance check and clarify warnings
INK2/SRU rounds each ruta independently to whole kronor, so with 11+
rutor the accumulated rounding can produce a 1-2 kr difference that
triggered a false "balance sheet not in balance" warning. Add a 2 kr
tolerance. Also clarify the unclosed fiscal year warning to indicate
that generation still works.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: also warn when equity/liabilities exist but assets are zero
Address Greptile review feedback — the balance check guard should
trigger when either side has a non-zero total, not only when assets > 0.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: support Nordea Datum CSV variant and add bank sync loading screen
Add 4th Nordea Business CSV format variant that uses standalone "Datum"
column header and YYYY/MM/DD date format. Also replace fire-and-forget
bank sync with an awaited flow showing a loading screen after first
bank connection, preventing users from navigating away before sync
completes.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: address PR review feedback — cleanup timeout, deps, naming
- Clear success setTimeout on unmount via useRef to prevent stale updates
- Add isSyncing to useEffect dependency array for Strict Mode safety
- Rename headers_detect to headersDetect (camelCase consistency)
- Remove redundant toLowerCase() since firstLine is already lowercased
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Previously the mobile deep link used the current URL as redirect,
causing BankID to open a new browser tab after auth instead of
returning to the original. Now uses redirect=null so the user
switches back manually and the polling picks up completion.
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: add BankID authentication via TIC Identity API
Integrate BankID as a login/signup method using the TIC Identity API.
Users can authenticate with BankID QR codes (desktop) or deep links (mobile),
link BankID to existing accounts, and skip TOTP MFA when BankID is linked.
Removes Step 0 (role choice) from onboarding for all users. Adds enrichment
data support for pre-filling company details from Bolagsverket during signup.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: address PR review — server-side rate limit, unlink clears MFA bypass
- Add per-IP rate limit (5s cooldown) on /bankid/start to prevent
unbounded billable TIC sessions from unauthenticated callers
- Add /bankid/unlink endpoint that deletes bankid_identities AND clears
app_metadata.bankid_linked so MFA enforcement resumes after unlink
- Update BankIdSettings to call server-side unlink instead of client-side delete
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: move rate limiter to module scope, add BankID logo and year-end skill
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: request explicit page size from Enable Banking API to fetch all transactions
The API defaults to ~10 transactions per page when no limit is specified,
causing incomplete syncs for users with more transactions.
* fix: enhance DELETE operations and add missing RLS policies for multi-tenant support
* fix: make new user checklist mobile responsive
Adjust spacing, padding, typography, and indentation for small screens
so the onboarding welcome screen works well on mobile devices.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: make expenses and bookkeeping verification views mobile responsive
- Expenses/new: stack form grids on mobile, replace line items table with
card layout, full-width action buttons
- Expenses/[id]: stack header and actions, card layout for line items and
payments, single-column info grid on mobile
- JournalEntryList: unify verification lines into card layout for all
screen sizes, hide redundant line descriptions that duplicate account
name or entry description, stack filter bar and action buttons on mobile
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: remove stray )); in provider_consents migration
Syntax error on line 35 caused MIGRATIONS_FAILED on the Supabase staging branch.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: enhance mobile responsiveness for invoices page and update dialog styles
* fix: make arcim migration active connections card mobile responsive
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: make new user checklist mobile responsive
Adjust spacing, padding, typography, and indentation for small screens
so the onboarding welcome screen works well on mobile devices.
* fix: make expenses and bookkeeping verification views mobile responsive
- Expenses/new: stack form grids on mobile, replace line items table with
card layout, full-width action buttons
- Expenses/[id]: stack header and actions, card layout for line items and
payments, single-column info grid on mobile
- JournalEntryList: unify verification lines into card layout for all
screen sizes, hide redundant line descriptions that duplicate account
name or entry description, stack filter bar and action buttons on mobile
* fix: remove stray )); in provider_consents migration
Syntax error on line 35 caused MIGRATIONS_FAILED on the Supabase staging branch.
* fix: enhance mobile responsiveness for invoices page and update dialog styles
* fix: MCP OAuth 303 redirect, send dialog auto-close, bank details null payload
- OAuth authorize: use 303 See Other instead of default 307, which
preserved POST method and caused Claude's callback to return 405
- SendInvoiceDialog: close dialog and show toast after email send
instead of leaving a success message that requires manual close
- BankDetailsSetupDialog: omit empty fields from payload instead of
sending null, which fails Zod validation on non-nullable schema fields
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* refactor: remove dead sentMessage state and fix stale comment
Remove sentMessage state, its success banner JSX, and the CheckCircle2
import — all unreachable after the dialog now auto-closes on email send.
Fix stale "to null" comment in BankDetailsSetupDialog.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: support Nordea Business CSV variants, polish API keys UI, fix transaction categorization
- Extend Nordea Business bank file parser to handle three CSV export
formats (classic, Betalare/Mottagare variant, Bokföringsdatum variant)
with proper detection guards against SEB/LF misidentification
- Rework ApiKeysPanel: add CopyBlock component, destructive confirm on
revoke, collapsible API-key-based connection methods, Claude.ai OAuth
instructions as recommended path, simplified scope badges
- Stop deriving is_business from category on manual transaction creation;
set null so categorization flow handles it correctly
- Show categorize button when journal_entry_id is missing regardless of
is_business value
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: address PR review — await clipboard, fix zero-scope label, simplify condition
- Await navigator.clipboard.writeText and catch failures
- Change zero-scope label from "Enbart läs" to "Inga behörigheter"
- Simplify redundant ternary condition in TransactionHistoryList
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: repair broken ternary in TransactionHistoryList JSX
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* refactor: remove unnecessary secondary action from EmptyInvoices component
* feat: add direct provider layer and provider_consents migration
Replace Arcim Sync gateway dependency with direct provider clients
for Fortnox, Visma, Briox, Bokio, and Björn Lundén. Adds OAuth
config, rate limiting, retry logic, data fetching, and consent
storage via new provider_consents/tokens/otc tables.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* refactor: migrate arcim extension to direct provider APIs
Replace Arcim Sync gateway calls with direct provider API access.
Use FortnoxClient.getText() for SIE endpoints that return plain text
instead of JSON. OAuth callback now returns HTML with postMessage
to communicate with the opener window instead of redirecting.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: use OAuth popup window instead of new tab
Open provider login in a centered popup that auto-closes on
completion via postMessage, keeping the user on a single tab.
Falls back to redirect flow if popup is blocked.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: add connection status, consent reuse, and SIE duplicate detection
- Add listConsents() to query active consents by company
- Add GET /status route returning consents, SIE import history, and
entity counts
- /connect reuses existing accepted consent instead of creating
duplicates, and cleans up abandoned (status 0) consents
- /status only returns accepted (status 1) consents
- /sie-data checks each file's SHA-256 hash against sie_imports to
report per-file import status (alreadyImported, importedAt)
- /sie-data blocks on SIE validation failure (mirrors manual upload)
- /import-sie validates unmapped accounts and auto-activates missing
BAS accounts in chart_of_accounts (mirrors manual upload)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: show active connections, SIE file status, and smart re-sync UI
- ProviderStep shows active connections with last import date, entity
counts, "Synka igen" button, and disconnect option
- Already-connected providers greyed out in selection grid
- OptionsStep shows per-fiscal-year import status (imported vs new)
- SIE toggle disabled with explanation when all files already imported
- handleStartMigration skips already-imported SIE files
- Auto-skip mapping step and disable SIE on re-sync when up to date
- Result step hides empty "0 importerade" rows and shows
"Allt är uppdaterat" when nothing new was fetched
- OptionRow supports disabled state
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: adjust COMING_SOON_PROVIDERS based on NODE_ENV for development and production
* Removed duplicate
* Removed duplicate
* refactor: redesign reports page navigation from grid boxes to bordered card layout
Replace the 4-column grid of uneven TabsList boxes with a CSS grid card
using auto-sized columns separated by 1px border dividers. All sections
now share equal height via items-stretch, with clear visual separation
between groups.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* chore: trigger Vercel deployment
* Update supabase/migrations/20260402010000_provider_consents.sql
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
* Update lib/providers/rate-limiter.ts
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
* chore: re-trigger checks after migration sync
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
* fix: MCP OAuth 303 redirect, send dialog auto-close, bank details null payload
- OAuth authorize: use 303 See Other instead of default 307, which
preserved POST method and caused Claude's callback to return 405
- SendInvoiceDialog: close dialog and show toast after email send
instead of leaving a success message that requires manual close
- BankDetailsSetupDialog: omit empty fields from payload instead of
sending null, which fails Zod validation on non-nullable schema fields
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* refactor: remove dead sentMessage state and fix stale comment
Remove sentMessage state, its success banner JSX, and the CheckCircle2
import — all unreachable after the dialog now auto-closes on email send.
Fix stale "to null" comment in BankDetailsSetupDialog.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: always use business PSU type for bank connections
EF (sole trader) users connecting to Nordea got personal accounts
because psu_type was set to 'personal' based on entity_type. Since
gnubok is accounting software, all bank connections should use
'business' PSU type regardless of entity type.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: document inbox extension with AI classification
Add invoice-inbox extension for email-based document processing with
AI-powered classification, supplier matching, and inbox management.
Includes MCP tools for document upload/listing, migration, and
supporting changes across document service, API keys, and banking.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: disable invoice-inbox extension, use dynamic import in MCP server
Keep invoice-inbox out of extensions.config.json until ready for
production. MCP server now dynamically imports classifyDocument to
avoid breaking when the extension is disabled.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: correct file size error message in invoice-inbox upload
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: sanitize document filenames and add server-side upload validation
Filenames with spaces or non-ASCII characters (e.g. Swedish ö, ä, å) caused
Supabase Storage to reject uploads with "Invalid key". This adds filename
sanitization, server-side size/type validation on both upload routes, and
fixes a duplicate-filename race condition in the upload UI.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: require MIME type and handle empty sanitized filenames
Address review feedback:
- MIME type check now rejects files with missing/empty Content-Type
instead of silently allowing them through
- Fallback to 'file' when sanitized base is empty (e.g. ööö.pdf)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
90 days missed transactions from late December for users connecting
in early April.
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: always use business PSU type for bank connections
EF (sole trader) users connecting to Nordea got personal accounts
because psu_type was set to 'personal' based on entity_type. Since
gnubok is accounting software, all bank connections should use
'business' PSU type regardless of entity type.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: remove stale companySettings reference from log
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: redirect bank OAuth callback to /settings/banking
The callback was redirecting to /settings which immediately redirects to
/settings/company, dropping the bank_connected and connection_id query
params. The auto-sync code that triggers the initial 90-day transaction
fetch lives in /settings/banking and never received the params.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* test: add coverage for invalid_code_format redirect path
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: use range overlap for duplicate period check (BFL 4:1 compliance)
The period duplicate check used exact-match on fiscal_year_start/end, missing
overlapping periods (e.g., partial-year file vs full-year import). Now uses
standard interval overlap test (start <= other_end AND end >= other_start).
Updated Swedish error messages to reflect overlap semantics.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: align JSDoc citation to BFL 4:1 for period overlap check
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: catch duplicate SIE import early with clear error message
- Add duplicate check in execute route before doing any work (defense in depth)
- Handle duplicate error from execute route in frontend
- Show "Filen har redan importerats" heading instead of generic "Kunde inte läsa filen"
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: catch duplicate SIE import early and batch account creation for performance
- Add duplicate check in execute route before doing any work (defense in depth)
- Handle duplicate error from execute route in frontend with clear Swedish message
- Replace sequential ensureAccountExists loop (50-100 DB round trips) with single
batch SELECT + batch INSERT — reduces import time from 3+ min to seconds
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: update mappings optimistically after creating missing accounts
Previously re-parsed the SIE file after account creation, which could fail
with a 409 duplicate error (leaving the "create accounts" card stuck).
Now optimistically marks created accounts as self-mapped and updates the
preview stats immediately.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: address Greptile P2 feedback — error handling and typed errorType prop
- Check batch insert error in executeSIEImport account creation safety net
- Replace brittle string-match error detection with typed errorType prop
- Remove stale file dependency from handleCreateAccounts useCallback
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: fix SIE import voucher range bugs from multi-tenant migration and remove describe transaction feature
- Fix reserve_voucher_range RPC parameter mismatch (p_user_id → p_company_id) causing duplicate voucher errors
- Fix create-accounts onConflict from user_id to company_id
- Add reserve-then-adjust pattern: pre-reserve voucher range before batch insert, release unused range on partial failure
- Add release_voucher_range DB function for safe rollback
- Remove DescribeTransactionDialog, describe/batch-describe API routes, and related schemas (feature superseded)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: address Greptile review — voucher range race condition and orphaned entries
- Add p_reserved_highest upper-bound guard to release_voucher_range to prevent
rolling back past numbers claimed by concurrent operations
- Move highestInsertedVoucher tracking to after both headers AND lines succeed,
preventing orphaned journal entries with no lines from being counted as "used"
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Expand the tax settings page with F-skatt, VAT registration, fiscal year start month, and salary payment toggles. Refactor SettingsFormWrapper to support onSuccess callbacks so local state only updates after server confirmation. Fix logo upload to use service client for storage RLS bypass. Allow empty email in settings schema. Update CLAUDE.md with comprehensive multi-tenant, auth, and engine documentation. Remove unused langchain skills.
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Remove AI-dependent extensions (ai-chat, ai-categorization, receipt-ocr,
invoice-inbox) and their infrastructure (lib/ai/*, ai-consent, LangChain/
Anthropic/OpenAI deps) to simplify core and reduce bundle size.
Restructure monolithic settings page into dedicated sub-pages (company,
bookkeeping, invoicing, tax, banking, api, account, team, templates) with
shared layout and sidebar navigation.
Add atomic commit_journal_entry RPC so voucher number increment and status
update happen in a single transaction — prevents burned numbers on constraint
failures. Add continuity check report and voucher gap explanation tracking.
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: complete multi-tenant refactor for reconciliation, arcim, settings validation
- Migrate bank-reconciliation to company_id (all functions + tests)
- Migrate arcim-migration entity mappers and orchestrator to company_id
- Fix enable-banking reconciliation calls to use companyId
- Add Swedish law validation to settings schema:
- VAT number required when VAT-registered (ML 11 kap. 8§)
- Moms period required when VAT-registered (SFL 26 kap.)
- Aktiebolag must use accrual accounting (BFNAR 2006:1)
- Fix fiscal year period creation: always 12 months after first year (BFL 3 kap.)
- Add plusgiro, website, pays_salaries fields to CompanySettings
- Add plusgiro to invoice PDF template
- Add fiscal period CRUD and opening balances API routes
- Add frame-src CSP directive for future iframe embedding
- Fix unlinked_1930_lines RPC to use company_id parameter
- Update CLAUDE.md documentation
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: address PR review findings (P1 + P2)
- Fix reconciliation events emitting companyId as userId — thread
actual userId through runReconciliation and manualLink
- Move VAT cross-field validation (vat_number, moms_period) from
schema refinements to route handler where effective stored state
is available, preventing false rejection on partial updates
- Add plusgiro format validation regex (N-N pattern)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: multi-tenant company refactor (GNU-19)
Introduce companies table, company_members, and user_preferences to
support multiple companies per user. All data scoping changes from
user_id to company_id across the entire codebase.
Key changes:
- Database migration: new tables, company_id on 40+ tables, backfill,
RLS rewrite from user_id to company-member-based, updated RPCs
- Types: Company, CompanyMember, CompanyRole, UserPreferences types;
company_id added to all entity interfaces; companyId on all events
- Engine: all 7 core functions take companyId; storno, period, year-end
services updated; 16 report generators updated
- Middleware: company context resolution (cookie → prefs → first company)
- API routes: ~120 routes updated with requireCompanyId()
- Frontend: CompanyProvider context, layout/dashboard/onboarding updated
- Extensions: context factory, 9 extensions, all lib files updated
- Tests: 1880 tests passing, all helpers updated with company_id defaults
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: add database migrations for multi-tenant company and team system (GNU-19)
Adds company_invitations, company creation RPC, team_members, account
deletion RPC, and teams table refactor migrations. Updates base
multi-tenant migration with cascading FKs and onboarding_step column.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: add team types and update core infrastructure for multi-tenancy (GNU-19)
Adds TeamRole, MemberSource, and Team types. Refactors Supabase service
client to be stateless, updates middleware for team-aware routing, extends
CompanyContext with team/role fields, and updates extension service types
to accept companyId.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* refactor: thread company_id through business logic functions (GNU-19)
Replaces user_id scoping with company_id across all lib modules:
bookkeeping, documents, transactions, invoices, reconciliation, tax,
deadlines, and import. Updates corresponding tests.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* refactor: thread company_id through API routes and extensions (GNU-19)
Updates all existing API routes to extract and pass companyId. Updates
enable-banking and arcim-migration extensions for company-scoped
transaction ingestion and sync.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: add company and team management API routes (GNU-19)
Adds CRUD endpoints for company members, company invitations, team
members, and team invitations. Includes invite token utilities, email
templates, and company switch server action.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: add team/company UI components, pages, and dashboard updates (GNU-19)
Adds CompanySwitcher, ConsultantEmptyState, Step0RoleChoice, company
members and team management panels. Updates dashboard layout for
team-aware routing, onboarding for multi-step role choice, and auth
callback for team invite acceptance. Ignores supabase/.branches/.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: add null guards for company in import page (GNU-19)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: move appUrl declaration to outer scope in invite route (GNU-19)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: add optional chaining for company.name in members section (GNU-19)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: add optional chaining for second company.name in members section (GNU-19)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: add null guards for company in extension components (GNU-19)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: pass companyId to executeSIEImport in arcim-migration extension (GNU-19)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: update tests to use companyId instead of userId and improve type handling
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: improve date filter UX with partial dates and Apply button (GNU-18)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: enhance banking settings with connection handling and integrity checks
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Replace === with crypto.timingSafeEqual in all 7 cron routes via shared lib/auth/cron.ts
- Add in-memory rate limiting (60 req/min) and expires_at support to calendar feed
- Add exponential backoff on MFA verify after 3 failed attempts
- Add 60s cooldown on password reset requests
- Validate bank callback auth code format before API call
- Redact session IDs from bank sync and callback logs
- Validate OAuth redirect_uris against allowlist (claude.ai, claude.com, localhost)
- Remove excessive PII/debug console logging from login page
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: soften button system with refined primary color (GNU-6)
Replace near-black primary with a lighter dark charcoal (210 5% 25%),
add subtle shadows to solid buttons, and unify border-radius across
all button sizes.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: add scout-design skill for design auditing and improvement tracking
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: event log, pending operations, and MCP staging
- Event log system: persist bus events to event_log table for external
automation platforms. Batch insert for transaction.synced. Daily
cleanup cron at 02:00 UTC.
- Pending operations: MCP write tools (categorize, create customer,
create invoice) now stage to pending_operations instead of executing
directly. Users review and commit/reject from /pending in the web UI.
- Granskning page: card-based review UI with expandable previews,
commit/reject dialogs. Only shown in nav when pending ops exist.
- Commit route re-executes using core lib functions (no extension
imports). Guards against stale state (double-commit, deleted entities).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: stage new MCP write tools after main merge
Add staging for 4 new write tools from #133:
- mark_invoice_paid, send_invoice, mark_invoice_sent,
match_transaction_invoice
- Expand pending_operations CHECK constraint
- Add commit executors with full execution logic
- Add UI labels and generic preview component
- Remove confirm parameter from categorize (single-call staging)
- Fix UUID in pending op title (fetch transaction description)
- Hide Granskning nav when no pending ops
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: address PR review feedback
- Fix TS build error: use `select('*, customer:customers(*)')` for
match_transaction_invoice to avoid array type inference
- Add status guard to commitSendInvoice (prevents duplicate sends)
- Replace auth.admin.getUserById with user email from session auth
- Restore optimistic lock check in commitMatchTransactionInvoice
- Fix tool description typo: expense_software → expense_office
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: add support contact links and improve SIE import UX
Add a SupportLink component with a contact dialog throughout the app
(nav, help page, settings, MFA, error pages, empty states). Improve
SIE import flow with phased loading states, structured skip breakdowns,
and an elapsed-time counter. Fix MFA enroll stale factor cleanup and
URL encoding for settings return path.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: address PR review — open redirect, XSS, test cleanup, fallback email
- Validate returnTo is a relative path in MFA enroll (prevents open redirect)
- Add afterEach import to event-log-handler tests (fixes handler leak)
- HTML-escape user-supplied subject and message in support email body
- Replace hardcoded personal email with support@gnubok.se fallback
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: move bank details from onboarding to first invoice creation
Bank details (account, bankgiro, invoice prefix) are now collected
contextually when the user creates their first invoice, rather than
during onboarding where most users skip them. This ensures invoices
always have payment information on the PDF.
- Remove onboarding step 5 (bank details), simplify to 4 steps
- Delete Step6ConnectBank component
- Add BankDetailsSetupDialog with bank account, bankgiro (Luhn),
IBAN/BIC (collapsible), and invoice prefix fields
- Intercept at "Granska & skapa" for invoice document type only
(proforma and delivery notes pass through without bank details)
- Show soft info banner on invoice form when bank details are missing
- Add controlled mode (value/onChange) to BankNameCombobox for reuse
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: address PR review — null-check race, escape key, starting number
- Fix P1: use `hasBankDetails === false` instead of `!hasBankDetails`
to avoid treating null (loading) state as missing bank details
- Fix P2: remove onEscapeKeyDown override so keyboard users can
dismiss the dialog (WCAG AA compliance)
- Add starting invoice number field alongside prefix, so users can
choose e.g. starting at 14 instead of 1
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: skip auto-categorization during bank sync when SIE overlap detected
Prevents double-booking when bank transactions are synced for a period
that already has journal entries from a SIE import. Reconciliation still
links transactions to existing GL lines; only new journal entry creation
is suppressed. A batch reconciliation sweep runs post-sync to catch
additional matches.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: enhance import page UI with improved card layout and new icons
* feat: update NewUserChecklist for improved onboarding experience with revised text and enhanced layout
* feat: add read/write scopes to API keys
API keys now require explicit scopes (e.g. transactions:read,
invoices:write) instead of having implicit full access. The create
dialog shows grouped checkboxes per domain with read/write split.
Legacy keys with null scopes default to read-only. MCP tools/list
is filtered by scope and tools/call rejects unauthorized calls.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Enhance API key scopes with suppliers and update descriptions for better clarity
* fix: drop function before recreating with changed return type
PostgreSQL cannot change return type via CREATE OR REPLACE.
Drop the existing function first to avoid SQLSTATE 42P13.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: add new migration to drop and recreate function with scopes return type
The original migration was already applied, so a new migration is needed
to DROP the function first before recreating with the updated return type.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: add DROP FUNCTION to original migration, remove redundant fix migration
Preview branches replay all migrations from scratch. The original migration
must DROP the function before recreating it with a changed return type,
otherwise PostgreSQL rejects the CREATE OR REPLACE. The separate fix
migration is no longer needed.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: rename migration to avoid duplicate version in schema_migrations
Version 20260325120000 is already recorded in the preview DB from a
prior failed apply. Renaming to 20260326130000 so Supabase treats it
as a new migration.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: event log, pending operations, and MCP staging
- Event log system: persist bus events to event_log table for external
automation platforms. Batch insert for transaction.synced. Daily
cleanup cron at 02:00 UTC.
- Pending operations: MCP write tools (categorize, create customer,
create invoice) now stage to pending_operations instead of executing
directly. Users review and commit/reject from /pending in the web UI.
- Granskning page: card-based review UI with expandable previews,
commit/reject dialogs. Only shown in nav when pending ops exist.
- Commit route re-executes using core lib functions (no extension
imports). Guards against stale state (double-commit, deleted entities).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: stage new MCP write tools after main merge
Add staging for 4 new write tools from #133:
- mark_invoice_paid, send_invoice, mark_invoice_sent,
match_transaction_invoice
- Expand pending_operations CHECK constraint
- Add commit executors with full execution logic
- Add UI labels and generic preview component
- Remove confirm parameter from categorize (single-call staging)
- Fix UUID in pending op title (fetch transaction description)
- Hide Granskning nav when no pending ops
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: address PR review feedback
- Fix TS build error: use `select('*, customer:customers(*)')` for
match_transaction_invoice to avoid array type inference
- Add status guard to commitSendInvoice (prevents duplicate sends)
- Replace auth.admin.getUserById with user email from session auth
- Restore optimistic lock check in commitMatchTransactionInvoice
- Fix tool description typo: expense_software → expense_office
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: add support contact links and improve SIE import UX
Add a SupportLink component with a contact dialog throughout the app
(nav, help page, settings, MFA, error pages, empty states). Improve
SIE import flow with phased loading states, structured skip breakdowns,
and an elapsed-time counter. Fix MFA enroll stale factor cleanup and
URL encoding for settings return path.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: address PR review — open redirect, XSS, test cleanup, fallback email
- Validate returnTo is a relative path in MFA enroll (prevents open redirect)
- Add afterEach import to event-log-handler tests (fixes handler leak)
- HTML-escape user-supplied subject and message in support email body
- Replace hardcoded personal email with support@gnubok.se fallback
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: event log, pending operations, and MCP staging
- Event log system: persist bus events to event_log table for external
automation platforms. Batch insert for transaction.synced. Daily
cleanup cron at 02:00 UTC.
- Pending operations: MCP write tools (categorize, create customer,
create invoice) now stage to pending_operations instead of executing
directly. Users review and commit/reject from /pending in the web UI.
- Granskning page: card-based review UI with expandable previews,
commit/reject dialogs. Only shown in nav when pending ops exist.
- Commit route re-executes using core lib functions (no extension
imports). Guards against stale state (double-commit, deleted entities).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: stage new MCP write tools after main merge
Add staging for 4 new write tools from #133:
- mark_invoice_paid, send_invoice, mark_invoice_sent,
match_transaction_invoice
- Expand pending_operations CHECK constraint
- Add commit executors with full execution logic
- Add UI labels and generic preview component
- Remove confirm parameter from categorize (single-call staging)
- Fix UUID in pending op title (fetch transaction description)
- Hide Granskning nav when no pending ops
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: address PR review feedback
- Fix TS build error: use `select('*, customer:customers(*)')` for
match_transaction_invoice to avoid array type inference
- Add status guard to commitSendInvoice (prevents duplicate sends)
- Replace auth.admin.getUserById with user email from session auth
- Restore optimistic lock check in commitMatchTransactionInvoice
- Fix tool description typo: expense_software → expense_office
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Adds ~15 new MCP tools covering invoice operations (send, mark paid, mark sent,
match to transaction), supplier queries, counterparty template suggestions,
chart of accounts, balance sheet, general ledger, AR/AP ledgers, fiscal periods,
and bank reconciliation status. Updates server instructions to reflect expanded scope.
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: display invoice references as tags instead of plain text
Replace the single-line text input for "Er referens" with a tag-style
input that lets users add/remove individual references as chips. Updates
the detail page, review modal, and PDF template to render comma-separated
references as wrapped badge/tag elements instead of a single string.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Fixed our reference field
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: separate AR/AP/accounting into distinct nav groups (#92)
Split the flat "Finans" sidebar group into three visually distinct
sections — Försäljning (AR), Inköp (AP), and Redovisning — so users
coming from Fortnox immediately find customer invoicing and supplier
invoices as top-level concepts.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: journal entry detail view, correction chain, and account name display
- Add journal entry detail page at /bookkeeping/[id] with full entry view
- Add correction chain API and component showing storno relationships
- Add JournalEntryStatusBadge component for entry status display
- Show debit/credit account names in template picker and review dialogs
- Expand client-side BAS account name mapping with additional accounts
- Show account codes on transaction inbox suggestion buttons
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: address review feedback — N+1 query, duplicate name, nav dedup
- Batch reverse-lookup into single query per BFS iteration (was N+1)
- Differentiate account 2393 from 2893 in display names
- Extract shared loop for desktop/mobile nav group rendering
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: counterparty templates, Skatteverket extension, VAT form completeness, and UI cleanup
- Add counterparty-based categorization templates (learned from user approvals
and auto-ingestion) with fuzzy matching in the mapping engine
- Add Skatteverket extension for direct VAT declaration submission via API
- Complete VAT declaration form with all 30 SKV 4700 boxes (ruta 08, 35-42, 50, 60-62)
- Fix ruta 49 formula to include import VAT (ruta 60+61+62)
- Simplify dashboard UI: remove redundant icons from stat cards, customer cards,
invoice list, supplier invoices; use Badge variants consistently
- Add SkatteverketPanel component to reports page
- Add categorization_templates and skatteverket_tokens migrations
- Update tests and helpers for new types
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: address PR review feedback — VAT detection, migration timestamps, dedup
- Fix detectVatTreatment to derive actual rate (12%/6%) from VAT line
description instead of hardcoding standard_25
- Rename skatteverket_tokens migration to 20260324120001 to avoid
duplicate timestamp with categorization_templates (fixes Supabase
deployment failure)
- Make refreshAccessToken accept previousRefreshCount param to enforce
refresh limit contract at the type level
- Fix rate limiter TOCTOU by claiming slot before await
- Extract formatRedovisare/formatRedovisningsperiod to shared
lib/skatteverket/format.ts — eliminates duplication between
mappers.ts and SkatteverketPanel.tsx
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: multi-line counterparty templates, batch matching, settings restructure
Counterparty template engine:
- Multi-line booking patterns (line_pattern JSONB) for complex entries
with split VAT, tax accounts, and ratio-based allocation
- Batch matching (findCounterpartyTemplatesBatch) — 1 DB query for all
transactions instead of up to 3 per transaction
- SIE voucher population (populateTemplatesFromSieVouchers) — extracts
patterns from historical vouchers on import with dominance filtering
- Source priority system (user_approved > sie_import > auto_learned)
- Centralized counterparty: prefix helpers to prevent string fragility
- Fix: re-approval path now updates line_pattern
Transaction categorization:
- /describe route returns counterparty_match in parallel with templates/AI
- /categorize route accepts counterparty_template_id for direct booking
- /suggest-categories uses batch matching, injects counterparty suggestions
- transaction-entries supports all_lines_complete for multi-line patterns
UI:
- TemplatePicker shows "Tidigare motparter" section (no AI extension needed)
- DescribeTransactionDialog shows counterparty match card with detail
- QuickReviewDialog supports counterparty line patterns
- JournalEntryPreview renders multi-line patterns with VAT/ratio math
- Inline LinePatternEntry types replaced with shared import from @/types
Settings restructure:
- 8 tabs → 5: merged Säkerhet + Utseende + Kalender into Konto
- Renamed "Motparter" → "Mallar"
- CounterpartyTemplatesPanel: click-to-expand detail view with account
lines, VAT, confidence, aliases, and delete
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: address PR review — account_override guard, DELETE body parsing, stale test
- Block account_override when counterparty_template_id is set (prevents
corrupting stored template via override → upsert correction path)
- Wrap DELETE request.json() in try-catch for malformed body (400 not 500)
- Clean up stale 3-query mock enqueues in test for batch-based find
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: separate AR/AP/accounting into distinct nav groups (#92)
Split the flat "Finans" sidebar group into three visually distinct
sections — Försäljning (AR), Inköp (AP), and Redovisning — so users
coming from Fortnox immediately find customer invoicing and supplier
invoices as top-level concepts.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: journal entry detail view, correction chain, and account name display
- Add journal entry detail page at /bookkeeping/[id] with full entry view
- Add correction chain API and component showing storno relationships
- Add JournalEntryStatusBadge component for entry status display
- Show debit/credit account names in template picker and review dialogs
- Expand client-side BAS account name mapping with additional accounts
- Show account codes on transaction inbox suggestion buttons
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: address review feedback — N+1 query, duplicate name, nav dedup
- Batch reverse-lookup into single query per BFS iteration (was N+1)
- Differentiate account 2393 from 2893 in display names
- Extract shared loop for desktop/mobile nav group rendering
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: counterparty templates, Skatteverket extension, VAT form completeness, and UI cleanup
- Add counterparty-based categorization templates (learned from user approvals
and auto-ingestion) with fuzzy matching in the mapping engine
- Add Skatteverket extension for direct VAT declaration submission via API
- Complete VAT declaration form with all 30 SKV 4700 boxes (ruta 08, 35-42, 50, 60-62)
- Fix ruta 49 formula to include import VAT (ruta 60+61+62)
- Simplify dashboard UI: remove redundant icons from stat cards, customer cards,
invoice list, supplier invoices; use Badge variants consistently
- Add SkatteverketPanel component to reports page
- Add categorization_templates and skatteverket_tokens migrations
- Update tests and helpers for new types
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: address PR review feedback — VAT detection, migration timestamps, dedup
- Fix detectVatTreatment to derive actual rate (12%/6%) from VAT line
description instead of hardcoding standard_25
- Rename skatteverket_tokens migration to 20260324120001 to avoid
duplicate timestamp with categorization_templates (fixes Supabase
deployment failure)
- Make refreshAccessToken accept previousRefreshCount param to enforce
refresh limit contract at the type level
- Fix rate limiter TOCTOU by claiming slot before await
- Extract formatRedovisare/formatRedovisningsperiod to shared
lib/skatteverket/format.ts — eliminates duplication between
mappers.ts and SkatteverketPanel.tsx
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Transaction updates. Email updates. Bookkeeping updates.
* Added email confirmation box
* Update components/invoices/SendInvoiceDialog.tsx
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
* Update app/(dashboard)/invoices/[id]/page.tsx
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
* fix: restore deleted useEffect and remove stray JSX closing tag
The SendInvoiceDialog useEffect body was accidentally removed in e32c9b3,
leaving only the dependency array. Also removes a stray `/>` in the
invoice detail page that broke the Turbopack build.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Enable clicking account rows in Trial Balance, Income Statement, and
Balance Sheet to navigate to the Huvudbok filtered to that account.
Voucher numbers in the Huvudbok now link to the journal entry detail
page. Breadcrumb trail supports tracing back through the navigation
chain.
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Enable clicking account rows in Trial Balance, Income Statement, and
Balance Sheet to navigate to the Huvudbok filtered to that account.
Voucher numbers in the Huvudbok now link to the journal entry detail
page. Breadcrumb trail supports tracing back through the navigation
chain.
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: allow scrolling in QuickReviewDialog when content overflows viewport
The dialog had no max-height or overflow handling, so tall content (e.g.
extern representation with warnings + journal preview) was clipped with
no way to scroll.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: add detailed error logging to Enable Banking integration
Adds structured console logging with full context (status codes,
response bodies, connection IDs, account UIDs, stack traces) to all
Enable Banking operations: connect, callback, sync, disconnect,
and the API client retry/error paths.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: add detailed error logging to login and register flows
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: implement KPI settings management with preferences and dynamic KPI display
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: separate AR/AP/accounting into distinct nav groups (#92)
Split the flat "Finans" sidebar group into three visually distinct
sections — Försäljning (AR), Inköp (AP), and Redovisning — so users
coming from Fortnox immediately find customer invoicing and supplier
invoices as top-level concepts.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: journal entry detail view, correction chain, and account name display
- Add journal entry detail page at /bookkeeping/[id] with full entry view
- Add correction chain API and component showing storno relationships
- Add JournalEntryStatusBadge component for entry status display
- Show debit/credit account names in template picker and review dialogs
- Expand client-side BAS account name mapping with additional accounts
- Show account codes on transaction inbox suggestion buttons
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: address review feedback — N+1 query, duplicate name, nav dedup
- Batch reverse-lookup into single query per BFS iteration (was N+1)
- Differentiate account 2393 from 2893 in display names
- Extract shared loop for desktop/mobile nav group rendering
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The dialog had no max-height or overflow handling, so tall content (e.g.
extern representation with warnings + journal preview) was clipped with
no way to scroll.
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: resolve BFL compliance violations in general ledger and trial balance
Fix two compliance violations and a pre-existing double-counting bug:
1. .in(entryIds) truncation (BFL 5:2 completeness) — general-ledger.ts and
journal-register.ts used .in() with dynamic ID arrays that silently
truncate at ~1000 rows. Migrated to joined queries with fetchAllRows
pagination, matching the pattern already used by trial-balance.ts.
2. Trial balance missing IB columns (BFNAR 2013:2) — opening_debit and
opening_credit were hardcoded to 0. Now computed from the
opening_balance_entry (set by year-end closing) or by summing prior-
period entries as a fallback.
3. Double-counting after year-end closing — the opening_balance_entry's
lines were counted as both IB and period activity. Now excluded from
period queries via .neq() when the OB entry exists.
Extracted shared getOpeningBalances() helper used by both trial balance
and general ledger. Refactored test mocks from positional arrays to
table-keyed queues for readability.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: add pagination and user_id filter to OB entry query
Address review feedback: the obEntryId fast path in getOpeningBalances
used a bare single-shot query without fetchAllRows (inconsistent with
the PR's truncation fix) and lacked the user_id defense-in-depth
filter required by CLAUDE.md guidelines.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: remove gnubok_categorize_with_receipt tool
The tool requires Claude to generate the entire base64-encoded file as
tool arguments token-by-token, which is extremely slow for large PDFs.
Receipt attachment should happen via the widget (where JavaScript
handles encoding) or through the web app.
The receipt matcher widget and gnubok_receipt_matcher tool remain —
they provide the intended UX for matching receipts to transactions.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: update widget to call gnubok_categorize_transaction
The widget was still calling the removed gnubok_categorize_with_receipt
tool. Updated to call gnubok_categorize_transaction instead (text-only,
no file upload). Receipt attachment via the widget is deferred to a
future iteration.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>