feat: implement skattekonto drift detection and alerting (#525)

* feat: implement skattekonto drift detection and alerting

- Add skattekonto drift computation logic to compare Skatteverket's saldo with GL 1630 sum.
- Implement alerting mechanism for significant drift changes, with throttling to prevent alert spamming.
- Introduce database functions to sum GL 1630 entries and list unbooked skattekonto rows.

feat: create own account transfer detection

- Develop logic to detect transfers between a company's own cash accounts based on counterparty IBAN.
- Implement tests to validate detection logic under various scenarios, including matching and non-matching IBANs.

feat: establish cash accounts as a first-class entity

- Create cash_accounts table to manage routable cash accounts, replacing ad-hoc JSONB structures.
- Implement functions for listing, upserting, and managing cash accounts, including primary account designation.

feat: enhance GL line reconciliation functionality

- Modify get_unlinked_1930_lines RPC to accept any account number for reconciliation, improving flexibility for different currencies.
- Update related functions to ensure compatibility with the new cash_accounts structure.

feat: capture counterparty IBAN in transactions

- Add counterparty_iban column to transactions table to facilitate intra-account transfer detection.
- Create index for efficient lookups based on counterparty IBAN.

* feat: Enhance cash account handling and reconciliation processes

- Updated reconciliation routes to enforce cash account validation for all account numbers, including '1930'.
- Improved error handling for unknown cash accounts in reconciliation status and unmatched entries routes.
- Changed CashAccountSelector to use sessionStorage instead of localStorage for better data privacy.
- Fixed mapping for employer payroll taxes to route to the correct account (2730 instead of 2731).
- Added safety checks for company IDs in the guessCounterAccount function to prevent injection vulnerabilities.
- Introduced atomic RPC for setting primary cash accounts to avoid intermediate states during updates.
- Seeded default cash accounts for new companies to ensure reconciliation routes are accessible from day one.
- Updated email notifications for drift detection to avoid exposing sensitive financial data.
- Enhanced bank reconciliation logic to handle multi-currency transactions correctly.
- Renamed and updated tests to reflect changes in the underlying RPCs and ensure accurate coverage.
- Migrated existing cash account rules to correct mappings in compliance with Swedish accounting standards.
This commit is contained in:
Mattsson
2026-05-19 16:10:18 +02:00
committed by GitHub
parent e211ab31be
commit 8a6ce7093e
42 changed files with 3420 additions and 206 deletions
+109
View File
@@ -125,3 +125,112 @@ processing_activities:
- tls_1_3_to_skatteverket
- bankid_signing_required_for_filing
- immutable_audit_log
- id: psd2.cash_account_mirror
name: PSD2-konton speglas till cash_accounts
purpose: >-
När en bank-anslutning via Enable Banking returnerar kontolista efter
lyckad PSD2-consent kopieras kontometadata (IBAN, valuta, kontonamn,
external_uid) till cash_accounts så att avstämning, motkontoresolver
och __PRIMARY_SEK__-sentinel kan rutta verifikat utan att läsa JSONB
från bank_connections.accounts_data vid varje fråga.
lawful_basis: art_6_1_b # contract (PSD2 consent + bookkeeping service)
special_category_basis: null
controller: gnubok-tenant
processor: anthropic-na
data_subjects:
- business_owner
data_categories:
- user.financial.bank_account # IBAN
- user.contact # account name (kontotitel)
recipients:
- name: Supabase
country: EU
role: processor
international_transfers:
applicable: false
mechanism: null
note: EU-only processor; no third-country transfer.
retention:
duration: consent_lifetime
basis: psd2_consent
stored_in:
- cash_accounts
- bank_connections.accounts_data
security_measures:
- rls_company_scoped
- data_minimization_no_balance_on_callback
- failure_emitted_to_event_log
- id: transactions.counterparty_iban
name: Motpartens IBAN på transaktioner
purpose: >-
Spara motpartens IBAN på transaktionsraden så att own-account-detector
kan identifiera överföringar mellan företagets egna konton (1930 → 1932
etc.) och bokföra båda benen automatiskt istället för att felbokföra
utflödet som extern kostnad. Krävs även för payment-matchning mot
leverantörsfakturor.
lawful_basis: art_6_1_b # contract (bookkeeping service)
special_category_basis: null
controller: gnubok-tenant
processor: anthropic-na
data_subjects:
- business_owner
- counterparty
data_categories:
- user.financial.bank_account # counterparty IBAN
recipients:
- name: Supabase
country: EU
role: processor
international_transfers:
applicable: false
mechanism: null
note: EU-only processor.
retention:
duration: 7y
basis: bfl_7_kap
stored_in:
- transactions.counterparty_iban
security_measures:
- rls_company_scoped
- immutable_after_post
- id: skattekonto.drift_alert
name: Skattekonto-drift via e-post
purpose: >-
Underrätta företagets kontaktadress när det cachade Skatteverket-saldot
avviker från GL 1630 utöver konfigurerad tolerans (> 1 SEK), så
bokföraren kan granska skattekonto-raderna. E-postmeddelandet
innehåller ingen finansiell siffra utan en länk till autentiserad
dashboard; mottagaren valideras mot company_members innan utskick.
lawful_basis: art_6_1_f # legitimate interest (bookkeeping accuracy)
special_category_basis: null
controller: gnubok-tenant
processor: resend
data_subjects:
- business_owner
- company_member
data_categories:
- user.contact.email
recipients:
- name: Resend
country: US
role: processor
international_transfers:
applicable: true
mechanism: scc_2021_c2p
note: >-
Resend (US) — SCC Module 2 (controller-to-processor). Outbound
payload limited to ett notifieringsmail utan finansiella belopp;
TIA dokumenterad i .compliance/tia/resend.md.
retention:
duration: 30d
basis: event_log_ttl
stored_in:
- event_log
security_measures:
- recipient_membership_check_before_send
- no_financial_figures_in_body
- tls_to_resend
- rls_company_scoped