11 Commits
Author SHA1 Message Date
Jordy Hoogeveen 04e70208bd bugfix 2026-09-10 16:51:06 +02:00
Jordy Hoogeveen ceff734793 bugfix 2026-09-10 16:24:30 +02:00
Jordy Hoogeveen 624f51679a bugfix 2026-09-10 15:40:27 +02:00
jhoogie 5f90331694 Merge pull request 'Versie 1.0.1 - versleepbare kolommen en een enkel Gitea-token' (#6) from update-1.0.1 into main 2026-09-10 15:01:55 +02:00
Jordy HoogeveenandClaude Opus 5 4e923fa998 Versienummer naar 1.0.2-dev voor de volgende cyclus
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-10 14:44:24 +02:00
jhoogie e5f78f5368 Merge pull request 'Versie 1.0.0 in package.json en README-badge, no-store op de API' (#5) from update-1.0.0 into main
Reviewed-on: http://10.0.3.108:3000/Vibe/VibeFinance/pulls/5
2026-09-09 22:05:57 +02:00
jhoogie bff64e5012 Merge pull request 'bugfixes and final release' (#4) from update-1.0.0 into main
Reviewed-on: http://10.0.3.108:3000/Vibe/VibeFinance/pulls/4
2026-09-09 17:44:00 +02:00
jhoogie 4e4a9ca3e1 Merge pull request 'bugfix update alarm' (#3) from update-0.1.9 into main
Reviewed-on: http://10.0.3.108:3000/Vibe/VibeFinance/pulls/3
2026-09-09 12:48:13 +02:00
jhoogie 00893fa6be Merge pull request 'Update 0.1.8' (#2) from update-0.1.8 into main
Reviewed-on: http://10.0.3.108:3000/Vibe/VibeFinance/pulls/2
2026-09-09 12:17:35 +02:00
jhoogie b5a068d3d8 Merge branch 'main' into update-0.1.8 2026-09-09 12:17:20 +02:00
jhoogie fdb9771916 Merge pull request 'bugfix test' (#1) from update-0.1.7 into main
Reviewed-on: http://10.0.3.108:3000/Vibe/VibeFinance/pulls/1
2026-09-08 22:27:49 +02:00
8 changed files with 404 additions and 99 deletions
+105 -25
View File
@@ -108,7 +108,19 @@ is schrijven, en dat gebeurt allemaal vanaf deze ene machine.
Er is geen apart host-token en geen apart registry-token: Er is geen apart host-token en geen apart registry-token:
- **`git push`** gaat over SSH (`gitea@…:Vibe/VibeFinance.git`), dus die gebruikt - **`git push`** gaat over SSH (`gitea@…:Vibe/VibeFinance.git`), dus die gebruikt
je SSH-sleutel en niet dit token. 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` - **De registry** heeft geen eigen variabele nodig: `release.ps1` en `dev.ps1`
vallen bij een ontbrekende `REGISTRY_TOKEN` terug op `GITEA_TOKEN`. Zet alleen vallen bij een ontbrekende `REGISTRY_TOKEN` terug op `GITEA_TOKEN`. Zet alleen
`REGISTRY_USER` erbij, zodat het script zelf kan inloggen als de credential `REGISTRY_USER` erbij, zodat het script zelf kan inloggen als de credential
@@ -143,21 +155,28 @@ backup — een eigen image als `latest` naar de registry pushen, en die host pul
| Status | Betekenis | | Status | Betekenis |
|---|---| |---|---|
| 401 | Token ongeldig of verlopen. Op de registry: helemaal niet ingelogd. | | 401 | Token ongeldig, verlopen of ingetrokken — Gitea herkent hem niet. Op de registry: helemaal niet ingelogd. |
| 403 | Het token mag de repo wél zien, maar mist de **scope** voor dit endpoint. Gitea noemt de vereiste scope in de response-body. | | 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. | | 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 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. je dus een nieuw token aan; bijwerken kan niet.
Nakijken wie een token is en wat hij ziet: **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 ```powershell
$h = @{ Authorization = "token $env:GITEA_TOKEN" } $u = "https://vibehoogie.duckdns.org/api/v1/user/repos"
(Invoke-RestMethod https://vibehoogie.duckdns.org/api/v1/user -Headers $h).login try { (Invoke-WebRequest $u -Headers @{ Authorization = "token $env:GITEA_TOKEN" } -UseBasicParsing).StatusCode }
(Invoke-RestMethod https://vibehoogie.duckdns.org/api/v1/user/repos -Headers $h).full_name 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 — 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: busybox-`wget` gooit die bij een foutstatus weg, en Node zit in het image:
@@ -199,7 +218,8 @@ in, dan valt de push in stap 3 om. Loopt dat toch mis, dan is
```powershell ```powershell
# 1. Versienummer in package.json van "x.x.x-dev" naar "x.x.x" # 1. Versienummer in package.json van "x.x.x-dev" naar "x.x.x"
# 2. Changelog.md: kop van "Niet vrijgegeven" naar "[x.x.x] - datum" # 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: # 3. Token staat in .env.release (zie Tokens) — of eenmalig in de shell:
$env:GITEA_TOKEN = "<vibefinance-workstation>" $env:GITEA_TOKEN = "<vibefinance-workstation>"
@@ -207,8 +227,9 @@ $env:GITEA_TOKEN = "<vibefinance-workstation>"
.\release.ps1 -DryRun # droogloop — toont alle stappen zonder uit te voeren .\release.ps1 -DryRun # droogloop — toont alle stappen zonder uit te voeren
.\release.ps1 -NoBuild # sla docker build over, alleen tag + release .\release.ps1 -NoBuild # sla docker build over, alleen tag + release
.\release.ps1 -SkipTests # sla de testsuite over (niet aanbevolen) .\release.ps1 -SkipTests # sla de testsuite over (niet aanbevolen)
.\release.ps1 -NoChangelog # publiceer bewust zonder release-notes
# 4. Versienummer in package.json naar "x.x.(x+1)-dev" voor volgende cyclus # Klaar. Het versienummer voor de volgende cyclus zet het script zelf.
``` ```
Het script bouwt één image voor `linux/amd64` en `linux/arm64`, zodat dezelfde Het script bouwt één image voor `linux/amd64` en `linux/arm64`, zodat dezelfde
@@ -216,22 +237,36 @@ tag op een Raspberry Pi en op een x86-server werkt.
**Wat het script zelf bijwerkt** — met de hand aanpassen is dus dubbel werk: **Wat het script zelf bijwerkt** — met de hand aanpassen is dus dubbel werk:
| Bestand | Wat | | Bestand | Wat | Wanneer |
|---|---| |---|---|---|
| `frontend/package.json` | versie gelijkgetrokken met de root `package.json` | | `Changelog.md` | kop `## [Niet vrijgegeven]` → `## [x.x.x] - datum` | vóór de build |
| `README.md` | de `versie-x.x.x`-badge bovenaan | | 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 |
Beide gebeuren vóór de build, en een `-DryRun` meldt ze zonder te schrijven. Ze Een `-DryRun` meldt alle vier zonder te schrijven. Ze blijven na een echte
blijven na een echte release als wijziging in je working tree staan; neem ze mee release als wijziging in je working tree staan; neem ze mee in de volgende
in de volgende commit. commit.
> **De changelog-kop moet exact `## [x.x.x]` zijn.** `release.ps1` zoekt die kop De laatste staat bewust ná het publiceren: breekt de release eerder af, dan
> om de release-notes te vullen. Staat je werk nog onder `## [Niet vrijgegeven]`, schuift het versienummer niet vooruit. Bijeffect dat je moet kennen — na een
> dan vindt het script niets en valt het terug op de tekst `"Release x.x.x"` — geslaagde release staat er een `-dev` nummer in `package.json`, en de controle
> dan staat er geen inhoudelijke release-notes in Gitea en ziet een gebruiker in bovenin het script weigert een `-dev` versie. Dat sluit een dubbele publicatie
> het belletje een placeholder. Dat overkwam 0.1.9. Achteraf repareren kan met uit, maar wil je dezelfde versie bewust opnieuw releasen (bijvoorbeeld omdat een
> een `PATCH` op `/repos/<org>/<repo>/releases/<id>`, maar vóór de release tag is verdwenen), zet het nummer dan eerst zelf terug naar `x.x.x`.
> omzetten is een stuk minder werk.
> **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 ### `.env.release` — token niet elke sessie opnieuw zetten
@@ -264,7 +299,12 @@ docker compose pull && docker compose up -d
docker compose down -v && docker compose up -d docker compose down -v && docker compose up -d
``` ```
Pullen vereist een registry-login op die host — zie 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). [Pullen op een deploy-machine](#pullen-op-een-deploy-machine).
### PostgreSQL versie-upgrade ### PostgreSQL versie-upgrade
@@ -434,6 +474,10 @@ Tags:
x.x.x-dev development — specifieke dev versie 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: Inloggen op de registry:
```bash ```bash
@@ -505,7 +549,43 @@ dat op het belletje in de topbalk en onder "Over VibeFinance".
Builds met een `-dev` suffix melden nooit (die lopen voor op de laatste release). 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` Wil je de melding tijdens ontwikkeling toch testen: open de app met `?updatecheck`
in de URL. 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** **Configuratie**
+70
View File
@@ -1,5 +1,75 @@
# Changelog # Changelog
## [Niet vrijgegeven]
### Gewijzigd
- Git-tags krijgen weer een `v`-prefix (`v1.0.4`), net als t/m `v1.0.0`. Sinds
1.0.1 was dat `1.0.1`, `1.0.2`, `1.0.3` — en omdat Gitea de tag op de
release-pagina toont, stond daar het kale nummer terwijl de release-naam wél
`v1.0.3` was. De image-tags in de registry houden bewust géén `v`; dat is de
conventie voor container-tags. De update-check verdraagt beide: backend en
frontend strippen een leidende `v` voordat ze versies vergelijken
### Opgelost
- Het omzetten van de changelog-kop slokte de lege regel eronder op, waardoor
`## [x.x.x] - datum` direct tegen `### Toegevoegd` aan kwam te staan. Oorzaak
was `\s*$` in het zoekpatroon: `\s` matcht ook newlines. Het patroon eindigt nu
op `[ \t]*(?=\r?$)` — een lookahead, want dit bestand heeft CRLF en met alleen
`[ \t]*$` matchte de kop helemaal niet meer (de `\r` zit ertussen). Zo blijft
de match binnen één regel én blijft het regeleinde ongemoeid
## [1.0.3] - 2026-09-10
### Toegevoegd
- `release.ps1` zet de changelog-kop `## [Niet vrijgegeven]` nu zelf om naar
`## [x.x.x] - datum`, net zoals het al deed met `frontend/package.json` en de
README-badge. Handmatig omzetten hoeft dus niet meer
- Staat er ook na die omzetting niets over deze versie in `Changelog.md`, dan
breekt het script af **vóór** de build met de melding wat je moet toevoegen.
Eerder viel het stil terug op de tekst `"Release x.x.x"` en meldde het
"Gepubliceerd" — dat overkwam 0.1.9 en 1.0.2, en is achteraf alleen met een
`PATCH` op de release te herstellen. Nieuwe switch `-NoChangelog` om bewust
zonder release-notes te publiceren
- `release.ps1` zet na een geslaagde release de versie in de root
`package.json` op `x.x.(x+1)-dev`. Dat was voorheen de laatste handmatige stap
van de release-workflow. Het staat bewust ná het publiceren, zodat een
afgebroken release het nummer niet vooruit schuift
### Opgelost
- **`-DryRun` in combinatie met `-Force` verwijderde écht de Git-tag.** De twee
commando's in stap 4 (`git tag -d` en `git push origin :refs/tags/x.x.x`)
liepen niet via `Invoke-Cmd` en hadden dus geen droogloop-controle. Gitea
ruimt de release op zodra de tag verdwijnt, dus een droogloop kon een
gepubliceerde release wissen — zo is de release van 1.0.2 verloren gegaan en
opnieuw aangemaakt. Onder `-DryRun` worden beide nu alleen gemeld
### Gewijzigd
- De changelog-controle staat vóór de drie auto-updates, zodat een afgebroken
release geen gewijzigde bestanden achterlaat terwijl hij "er is niets
gepubliceerd" meldt
- Stap 5 leest de release-notes uit het geheugen in plaats van opnieuw van
schijf. Een droogloop schrijft de kop niet, en toonde daardoor de placeholder
in de payload — precies wat je met een droogloop wilt uitsluiten
- De Quick Start in `README.md` begint nu met het ophalen van
`docker-compose.yml` (clone, of alleen die twee bestanden via `raw`). Zonder
dat bestand antwoordt `docker compose pull` met `no configuration file
provided: not found`, en die stap ontbrak. Beide foutmeldingen staan er nu bij
met hun oorzaak
## [1.0.2] - 2026-09-10
### Gewijzigd
- De update-melding op het belletje toont alleen nog de kop, de versieregel en de
link naar de release. De release-notes stonden er als ruwe Markdown in — in een
kaart van 280px leverde dat zichtbare `### `-koppen en afgekapte regels op.
`/api/update-check` stuurt `notes` nog wel mee, zodat ze later ergens met meer
ruimte gebruikt kunnen worden
- `BEHEER.md` legt vast dat de release-link uit Gitea's `ROOT_URL` wordt
samengesteld en niet per release wordt opgeslagen: na een `ROOT_URL`-wijziging
plus herstart zijn álle releases in één keer goed, ook de oude. Verder staat er
nu hoe je aan het verschil tussen `401` en `403` ziet of een token nog leeft, en
hoe je anoniem over https fetcht als SSH niet meedoet
## [1.0.1] - 2026-09-10 ## [1.0.1] - 2026-09-10
### Toegevoegd ### Toegevoegd
+37 -5
View File
@@ -10,7 +10,7 @@ Eigen vermogen · Schulden · Voortgang · Gebruikersbeheer
![Node.js](https://img.shields.io/badge/Node.js_22-339933?style=flat&logo=node.js&logoColor=white) ![Node.js](https://img.shields.io/badge/Node.js_22-339933?style=flat&logo=node.js&logoColor=white)
![PostgreSQL](https://img.shields.io/badge/PostgreSQL_18-4169E1?style=flat&logo=postgresql&logoColor=white) ![PostgreSQL](https://img.shields.io/badge/PostgreSQL_18-4169E1?style=flat&logo=postgresql&logoColor=white)
![Docker](https://img.shields.io/badge/Docker_Compose-2496ED?style=flat&logo=docker&logoColor=white) ![Docker](https://img.shields.io/badge/Docker_Compose-2496ED?style=flat&logo=docker&logoColor=white)
![Version](https://img.shields.io/badge/versie-1.0.1-8b5cf6?style=flat) ![Version](https://img.shields.io/badge/versie-1.0.3-8b5cf6?style=flat)
![Built with Claude](https://img.shields.io/badge/Gebouwd_met-Claude.ai-8b5cf6?style=flat&logo=anthropic&logoColor=white) ![Built with Claude](https://img.shields.io/badge/Gebouwd_met-Claude.ai-8b5cf6?style=flat&logo=anthropic&logoColor=white)
<img src="docs/screenshot-dashboard.png" alt="VibeFinance dashboard" width="820"> <img src="docs/screenshot-dashboard.png" alt="VibeFinance dashboard" width="820">
@@ -32,7 +32,25 @@ Deze applicatie is volledig ontworpen en ontwikkeld met behulp van [Claude.ai](h
De app draait in **2 containers**: `app` (Express API + gebouwde frontend) en De app draait in **2 containers**: `app` (Express API + gebouwde frontend) en
`postgres` (database). `postgres` (database).
**`.env`** — kopieer `.env.example` en vul in: **1. De bestanden op de server zetten.** `docker compose` leest
`docker-compose.yml` uit de map waarin je het commando draait, dus dat bestand
moet er eerst staan. De organisatie in Gitea is publiek, dus dit kan anoniem:
```bash
git clone https://vibehoogie.duckdns.org/Vibe/VibeFinance.git
cd VibeFinance
```
Wil je de repo niet op je server, dan zijn deze twee bestanden genoeg:
```bash
mkdir -p vibefinance && cd vibefinance
base=https://vibehoogie.duckdns.org/Vibe/VibeFinance/raw/branch/main
curl -fsSLO $base/docker-compose.yml
curl -fsSL $base/.env.example -o .env.example
```
**2. `.env` aanmaken** — kopieer `.env.example` en vul in:
```env ```env
POSTGRES_USER=vibefinance POSTGRES_USER=vibefinance
@@ -46,15 +64,21 @@ APP_PORT=3400
openssl rand -hex 64 openssl rand -hex 64
``` ```
**3. Starten:**
```bash ```bash
cp .env.example .env # en vul de waarden in cp .env.example .env # en vul de waarden in
docker compose pull && docker compose up -d docker compose pull && docker compose up -d
``` ```
De `Vibe`-organisatie in Gitea is publiek, dus een pull werkt anoniem — geen Twee foutmeldingen en wat ze betekenen:
`docker login` nodig. Krijg je toch `401 Unauthorized` of "pull access denied",
dan staat de organisatie weer op privé: - **`no configuration file provided: not found`** — je staat in een map zonder
`docker-compose.yml`. Controleer met `ls docker-compose.yml`, of geef het
bestand expliciet mee: `docker compose -f /pad/naar/docker-compose.yml up -d`.
- **`401 Unauthorized`** of **"pull access denied"** — de organisatie staat niet
meer op publiek. Dan alsnog inloggen:
```bash ```bash
docker login vibehoogie.duckdns.org # wachtwoord = Gitea-token met read:package docker login vibehoogie.duckdns.org # wachtwoord = Gitea-token met read:package
@@ -129,6 +153,13 @@ $env:GITEA_TOKEN = "<token met write:package + write:repository>"
Draait de tests, bouwt het app-image voor `amd64` + `arm64` (Raspberry Pi), Draait de tests, bouwt het app-image voor `amd64` + `arm64` (Raspberry Pi),
pusht naar de registry, zet de Git-tag en publiceert de Gitea-release. pusht naar de registry, zet de Git-tag en publiceert de Gitea-release.
Het script regelt ook het bijwerken eromheen: de changelog-kop
`## [Niet vrijgegeven]` wordt `## [x.x.x] - datum`, de versie in
`frontend/package.json` en de badge hierboven gaan mee, en ná het publiceren
zet het de root `package.json` op `x.x.(x+1)-dev` voor de volgende cyclus.
Beschrijft de changelog niets over deze versie, dan stopt het script vóór de
build — anders zou de release met een placeholder als notes online komen.
--- ---
## 🗂️ Functionaliteit ## 🗂️ Functionaliteit
@@ -171,6 +202,7 @@ vibefinance/
│ ├── vite.config.js # /api proxy naar de API in dezelfde container │ ├── vite.config.js # /api proxy naar de API in dezelfde container
│ └── src/ │ └── src/
│ ├── App.jsx # Root – wiring + idle-logout │ ├── App.jsx # Root – wiring + idle-logout
│ ├── App.css # Reset + losse klassen (o.a. .kolom-grip)
│ ├── main.jsx │ ├── main.jsx
│ ├── version.js # Draaiende versie (__APP_VERSION__ uit de build) │ ├── version.js # Draaiende versie (__APP_VERSION__ uit de build)
│ ├── constants/ # Kleuren, tabs, begindata │ ├── constants/ # Kleuren, tabs, begindata
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "vibefinance-frontend", "name": "vibefinance-frontend",
"version": "1.0.1", "version": "1.0.3",
"private": true, "private": true,
"type": "module", "type": "module",
"scripts": { "scripts": {
+4 -8
View File
@@ -209,14 +209,10 @@ function AppInner() {
<div style={{ fontSize: 12, color: T.muted, lineHeight: 1.5 }}> <div style={{ fontSize: 12, color: T.muted, lineHeight: 1.5 }}>
v{nieuweVersie.latest} is uitgebracht. Je gebruikt momenteel v{version}. v{nieuweVersie.latest} is uitgebracht. Je gebruikt momenteel v{version}.
</div> </div>
{nieuweVersie.notes && ( {/* De release-notes zelf staan hier niet: dat is Markdown
<div style={{ uit de changelog, en die kwam als ruwe `### `-koppen in
fontSize: 11, color: T.subtext, marginTop: 6, lineHeight: 1.5, een smalle kolom te staan. Wie de details wil, volgt de
maxHeight: 130, overflowY: "auto", whiteSpace: "pre-wrap", link naar de release. */}
}}>
{nieuweVersie.notes}
</div>
)}
{nieuweVersie.url && ( {nieuweVersie.url && (
<a href={nieuweVersie.url} target="_blank" rel="noreferrer" style={{ <a href={nieuweVersie.url} target="_blank" rel="noreferrer" style={{
display: "inline-block", marginTop: 8, display: "inline-block", marginTop: 8,
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "vibefinance", "name": "vibefinance",
"version": "1.0.1", "version": "1.0.4",
"description": "VibeFinance — persoonlijk vermogensbeheer", "description": "VibeFinance — persoonlijk vermogensbeheer",
"private": true, "private": true,
"repository": "https://vibehoogie.duckdns.org/vibe/VibeFinance", "repository": "https://vibehoogie.duckdns.org/vibe/VibeFinance",
+170 -44
View File
@@ -9,6 +9,16 @@
# .\release.ps1 -SkipTests # sla de testsuite over (niet aanbevolen) # .\release.ps1 -SkipTests # sla de testsuite over (niet aanbevolen)
# .\release.ps1 -DryRun # toon alle commando's zonder iets uit te voeren # .\release.ps1 -DryRun # toon alle commando's zonder iets uit te voeren
# .\release.ps1 -Force # sla conflictcontrole over, overschrijf tags # .\release.ps1 -Force # sla conflictcontrole over, overschrijf tags
# .\release.ps1 -NoChangelog # publiceer bewust zonder release-notes
#
# Het script werkt zelf vier dingen bij, dus die hoef je niet met de hand te
# doen: de changelog-kop `## [Niet vrijgegeven]` -> `## [x.x.x] - datum`, de
# versie in frontend/package.json, de versiebadge in README.md, en ná het
# publiceren de versie in de root package.json -> `x.x.(x+1)-dev`.
#
# LET OP bij -Force: dat verwijdert de bestaande tag lokaal en op origin, en
# Gitea gooit de bijbehorende release daarmee weg. Onder -DryRun wordt dat
# alleen gemeld (dat was eerder niet zo — zie stap 4).
# #
# Vereisten: # Vereisten:
# - Docker Desktop actief # - Docker Desktop actief
@@ -16,6 +26,9 @@
# - docker buildx builder actief: docker buildx create --use # - docker buildx builder actief: docker buildx create --use
# - Git geinstalleerd en working directory is de repo root # - Git geinstalleerd en working directory is de repo root
# - root package.json bevat een schoon versienummer ZONDER -dev suffix # - root package.json bevat een schoon versienummer ZONDER -dev suffix
# - Changelog.md beschrijft deze versie, onder `## [Niet vrijgegeven]` of
# onder een kop `## [x.x.x]`; anders breekt het script af (-NoChangelog
# omzeilt dat)
# - GITEA_TOKEN in de omgeving (token met release-rechten) voor stap 5, # - GITEA_TOKEN in de omgeving (token met release-rechten) voor stap 5,
# de Gitea-release waar de update-melding in de app op afgaat # de Gitea-release waar de update-melding in de app op afgaat
@@ -23,7 +36,10 @@ param(
[switch]$NoBuild, [switch]$NoBuild,
[switch]$SkipTests, [switch]$SkipTests,
[switch]$DryRun, [switch]$DryRun,
[switch]$Force [switch]$Force,
# Releasen zonder inhoudelijke release-notes. Zonder deze switch breekt het
# script af wanneer de changelog niets over deze versie zegt.
[switch]$NoChangelog
) )
$ErrorActionPreference = "Stop" $ErrorActionPreference = "Stop"
@@ -75,42 +91,13 @@ if ($appVersion -match "-dev$") {
exit 1 exit 1
} }
# ── Versie synchroniseren naar frontend/package.json ────────────────────── # Git-tag met `v`-prefix, net als de release-naam hieronder en net als de tags
# Een droogloop schrijft hier niet: anders laat -DryRun een gewijzigd bestand # t/m v1.0.0. Gitea toont de tag op de release-pagina, dus zonder prefix stond
# achter, en tagt de echte release daarna een vervuilde working tree. # daar het kale nummer. De image-tags in de registry houden bewust géén `v`:
$frontendPkgPath = Join-Path $PSScriptRoot "frontend/package.json" # dat is de conventie voor container-tags.
$frontendPkg = Get-Content $frontendPkgPath -Raw | ConvertFrom-Json # De update-check verdraagt beide: zowel backend/src/routes/update.js als
if ($frontendPkg.version -ne $appVersion) { # useUpdateCheck.js strippen een leidende `v` voordat ze versies vergelijken.
if ($DryRun) { $gitTag = "v$appVersion"
Write-Host "[DRY-RUN] Versie naar frontend synchroniseren: $($frontendPkg.version) -> $appVersion" -ForegroundColor Yellow
} else {
$frontendPkg.version = $appVersion
[System.IO.File]::WriteAllText($frontendPkgPath, ($frontendPkg | ConvertTo-Json -Depth 10))
Write-Host "Versie gesynchroniseerd naar frontend: $appVersion" -ForegroundColor Green
}
}
# ── Versiebadge in README.md ──────────────────────────────────────────────
# Anders loopt die badge stil achter: hij stond drie releases achter voordat
# dit erin zat, en het script kent het nummer toch al. Zelfde regel als
# hierboven: een droogloop meldt het, maar schrijft niet.
$readmePath = Join-Path $PSScriptRoot "README.md"
if (Test-Path $readmePath) {
$readme = [System.IO.File]::ReadAllText($readmePath)
$patroon = "badge/versie-[^-]+-"
$nieuw = "badge/versie-$appVersion-"
$huidig = [regex]::Match($readme, $patroon)
if ($huidig.Success -and $huidig.Value -ne $nieuw) {
if ($DryRun) {
Write-Host "[DRY-RUN] Versiebadge in README.md: $($huidig.Value) -> $nieuw" -ForegroundColor Yellow
} else {
[System.IO.File]::WriteAllText($readmePath, ($readme -replace $patroon, $nieuw))
Write-Host "Versiebadge in README.md bijgewerkt: $appVersion" -ForegroundColor Green
}
}
}
$gitTag = "$appVersion"
# ── Registry tags (één image voor frontend + backend) ───────────────────── # ── Registry tags (één image voor frontend + backend) ─────────────────────
$appBase = "$registry/$appImage" $appBase = "$registry/$appImage"
@@ -151,12 +138,13 @@ function Write-Step {
Write-Host "── $Label" -ForegroundColor Cyan Write-Host "── $Label" -ForegroundColor Cyan
} }
# Haalt de sectie van deze versie uit Changelog.md als release-notes. # Haalt de sectie van deze versie uit changelog-tekst. Werkt op een string en
function Get-ChangelogSection { # niet op het bestand, zodat een droogloop kan valideren tegen de kop die hij
param([string]$Version) # zou schrijven zonder die daadwerkelijk te schrijven.
$path = Join-Path $PSScriptRoot "Changelog.md" function Get-ChangelogSectionFromText {
if (-not (Test-Path $path)) { return "" } param([string]$Text, [string]$Version)
$lines = Get-Content $path if (-not $Text) { return "" }
$lines = $Text -split "\r?\n"
$start = -1 $start = -1
$needle = "^##\s*\[" + [regex]::Escape($Version) + "\]" $needle = "^##\s*\[" + [regex]::Escape($Version) + "\]"
for ($i = 0; $i -lt $lines.Count; $i++) { for ($i = 0; $i -lt $lines.Count; $i++) {
@@ -172,6 +160,99 @@ function Get-ChangelogSection {
return (($out -join "`n").Trim()) return (($out -join "`n").Trim())
} }
# ── Changelog-kop vrijgeven ───────────────────────────────────────────────
# De release-notes komen uit de sectie `## [x.x.x]` in Changelog.md. Stond het
# werk nog onder `## [Niet vrijgegeven]`, dan vond het script niets en werd stil
# de placeholder "Release x.x.x" gepubliceerd — dat gebeurde bij 0.1.9 en 1.0.2,
# en is achteraf alleen met een PATCH op de release te herstellen. Daarom zet het
# script de kop nu zelf om, en breekt het af als er niets te melden valt.
# Zelfde regel als bij de andere auto-updates: een droogloop meldt, maar schrijft
# niet.
$changelogPath = Join-Path $PSScriptRoot "Changelog.md"
$nieuweKop = "## [$appVersion] - $(Get-Date -Format 'yyyy-MM-dd')"
$changelogTxt = if (Test-Path $changelogPath) { [System.IO.File]::ReadAllText($changelogPath) } else { "" }
$kopPatroon = "(?m)^##\s*\[" + [regex]::Escape($appVersion) + "\]"
# Niet `\s*$`: `\s` matcht ook newlines, en dan slokt de match de lege regel ná
# de kop op — die verdween daardoor bij het omzetten. En niet `[ \t]*$` alleen:
# dit bestand heeft CRLF (zie .gitattributes), dus `$` staat achter een `\r` die
# geen space of tab is. De lookahead laat het regeleinde buiten de match, zodat
# de CRLF intact blijft.
$onderwegPatroon = "(?m)^##[ \t]*\[[ \t]*Niet vrijgegeven[ \t]*\][ \t]*(?=\r?$)"
# Eerst alleen in het geheugen omzetten. Schrijven gebeurt na de controle
# hieronder: bij een lege `[Niet vrijgegeven]`-sectie zou de kop anders al
# vervangen zijn terwijl het script daarna afbreekt, en dan blijft er een
# aangepaste changelog achter bij een release die niet doorging.
$kopOmzetten = ($changelogTxt -notmatch $kopPatroon -and $changelogTxt -match $onderwegPatroon)
if ($kopOmzetten) {
# $nieuweKop bevat geen '$', dus veilig als vervangingstekst.
$changelogTxt = [regex]::Replace($changelogTxt, $onderwegPatroon, $nieuweKop)
}
if (-not (Get-ChangelogSectionFromText $changelogTxt $appVersion) -and -not $NoChangelog) {
Write-Host ""
Write-Host "Changelog.md zegt niets over $appVersion." -ForegroundColor Red
Write-Host ""
Write-Host "Zonder notes komt er alleen de tekst 'Release $appVersion' in de Gitea-release," -ForegroundColor Yellow
Write-Host "en dat is achteraf alleen met een PATCH op de release te herstellen." -ForegroundColor Yellow
Write-Host ""
Write-Host "Zet je wijzigingen in Changelog.md onder een kop:" -ForegroundColor White
Write-Host " ## [Niet vrijgegeven]" -ForegroundColor White
Write-Host "Die zet dit script bij de volgende run zelf om naar '$nieuweKop'." -ForegroundColor White
Write-Host ""
Write-Host "Bewust zonder release-notes publiceren? Draai met -NoChangelog." -ForegroundColor DarkGray
Write-Host ""
Write-Host "Er is niets gepubliceerd." -ForegroundColor DarkGray
exit 1
}
# De controle is doorstaan, dus nu pas schrijven.
if ($kopOmzetten) {
if ($DryRun) {
Write-Host "[DRY-RUN] Changelog-kop vrijgeven: '## [Niet vrijgegeven]' -> '$nieuweKop'" -ForegroundColor Yellow
} else {
[System.IO.File]::WriteAllText($changelogPath, $changelogTxt)
Write-Host "Changelog-kop vrijgegeven: $nieuweKop" -ForegroundColor Green
}
}
# ── Versie synchroniseren naar frontend/package.json ──────────────────────
# Staat na de changelog-controle: anders laat een afgebroken release wél een
# gewijzigde working tree achter terwijl hij "niets gepubliceerd" meldt.
# Een droogloop schrijft hier niet, om dezelfde reden.
$frontendPkgPath = Join-Path $PSScriptRoot "frontend/package.json"
$frontendPkg = Get-Content $frontendPkgPath -Raw | ConvertFrom-Json
if ($frontendPkg.version -ne $appVersion) {
if ($DryRun) {
Write-Host "[DRY-RUN] Versie naar frontend synchroniseren: $($frontendPkg.version) -> $appVersion" -ForegroundColor Yellow
} else {
$frontendPkg.version = $appVersion
[System.IO.File]::WriteAllText($frontendPkgPath, ($frontendPkg | ConvertTo-Json -Depth 10))
Write-Host "Versie gesynchroniseerd naar frontend: $appVersion" -ForegroundColor Green
}
}
# ── Versiebadge in README.md ──────────────────────────────────────────────
# Anders loopt die badge stil achter: hij stond drie releases achter voordat
# dit erin zat, en het script kent het nummer toch al. Zelfde regel als
# hierboven: een droogloop meldt het, maar schrijft niet.
$readmePath = Join-Path $PSScriptRoot "README.md"
if (Test-Path $readmePath) {
$readme = [System.IO.File]::ReadAllText($readmePath)
$patroon = "badge/versie-[^-]+-"
$nieuw = "badge/versie-$appVersion-"
$huidig = [regex]::Match($readme, $patroon)
if ($huidig.Success -and $huidig.Value -ne $nieuw) {
if ($DryRun) {
Write-Host "[DRY-RUN] Versiebadge in README.md: $($huidig.Value) -> $nieuw" -ForegroundColor Yellow
} else {
[System.IO.File]::WriteAllText($readmePath, ($readme -replace $patroon, $nieuw))
Write-Host "Versiebadge in README.md bijgewerkt: $appVersion" -ForegroundColor Green
}
}
}
# ── Samenvatting ─────────────────────────────────────────────────────────── # ── Samenvatting ───────────────────────────────────────────────────────────
Write-Host "" Write-Host ""
Write-Host "════════════════════════════════════════" -ForegroundColor Cyan Write-Host "════════════════════════════════════════" -ForegroundColor Cyan
@@ -365,15 +446,25 @@ if (-not $NoBuild) {
Write-Step "[4/5] Git-tag aanmaken en pushen" Write-Step "[4/5] Git-tag aanmaken en pushen"
if ($Force) { if ($Force) {
# LET OP: deze twee commando's gingen niet via Invoke-Cmd en hadden dus geen
# -DryRun-controle. Een `-DryRun -Force` verwijderde daardoor écht de tag,
# lokaal en op origin — en Gitea ruimt de release op zodra de tag verdwijnt.
# Zo is de release van 1.0.2 verloren gegaan.
if ($DryRun) {
Write-Host "[DRY-RUN] git tag -d $gitTag" -ForegroundColor Yellow
Write-Host "[DRY-RUN] git push origin :refs/tags/$gitTag" -ForegroundColor Yellow
} else {
Write-Host "Bestaande lokale tag verwijderen (indien aanwezig)..." -ForegroundColor Yellow Write-Host "Bestaande lokale tag verwijderen (indien aanwezig)..." -ForegroundColor Yellow
$ErrorActionPreference = "SilentlyContinue" $ErrorActionPreference = "SilentlyContinue"
git tag -d $gitTag 2>$null | Out-Null git tag -d $gitTag 2>$null | Out-Null
$ErrorActionPreference = "Stop" $ErrorActionPreference = "Stop"
Write-Host "Bestaande remote tag verwijderen (indien aanwezig)..." -ForegroundColor Yellow Write-Host "Bestaande remote tag verwijderen (indien aanwezig)..." -ForegroundColor Yellow
Write-Host " Gitea verwijdert de bijbehorende release mee." -ForegroundColor DarkGray
$ErrorActionPreference = "SilentlyContinue" $ErrorActionPreference = "SilentlyContinue"
git push origin ":refs/tags/$gitTag" 2>$null | Out-Null git push origin ":refs/tags/$gitTag" 2>$null | Out-Null
$ErrorActionPreference = "Stop" $ErrorActionPreference = "Stop"
} }
}
Write-Host "Git-tag aanmaken: $gitTag" -ForegroundColor White Write-Host "Git-tag aanmaken: $gitTag" -ForegroundColor White
Invoke-Cmd @("git", "tag", "-a", $gitTag, "-m", "Release $gitTag") Invoke-Cmd @("git", "tag", "-a", $gitTag, "-m", "Release $gitTag")
@@ -405,7 +496,10 @@ if (-not $releaseApi) {
Write-Host "Geen GITEA_TOKEN in de omgeving — release overgeslagen." -ForegroundColor Yellow Write-Host "Geen GITEA_TOKEN in de omgeving — release overgeslagen." -ForegroundColor Yellow
Write-Host " Zonder release ziet de app geen update-melding voor $appVersion." -ForegroundColor DarkGray Write-Host " Zonder release ziet de app geen update-melding voor $appVersion." -ForegroundColor DarkGray
} else { } else {
$notes = Get-ChangelogSection $appVersion # Uit $changelogTxt en niet opnieuw van schijf: in een droogloop is de kop
# nog niet geschreven, en dan zou de payload hier de placeholder tonen —
# precies wat je met een droogloop wilt uitsluiten.
$notes = Get-ChangelogSectionFromText $changelogTxt $appVersion
if (-not $notes) { $notes = "Release $appVersion" } if (-not $notes) { $notes = "Release $appVersion" }
$payload = @{ $payload = @{
tag_name = $gitTag tag_name = $gitTag
@@ -451,6 +545,38 @@ Write-Host " Git-tag: $gitTag -> origin" -ForegroundColor Green
Write-Host "════════════════════════════════════════" -ForegroundColor Cyan Write-Host "════════════════════════════════════════" -ForegroundColor Cyan
Write-Host "" Write-Host ""
# ── Versie naar de volgende dev-cyclus ────────────────────────────────────
# Was voorheen stap 4 met de hand. Gebeurt hier, ná het publiceren, zodat een
# afgebroken release het versienummer niet vooruit zet. Bijkomend voordeel: de
# `-dev` suffix laat dezelfde release niet nog eens draaien (de controle boven
# in dit script weigert een `-dev` versie), dus een dubbele publicatie is
# meteen uitgesloten. Wil je bewust opnieuw releasen, zet het nummer dan zelf
# terug.
if ($appVersion -match '^(\d+)\.(\d+)\.(\d+)$') {
$volgende = "{0}.{1}.{2}-dev" -f $Matches[1], $Matches[2], ([int]$Matches[3] + 1)
$rootPkgPath = Join-Path $PSScriptRoot "package.json"
if ($DryRun) {
Write-Host "[DRY-RUN] Versie in package.json: $appVersion -> $volgende" -ForegroundColor Yellow
} else {
# Gerichte tekstvervanging in plaats van ConvertTo-Json: dat zou het hele
# bestand herschrijven en de opmaak van de andere velden aantasten.
$rootTxt = [System.IO.File]::ReadAllText($rootPkgPath)
$treffer = [regex]::Match($rootTxt, '"version"\s*:\s*"' + [regex]::Escape($appVersion) + '"')
if ($treffer.Success) {
$rootTxt = $rootTxt.Remove($treffer.Index, $treffer.Length).Insert($treffer.Index, '"version": "' + $volgende + '"')
[System.IO.File]::WriteAllText($rootPkgPath, $rootTxt)
Write-Host "Versie in package.json naar de volgende cyclus: $volgende" -ForegroundColor Green
Write-Host " Commit dit mee, samen met de changelog-kop en de README-badge." -ForegroundColor DarkGray
Write-Host ""
} else {
Write-Host "Kon '$appVersion' niet terugvinden in package.json — versie niet bijgewerkt." -ForegroundColor Yellow
}
}
} else {
Write-Host "Versie '$appVersion' is geen x.y.z — volgende dev-versie niet automatisch gezet." -ForegroundColor Yellow
}
# Expliciete 0: anders erft de caller de exitcode van het laatste # Expliciete 0: anders erft de caller de exitcode van het laatste
# docker-commando (bijv. de registry-check). # docker-commando (bijv. de registry-check).
exit 0 exit 0
+1
View File
@@ -9,6 +9,7 @@
# ./release.sh -SkipTests # sla de testsuite over (niet aanbevolen) # ./release.sh -SkipTests # sla de testsuite over (niet aanbevolen)
# ./release.sh -DryRun # toon alle commando's zonder iets uit te voeren # ./release.sh -DryRun # toon alle commando's zonder iets uit te voeren
# ./release.sh -Force # sla conflictcontrole over, overschrijf tags # ./release.sh -Force # sla conflictcontrole over, overschrijf tags
# ./release.sh -NoChangelog # publiceer bewust zonder release-notes
# #
# Combinaties: # Combinaties:
# ./release.sh -Force -NoBuild # ./release.sh -Force -NoBuild