621 lines
25 KiB
Markdown
621 lines
25 KiB
Markdown
# VibeFinance — Beheer
|
|
|
|
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.
|
|
|
|
---
|
|
|
|
## Ontwikkeling
|
|
|
|
```powershell
|
|
.\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
|
|
```
|
|
|
|
> Op macOS/Linux: gebruik `./dev.sh` met dezelfde argumenten.
|
|
|
|
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.
|
|
|
|
### Welke versie de dev-app toont
|
|
|
|
De versie in "Over VibeFinance" komt uit `VITE_APP_VERSION`. `dev.ps1` leest die
|
|
uit de **root** `package.json`, zet hem in de omgeving en synct hem naar
|
|
`frontend/package.json`. In de dev-container is het een *runtime*-variabele
|
|
(`docker-compose.dev.yml`, sectie `environment`) en geen build-arg: Vite bakt
|
|
`__APP_VERSION__` in bij het **starten** van de dev-server, niet bij het bouwen
|
|
van het image. Is hij leeg, dan valt `vite.config.js` terug op
|
|
`frontend/package.json`.
|
|
|
|
Ziet de app een oude versie, dan draait de dev-server nog van vóór de bump —
|
|
`.\dev.ps1 up` hercreëert de container en start Vite opnieuw. Start je de stack
|
|
handmatig met `docker compose -f docker-compose.dev.yml up`, dan staat
|
|
`VITE_APP_VERSION` niet in je shell en zie je de versie uit
|
|
`frontend/package.json`.
|
|
|
|
> Een versie met een suffix (`1.0.1-dev`) onderdrukt de update-melding
|
|
> permanent — zie [Update-notificaties](#update-notificaties).
|
|
|
|
---
|
|
|
|
## Testen
|
|
|
|
```powershell
|
|
.\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)
|
|
```
|
|
|
|
Alles loopt in Docker; Node op de host is niet nodig.
|
|
|
|
| Stap | Wat er gebeurt |
|
|
|---|---|
|
|
| Dependency-check | `docker/check-updates.mjs` vergelijkt `package.json` met het npm-register |
|
|
| 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 |
|
|
|
|
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:
|
|
|
|
```bash
|
|
docker compose -f docker-compose.dev.yml exec app npm test
|
|
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
|
|
```
|
|
|
|
---
|
|
|
|
## Tokens
|
|
|
|
**Eén token, op het werkstation.** Dat is genoeg omdat de `Vibe`-organisatie op
|
|
public staat: alles wat alleen *leest* heeft geen token meer nodig — `git clone`,
|
|
`docker compose pull` en de update-check van de app werken anoniem. Wat overblijft
|
|
is schrijven, en dat gebeurt allemaal vanaf deze ene machine.
|
|
|
|
| Token | Machine | Scopes | Gebruikt voor |
|
|
|---|---|---|---|
|
|
| `vibefinance-workstation` | dit werkstation | `write:package`, `write:repository` | `docker push` (`release.ps1`, `dev.ps1 push`) én het aanmaken van de Gitea-release |
|
|
|
|
Er is geen apart host-token en geen apart registry-token:
|
|
|
|
- **`git push`** gaat over SSH (`gitea@…:Vibe/VibeFinance.git`), dus die gebruikt
|
|
je SSH-sleutel en niet dit token. Werkt SSH even niet — bijvoorbeeld omdat de
|
|
ssh-agent niet meedoet in een niet-interactieve shell, wat `Permission denied
|
|
(publickey,password)` geeft — dan kun je *lezen* nu anoniem over https, omdat
|
|
de organisatie public is:
|
|
|
|
```powershell
|
|
git fetch https://vibehoogie.duckdns.org/Vibe/VibeFinance.git --prune --tags "+refs/heads/*:refs/remotes/origin/*"
|
|
```
|
|
|
|
Die refspec werkt ook `origin/*` bij, dus daarna doen `git merge --ff-only
|
|
origin/main` en `git log origin/main` het weer. Pushen blijft SSH; `release.ps1`
|
|
leest daarvoor `core.sshCommand` uit, omdat op Windows alleen de OpenSSH van het
|
|
systeem met de ssh-agent praat en Git's eigen `ssh` niet.
|
|
- **De registry** heeft geen eigen variabele nodig: `release.ps1` en `dev.ps1`
|
|
vallen bij een ontbrekende `REGISTRY_TOKEN` terug op `GITEA_TOKEN`. Zet alleen
|
|
`REGISTRY_USER` erbij, zodat het script zelf kan inloggen als de credential
|
|
store leeg is.
|
|
- **De Docker-host** hoeft niets meer te hebben: pull en update-check zijn anoniem.
|
|
|
|
Aanmaken: Gitea → Settings → Applications → Generate New Token, met **beide**
|
|
scopes aangevinkt. Doe dat onder een account dat push-rechten op de repo heeft —
|
|
lid zijn van de organisatie is daarvoor niet automatisch genoeg. Scopes van een
|
|
bestaand token zijn later niet aan te passen, dus vink ze in één keer goed aan.
|
|
|
|
**Waar hij terechtkomt** — `.env.release` naast de scripts, niet in git
|
|
(`.gitignore` pakt `.env.*`):
|
|
|
|
```ini
|
|
GITEA_TOKEN=<token met write:package + write:repository>
|
|
REGISTRY_USER=<je Gitea-account>
|
|
```
|
|
|
|
Een variabele die al in je shell staat wint, zodat je per run kunt afwijken. Een
|
|
lege waarde in het bestand wordt overgeslagen.
|
|
|
|
**Als de organisatie weer privé gaat** heb je er wél een tweede bij nodig: een
|
|
read-only token op de Docker-host, voor `docker compose pull` en
|
|
`UPDATE_CHECK_TOKEN`. Houd dat token dan read-only. Het staat in platte tekst in
|
|
`.env` op een server die de app op poort 3400 publiceert; met schrijfrechten kan
|
|
wie bij dat bestand komt — via de container, een shell op die host, of een
|
|
backup — een eigen image als `latest` naar de registry pushen, en die host pullt
|
|
`latest` zelf. Read-only houdt je eigen deploy-pad uit de aanvalsketen.
|
|
|
|
### Wat een foutcode betekent
|
|
|
|
| Status | Betekenis |
|
|
|---|---|
|
|
| 401 | Token ongeldig, verlopen of ingetrokken — Gitea herkent hem niet. Op de registry: helemaal niet ingelogd. |
|
|
| 403 | Het token **bestaat en werkt**, maar mist de **scope** voor dit endpoint. Gitea noemt de vereiste scope in de response-body. |
|
|
| 404 | Het token mag de repo niet zien. Gitea geeft geen 403, om niet te verklappen dat iets bestaat: verkeerd account, of geen toegang tot de organisatie. Nu de organisatie public is, wijst een 404 op een leesactie eerder op een verkeerde URL dan op rechten. |
|
|
|
|
Scopes van een bestaand token zijn in Gitea niet aan te passen. Bij een 403 maak
|
|
je dus een nieuw token aan; bijwerken kan niet.
|
|
|
|
**Leeft mijn token nog?** Juist dat onderscheid tussen 401 en 403 is de test.
|
|
Vraag *niet* `/api/v1/user` op om te kijken "wie het token is": het
|
|
werkstation-token heeft geen `read:user`, dus dat endpoint geeft altijd 403 en
|
|
zegt niets over geldigheid. Kijk naar de statuscode, niet naar de inhoud:
|
|
|
|
```powershell
|
|
$u = "https://vibehoogie.duckdns.org/api/v1/user/repos"
|
|
try { (Invoke-WebRequest $u -Headers @{ Authorization = "token $env:GITEA_TOKEN" } -UseBasicParsing).StatusCode }
|
|
catch { $_.Exception.Response.StatusCode.value__ }
|
|
```
|
|
|
|
`403` = het token leeft (alleen deze scope ontbreekt). `401` = ingetrokken of
|
|
fout gekopieerd. Nagemeten op 2026-09-10: geen header `401`, een nep-token van 40
|
|
nullen `401`, het werkstation-token `403`.
|
|
|
|
Vanuit de app-container op de host valt de body van een fout anders weg —
|
|
busybox-`wget` gooit die bij een foutstatus weg, en Node zit in het image:
|
|
|
|
```bash
|
|
# Anoniem, zoals de app het doet zonder UPDATE_CHECK_TOKEN
|
|
docker exec vibefinance_app node -e 'fetch(process.env.UPDATE_CHECK_URL,{headers:{Accept:"application/json"}}).then(async r=>console.log(r.status, (await r.text()).slice(0,300)))'
|
|
|
|
# Mét token, precies zoals routes/update.js de header opbouwt
|
|
docker exec vibefinance_app node -e 'const t=process.env.UPDATE_CHECK_TOKEN; fetch(process.env.UPDATE_CHECK_URL,{headers:{Accept:"application/json",...(t&&{Authorization:`token ${t}`})}}).then(async r=>console.log(r.status, (await r.text()).slice(0,300)))'
|
|
```
|
|
|
|
> Let op: een **ongeldig** token geeft `401`, ook op deze publieke repo — Gitea
|
|
> valt bij een verkeerd token niet terug op anonieme toegang. Krijg je 401
|
|
> terwijl anoniem `200` geeft, haal `UPDATE_CHECK_TOKEN` dan uit `.env` in plaats
|
|
> van hem te vervangen. Een *leeg* token is onschuldig: `Authorization: token `
|
|
> negeert Gitea (`200`), en `config/index.js` zet met `|| null` bij een lege
|
|
> waarde helemaal geen header. Nagemeten op 2026-09-10:
|
|
> geen header `200`, `token ongeldig123` `401`, leeg `200`.
|
|
|
|
### Oude tokens opruimen
|
|
|
|
Nu er één token overblijft, kunnen de rest weg — maar niet op de gok. De lijst
|
|
onder Settings → Applications heeft een kolom **Last used**. Werkwijze:
|
|
|
|
1. Zet het nieuwe token in `.env.release` en draai een release die helemaal
|
|
doorloopt (inclusief `docker push` en stap 5).
|
|
2. Kijk in de lijst welk token net **Last used** heeft gekregen.
|
|
3. Wacht een dag en trek de tokens in die niet meer meebewegen.
|
|
|
|
Betrouwbaarder dan uit de naam afleiden wat waar in gebruik is. Trek vooral niets
|
|
in vóór die controle: het token achter je `docker login` zit in de credential
|
|
store en niet in een bestand, dus je ziet aan niets welke het is — trek je die
|
|
in, dan valt de push in stap 3 om. Loopt dat toch mis, dan is
|
|
`docker login vibehoogie.duckdns.org` met het nieuwe token genoeg.
|
|
|
|
---
|
|
|
|
## Release workflow
|
|
|
|
```powershell
|
|
# 1. Versienummer in package.json van "x.x.x-dev" naar "x.x.x"
|
|
# 2. Wijzigingen in Changelog.md onder de kop "## [Niet vrijgegeven]"
|
|
# (de kop zelf omzetten hoeft niet — dat doet het script)
|
|
# 3. Token staat in .env.release (zie Tokens) — of eenmalig in de shell:
|
|
$env:GITEA_TOKEN = "<vibefinance-workstation>"
|
|
|
|
.\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)
|
|
.\release.ps1 -NoChangelog # publiceer bewust zonder release-notes
|
|
|
|
# Klaar. Het versienummer voor de volgende cyclus zet het script zelf.
|
|
```
|
|
|
|
Het script bouwt één image voor `linux/amd64` en `linux/arm64`, zodat dezelfde
|
|
tag op een Raspberry Pi en op een x86-server werkt.
|
|
|
|
**Wat het script zelf bijwerkt** — met de hand aanpassen is dus dubbel werk:
|
|
|
|
| Bestand | Wat | Wanneer |
|
|
|---|---|---|
|
|
| `Changelog.md` | kop `## [Niet vrijgegeven]` → `## [x.x.x] - datum` | vóór de build |
|
|
| Git-tag | `vx.x.x` op `HEAD`, gepusht naar origin | stap 4 |
|
|
| `frontend/package.json` | versie gelijkgetrokken met de root `package.json` | vóór de build |
|
|
| `README.md` | de `versie-x.x.x`-badge bovenaan | vóór de build |
|
|
| `package.json` (root) | versie → `x.x.(x+1)-dev` voor de volgende cyclus | **ná** het publiceren |
|
|
|
|
Een `-DryRun` meldt alle vier zonder te schrijven. Ze blijven na een echte
|
|
release als wijziging in je working tree staan; neem ze mee in de volgende
|
|
commit.
|
|
|
|
De laatste staat bewust ná het publiceren: breekt de release eerder af, dan
|
|
schuift het versienummer niet vooruit. Bijeffect dat je moet kennen — na een
|
|
geslaagde release staat er een `-dev` nummer in `package.json`, en de controle
|
|
bovenin het script weigert een `-dev` versie. Dat sluit een dubbele publicatie
|
|
uit, maar wil je dezelfde versie bewust opnieuw releasen (bijvoorbeeld omdat een
|
|
tag is verdwenen), zet het nummer dan eerst zelf terug naar `x.x.x`.
|
|
|
|
> **Zonder changelog-sectie breekt het script af.** De release-notes komen uit de
|
|
> sectie `## [x.x.x]` in `Changelog.md`. Vond het script daar niets, dan
|
|
> publiceerde het stil de tekst `"Release x.x.x"` — dat gebeurde bij 0.1.9 en
|
|
> 1.0.2. Nu zet het de kop `## [Niet vrijgegeven]` zelf om, en als er ook dán
|
|
> niets over deze versie in staat, stopt het vóór de build met de melding wat je
|
|
> moet toevoegen. Wil je bewust zonder notes publiceren, gebruik `-NoChangelog`.
|
|
>
|
|
> De controle staat vóór de drie auto-updates hierboven, zodat een afgebroken
|
|
> release geen gewijzigde bestanden achterlaat. Is een release toch al gepubliceerd
|
|
> met de placeholder, dan repareer je dat met een `PATCH` op
|
|
> `/repos/<org>/<repo>/releases/<id>` met de juiste `body`.
|
|
|
|
### `.env.release` — token niet elke sessie opnieuw zetten
|
|
|
|
Staat er een `.env.release` naast `release.ps1`, dan leest het script die in
|
|
voordat er iets gebeurt, en hoeft stap 3 niet meer met de hand:
|
|
|
|
```ini
|
|
# .env.release — staat in .gitignore, hoort alleen op de release-machine
|
|
GITEA_TOKEN=<vibefinance-workstation>
|
|
REGISTRY_USER=<gitea-gebruiker>
|
|
```
|
|
|
|
`REGISTRY_TOKEN` hoeft er niet in: beide scripts vallen bij een ontbrekende
|
|
`REGISTRY_TOKEN` terug op `GITEA_TOKEN`. Zie [Tokens](#tokens) voor de scopes en
|
|
voor wat een 401, 403 of 404 van Gitea betekent.
|
|
|
|
Een variabele die al in je shell staat wint, zodat je per run kunt afwijken zonder
|
|
het bestand aan te passen. Het script logt alleen welke namen het heeft geladen,
|
|
nooit de waarden.
|
|
|
|
---
|
|
|
|
## 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
|
|
```
|
|
|
|
Draai dit in de map met `docker-compose.yml` en `.env`. `docker compose` zoekt
|
|
dat bestand namelijk in de huidige map en kijkt niet omhoog; staat het er niet,
|
|
dan is het antwoord `no configuration file provided: not found`. Met
|
|
`docker compose -f /pad/naar/docker-compose.yml` kun je het expliciet meegeven.
|
|
|
|
Pullen zelf werkt anoniem zolang de organisatie public is — zie
|
|
[Pullen op een deploy-machine](#pullen-op-een-deploy-machine).
|
|
|
|
### 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
|
|
```
|
|
|
|
---
|
|
|
|
## Architectuur — één app-container
|
|
|
|
De Express-app serveert zowel de API als de gebouwde frontend:
|
|
|
|
| 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.
|
|
|
|
> 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`.
|
|
|
|
---
|
|
|
|
## Logs en diagnose
|
|
|
|
```bash
|
|
# Live logs (dev) — beide processen van de app-container
|
|
docker compose -f docker-compose.dev.yml logs -f app
|
|
|
|
# Live logs (productie)
|
|
docker compose logs -f
|
|
|
|
# Shell in de app-container (dev)
|
|
docker compose -f docker-compose.dev.yml exec app sh
|
|
|
|
# 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
|
|
- [ ] `APP_PORT` aanpassen indien poort 3400 al in gebruik is
|
|
- [ ] Testsuite groen (`test.ps1` / `./test.sh`)
|
|
- [ ] TLS afhandelen via een externe reverse proxy (bijv. Nginx Proxy Manager, Caddy, Traefik)
|
|
|
|
---
|
|
|
|
## 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("*")`.
|
|
|
|
---
|
|
|
|
## Registry
|
|
|
|
```
|
|
vibehoogie.duckdns.org/vibe/vibefinance-app (frontend + backend in één image)
|
|
|
|
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
|
|
```
|
|
|
|
> Image-tags hebben géén `v`-prefix (`1.0.4`), Git-tags wél (`v1.0.4`). Dat is
|
|
> geen inconsistentie maar de conventie aan beide kanten: container-registries
|
|
> taggen op het kale nummer, Git-releases met `v`.
|
|
|
|
Inloggen op de registry:
|
|
|
|
```bash
|
|
docker login vibehoogie.duckdns.org
|
|
```
|
|
|
|
Gebruikersnaam is je Gitea-account, wachtwoord het **access token** van deze
|
|
machine — `vibefinance-workstation`, zie [Tokens](#tokens). 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 `REGISTRY_USER` in `.env.release`, dan logt
|
|
het script zelf in met `GITEA_TOKEN` — een aparte `REGISTRY_TOKEN` is alleen
|
|
nodig als je daar bewust een ánder token voor wilt gebruiken.
|
|
|
|
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
|
|
```
|
|
|
|
### Pullen op een deploy-machine
|
|
|
|
De organisatie is public, dus een **pull** werkt anoniem — `docker compose pull &&
|
|
docker compose up -d` en klaar, zonder `docker login`.
|
|
|
|
Controleren zonder te pullen:
|
|
|
|
```bash
|
|
docker manifest inspect vibehoogie.duckdns.org/vibe/vibefinance-app:latest
|
|
```
|
|
|
|
Krijg je `401 Unauthorized`, "no basic auth credentials" of "pull access denied",
|
|
dan is het package niet publiek leesbaar (organisatie weer op privé, of de
|
|
package-eigenaar wijkt af van de organisatie). Dan alsnog eenmalig op de host:
|
|
|
|
```bash
|
|
docker login vibehoogie.duckdns.org
|
|
# gebruikersnaam: je Gitea-account
|
|
# wachtwoord: een token met read:package
|
|
```
|
|
|
|
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`.
|
|
|
|
Moet je terug naar een token, dan kan datzelfde token ook als
|
|
`UPDATE_CHECK_TOKEN` in de `.env` op deze host — één token voor beide, zie
|
|
[Tokens](#tokens).
|
|
|
|
---
|
|
|
|
## Update-notificaties
|
|
|
|
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. Let op dat `isNieuwer` alleen bij een écht hoger nummer aanslaat — bij
|
|
`1.0.2-dev` naast release `1.0.1` blijft de kaart dus ook met `?updatecheck` leeg.
|
|
Zet dan tijdelijk een lagere versie in de root `package.json`.
|
|
|
|
**Wat de melding toont**
|
|
|
|
Alleen de kop, de versieregel en een link:
|
|
|
|
```
|
|
🔔 Nieuwe versie beschikbaar
|
|
v1.0.1 is uitgebracht. Je gebruikt momenteel v1.0.0.
|
|
Release bekijken →
|
|
```
|
|
|
|
De release-notes staan er bewust **niet** in. `/api/update-check` stuurt ze wel
|
|
mee als `notes`, maar dat is de ruwe Markdown uit de changelog; in een kaart van
|
|
280px leverde dat zichtbare `### `-koppen en afgekapte regels op. Wie de details
|
|
wil, volgt de link. Het veld blijft in de API zitten voor het geval je ze ooit
|
|
ergens met meer ruimte wilt tonen — dan is Markdown renderen de volgende stap.
|
|
|
|
**De release-link hangt aan Gitea's `ROOT_URL`**
|
|
|
|
De `url` in het antwoord is de `html_url` van de release, en die stelt Gitea bij
|
|
elk verzoek samen uit `ROOT_URL` in `app.ini` — hij wordt *niet* per release
|
|
opgeslagen. Staat `ROOT_URL` op een intern adres, dan wijst "Release bekijken"
|
|
naar iets dat buiten je netwerk niet bestaat, terwijl de melding zelf gewoon
|
|
werkt (die leest alleen het versienummer).
|
|
|
|
Nakijken welke waarde Gitea daadwerkelijk gebruikt — de `issuer` is `ROOT_URL`:
|
|
|
|
```bash
|
|
curl -s https://vibehoogie.duckdns.org/.well-known/openid-configuration | grep issuer
|
|
```
|
|
|
|
`app.ini` wordt alleen bij het opstarten gelezen, dus na een wijziging moet Gitea
|
|
herstarten. Omdat de URL wordt samengesteld en niet bewaard, zijn daarna álle
|
|
releases in één keer goed — ook de oude. Een `PATCH` per release is niet nodig.
|
|
|
|
**Configuratie**
|
|
|
|
De bron staat in de root `package.json`:
|
|
|
|
```json
|
|
"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` | Optioneel. De `Vibe`-organisatie is public, dus `releases/latest` antwoordt anoniem met `200` en de check heeft geen token nodig. Gaat de organisatie weer privé, dan is het host-token nodig (`read:repository`, zie [Tokens](#tokens)): zonder geeft `releases/latest` dan 404, met een verkeerde scope 403 — in beide gevallen blijft de melding leeg, met alleen een `WARN` in het containerlog. |
|
|
|
|
**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 het werkstation-token met `write:repository` nodig
|
|
(zie [Tokens](#tokens)), meestal al aanwezig via `.env.release`:
|
|
|
|
```powershell
|
|
$env:GITEA_TOKEN = "<vibefinance-workstation>" # of gewoon uit .env.release
|
|
.\release.ps1
|
|
```
|
|
|
|
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.
|