c9625fa45ce2da90a3bbb7228da32f2802e37bbf
11
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
e11f70b347 |
Bug/gh issues fiz (#1103)
* refactor: optimize page loading and data fetching * fix: resolve recurring production runtime errors * feat: add MCP company and customer updates * fix: handle year-end tax adjustments * feat: harden annual report compliance * fix: expand invoice logo and font support * fix: sanitize API route error responses * fix: sanitize user-facing error messages * feat: persist onboarding and tax assessment notices * fix: reduce cloud backup audit churn * feat: refine invoice editor layout * fix: show saved tax adjustments in INK2 * fix: complete annual report API mappings * docs: record operational safeguards and decisions * fix: harden annual report review findings * fix: adjust column span for description based on VAT registration * New css class name |
||
|
|
7d7f604e00 |
Add/stripe invoice link (#998)
* feat(supplier-invoices): show registered invoices under "Att betala" with inline approve Registered supplier invoices are already booked as debt (2440) but were hidden from the "Att betala" tab until approved, which confused users. The tab now shows registered invoices too, marked "Ej godkand" with a compact inline approve button. Approval remains the gate for payment, not visibility; status model and approve API untouched. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(reports): add date range filter to huvudbok (kontoanalys) Mounts the existing ReportDateRange control on /reports/huvudbok so the ledger can be narrowed to any date range within the fiscal year, matching Fortnox kontoanalys. Lines before the range roll into each account's opening balance so running balances stay correct at the range start; lines after the range are dropped. Applies to the XLSX export too. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(invoices): add optional payment link on invoices (paste-link MVP) The user pastes a payment link created in their PSP dashboard (e.g. a Stripe Payment Link) onto an invoice. The recipient gets a "Betala online" button in the invoice email and a QR code + clickable link in the PDF payment box. No PSP integration server-side: this is the demand probe; a future Stripe Connect integration would auto-fill the same column. - invoices.payment_link_url (migration 20260709090000), https-only + 2048-char cap enforced in CreateInvoiceSchema; empty string normalises to undefined and build-invoice-write always writes a concrete value so clearing the field on a draft edit NULLs the column - editor field (real invoices only) with one-link-per-invoice hint; strings in sv+en (messages landed via e0e11066) - email button (customer.language, hidden for credit notes/proforma/ delivery notes, URL escaped for the href attribute) + URL in the plain-text part - PDF QR + link row following the Swish QR pattern; wired into send, download and preview routes - derived documents (credit note, proforma convert, recurring) do NOT copy the link: it encodes one amount for one specific invoice - MCP gnubok_create_invoice accepts payment_link_url (validated at staging and re-checked in the commit executor); v1 API exposes the column; tools/list token ceiling bumped 45K -> 45.5K (ledger entry in payload-size.bench.test.ts, headroom was <10 tokens) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(invoices): show oresavrundning on editor/form totals, supplier list and invoice email The rounding logic (getDisplayTotal) was correct but only applied on the PDF, invoice list/detail and review dialog. The invoice editor summary, the supplier invoice form totals and the supplier invoice list showed the raw ore total right next to the toggle, and the invoice email said "Att betala" with the unrounded invoice.total while the attached PDF showed the rounded amount (and the email also ignored the ROT/RUT deduction). Extract the PDF's Att betala block into getAmountToPay (lib/invoices/rounding.ts) and point PDF + email at it so they cannot drift; behavior-identical refactor for the PDF. Booked amounts stay ore-exact; display-only as designed. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * test(reports): adapt huvudbok date-range tests to the two-step entry-lines fetch The date-range tests (0969168f) mocked the old single-query shape with the parent entry embedded on each line; main's refactor (fetchEntryLines) queries journal_entries first and reattaches. Queue entry rows like the other tests so the merge of the two features is actually exercised. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(invoices): fetch full invoice projection in v1 send so ROT/RUT deduction and payment link reach the PDF and email The v1 send route's hand-rolled column list omitted deduction_total, deduction_personnummer_last4, payment_link_url and the item-level ROT/RUT fields, so invoices sent via the public API overstated 'Att betala' and dropped the deduction box. Reuse the shared INVOICE_FULL_COLUMNS/INVOICE_ITEM_FULL_COLUMNS so the send row can never drift from the GET shape again. Also harden the supplier-invoice inline approve: a thrown fetch left the button stuck spinning; failures now refetch the true server state. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
a8801430f4 |
fix(reports): stop driving report queries from the unfiltered journal_entry_lines side (#971)
* fix(reports): drive report line queries from journal_entries, not the unfiltered lines side
Every report generator fetched journal_entry_lines with a
journal_entries!inner(...) embed and put the tenant filter on the
embedded side (.eq('journal_entries.company_id', ...)). PostgREST
compiles that to a correlated INNER JOIN LATERAL with a parameterized
LIMIT inside, which blocks join reordering: Postgres walked the ENTIRE
journal_entry_lines table (603k rows, all tenants) per report query.
Measured in production: 13.6 s vs 2.7 ms for the equivalent plain join,
against Supabase's 8 s statement_timeout; nightly cloud backups failed
for 5 of 11 companies on 2026-07-09 and a GL report 500'd.
Introduce lib/bookkeeping/entry-lines.ts with a shared two-step fetch:
1. fetch matching journal_entries (id + caller-selected columns)
filtered by company_id / fiscal_period_id / status / entry_date /
source_type, paginated via fetchAllRows;
2. fetch journal_entry_lines with .in('journal_entry_id', chunk) in
chunks of 100 ids (URL-length safety), paginated per chunk;
3. reattach the parent entry to each line under the embed's key shape
(line.journal_entries = {...}, aliasable) and sort lines by id
ascending to preserve the old .order('id') semantics.
Converted call sites (selected columns and filters preserved):
trial-balance (x2), general-ledger, journal-register, sie-export
(reuses its existing entry list via fetchLinesByEntryIds),
vat-declaration, dimension-pnl, opening-balances, monthly-breakdown,
periodisk-sammanstallning, rc-basis-gaps (sibling-line fetch now also
chunked), ar-reconciliation, supplier-reconciliation,
bank-reconciliation, asset-service (x2), bolagsskatt-calculator,
sarskild-loneskatt-calculator.
Tests: unit tests for the helper (chunk size, reattachment shape,
forced id/journal_entry_id columns, empty result, cross-chunk sort,
error propagation); existing report/reconciliation/bokslut test mocks
updated to the two-step query shape, preserving every assertion about
report output.
From the 2026-07-09 production log triage.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(reports): stop echoing raw error messages from the general-ledger route
The catch handler returned err.message to the client in
details.reason; internal error strings (SQL fragments, table names,
timeout messages) must not reach the browser. The error is already
logged server-side with the request id, so the client envelope keeps
only the REPORT_GENERATION_FAILED code.
From the 2026-07-09 production log triage.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
|
||
|
|
abe9ac9d8c |
Fix/attributes config (#926)
* fix(git): pin LF on generated extension registry and vitest snapshots setup:extensions and vitest write these files with LF; with core.autocrlf=true git expects CRLF and flags them as phantom modifications on every dev/build run. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(security): enforce MFA on mcp-oauth consent and gate viewer storno route mcp-oauth/authorize renders an HTML consent page and issues 303 redirects that withRouteContext cannot express, so it kept raw getUser() and thereby skipped the AAL2 gate: a password-only (AAL1) session could approve consent that mints a long-lived, MFA-bypassing API key. Add a route-local requireAal2() step-up on GET and POST; AAL1 sessions redirect to /mfa/verify, BankID users are exempt. Separately, POST /api/reports/vat-declaration/rc-basis-gaps/fix calls correctEntry() (storno of a posted entry) but lacked requireWrite, so viewer-role members could trigger it. Add { requireWrite: true }. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(api): route transactions endpoints through withRouteContext Migrate the transactions routes off hand-rolled supabase.auth.getUser() onto the MFA-enforcing withRouteContext wrapper; add requireWrite on mutating handlers (book, uncategorize, attach-document, ignore, batch-match, create-from-document). Behavior and response shapes preserved; tests updated to the wrapper mock pattern. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(api): route SIE import and bank reconciliation through withRouteContext Migrate import/sie and reconciliation/bank routes onto the MFA-enforcing wrapper; requireWrite on mutations (import execute, create-accounts, mappings write verbs, link/unlink/run/mark-opening-balance). Reads (status, unmatched-entries) stay ungated. Response shapes preserved; tests added/updated to the wrapper mock pattern. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(api): route salary endpoints through withRouteContext Migrate salary employees and runs routes (plus ku, payroll-config, tax-tables) onto the MFA-enforcing wrapper; requireWrite on mutations. Personnummer masking/encryption untouched; file downloads (AGI XML, payslip PDF, payment files) keep their headers. Two payment-file GETs retain requireWrite because they stamp *_file_generated_at and previously gated viewers. Tests added/updated to the wrapper mock pattern. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(api): route report endpoints through withRouteContext Migrate the read-only report routes (trial balance, balansrapport, resultatrapport, income statement, ledgers, KPI, VAT declaration, salary journal, monthly breakdown, journal register, continuity check, full archive, etc.) onto the MFA-enforcing wrapper. All read-only, no requireWrite. JSON/XLSX/PDF/ZIP response bodies and headers preserved byte-for-byte; tests updated to the wrapper mock pattern. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(api): route invoices, skatteverket, agent and extension endpoints through withRouteContext Migrate invoices, supplier-invoices, skatteverket tax-payments, and dynamic extension routes onto the MFA-enforcing wrapper with requireWrite on mutations. The two NDJSON streaming agent routes (invoke, onboarding/stream) use requireAuth() directly (the wrapper can't wrap a streaming response) so MFA is still enforced. skatteverket payment-file GET keeps requireWrite (stamps a generated-at field). Response shapes and file headers preserved; tests added/updated. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(api): route documents, events, team and account endpoints through withRouteContext Migrate documents, events, kpi/preferences, vat/validate, support/contact onto the MFA-enforcing wrapper with requireWrite on mutations. account/password, team/accept and team/members use requireAuth() directly (user-level or pre-membership flows with no active company context) so MFA is still enforced. events keeps its dual API-key-or-session auth. Document retention guard untouched; tests added/updated. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(api): route settings and pending-operations endpoints through withRouteContext Migrate settings (api-keys, oauth-clients, booking-templates, counterparty-templates, logo, company settings) and pending-operations (commit, bulk-commit, reject, edit-before-approve) onto the MFA-enforcing wrapper with requireWrite on mutations. Credential-guarding routes keep their per-user ownership filters. Response shapes preserved; tests added/updated to the wrapper mock pattern. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * chore(guards): ratchet raw-route-auth baseline 119->1 after A1 migration Lock in the withRouteContext migration so the count cannot regress. The single remaining entry, mcp-oauth/authorize, is a documented exception (HTML consent + redirects, MFA enforced via route-local step-up). Record the campaign and requireWrite decisions in DECISIONS.md. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(vat): add eSKD momsdeklaration file export for "Deklarera via fil" Generate the Skatteverket eSKDUpload v6.0 XML file so users can file VAT by upload instead of typing every ruta into the form. Extract buildFiledAmounts() as the shared whole-krona source of truth (öre truncated per SFL 22 kap 1 §) so the XML file and the manual-filing PDF can never disagree. Adds the /eskd API route, an XML option in the report export menu, and the upload button on the manual-filing card. Strings in sv + en. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(vat): add 'vat_settlement' source type and update related components * fix(booking): adjust search input layout and enable autofocus * fix(vat): support 12-digit org numbers and adjust emission order for eSKD file * fix(migration): add 'vat_settlement' to journal_entries.source_type CHECK --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
ec27228a8e |
style: remove em/en dashes repo-wide, add CLAUDE.md rule against them (#890)
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> |
||
|
|
01dbef4015 |
feat(dimensions): PR4 reports — dimension-filtered P&L + Resultat per projekt/kostnadsställe (#862)
* feat(dimensions): PR4 reports — dimension-filtered P&L everywhere + Resultat per projekt/kostnadsställe The Project P&L milestone of the dimensions plan (dev_docs §7 PR4). One choke point lights up everything: generateTrialBalance gains options.dimensions (SIE dim → code map) pushed down as jsonb containment (dimensions @>, served by idx_jel_dimensions_gin) on both line queries, with company-wide opening balances dropped when filtered (they cannot be dimension-scoped; P&L-safe by whitelist). Resultatrapport, resultaträkning, huvudbok, monthly-breakdown and the TB drill-down inherit the filter; the KPI route filters only its P&L-side inputs (income statement, months, expense composition) — never cash/VAT. New report lib/reports/dimension-pnl.ts — "Resultat per projekt/ kostnadsställe" (Fortnox Resultatrapport projekt): value-as-column matrix over one dimension with an explicit "(Utan dimension)" bucket computed as the residual against the same trial-balance pass resultatrapport uses, so every row and the Totalt column reconcile with the unfiltered resultatrapport by construction. Registered in REPORT_CATALOG (visible only when dimensions_enabled), slug-routed view + xlsx export. UI: DimensionFilter (dimension + value picker, persistent "Filtrerad — ej fullständig rapport" chip) mounts in FocusedReport for catalog entries flagged dimensions: true; huvudbok rows show line dim codes. Statutory exclusion pinned by TEST, not convention: lib/reports/__tests__/dimension-statutory-guard.test.ts fails if the filter parser leaks into balance sheet, balansrapport, kassaflöde, VAT, SIE or full-archive routes/generators, or if the catalog whitelist widens. MCP: new gnubok_get_dimension_pnl (reports:read); dimensions filter arg on get_trial_balance/get_income_statement/get_general_ledger with resolve-don't-select (names → registry codes, resolution echoes); query_journal totals fixed to aggregate the FULL match set (was silently slice-scoped while claiming otherwise) with an honest totals_scope field, plus group_by / group_by_dimension aggregation. Also: voucher-detail dim-6 badge now uses the registry name instead of the non-standard "PR" abbreviation (#859 review follow-up). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(dimensions): address #862 review — export disclosure, prior-column suppression, period-label honesty, route hardening - Filtered XLSX/PDF exports now carry the partial-view disclosure past the file boundary (BFNAR 2013:2): filename suffix (-dim6-p001), a "Filtrerad … — ej fullständig rapport" row on every sheet, and a header note/title line in the PDFs. - Resultatrapport drops the prior-year column when a dimension filter is active — project codes are time-limited under K2/K3, so "this code last year" may be a different project (same rule as narrowed date ranges). - dimension-pnl no longer accepts fromDate: the matrix is cumulative from period_start by design (closing-balance semantics), and the period label now states exactly that instead of echoing a lower bound that was never applied. Routes/MCP tool updated to toDate-only. - dimension-pnl routes 404 on an unknown/foreign period id and cap dim_no to 4 digits (matching the MCP tool's PostgREST-path guard, which the generator now also enforces itself). - Statutory-guard test's generateTrialBalance call-site scan is paren-aware instead of a 300-char window; added fully-untagged and injection-guard test cases. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
32d9978f1b |
Fix/chrome pdf preview csp (#572)
* feat: add option to exclude year-end closing entries in SIE export and related reports * delete docs * fix: allow Chrome's PDF viewer in verifikat document preview The /api/documents/:id/inline route shipped with `object-src 'none'` in its CSP, which blocked Chrome's built-in PDF viewer (it renders inline PDFs via an internal <embed>). Users on Chrome saw "Det här innehållet har blockerats" when expanding a PDF attachment in the bookkeeping view; Firefox (PDF.js) and Edge (own viewer) were unaffected, and JPGs worked because <img> isn't subject to object-src. Drops the CSP for this route to the minimum needed for embeddability: `frame-ancestors 'self'`. X-Content-Type-Options: nosniff plus the fixed Content-Type from the handler already block MIME confusion; X-Frame-Options: SAMEORIGIN + frame-ancestors still block clickjacking. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat(auth): add webmail deep link to email confirmation screens Mirrors Stripe's signup UX: after asking the user to verify their email, detect their webmail provider from the domain and show a button that opens the inbox in a new tab. Gmail gets a from:<sender> search pre-populated; Outlook/Yahoo/iCloud/Proton open the inbox directly. Unknown / custom domains fall back to the existing copy. Sender address is configurable via NEXT_PUBLIC_BRANDING_AUTH_EMAIL_FROM (default noreply@gnubok.se) so white-label installs can match their Supabase Auth SMTP config. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(auth): unblock first-time password set for BankID users with MFA Supabase rejects updateUser({password}) and mfa.unenroll with "AAL2 session is required" whenever a TOTP factor is enrolled. BankID magic-link logins produce AAL1, and middleware skips MFA enforcement for bankid_linked users, so they had no path to AAL2 — leaving them unable to set a backup password or disable MFA without going through the email-recovery escape hatch. - /api/account/password: branch on app_metadata.has_password. First-time set writes via service.auth.admin.updateUserById (no existing credential to protect, AAL2 guard does not apply). Change-password keeps the user-session updateUser so AAL2 still fires for credential rotation. - /mfa/verify: accept a safeReturnTo query param and route there after successful verify, so step-up flows can land back where they came from. - SecuritySettings: detect the AAL2 error from both change-password and mfa.unenroll and redirect through /mfa/verify?returnTo=/settings/account instead of toasting a dead-end error. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * Add tests and rounding utility for öre precision in bokslut calculations - Implemented `roundOre` function for rounding SEK amounts to two decimal places, ensuring consistent monetary calculations. - Introduced `ORE_TOLERANCE` constant for comparing rounded amounts, facilitating invariant checks in financial entries. - Created comprehensive tests for `roundOre`, covering typical cases, edge cases, and idempotency. - Added year-end invariants tests to verify database-level guarantees for closing entries, ensuring they balance to the öre and reject discrepancies. - Developed end-to-end tests for the dispositions chain, validating the correctness of calculations across various scenarios. * fix: update PDF rendering to remove Swish QR code generation and set default to disable Swish visibility * fix: enhance security by rejecting data URIs in safeReturnTo function tests * fix: improve rounding logic in roundOre function and add customer_type migration * fix: add customer_type column to customers and enforce CHECK constraint --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
5725c25bf1 |
Logs/improved logging (#398)
* feat(mcp): add create_transactions tool with /pending approval gate New MCP tool gnubok_create_transactions stages 1–10 transactions per call as pending_operations of type create_transaction (risk: medium). Each item becomes its own card on /pending; on confirm, the executor inserts the row into transactions with import_source='mcp' so MCP-staged ingestion is distinguishable from PSD2 sync. Designed for skill workflows that pull external data (e.g., Airtable) and want the user to gate the writes. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(bas): strip concatenated group headers from corrupted account names A chart-data import bug had glued the next group's header onto the last account in each preceding group across all eight bas-data class files (e.g. account 2670 read "Utgående moms på försäljning inom EU, OSS 27 PERSONALENS SKATTER, AVGIFTER OCH LÖNEAVDRAG"). The corrupted names surface in transaction dropdowns, ledgers, SIE exports and årsredovisning, and risk VAT miscategorization on the OSS (2670) and blandad-verksamhet (6999) accounts specifically. - Cleans 69 account_name and 64 description fields across class-1..8 files - Adds a regression test asserting no name contains a concatenated header - Ships an idempotent safety-net migration that updates already-seeded chart_of_accounts rows, gated on the corrupted string so user customizations are preserved Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat(errors): add structured error codes and handling for various operations - Introduced a new structured error registry in `structured-errors.ts` to standardize error handling across the application. - Added Swedish and English messages for various error scenarios, including validation, authorization, and bookkeeping errors. - Implemented a client-side error toast in `use-error-toast.ts` to display user-friendly error messages with remediation hints. - Created a wrapper for recording operation outcomes in `record-operation.ts`, enhancing audit capabilities for operations. - Developed a provider call wrapper in `with-provider-call.ts` to handle external HTTP calls with structured logging and error mapping. - Added a new SQL migration to extend the processing history with new event types and aggregate types for better operational telemetry. * Refactor supplier API routes to use context-based logging and error handling - Replaced direct Supabase client usage in GET and POST routes with context-based approach using `withRouteContext`. - Enhanced error handling to provide structured error responses for supplier creation and listing. - Updated logging to include request IDs for better traceability. - Introduced new error codes for supplier-related operations. - Refactored tax deadlines cron job to utilize context and improved error handling. - Updated ESLint configuration to enforce logging practices across API and lib directories. - Enhanced arcim migration extension with structured error handling and logging. - Added classification for provider errors to improve user-facing error messages. - Introduced request ID in extension context for better log correlation. * fix(route-context): update DynamicParams type for improved type safety in route handlers * feat(transactions): add 'create_transaction' operation to PendingOperationType * fix(route): ensure companyId is non-nullable in loadAndDeriveAbsence function * fix(route-context): ensure companyId is always non-null by short-circuiting with COMPANY_CONTEXT_MISSING --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
0dd1f5ebc1 |
feat: multi-tenant company refactor (GNU-19) (#153)
* 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> |
||
|
|
03b569d708 |
refactor: consolidate extension system to general-only with manifest-driven architecture
- Remove all sector-specific extensions (construction, ecommerce, export, hotel, restaurant, tech) — only general-purpose extensions remain - Move NE-bilaga and SRU export from extensions to core reports (lib/reports/) - Move moms-box-mapping from extensions/export/shared to lib/vat/ - Replace per-extension API routes with catch-all dispatcher (app/api/extensions/ext/[...path]/route.ts) - Add manifest.json for each extension with metadata, env vars, and deps - Add api-routes.ts pattern for extension-defined API endpoints - Add code generation scripts (generate-extension-registry, create-extension) - Add extensions.config.json for opt-in extension loading - Add extensions.schema.json for config validation - Add email service interface with noop default (lib/email/service.ts) - Add CI workflow (core-build.yml) to verify core builds with zero extensions - Add migration 045: expand account_type CHECK for untaxed_reserves - Update CLAUDE.md with comprehensive extension system documentation - Update all report engines and bookkeeping services for new imports - Clean up extensions.schema.json to only list existing extensions Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> |
||
|
|
ba94f60d06 |
feat: add review confirmation dialogs and BAS account number tooltips
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> |