2026-09-04 09:19:14 +02:00
# VibeFinance — Beheer
2026-09-04 11:51:29 +02:00
De app draait in **2 containers** : `app` (Express API + gebouwde frontend) en
`postgres` . Eén image, één origin — geen aparte webserver en geen interne proxy.
2026-09-04 09:19:14 +02:00
---
## Ontwikkeling
```powershell
2026-09-04 11:51:29 +02:00
.\ dev . ps1 # build + start (standaard)
.\ dev . ps1 build # alleen bouwen
.\ dev . ps1 up -Target app # alleen de app herbouwen + herstarten
.\ dev . ps1 up -Target postgres # alleen de database herstarten
.\ dev . ps1 logs # logs van de app volgen
.\ dev . ps1 test # testsuite draaien
.\ dev . ps1 down # stoppen én volumes wissen
.\ dev . ps1 push # dev-image naar registry pushen
2026-09-04 09:19:14 +02:00
```
> Op macOS/Linux: gebruik `./dev.sh` met dezelfde argumenten.
2026-09-04 11:51:29 +02:00
In dev draait één container beide processen (zie `docker/dev-entrypoint.sh` ):
| Adres | Wat |
|---|---|
| http://localhost | Vite dev-server met hot reload |
| http://localhost:3001/api/health | de API rechtstreeks |
Vite proxyt `/api` naar `localhost:3001` binnen dezelfde container.
> ⚠️ Alleen `.\dev.ps1 down` wist de development-database (`docker compose down -v`).
> `.\dev.ps1 up` doet een gewone `down` en laat het volume staan.
---
## Testen
```powershell
2026-09-04 12:21:06 +02:00
.\ test . ps1 # dependency-check + backend-tests + build + smoketest
.\ test . ps1 -Unit # dependency-check + backend-tests
.\ test . ps1 -NoSmoke # zonder de stack te starten
.\ test . ps1 -Strict # faal als een dependency achterloopt
.\ test . ps1 -SkipDeps # dependency-check overslaan (bijv. offline)
2026-09-04 11:51:29 +02:00
```
Alles loopt in Docker; Node op de host is niet nodig.
| Stap | Wat er gebeurt |
|---|---|
2026-09-04 12:21:06 +02:00
| Dependency-check | `docker/check-updates.mjs` vergelijkt `package.json` met het npm-register |
2026-09-04 11:51:29 +02:00
| Backend-tests | `Dockerfile` target `test` → `node --test` in `backend/test/` , zonder database |
| Productiebuild | `Dockerfile` target `production` — faalt de Vite-build, faalt deze stap |
| Smoketest | app + postgres starten en `/api/health` en `/` opvragen |
2026-09-04 12:21:06 +02:00
De dependency-check draait standaard bij elke testronde, dus je ziet direct of
er updates open staan. Pakketten die bewust achterblijven zet je met een reden
in `docker/update-exceptions.json` ; die worden als `[vast ]` gemeld en laten de
check niet falen. Zonder netwerk: `-SkipDeps` . In een CI-gate: `-Strict` .
De check los draaien:
```bash
docker run --rm -v ${ PWD } :/repo -w /repo node:22-alpine node docker/check-updates.mjs
docker run --rm -v ${ PWD } :/repo -w /repo node:22-alpine node docker/check-updates.mjs --strict
```
Losse backend-tests en linting in een lopende dev-container:
2026-09-04 09:19:14 +02:00
```bash
2026-09-04 11:51:29 +02:00
docker compose -f docker-compose.dev.yml exec app npm test
2026-09-04 12:21:06 +02:00
docker compose -f docker-compose.dev.yml exec app npm run lint
docker compose -f docker-compose.dev.yml exec -w /app/frontend app npm run lint
2026-09-04 09:19:14 +02:00
```
2026-09-04 12:21:06 +02:00
---
2026-09-04 09:19:14 +02:00
---
## Release workflow
```powershell
# 1. Versienummer in package.json van "x.x.x-dev" naar "x.x.x"
2026-09-04 11:51:29 +02:00
# 2. Changelog.md bijwerken — die sectie wordt de release-notes
# 3. Token met release-rechten zetten
$env:GITEA_TOKEN = "<token>"
.\ release . ps1 # test, bouw (amd64+arm64), push, tag, Gitea-release
.\ release . ps1 -DryRun # droogloop — toont alle stappen zonder uit te voeren
.\ release . ps1 -NoBuild # sla docker build over, alleen tag + release
.\ release . ps1 -SkipTests # sla de testsuite over (niet aanbevolen)
2026-09-04 09:19:14 +02:00
2026-09-04 11:51:29 +02:00
# 4. Versienummer in package.json naar "x.x.(x+1)-dev" voor volgende cyclus
2026-09-04 09:19:14 +02:00
```
2026-09-04 11:51:29 +02:00
Het script bouwt één image voor `linux/amd64` en `linux/arm64` , zodat dezelfde
tag op een Raspberry Pi en op een x86-server werkt.
2026-09-04 09:19:14 +02:00
---
## Docker
```bash
# Update via pre-built images
docker compose pull && docker compose up -d
# Reset inclusief database ⚠️ wist alle data
docker compose down -v && docker compose up -d
```
2026-09-09 11:04:26 +02:00
Pullen vereist een registry-login op die host — zie
[Pullen op een deploy-machine ](#pullen-op-een-deploy-machine ).
2026-09-04 09:19:14 +02:00
### PostgreSQL versie-upgrade
Bij een upgrade van PostgreSQL (bijv. 16 → 18) is de bestaande data niet compatibel. Stappen:
```bash
# 1. Backup maken
docker exec vibefinance_postgres pg_dump -U vibefinance vibefinance > backup-$( date +%F) .sql
# 2. Oude containers en volumes verwijderen
docker compose down -v
# 3. Nieuwe versie starten
docker compose up -d
# 4. Backup terugzetten
docker exec -i vibefinance_postgres psql -U vibefinance -d vibefinance < backup-YYYY-MM-DD.sql
```
---
2026-09-04 11:51:29 +02:00
## Architectuur — één app-container
2026-09-04 09:19:14 +02:00
2026-09-04 11:51:29 +02:00
De Express-app serveert zowel de API als de gebouwde frontend:
2026-09-04 09:19:14 +02:00
2026-09-04 11:51:29 +02:00
| Verzoek | Wat de app doet |
|---|---|
| `/api/...` | REST API (rate limited) |
| `/assets/...` | statische build uit `STATIC_DIR` , 1 jaar `immutable` gecached |
| al het overige | `index.html` — fallback voor React-routing |
`STATIC_DIR` staat standaard op `/app/public` ; daar zet de `Dockerfile` de
Vite-build neer. Bestaat die map niet (bijv. in dev), dan serveert de app
alleen de API en logt dat bij het starten.
2026-09-04 09:19:14 +02:00
2026-09-04 11:51:29 +02:00
> Ontbreekt de build in het image, dan krijg je op `/` een 404 en werkt alleen
> `/api/...`. Controleer dan de `frontend-build` stage in de `Dockerfile`.
2026-09-04 09:19:14 +02:00
---
## Logs en diagnose
```bash
2026-09-04 11:51:29 +02:00
# Live logs (dev) — beide processen van de app-container
docker compose -f docker-compose.dev.yml logs -f app
2026-09-04 09:19:14 +02:00
# Live logs (productie)
docker compose logs -f
2026-09-04 11:51:29 +02:00
# Shell in de app-container (dev)
docker compose -f docker-compose.dev.yml exec app sh
2026-09-04 09:19:14 +02:00
# Status containers
docker compose ps
# Database inspecteren (dev)
docker exec -it vibefinance-postgres-dev psql -U vibefinance -d vibefinance
# Database inspecteren (productie)
docker exec -it vibefinance_postgres psql -U vibefinance -d vibefinance
```
---
## Data persistentie
De backend slaat alle data op in **PostgreSQL** .
| Omgeving | Volume | Mount pad |
|---|---|---|
| Productie | `vibefinance_pgdata` | `/var/lib/postgresql` |
| Development | `postgres_dev_data` | `/var/lib/postgresql` |
> PostgreSQL 18 gebruikt `PGDATA=/var/lib/postgresql/18/docker`. Het volume is gemount op `/var/lib/postgresql` zodat data bewaard blijft na een container restart.
**Backup maken:**
```bash
# Dev
docker exec vibefinance-postgres-dev pg_dump -U vibefinance vibefinance > backup-$( date +%F) .sql
# Productie
docker exec vibefinance_postgres pg_dump -U vibefinance vibefinance > backup-$( date +%F) .sql
```
**Backup terugzetten:**
```bash
# Dev
docker exec -i vibefinance-postgres-dev psql -U vibefinance -d vibefinance < backup-2026-04-08.sql
# Productie
docker exec -i vibefinance_postgres psql -U vibefinance -d vibefinance < backup-2026-04-08.sql
```
---
## Gebruikersbeheer
De eerste geregistreerde gebruiker krijgt automatisch de **Admin** -rol. Verdere accounts kunnen via de app aangemaakt worden (Gebruikersbeheer, Admin vereist) of via de API.
Rollen:
| Rol | Rechten |
|---|---|
| `Admin` | Alles, inclusief gebruikersbeheer |
| `Bewerker` | Data lezen en bewerken |
| `Viewer` | Alleen lezen |
---
## Productie checklist
- [ ] `POSTGRES_PASSWORD` instellen op een sterk wachtwoord
- [ ] `JWT_SECRET` aanpassen (genereer met `openssl rand -hex 64` )
- [ ] `CORS_ORIGIN` instellen op je domeinnaam
2026-09-04 11:51:29 +02:00
- [ ] `APP_PORT` aanpassen indien poort 3400 al in gebruik is
- [ ] Testsuite groen (`test.ps1` / `./test.sh` )
2026-09-04 09:19:14 +02:00
- [ ] TLS afhandelen via een externe reverse proxy (bijv. Nginx Proxy Manager, Caddy, Traefik)
---
2026-09-04 12:21:06 +02:00
## Dependencies bijwerken
Node hoeft niet op de host te staan; de lockfiles zijn met een container bij te
werken. Per map (`frontend` en `backend` ):
```bash
# Laatste versies opzoeken
docker run --rm -v ${ PWD } /frontend:/w -w /w node:22-alpine npm outdated
# Versies in package.json aanpassen, daarna de lockfile herschrijven
docker run --rm -v ${ PWD } /frontend:/w -w /w node:22-alpine npm install --package-lock-only
```
Daarna altijd de testsuite draaien — die bouwt ook het productie-image, dus een
kapotte upgrade valt meteen op:
```powershell
.\ test . ps1
```
En de dev-stack herbouwen. `node_modules` staan in anonieme volumes; zonder
`--renew-anon-volumes` blijven de oude versies staan. `.\dev.ps1 up` doet dit
al automatisch:
```powershell
.\ dev . ps1 up
```
> Let op bij majors: `eslint-plugin-react` loopt achter op ESLint (peer
> `<= ^9.7`), daarom staat de frontend op ESLint 9 en de backend op 10.
> Express 5 vereist benoemde wildcards in routes (`/api/*splat`); `server.js`
> gebruikt daarom pad-loze middleware in plaats van `app.get("*")`.
---
2026-09-04 09:19:14 +02:00
## Registry
```
2026-09-04 11:51:29 +02:00
vibehoogie.duckdns.org/vibe/vibefinance-app (frontend + backend in één image)
2026-09-04 09:19:14 +02:00
Tags:
latest productie — meest recente release
x.x.x productie — specifieke versie
latest-dev development — meest recente dev build
x.x.x-dev development — specifieke dev versie
```
2026-09-04 22:47:48 +02:00
Inloggen op de registry:
2026-09-04 09:19:14 +02:00
```bash
2026-09-04 11:51:29 +02:00
docker login vibehoogie.duckdns.org
2026-09-04 09:19:14 +02:00
```
2026-09-04 22:47:48 +02:00
Gebruikersnaam is je Gitea-account, wachtwoord een **access token** met scope
`write:package` (Gitea → Settings → Applications → Generate New Token). Zonder
login faalt een push met `401 Unauthorized` ; `release.ps1` en `dev.ps1 push`
controleren dit vóór de build en stoppen dan meteen.
Liever niet handmatig inloggen? Zet deze variabelen, dan logt het script zelf in:
```powershell
$env:REGISTRY_USER = "<gitea-gebruiker>"
$env:REGISTRY_TOKEN = "<gitea-token met write:package>"
```
Twee valkuilen: log in op `vibehoogie.duckdns.org` **zonder** `:3000` (dat is een
aparte sleutel in de credential store), en doe het als dezelfde Windows-gebruiker
in dezelfde shell — Docker-credentials zijn per gebruikersprofiel.
Controleren wat er is opgeslagen:
```powershell
docker-credential -desktop list
```
2026-09-09 11:04:26 +02:00
### Pullen op een deploy-machine
Het package is privé, dus ook een **pull** vereist een login — anoniem geeft
`401 Unauthorized` (`docker compose pull` meldt dan "no basic auth credentials"
of "pull access denied"). Eenmalig op de Docker-host:
```bash
docker login vibehoogie.duckdns.org
# gebruikersnaam: je Gitea-account
# wachtwoord: access token met scope read:package
```
Daarna werkt `docker compose pull && docker compose up -d` . De login komt in
`~/.docker/config.json` van de gebruiker die het commando uitvoert — doe het dus
als dezelfde gebruiker (bij `sudo docker` is dat root). Log in op
`vibehoogie.duckdns.org` **zonder** `:3000` .
Controleren zonder te pullen:
```bash
docker manifest inspect vibehoogie.duckdns.org/vibe/vibefinance-app:latest
```
2026-09-04 09:19:14 +02:00
---
## Update-notificaties
2026-09-04 09:19:23 +02:00
De app vergelijkt de draaiende versie met de laatste **release** op Gitea en toont
dat op het belletje in de topbalk en onder "Over VibeFinance".
**Hoe de check loopt**
1. De frontend vraagt `/api/update-check` op de eigen backend — de Gitea API stuurt
geen CORS-headers, dus de browser mag die niet direct bevragen.
2. De backend haalt `releases/latest` bij Gitea op en cachet het antwoord 15 minuten.
3. De frontend kijkt bij het openen, daarna elk half uur en bij het terugkeren naar
het tabblad. Alleen een écht hoger versienummer geeft een melding.
Builds met een `-dev` suffix melden nooit (die lopen voor op de laatste release).
Wil je de melding tijdens ontwikkeling toch testen: open de app met `?updatecheck`
in de URL.
**Configuratie**
De bron staat in de root `package.json` :
2026-09-04 09:19:14 +02:00
```json
2026-09-04 09:19:23 +02:00
"repository" : "https://vibehoogie.duckdns.org/vibe/VibeFinance" ,
"updateCheckUrl" : "https://vibehoogie.duckdns.org/api/v1/repos/vibe/VibeFinance/releases/latest"
```
`dev.ps1` zet die URL als `UPDATE_CHECK_URL` in de omgeving; in productie komt hij
uit `.env` (of de default in `docker-compose.yml` ). Beschikbare backend-variabelen:
| Variabele | Betekenis |
|---|---|
| `UPDATE_CHECK_URL` | Release-API die gepolld wordt. Leeg = melding uit. |
| `UPDATE_CHECK_TOKEN` | Alleen nodig als de repo in Gitea niet publiek leesbaar is. |
**Een release publiceren**
Een kale Git-tag is niet genoeg: `releases/latest` geeft alleen echte releases terug.
`release.ps1` maakt die aan (stap 4) met de changelog-sectie van die versie als
release-notes. Daarvoor is een Gitea-token met release-rechten nodig:
```powershell
$env:GITEA_TOKEN = "<token>"
.\ release . ps1
2026-09-04 09:19:14 +02:00
```
2026-09-04 09:19:23 +02:00
Zonder token slaat het script die stap over met een waarschuwing — images en tag
staan dan wel klaar, maar gebruikers zien geen melding tot de release bestaat.