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:
@@ -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
|
||||
@@ -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";
|
||||
}
|
||||
}
|
||||
@@ -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!"
|
||||
Reference in New Issue
Block a user