feat: production readiness — 3-extension deploy with security hardening and observability

- Strip extensions to enable-banking, ai-categorization, ai-chat only
- Remove push-notifications cron from vercel.json
- Add security headers (HSTS, CSP, X-Frame-Options, Permissions-Policy)
- Add /api/health endpoint for uptime monitoring
- Add env var validation in ensureInitialized()
- Fix SIE4 #IB opening balance records from year-end closing entry
- Replace in-memory ai-chat rate limiter with Supabase-backed distributed rate limiting
- Add Sentry error tracking scaffolding (@sentry/nextjs, instrumentation hook)
- Add AI token usage tracking (migration 047, usage-tracker, wired into both AI extensions)
- Include pending enable-banking and dashboard improvements

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Jakob Wennberg
2026-03-02 11:32:43 +01:00
co-authored by Claude Opus 4.6
parent 1a1c6ba40f
commit 13725ffc16
33 changed files with 2852 additions and 271 deletions
@@ -1,12 +1,7 @@
// AUTO-GENERATED — do not edit. Run `npm run setup:extensions` to regenerate.
export const ENABLED_EXTENSION_IDS: ReadonlySet<string> = new Set([
'receipt-ocr',
'enable-banking',
'ai-categorization',
'ai-chat',
'push-notifications',
'invoice-inbox',
'calendar',
'enable-banking',
'email',
])
+2 -12
View File
@@ -1,21 +1,11 @@
// AUTO-GENERATED — do not edit. Run `npm run setup:extensions` to regenerate.
import type { Extension } from '../types'
import { receiptOcrExtension } from '@/extensions/general/receipt-ocr'
import { enableBankingExtension } from '@/extensions/general/enable-banking'
import { aiCategorizationExtension } from '@/extensions/general/ai-categorization'
import { aiChatExtension } from '@/extensions/general/ai-chat'
import { pushNotificationsExtension } from '@/extensions/general/push-notifications'
import { invoiceInboxExtension } from '@/extensions/general/invoice-inbox'
import { calendarExtension } from '@/extensions/general/calendar'
import { enableBankingExtension } from '@/extensions/general/enable-banking'
import { emailExtension } from '@/extensions/general/email'
export const FIRST_PARTY_EXTENSIONS: Extension[] = [
receiptOcrExtension,
enableBankingExtension,
aiCategorizationExtension,
aiChatExtension,
pushNotificationsExtension,
invoiceInboxExtension,
calendarExtension,
enableBankingExtension,
emailExtension,
]
@@ -4,21 +4,16 @@ import type { ExtensionDefinition } from '../types'
export const EXTENSION_DEFINITIONS: Record<string, ExtensionDefinition[]> = {
'general': [
{
"slug": "receipt-ocr",
"name": "Kvittoscanning",
"slug": "enable-banking",
"name": "Bankintegration (PSD2)",
"sector": "general",
"category": "import",
"icon": "Camera",
"icon": "Landmark",
"dataPattern": "manual",
"description": "Skanna kvitton och extrahera data automatiskt",
"longDescription": "Ladda upp kvittofoton och låt systemet automatiskt extrahera leverantör, belopp, moms och datum. Sparar tid och minskar manuell inmatning.",
"description": "Automatisk banktransaktionssynk via PSD2",
"longDescription": "Koppla ditt bankkonto direkt och synka transaktioner automatiskt via säker PSD2-bankintegration. Stöder de flesta svenska banker.",
"hasOwnData": true,
"quickAction": {
"label": "Skanna kvitto",
"description": "Fotografera & spara",
"icon": "Camera",
"href": "/receipts/scan"
}
"subscriptionNotice": "Denna integration kräver ett aktivt Enable Banking-abonnemang. Utan abonnemang kommer bankintegration inte att fungera."
},
{
"slug": "ai-categorization",
@@ -62,79 +57,5 @@ export const EXTENSION_DEFINITIONS: Record<string, ExtensionDefinition[]> = {
"event": "open-ai-chat"
}
},
{
"slug": "push-notifications",
"name": "Push-notiser",
"sector": "general",
"category": "operations",
"icon": "Bell",
"dataPattern": "core",
"description": "Händelsenotiser för bokföringsaktiviteter",
"longDescription": "Få push-notiser direkt i webbläsaren när viktiga händelser sker — nya fakturor, förfallna betalningar, slutförda bokföringar med mera.",
"readsCoreTables": [
"journal_entries",
"invoices",
"receipts"
]
},
{
"slug": "invoice-inbox",
"name": "Dokumentinkorg",
"sector": "general",
"category": "import",
"icon": "Inbox",
"dataPattern": "manual",
"description": "Ta emot alla dokument via e-post — fakturor, kvitton och myndighetspost",
"longDescription": "Skicka alla affärsdokument till en dedikerad e-postadress. AI klassificerar automatiskt dokumenttyp (faktura, kvitto, myndighetspost), extraherar data och matchar mot transaktioner. En inkorg för alla dokument.",
"hasOwnData": true,
"quickAction": {
"label": "Dokumentinkorg",
"description": "Granska inkommande dokument",
"icon": "Inbox",
"href": "/e/general/invoice-inbox"
}
},
{
"slug": "calendar",
"name": "Kalender",
"sector": "general",
"category": "operations",
"icon": "Calendar",
"dataPattern": "core",
"description": "Fullständig kalendervy med månads-, vecko- och dagsvisning",
"longDescription": "Se alla fakturadatum och deadlines i en interaktiv kalender med månads-, vecko- och dagsvy.",
"readsCoreTables": [
"invoices",
"deadlines",
"customers"
]
},
{
"slug": "enable-banking",
"name": "Bankintegration (PSD2)",
"sector": "general",
"category": "import",
"icon": "Landmark",
"dataPattern": "manual",
"description": "Automatisk banktransaktionssynk via PSD2",
"longDescription": "Koppla ditt bankkonto direkt och synka transaktioner automatiskt via säker PSD2-bankintegration. Stöder de flesta svenska banker.",
"hasOwnData": true,
"subscriptionNotice": "Denna integration kräver ett aktivt Enable Banking-abonnemang. Utan abonnemang kommer bankintegration inte att fungera."
},
{
"slug": "email",
"name": "E-post (Resend)",
"sector": "general",
"category": "operations",
"icon": "Mail",
"dataPattern": "core",
"description": "Skicka fakturor och påminnelser via e-post",
"longDescription": "Aktiverar e-postfunktioner: skicka fakturor till kunder, automatiska betalningspåminnelser (15/30/45 dagar), och e-postmeddelanden. Kräver ett Resend-konto med verifierad domän.",
"readsCoreTables": [
"invoices",
"customers",
"company_settings"
]
},
],
}
+1 -5
View File
@@ -4,11 +4,7 @@ import type { ComponentType } from 'react'
import type { WorkspaceComponentProps } from '../workspace-registry'
export const WORKSPACES: Record<string, ComponentType<WorkspaceComponentProps>> = {
'general/receipt-ocr': dynamic(() => import('@/components/extensions/general/ReceiptOcrWorkspace')),
'general/enable-banking': dynamic(() => import('@/components/extensions/general/EnableBankingWorkspace')),
'general/ai-categorization': dynamic(() => import('@/components/extensions/general/AiCategorizationWorkspace')),
'general/ai-chat': dynamic(() => import('@/components/extensions/general/AiChatWorkspace')),
'general/push-notifications': dynamic(() => import('@/components/extensions/general/PushNotificationsWorkspace')),
'general/invoice-inbox': dynamic(() => import('@/components/extensions/general/DocumentInboxWorkspace')),
'general/calendar': dynamic(() => import('@/components/extensions/general/CalendarWorkspace')),
'general/enable-banking': dynamic(() => import('@/components/extensions/general/EnableBankingWorkspace')),
}