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
This commit is contained in:
Mattsson
2026-07-21 23:00:15 +02:00
committed by GitHub
parent 702512437a
commit e11f70b347
467 changed files with 17569 additions and 2221 deletions
@@ -1,5 +1,6 @@
import { NextResponse } from 'next/server'
import { withRouteContext } from '@/lib/api/with-route-context'
import { getErrorMessage as getUserErrorMessage } from '@/lib/errors/get-error-message'
// GET /api/documents/:id/extraction-status
//
@@ -29,7 +30,7 @@ export const GET = withRouteContext<{ params: Promise<{ id: string }> }>(
.eq('company_id', companyId)
.maybeSingle()
if (error) return NextResponse.json({ error: error.message }, { status: 500 })
if (error) return NextResponse.json({ error: getUserErrorMessage(error) }, { status: 500 })
if (!data) return NextResponse.json({ error: 'Not found' }, { status: 404 })
const extractedAt = data.extracted_at as string | null
+2 -1
View File
@@ -2,6 +2,7 @@ import { NextResponse } from 'next/server'
import { requireAuth } from '@/lib/auth/require-auth'
import { createServiceClient } from '@/lib/supabase/server'
import { contentDisposition } from '@/lib/api/content-disposition'
import { getErrorMessage as getUserErrorMessage } from '@/lib/errors/get-error-message'
/**
* GET /api/documents/:id/inline
@@ -83,7 +84,7 @@ export async function GET(
if (downloadError || !blob) {
return NextResponse.json(
{ error: `Failed to download document: ${downloadError?.message ?? 'unknown error'}` },
{ error: `Failed to download document: ${getUserErrorMessage(downloadError) ?? 'unknown error'}` },
{ status: 500 }
)
}
+4 -3
View File
@@ -4,6 +4,7 @@ import { linkToJournalEntry } from '@/lib/core/documents/document-service'
import { withRouteContext } from '@/lib/api/with-route-context'
import { errorResponseFromCode } from '@/lib/errors/get-structured-error'
import { LinkDocumentSchema } from '@/lib/api/schemas'
import { getErrorMessage as getUserErrorMessage } from '@/lib/errors/get-error-message'
ensureInitialized()
@@ -73,7 +74,7 @@ export const POST = withRouteContext(
// Non-fatal: the verifikat ↔ underlag link already succeeded.
opLog.warn('inbox item stamp after link failed', {
inboxItemId: body.inbox_item_id,
reason: inboxError.message,
reason: getUserErrorMessage(inboxError),
})
} else if (!stamped || stamped.length === 0) {
// Zero rows updated means the supplied inbox_item_id / document_id
@@ -100,7 +101,7 @@ export const POST = withRouteContext(
// pin is row-level UX on the /transactions list.
opLog.warn('transaction pin after link failed', {
transactionId: body.transaction_id,
reason: pinError.message,
reason: getUserErrorMessage(pinError),
})
}
}
@@ -125,7 +126,7 @@ export const POST = withRouteContext(
}
return errorResponseFromCode('DOC_LINK_FAILED', opLog, {
requestId,
details: { reason: message || 'unknown' },
details: { reason: getUserErrorMessage(err) },
})
}
},
+3 -2
View File
@@ -3,6 +3,7 @@ import { ensureInitialized } from '@/lib/init'
import { withRouteContext } from '@/lib/api/with-route-context'
import { deleteDocument } from '@/lib/core/documents/document-service'
import { eventBus } from '@/lib/events'
import { getErrorMessage as getUserErrorMessage } from '@/lib/errors/get-error-message'
ensureInitialized()
@@ -34,7 +35,7 @@ export const GET = withRouteContext<{ params: Promise<{ id: string }> }>(
if (signError) {
return NextResponse.json(
{ error: `Failed to create download URL: ${signError.message}` },
{ error: `Failed to create download URL: ${getUserErrorMessage(signError)}` },
{ status: 500 }
)
}
@@ -80,7 +81,7 @@ export const DELETE = withRouteContext<{ params: Promise<{ id: string }> }>(
} catch (error) {
console.error('[documents/DELETE] Failed to delete document:', error)
return NextResponse.json(
{ error: error instanceof Error ? error.message : 'Failed to delete document' },
{ error: error instanceof Error ? getUserErrorMessage(error) : 'Failed to delete document' },
{ status: 500 }
)
}
+2 -1
View File
@@ -2,6 +2,7 @@ import { NextResponse } from 'next/server'
import { ensureInitialized } from '@/lib/init'
import { withRouteContext } from '@/lib/api/with-route-context'
import { verifyIntegrity } from '@/lib/core/documents/document-service'
import { getErrorMessage as getUserErrorMessage } from '@/lib/errors/get-error-message'
ensureInitialized()
@@ -21,7 +22,7 @@ export const POST = withRouteContext<{ params: Promise<{ id: string }> }>(
} catch (error) {
console.error('[documents/verify/POST] Verification failed:', error)
return NextResponse.json(
{ error: error instanceof Error ? error.message : 'Verification failed' },
{ error: error instanceof Error ? getUserErrorMessage(error) : 'Verification failed' },
{ status: 500 }
)
}
+3 -2
View File
@@ -2,6 +2,7 @@ import { NextResponse } from 'next/server'
import { ensureInitialized } from '@/lib/init'
import { withRouteContext } from '@/lib/api/with-route-context'
import { createNewVersion, validateDocumentFile } from '@/lib/core/documents/document-service'
import { getErrorMessage as getUserErrorMessage } from '@/lib/errors/get-error-message'
ensureInitialized()
@@ -42,7 +43,7 @@ export const POST = withRouteContext<{ params: Promise<{ id: string }> }>(
} catch (error) {
console.error('[documents/versions/POST] Version creation failed:', error)
return NextResponse.json(
{ error: error instanceof Error ? error.message : 'Version creation failed' },
{ error: error instanceof Error ? getUserErrorMessage(error) : 'Version creation failed' },
{ status: 500 }
)
}
@@ -83,7 +84,7 @@ export const GET = withRouteContext<{ params: Promise<{ id: string }> }>(
.order('version', { ascending: true })
if (versionsError) {
return NextResponse.json({ error: versionsError.message }, { status: 500 })
return NextResponse.json({ error: getUserErrorMessage(versionsError) }, { status: 500 })
}
return NextResponse.json({ data: versions })
+2 -1
View File
@@ -1,5 +1,6 @@
import { NextResponse } from 'next/server'
import { withRouteContext } from '@/lib/api/with-route-context'
import { getErrorMessage as getUserErrorMessage } from '@/lib/errors/get-error-message'
/**
* GET /api/documents/counts?journal_entry_ids=id1,id2,...
@@ -34,7 +35,7 @@ export const GET = withRouteContext('document.counts', async (request, ctx) => {
.in('journal_entry_id', ids)
if (error) {
return NextResponse.json({ error: error.message }, { status: 500 })
return NextResponse.json({ error: getUserErrorMessage(error) }, { status: 500 })
}
// Group and count by journal_entry_id
+3 -2
View File
@@ -2,6 +2,7 @@ import { NextResponse } from 'next/server'
import { ensureInitialized } from '@/lib/init'
import { uploadDocument, validateDocumentFile } from '@/lib/core/documents/document-service'
import { withRouteContext } from '@/lib/api/with-route-context'
import { getErrorMessage } from '@/lib/errors/get-error-message'
import { errorResponse, errorResponseFromCode } from '@/lib/errors/get-structured-error'
import type { DocumentUploadSource } from '@/types'
@@ -78,7 +79,7 @@ export const POST = withRouteContext(
if (/locked\/closed fiscal period|Bokföringen är låst/i.test(message)) {
return errorResponseFromCode('DOC_UPLOAD_PERIOD_LOCKED', opLog, {
requestId,
details: { reason: message },
details: { reason: getErrorMessage(err) },
})
}
// Magic-byte validation rejections (validateDocumentMagicBytes) are a
@@ -88,7 +89,7 @@ export const POST = withRouteContext(
opLog.warn('document upload rejected by content validation', { reason: message })
return errorResponseFromCode('DOC_UPLOAD_INVALID_CONTENT', opLog, {
requestId,
details: { reason: message },
details: { reason: getErrorMessage(err) },
})
}
// Full error is logged above; the raw message can leak storage-layer