* feat: add sandbox infrastructure — migration, types, and middleware
Add database migration for sandbox support:
- Add `is_sandbox` boolean column to company_settings
- Update 4 enforcement trigger functions (journal entry immutability,
journal entry line immutability, retention enforcement, document
deletion blocking) to bypass checks for sandbox users
- Add `cleanup_sandbox_user()` SECURITY DEFINER function that handles
FK-safe deletion order (document_attachments → journal_entry_lines →
journal_entries → supplier_invoices → auth.users cascade)
- Add `cleanup_expired_sandbox_users()` function that loops over
sandbox users older than N hours with per-user error handling
Update TypeScript types:
- Add `is_sandbox: boolean` to CompanySettings interface
- Add `is_sandbox: false` to makeCompanySettings() test factory
Update middleware:
- Add `/sandbox` to public routes so the landing page is accessible
without authentication
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: add sandbox landing page, seed API, cleanup cron, and banner
Sandbox landing page (app/sandbox/page.tsx):
- Client component matching the existing auth page aesthetic
- Auth check: if logged in as real user, shows message to use incognito
- Otherwise shows feature overview (invoices, transactions, bookkeeping,
reports) with "Starta sandbox" button
- On click: signInAnonymously() → POST /api/sandbox/seed → redirect
- Uses window.location.href for full page load (ensures middleware
picks up new session cookies)
Seed API (app/api/sandbox/seed/route.ts):
- POST handler gated to anonymous users only (403 for real users)
- Idempotent: returns { seeded: false } if company_settings exists
- Seeds ~40 rows: profile, company_settings (is_sandbox: true,
onboarding_complete: true), chart of accounts (via RPC),
fiscal period, 3 customers (Swedish business, EU business,
individual), 4 invoices (paid/sent/overdue/draft), 4 invoice
items, 2 posted journal entries with 5 lines, 8 transactions
(3 categorized, 2 income, 3 uncategorized), 2 deadlines
- Journal entries inserted directly (not via engine) to avoid
event emission, using next_voucher_number() RPC
Cleanup cron (app/api/sandbox/cleanup/cron/route.ts):
- GET handler with CRON_SECRET Bearer token auth
- Creates service role Supabase client
- Calls cleanup_expired_sandbox_users RPC (24h default)
Sandbox banner (components/dashboard/SandboxBanner.tsx):
- Amber bar with dismiss button (client state, reappears on reload)
- Text: "Sandlådemiljö — dina data raderas automatiskt efter 24 timmar"
- "Skapa konto" link to /register
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: integrate sandbox into dashboard — banner, nav, settings safeguards
Dashboard layout (app/(dashboard)/layout.tsx):
- Fetch is_sandbox from company_settings
- Render SandboxBanner at top of page for sandbox users
- Pass isSandbox prop to DashboardNav
- Hide RecaptIdentify analytics for sandbox users
Root page (app/page.tsx):
- Same sandbox banner and isSandbox prop treatment as dashboard layout
(root page has its own layout, not wrapped by (dashboard)/layout)
DashboardNav (components/dashboard/DashboardNav.tsx):
- Add optional isSandbox prop
- Change logout button text to "Avsluta sandbox" when isSandbox
- Redirect to /sandbox instead of /login on logout for sandbox users
- Applied to both desktop sidebar and mobile drawer logout buttons
Settings page (app/(dashboard)/settings/page.tsx):
- Hide "Bank (PSD2)" tab entirely for sandbox users — prevents
connecting real bank accounts from a temporary anonymous session
- Hide "Radera konto" card for sandbox users — account auto-deletes
via cron, and the delete flow requires email confirmation
Vercel config (vercel.json):
- Add sandbox cleanup cron at 04:00 UTC daily
(/api/sandbox/cleanup/cron)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: remove audit trigger for non-existent tax_codes table
Migration 018 referenced public.tax_codes which was never created
(migration 012 is a placeholder). This caused failures when running
migrations from scratch on a fresh database.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: remove ALTER FUNCTION for 3 non-existent functions
Removed search_path pinning for create_invoice_with_items,
seed_asset_categories, and update_reconciliation_session_counts —
none of these functions were ever created in any migration.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: remove ALTER for generate_invoice_number (created in later migration)
The function is created in migration 20260306 with search_path already
set, but migration 20260304 tried to ALTER it before it existed.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Fixed redirect issue
* Update app/api/sandbox/seed/route.ts
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
* Update app/api/sandbox/seed/route.ts
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
* Update app/sandbox/page.tsx
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
* Fixed catch block issue
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
Broad update across dashboard pages, components, extensions, and lib code. Includes ESLint config additions, onboarding flow redesign, settings page refactor, help page content expansion, dead code removal, and test mock fixes. Adds dev docs and public assets.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remove ai-chat from extensions.config.json and docker/extensions.hosted.json
(kept in self-hosted config). Remove ChatWidget imports from dashboard layout
and root page. Reposition chat widget FAB and panel to bottom-right corner.
Regenerate extension registry.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Auto-create documents storage bucket on first upload. Default legacy general
extensions to enabled when no toggle row exists. Add ChatWidget to dashboard
root page with open-ai-chat event support and AI assistant quick action.
Add ensureInitialized to supplier invoices route for event emission.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remove influencer-specific features (campaigns, TikTok, gifts, shadow ledger,
contracts, briefings) and consolidate into a clean ERP foundation with core
bookkeeping, invoicing, receipts, tax reporting, and calendar functionality.
Reorganize database migrations into a clean numbered sequence.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>