Add README with setup and dev server instructions
Covers features, tech stack, prerequisites, database setup, environment variables, available scripts, deployment notes, project structure, and per-company role permissions. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,223 @@
|
||||
# Buildfor Life Budget
|
||||
|
||||
A self-hosted, multi-company budget and project tracking tool built for internal use at Buildfor Life (B4L). Designed as a replacement for Actual Budget, with support for multiple companies, role-based access, project-level budget allocation, and an expense approval workflow.
|
||||
|
||||
---
|
||||
|
||||
## Features
|
||||
|
||||
- **Multi-company** — manage multiple companies from a single instance; each with its own members, budget, and data
|
||||
- **Role-based access control** — per-company roles (admin, manager, user, viewer) with fine-grained permissions
|
||||
- **Project budget allocation** — allocate funds from the company pool to individual projects
|
||||
- **Expense submission and approval** — users submit expenses; managers/admins approve or reject
|
||||
- **Categories and tags** — organise expenses with categories and free-form tags
|
||||
- **Reports** — spending by category, spending by project, monthly trend, and budget vs actual
|
||||
- **CSV import** — migrate historical data from Actual Budget via CSV upload
|
||||
- **Audit log** — full company-scoped changelog of all significant actions
|
||||
- **Company and user management** — soft-delete companies, disable or permanently delete users (system admin only)
|
||||
- **Local authentication** — email + password with Argon2 password hashing
|
||||
- **OIDC SSO** — optional generic OIDC provider (Keycloak, Authentik, etc.) alongside local auth
|
||||
- **Light / dark mode** — toggle persisted to `localStorage`
|
||||
|
||||
---
|
||||
|
||||
## Tech Stack
|
||||
|
||||
- **Framework**: SvelteKit 5 with `adapter-node`
|
||||
- **Database**: PostgreSQL 14+ via `pg` driver
|
||||
- **ORM / migrations**: Drizzle ORM + Drizzle Kit
|
||||
- **Styling**: Tailwind CSS v4
|
||||
- **Auth**: `@node-rs/argon2` (password hashing), `@oslojs/crypto` (session tokens), generic OIDC
|
||||
- **Charts**: Chart.js
|
||||
- **CSV parsing**: PapaParse
|
||||
|
||||
---
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Node.js 20 or later
|
||||
- PostgreSQL 14 or later
|
||||
- A dedicated database user with full privileges on the `public` schema
|
||||
|
||||
---
|
||||
|
||||
## Setup
|
||||
|
||||
### 1. Clone the repository
|
||||
|
||||
```bash
|
||||
git clone https://git.b4l.co.th/B4L/buildfor_life_budget.git
|
||||
cd buildfor_life_budget
|
||||
```
|
||||
|
||||
### 2. Install dependencies
|
||||
|
||||
```bash
|
||||
npm install
|
||||
```
|
||||
|
||||
### 3. Create the database
|
||||
|
||||
```sql
|
||||
CREATE USER budget_app WITH PASSWORD 'your_password';
|
||||
CREATE DATABASE buildfor_life_budget OWNER budget_app;
|
||||
\c buildfor_life_budget
|
||||
GRANT ALL ON SCHEMA public TO budget_app;
|
||||
```
|
||||
|
||||
### 4. Configure environment variables
|
||||
|
||||
```bash
|
||||
cp .env.example .env
|
||||
```
|
||||
|
||||
Edit `.env` and fill in the required values (see [Environment Variables](#environment-variables) below).
|
||||
|
||||
### 5. Push the database schema
|
||||
|
||||
```bash
|
||||
npm run db:push
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Running the Dev Server
|
||||
|
||||
```bash
|
||||
npm run dev
|
||||
```
|
||||
|
||||
The app is available at [http://localhost:5173](http://localhost:5173).
|
||||
|
||||
---
|
||||
|
||||
## First-Time Admin Bootstrap
|
||||
|
||||
The first user to register receives a regular user account with no company access. To grant system-admin privileges, run the following SQL against the database:
|
||||
|
||||
```sql
|
||||
UPDATE users
|
||||
SET is_system_admin = true
|
||||
WHERE email = 'you@example.com';
|
||||
```
|
||||
|
||||
Only system admins can create companies. All other users must be invited to a company by an admin or manager.
|
||||
|
||||
---
|
||||
|
||||
## Available Scripts
|
||||
|
||||
| Script | Description |
|
||||
|---|---|
|
||||
| `npm run dev` | Start the Vite development server (port 5173) |
|
||||
| `npm run build` | Compile for production into `./build/` |
|
||||
| `npm run preview` | Preview the production build locally |
|
||||
| `npm run check` | Run `svelte-check` type checking |
|
||||
| `npm run db:push` | Push schema changes directly to the database (dev) |
|
||||
| `npm run db:generate` | Generate a new Drizzle migration file |
|
||||
| `npm run db:migrate` | Apply pending migrations |
|
||||
| `npm run db:studio` | Open Drizzle Studio in the browser |
|
||||
|
||||
---
|
||||
|
||||
## Building for Production
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
node build
|
||||
```
|
||||
|
||||
The build output lives in `./build/`. The app is started with `node build` and reads configuration from environment variables or `.env`.
|
||||
|
||||
---
|
||||
|
||||
## Environment Variables
|
||||
|
||||
| Variable | Required | Description |
|
||||
|---|---|---|
|
||||
| `PORT` | No | Port the Node server listens on (default: `3000`) |
|
||||
| `HOST` | No | Bind address (default: `127.0.0.1`) |
|
||||
| `ORIGIN` | Yes | Public-facing URL — used by SvelteKit for CSRF protection (e.g. `https://budget.b4l.co.th`) |
|
||||
| `DATABASE_URL` | Yes | PostgreSQL connection string, e.g. `postgresql://user:pass@localhost:5432/dbname` |
|
||||
| `OIDC_ISSUER_URL` | No | OIDC provider issuer URL. Leave blank to disable SSO. |
|
||||
| `OIDC_CLIENT_ID` | No | OIDC client ID |
|
||||
| `OIDC_CLIENT_SECRET` | No | OIDC client secret |
|
||||
| `OIDC_REDIRECT_URI` | No | Callback URL registered with the OIDC provider (e.g. `https://budget.b4l.co.th/oidc/callback`) |
|
||||
|
||||
---
|
||||
|
||||
## Deployment
|
||||
|
||||
Ready-to-use deployment files are in the `deploy/` directory:
|
||||
|
||||
| File | Purpose |
|
||||
|---|---|
|
||||
| `buildfor-life-budget.service` | systemd unit file — runs `node build` as a hardened service under the `budget-app` user |
|
||||
| `nginx.conf` | nginx reverse proxy — TLS termination, HTTP→HTTPS redirect, static asset caching, WebSocket upgrade headers |
|
||||
| `setup.sh` | Server provisioning helper script |
|
||||
|
||||
The app is served at `https://budget.b4l.co.th` behind nginx, which proxies to the Node process on `127.0.0.1:3000`.
|
||||
|
||||
---
|
||||
|
||||
## Project Structure
|
||||
|
||||
```
|
||||
buildfor_life_budget/
|
||||
├── src/
|
||||
│ ├── app.html # HTML shell
|
||||
│ ├── app.css # Global styles (Tailwind entry point)
|
||||
│ ├── hooks.server.ts # Session validation, auth middleware
|
||||
│ ├── lib/
|
||||
│ │ ├── components/ # Shared Svelte components
|
||||
│ │ ├── server/
|
||||
│ │ │ ├── auth/ # Session management, OIDC helpers
|
||||
│ │ │ ├── db/
|
||||
│ │ │ │ ├── schema.ts # Drizzle table definitions
|
||||
│ │ │ │ └── index.ts # Database client
|
||||
│ │ │ ├── audit.ts # Audit log helpers
|
||||
│ │ │ └── authorization.ts # Role/permission checks
|
||||
│ │ ├── stores/ # Svelte stores (e.g. theme)
|
||||
│ │ ├── types/ # Shared TypeScript types
|
||||
│ │ └── utils/ # Misc utility functions
|
||||
│ └── routes/
|
||||
│ ├── (auth)/ # Login, register, OIDC callback
|
||||
│ └── (app)/ # Authenticated area
|
||||
│ ├── dashboard/ # Home dashboard
|
||||
│ ├── companies/
|
||||
│ │ └── [companyId]/
|
||||
│ │ ├── projects/ # Project list and detail
|
||||
│ │ ├── expenses/ # Expense submission and approval
|
||||
│ │ ├── budget/ # Budget allocation
|
||||
│ │ ├── categories/ # Category management
|
||||
│ │ ├── reports/ # Spending reports and charts
|
||||
│ │ ├── import/ # CSV import (Actual Budget migration)
|
||||
│ │ └── settings/ # Company settings
|
||||
│ └── admin/ # System admin panel (users, companies)
|
||||
├── deploy/ # systemd unit, nginx config, setup script
|
||||
├── drizzle.config.ts # Drizzle Kit configuration
|
||||
├── svelte.config.js # SvelteKit / adapter-node config
|
||||
├── vite.config.ts # Vite / Tailwind plugin config
|
||||
└── .env.example # Environment variable template
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## User Roles
|
||||
|
||||
Roles are assigned per company. A user can have different roles in different companies.
|
||||
|
||||
| Role | Description |
|
||||
|---|---|
|
||||
| **Admin** | Full company control — manage members, roles, categories, settings, and approve or reject any expense |
|
||||
| **Manager** | Manage projects and budgets, approve or reject expenses submitted by users |
|
||||
| **User** | Submit and manage their own expenses, view project budgets |
|
||||
| **Viewer** | Read-only access to company budgets, projects, and reports |
|
||||
|
||||
System admins (set via SQL) can create and archive companies and disable or permanently delete any user account, regardless of company membership.
|
||||
|
||||
---
|
||||
|
||||
## License
|
||||
|
||||
Private / internal — all rights reserved.
|
||||
Reference in New Issue
Block a user