Files
accounted/next.config.ts
T
Jakob Wennberg 8cce21983f fix: trial balance 1000-row limit and rename /nyckeltal to /kpi (#79)
* fix: trial balance silently truncated at 1000 entries, rename /nyckeltal to /kpi

Trial balance bug:
- The old implementation fetched journal entry IDs (capped at 1000 by
  Supabase default limit), then queried lines via .in(entryIds) which
  also hit URL length limits with large arrays of UUIDs.
- SIE imports create thousands of entries → KPIs showed zero.
- Replaced with a single joined query (journal_entry_lines → journal_entries)
  using fetchAllRows() pagination. No row limit, no URL length issue.
- Removed the non-existent generate_trial_balance RPC call.

Page rename:
- /nyckeltal → /kpi (CLAUDE.md: all code in English)
- Nav label stays "Nyckeltal" (user-facing Swedish UI)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: select filtered columns in joined query, rename component, add redirect

- Select user_id/fiscal_period_id/status from journal_entries!inner()
  so PostgREST applies embedded filters reliably (defense in depth)
- Rename NyckeltalPage → KpiPage per English code convention
- Add permanent /nyckeltal → /kpi redirect for existing bookmarks

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 17:21:34 +01:00

71 lines
1.9 KiB
TypeScript

import type { NextConfig } from "next";
import { withSentryConfig } from "@sentry/nextjs";
const isDev = process.env.NODE_ENV === "development";
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL ?? "";
const cspDirectives = [
"default-src 'self'",
`connect-src 'self' ${supabaseUrl} https://*.supabase.co wss://*.supabase.co https://*.ingest.sentry.io https://*.enablebanking.com https://*.recapt.app`,
`style-src 'self' 'unsafe-inline' https://*.enablebanking.com`,
`script-src 'self' 'unsafe-inline'${isDev ? " 'unsafe-eval'" : ""} https://*.enablebanking.com https://cdn.recapt.app`,
"img-src 'self' data: blob: https:",
"font-src 'self'",
"worker-src 'self' blob:",
"frame-ancestors 'none'",
].join("; ");
const nextConfig: NextConfig = {
output: 'standalone',
async redirects() {
return [
{
source: '/nyckeltal',
destination: '/kpi',
permanent: true,
},
]
},
async headers() {
return [
{
source: "/(.*)",
headers: [
{
key: "Strict-Transport-Security",
value: "max-age=63072000; includeSubDomains; preload",
},
{
key: "X-Frame-Options",
value: "DENY",
},
{
key: "X-Content-Type-Options",
value: "nosniff",
},
{
key: "Referrer-Policy",
value: "strict-origin-when-cross-origin",
},
{
key: "Permissions-Policy",
value: "camera=(), microphone=(), geolocation=(), payment=()",
},
{
key: "Content-Security-Policy",
value: cspDirectives,
},
],
},
];
},
};
export default withSentryConfig(nextConfig, {
silent: !process.env.SENTRY_AUTH_TOKEN,
org: process.env.SENTRY_ORG,
project: process.env.SENTRY_PROJECT,
...(process.env.SENTRY_AUTH_TOKEN ? {} : { sourcemaps: { disable: true } }),
});