Files
accounted/app/(onboarding)/layout.tsx
T
Jakob Wennberg b387a77bfd chore: remove Sentry, consolidate migrations, add test coverage (#244)
* chore: remove Sentry, consolidate migrations, add test coverage

Remove @sentry/nextjs and all Sentry integration code — error tracking
now handled by Recapt. Consolidate 22 incremental migrations into a
single schema sync migration. Add 6 new test suites (auth, invoice
matching, VAT rules, opening balances) and extend report tests with
edge cases. Update Docker image name to gnubok, sync crontabs and
extension presets, fix CSP missing space, simplify journal entry
missing-document dialog.

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

* fix: remove viewer bank import migration never applied to production

20260413150000_viewer_bank_import_permissions.sql (PR #234) was merged
to main but never applied to the production database. It references
current_active_company_id() which does not exist in production either.
This breaks fresh installs and Supabase preview branches because the
migration runs before the consolidated schema sync.

Remove it so the migration chain matches production. The viewer bank
import RLS policies should be re-added in a future migration alongside
the helper functions they depend on.

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

* fix: correct delete policies for tables without company_id column

Seven tables in the generic delete-policy loop don't have a direct
company_id column, causing fresh installs to fail with "column
company_id does not exist". Fix by moving them out of the loop:

- invoice_items, journal_entry_lines, receipt_line_items,
  supplier_invoice_items → join through parent table
- extension_toggles, notification_settings, push_subscriptions →
  user-scoped (auth.uid() = user_id)

All policies match their existing production definitions.

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-04-15 10:52:00 +02:00

58 lines
2.1 KiB
TypeScript

import Link from 'next/link'
import { Settings } from 'lucide-react'
import { createClient, createServiceClient } from '@/lib/supabase/server'
export default async function OnboardingLayout({
children,
}: {
children: React.ReactNode
}) {
const supabase = await createClient()
const { data: { user } } = await supabase.auth.getUser()
// Only show the settings escape hatch for users who have completed
// onboarding at least once — i.e. they have a company_members row, even if
// it points to an archived company. Absolute first-time users don't need
// it and it clutters the welcome screen.
//
// Must use the service client: RLS on company_members goes through
// user_company_ids(), which filters out archived companies, so an
// authenticated query would return nothing for a user who archived their
// last company and make the escape hatch disappear exactly when it's
// needed most. Scoped to user_id = user.id, so no cross-user exposure.
let hasCompletedOnboarding = false
if (user) {
const service = createServiceClient()
const { data } = await service
.from('company_members')
.select('company_id')
.eq('user_id', user.id)
.limit(1)
.maybeSingle()
hasCompletedOnboarding = !!data
}
return (
<div className="min-h-screen bg-background flex items-center justify-center">
<div className="w-full max-w-lg px-5">
{children}
</div>
{/* Escape hatch: a user who archived their last company can still
reach account settings (and the delete-account flow) from here.
Hidden for absolute first-time users (no memberships ever). */}
{user && hasCompletedOnboarding && (
<Link
href="/settings/account"
aria-label="Kontoinställningar"
title="Kontoinställningar"
className="fixed bottom-5 right-5 z-50 flex h-10 w-10 items-center justify-center rounded-full border border-border bg-background/80 text-muted-foreground shadow-sm backdrop-blur transition-colors hover:border-foreground/40 hover:text-foreground"
>
<Settings className="h-4 w-4" />
</Link>
)}
</div>
)
}