Fix/vat parent accounts (#438)

* feat(enable-banking): add support for account selection and syncing

- Updated StoredAccount interface to include an 'enabled' flag for account syncing preferences.
- Enhanced ensureFiscalPeriod function to handle overlapping fiscal periods with posted entries and opening balances.
- Added tests for fiscal period validation and account syncing logic.
- Implemented AccountPickerDialog component for user account selection.
- Created API routes for PATCH /accounts and POST /sync to manage account syncing.
- Introduced 'pending_selection' status for bank connections to allow user account selection before syncing.
- Updated database migration to support new connection status and backfill existing accounts with enabled=true.

* feat(enable-banking): implement account selection and consent event logging

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Mattsson
2026-05-11 17:12:00 +02:00
committed by GitHub
co-authored by Claude Opus 4.7
parent d0fbc2b616
commit a53a119a2e
20 changed files with 1761 additions and 112 deletions
+12
View File
@@ -39,6 +39,11 @@ const PERSISTED_EVENT_TYPES: CoreEventType[] = [
'mcp.tool_called',
'mcp.tools_list_called',
'mcp.resource_read',
// Bank connection consent lifecycle — required audit trail per ASVS V16
// and GDPR Art.30 (records of processing) for PSD2 consent decisions.
'bank_connection.consent_granted',
'bank_connection.account_selection_changed',
'bank_connection.revoked',
]
// Excluded (with reasoning):
@@ -65,6 +70,13 @@ function extractEntityId(payload: Record<string, unknown>): string | null {
}
}
// Flat-string ID fields on events that don't carry a full entity object.
// Bank connection events fall into this category — the connection lives in
// an extension table, so we record its id directly.
if (typeof payload.connectionId === 'string') {
return payload.connectionId
}
// For journal_entry.corrected: use the corrected entry's ID
if ('corrected' in payload) {
const corrected = payload.corrected
+5
View File
@@ -35,6 +35,11 @@ export type CoreEvent =
| { type: 'transaction.synced'; payload: { transactions: Transaction[]; userId: string; companyId: string } }
| { type: 'transaction.categorized'; payload: { transaction: Transaction; account: string; taxCode: string; userId: string; companyId: string } }
| { type: 'transaction.reconciled'; payload: { transaction: Transaction; journalEntryId: string; method: ReconciliationMethod; userId: string; companyId: string } }
// Bank connection lifecycle — consent + account selection are the
// GDPR/PSD2 audit points; emitted to event_log for compliance trail.
| { type: 'bank_connection.consent_granted'; payload: { connectionId: string; bankName: string | null; accountCount: number; consentExpiresAt: string | null; userId: string; companyId: string } }
| { type: 'bank_connection.account_selection_changed'; payload: { connectionId: string; bankName: string | null; previousStatus: string; newStatus: string; enabledCount: number; totalCount: number; userId: string; companyId: string } }
| { type: 'bank_connection.revoked'; payload: { connectionId: string; bankName: string | null; userId: string; companyId: string } }
// Periods
| { type: 'period.locked'; payload: { period: FiscalPeriod; userId: string; companyId: string } }
| { type: 'period.unlocked'; payload: { period: FiscalPeriod; userId: string; companyId: string } }