Initial commit: Buildfor Life Budget app

Multi-company budget/project tracking tool built with SvelteKit 5,
PostgreSQL (Drizzle ORM), and Tailwind CSS v4.

Features:
- Auth: local (email/password with Argon2) + generic OIDC
- 4 roles per company: admin, manager, user, viewer
- Multi-company with per-company user membership
- Projects with budget allocation from company pool
- Expense submission with approval workflow
- Categories and tags for expense organization
- Reports with spending breakdowns (by category, project, time)
- CSV import for Actual Budget migration
- Company audit log tracking all budget and admin actions
- Remaining budget hero display on overview and budget pages
- Admin-only company creation; new users wait for invitation
- Deployment configs for systemd + nginx (bare metal/Proxmox)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-06 11:51:32 +07:00
commit 7a4ba0537f
86 changed files with 8963 additions and 0 deletions
+47
View File
@@ -0,0 +1,47 @@
<script lang="ts">
import type { LayoutData } from './$types';
import Sidebar from '$lib/components/layout/Sidebar.svelte';
let { data, children } = $props();
let sidebarOpen = $state(true);
</script>
<div class="flex h-screen bg-gray-50">
<Sidebar
user={data.user}
companies={data.companies}
open={sidebarOpen}
onToggle={() => (sidebarOpen = !sidebarOpen)}
/>
<div class="flex flex-1 flex-col overflow-hidden">
<!-- Top bar -->
<header class="flex h-14 items-center justify-between border-b border-gray-200 bg-white px-6">
<button
onclick={() => (sidebarOpen = !sidebarOpen)}
class="rounded-md p-1.5 text-gray-500 hover:bg-gray-100 lg:hidden"
>
<svg class="h-5 w-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16" />
</svg>
</button>
<div class="flex items-center gap-3 ml-auto">
<span class="text-sm text-gray-700">{data.user.displayName ?? data.user.email}</span>
<form method="POST" action="/logout">
<button
type="submit"
class="rounded-md px-3 py-1.5 text-sm text-gray-600 hover:bg-gray-100"
>
Sign Out
</button>
</form>
</div>
</header>
<!-- Main content -->
<main class="flex-1 overflow-y-auto p-6">
{@render children()}
</main>
</div>
</div>