- Progressive Web App with Express + JSON backend - PIN-based auth, multi-device sync - Invoice + Statement PDF generation (branded, Grandstander + Nunito) - Mobile + Desktop responsive layouts - n8n backup integration - Custom logo upload - Settings for business info, fees, banking - Bulk invoice generation - Web Share API integration
234 lines
6.8 KiB
Markdown
234 lines
6.8 KiB
Markdown
# Deploying Slim Uiltjies AfterCare on Coolify
|
||
|
||
Step-by-step guide for hosting on [Coolify](https://coolify.io) (self-hosted PaaS).
|
||
|
||
## Prerequisites
|
||
|
||
- A running Coolify instance (v4.x)
|
||
- A Git repository with this code (GitHub, GitLab, Gitea, etc.)
|
||
- A domain you control (optional but recommended for HTTPS)
|
||
|
||
---
|
||
|
||
## Option A — One-click: Git repository (recommended)
|
||
|
||
### 1. Push your code
|
||
|
||
```bash
|
||
cd /Volumes/EXT/DEVELOPMENT/SLIMUILTIES
|
||
git init
|
||
git add .
|
||
git commit -m "Initial Slim Uiltjies app"
|
||
git remote add origin git@github.com:YOUR-USER/slimuiltjies.git
|
||
git push -u origin main
|
||
```
|
||
|
||
### 2. In Coolify, create a new Application
|
||
|
||
- Go to **Projects → + New → Application**
|
||
- Choose **Private Repository** (with deploy key) or **Public Repository**
|
||
- Pick your repo + branch (`main`)
|
||
- **Build Pack:** `Dockerfile`
|
||
- **Port:** `3000`
|
||
|
||
### 3. Add a Persistent Volume (CRITICAL — protects your data)
|
||
|
||
In the **Storage** tab of your new service:
|
||
|
||
| Mount Path | Size |
|
||
|---|---|
|
||
| `/data` | 1 GB (plenty for years of invoices) |
|
||
|
||
Without this step, **every redeploy will wipe your data**.
|
||
|
||
### 4. Set Environment Variables
|
||
|
||
In the **Environment Variables** tab:
|
||
|
||
| Key | Value | Notes |
|
||
|---|---|---|
|
||
| `ADMIN_PIN` | `847291` | **Change this before going live.** 6–8 digits recommended. |
|
||
| `N8N_WEBHOOK_URL` | _(empty by default)_ | Optional. Paste your n8n backup webhook URL when ready (see §6). |
|
||
| `N8N_WEBHOOK_TOKEN` | _(empty)_ | Optional auth token if your n8n webhook requires it. |
|
||
| `PORT` | `3000` | Don't change unless you know what you're doing. |
|
||
|
||
### 5. Set the domain
|
||
|
||
In **Domains**:
|
||
|
||
- Click **+ Add Domain**
|
||
- Enter your domain: `invoices.slimuiltjies.co.za`
|
||
- Coolify auto-provisions Let's Encrypt HTTPS
|
||
|
||
### 6. Deploy
|
||
|
||
Click **Deploy**. Watch the build logs. When you see `[server] Slim Uiltjies listening on :3000`, you're live.
|
||
|
||
### 7. Test
|
||
|
||
- Visit `https://invoices.slimuiltjies.co.za`
|
||
- Should see the PIN login screen
|
||
- Enter your PIN
|
||
- The app opens with the sample data
|
||
|
||
---
|
||
|
||
## Option B — Docker Compose
|
||
|
||
If you prefer compose-style configuration:
|
||
|
||
Create `docker-compose.yml` in this directory:
|
||
|
||
```yaml
|
||
version: "3.8"
|
||
services:
|
||
slimuiltjies:
|
||
build: .
|
||
container_name: slimuiltjies
|
||
restart: unless-stopped
|
||
ports:
|
||
- "3000:3000"
|
||
volumes:
|
||
- ./data:/data
|
||
environment:
|
||
- ADMIN_PIN=847291
|
||
- DATA_FILE=/data/data.json
|
||
- NODE_ENV=production
|
||
```
|
||
|
||
In Coolify: **+ New → Docker Compose** → paste the contents → set up domain → deploy.
|
||
|
||
This keeps the data file on the host (so `cp data/data.json data-2026-08-08.json` works for backups).
|
||
|
||
---
|
||
|
||
## 🔒 Before you go live (security checklist)
|
||
|
||
- [ ] **Change `ADMIN_PIN`** from the default `847291` to something only you know
|
||
- [ ] **Enable HTTPS** (Coolify does this automatically via Let's Encrypt)
|
||
- [ ] **Set up backups** — either n8n (see below) or periodic `cp` of `/data/data.json`
|
||
- [ ] **Test the PIN lockout** — close browser, reopen, confirm login screen appears
|
||
- [ ] **Bookmark the PWA install prompt** — on iPhone Safari → Share → Add to Home Screen
|
||
|
||
---
|
||
|
||
## 💾 Backup strategies
|
||
|
||
The app stores everything in `/data/data.json`. Backup options, cheapest to fanciest:
|
||
|
||
### Option 1 — Manual copy
|
||
|
||
SSH into your Coolify host:
|
||
```bash
|
||
docker cp slimuiltjies:/data/data.json ./slimuiltjies-backup-$(date +%F).json
|
||
```
|
||
Run weekly via cron.
|
||
|
||
### Option 2 — n8n auto-backup (recommended)
|
||
|
||
See §6 below. Every save is POSTed to an n8n webhook, where you can:
|
||
- Store in a database
|
||
- Email yourself a weekly summary
|
||
- Snapshot to Dropbox / S3 / Google Drive
|
||
- Pipe to an AI agent for queries
|
||
|
||
### Option 3 — Coolify's built-in storage snapshots
|
||
|
||
In **Storage → /data → Snapshots**, enable scheduled snapshots. Simple but coarse (file-level).
|
||
|
||
---
|
||
|
||
## 🔁 Setting up n8n backup (optional but recommended)
|
||
|
||
### Step 1 — Deploy n8n on Coolify (if you don't have it)
|
||
|
||
Coolify has a one-click n8n template: **+ New → Service → n8n**. Deploy it as a separate service on the same Coolify instance.
|
||
|
||
### Step 2 — Create the backup workflow in n8n
|
||
|
||
1. In n8n, create a new workflow
|
||
2. Add a **Webhook** trigger node:
|
||
- HTTP Method: `POST`
|
||
- Path: `slimuiltjies-backup`
|
||
- Authentication: Header Auth (create a credential with a random secret like `n8n-slim-secret-xyz123`)
|
||
3. Add a **Set** node to capture the body data
|
||
4. Add a **Postgres / MySQL / NocoDB** node to insert the data into a table
|
||
5. **Save** and copy the webhook URL
|
||
|
||
### Step 3 — Configure in the app
|
||
|
||
In the Slim Uiltjies app:
|
||
- Go to **Settings → Data**
|
||
- Paste your n8n webhook URL into the **"Auto-backup to n8n"** field
|
||
- Paste your auth token
|
||
- Tap **Test backup** — you should see a new record appear in n8n
|
||
|
||
Every change after that is pushed to n8n within ~30 seconds.
|
||
|
||
---
|
||
|
||
## 📱 Installing on phones (PWA)
|
||
|
||
Once deployed at your domain:
|
||
|
||
- **iPhone (Safari):** Visit your URL → tap Share → Add to Home Screen
|
||
- **Android (Chrome):** Visit your URL → tap the install banner at the bottom
|
||
|
||
The app icon is your owl mascot. It opens full-screen like a native app.
|
||
|
||
---
|
||
|
||
## 🐛 Troubleshooting
|
||
|
||
### "Login screen won't accept my PIN"
|
||
|
||
The PIN is case-sensitive and must match `ADMIN_PIN` exactly. To reset:
|
||
1. In Coolify, change `ADMIN_PIN` to a new value
|
||
2. Click **Redeploy**
|
||
3. Log in with the new PIN
|
||
|
||
If you forgot the PIN entirely:
|
||
1. SSH into the Coolify host
|
||
2. `docker exec -it slimuiltjies sh`
|
||
3. `cat /data/data.json` to confirm data is there (don't lose it!)
|
||
4. Redeploy with a new `ADMIN_PIN` via Coolify
|
||
|
||
### "Data disappeared after redeploy"
|
||
|
||
You forgot the Persistent Volume. To recover:
|
||
1. SSH into the host and check `/data/` — if it's empty, data is gone
|
||
2. Restore from your most recent backup (`cp backup.json /data/data.json`)
|
||
3. Add the Persistent Volume mount before redeploying again
|
||
|
||
### "App won't load — stuck on splash screen"
|
||
|
||
Check the browser console (F12) for errors. Common causes:
|
||
- Old cached SW from before the deploy — clear site data or use incognito
|
||
- Wrong domain in `manifest.json` — should be auto-relative, but check `<base>` tag if you added one
|
||
|
||
### "PDF generation is broken"
|
||
|
||
Check the browser console for jsPDF errors. Usually caused by:
|
||
- HTTPS not enabled (jsPDF needs it for some browsers)
|
||
- Service worker serving old code — force refresh
|
||
|
||
---
|
||
|
||
## 📊 Resource requirements
|
||
|
||
- **RAM:** ~50 MB idle, ~150 MB peak (during PDF generation)
|
||
- **CPU:** minimal
|
||
- **Disk:** data.json grows ~50 KB/month. 1 GB volume = 20+ years of headroom
|
||
- **Network:** tiny — single JSON sync every change
|
||
|
||
A free-tier Coolify instance handles this easily.
|
||
|
||
---
|
||
|
||
## 🔄 Updating the app
|
||
|
||
1. Push changes to your Git repo
|
||
2. Click **Redeploy** in Coolify
|
||
3. The Persistent Volume preserves `/data/data.json` across deploys
|
||
|
||
To verify the data is preserved, SSH in and `cat /data/data.json` before and after a redeploy.
|