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
+26
View File
@@ -0,0 +1,26 @@
[Unit]
Description=Buildfor Life Budget App
After=network.target postgresql.service
[Service]
Type=simple
User=budget-app
Group=budget-app
WorkingDirectory=/opt/buildfor-life-budget
EnvironmentFile=/opt/buildfor-life-budget/.env
ExecStart=/usr/bin/node build
Restart=on-failure
RestartSec=5
StandardOutput=journal
StandardError=journal
SyslogIdentifier=b4l-budget
# Security hardening
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/opt/buildfor-life-budget
PrivateTmp=true
[Install]
WantedBy=multi-user.target
+43
View File
@@ -0,0 +1,43 @@
server {
listen 80;
server_name budget.b4l.co.th;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
server_name budget.b4l.co.th;
ssl_certificate /etc/letsencrypt/live/budget.b4l.co.th/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/budget.b4l.co.th/privkey.pem;
# Security headers
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
add_header Referrer-Policy strict-origin-when-cross-origin;
# Compression
gzip on;
gzip_types text/plain text/css application/json application/javascript text/xml;
gzip_min_length 1000;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
proxy_cache_bypass $http_upgrade;
}
# Cache immutable static assets
location /_app/immutable/ {
proxy_pass http://127.0.0.1:3000;
expires 1y;
add_header Cache-Control "public, immutable";
}
}
+48
View File
@@ -0,0 +1,48 @@
#!/bin/bash
# Buildfor Life Budget - Server Setup Script
# Run on a fresh Debian/Ubuntu Proxmox VM
set -euo pipefail
APP_USER="budget-app"
APP_DIR="/opt/buildfor-life-budget"
DOMAIN="budget.b4l.co.th"
echo "=== Installing dependencies ==="
apt-get update
apt-get install -y nginx certbot python3-certbot-nginx postgresql nodejs npm
echo "=== Setting up PostgreSQL ==="
sudo -u postgres psql <<SQL
CREATE USER budget_app WITH PASSWORD 'CHANGE_ME_IMMEDIATELY';
CREATE DATABASE buildfor_life_budget OWNER budget_app;
SQL
echo "=== Creating app user ==="
useradd --system --no-create-home --shell /usr/sbin/nologin $APP_USER
echo "=== Creating app directory ==="
mkdir -p $APP_DIR
chown $APP_USER:$APP_USER $APP_DIR
echo "=== Copying nginx config ==="
cp nginx.conf /etc/nginx/sites-available/$DOMAIN
ln -sf /etc/nginx/sites-available/$DOMAIN /etc/nginx/sites-enabled/
nginx -t && systemctl reload nginx
echo "=== Setting up SSL ==="
certbot --nginx -d $DOMAIN --non-interactive --agree-tos --email admin@b4l.co.th
echo "=== Installing systemd service ==="
cp buildfor-life-budget.service /etc/systemd/system/
systemctl daemon-reload
systemctl enable buildfor-life-budget
echo ""
echo "=== Setup complete ==="
echo "Next steps:"
echo "1. Copy the built application to $APP_DIR"
echo "2. Create $APP_DIR/.env (see .env.example)"
echo "3. Run: cd $APP_DIR && npx drizzle-kit migrate"
echo "4. Run: systemctl start buildfor-life-budget"
echo "5. CHANGE the PostgreSQL password!"