From e315039c3571cdea1d0b00a47378cd4c83735222 Mon Sep 17 00:00:00 2001 From: Jordy Hoogeveen Date: Fri, 11 Sep 2026 14:05:55 +0200 Subject: [PATCH] bugfix --- BEHEER.md | 37 +++++++++++++++----- Changelog.md | 29 ++++++++++++++++ README.md | 38 ++++++++++++++++----- frontend/public/icons/vibefinance-logo.png | Bin 0 -> 57322 bytes 4 files changed, 87 insertions(+), 17 deletions(-) create mode 100644 frontend/public/icons/vibefinance-logo.png diff --git a/BEHEER.md b/BEHEER.md index 4c03ac5..8efa72b 100644 --- a/BEHEER.md +++ b/BEHEER.md @@ -333,9 +333,11 @@ 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 | +| `/api/...` | REST API (rate limited, `Cache-Control: no-store`) | +| `/assets/...` | gehashte build-bestanden uit `STATIC_DIR`, 1 jaar `immutable` | +| `/favicon.svg`, `/icons/...` | vaste namen, dus `max-age=0, must-revalidate` | +| pad mét extensie zonder bestand | echte 404, niet `index.html` | +| al het overige | `index.html` — fallback voor React-routing, `no-store` | `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 @@ -381,6 +383,12 @@ De backend slaat alle data op in **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. +Daarnaast heeft de app zelf een backup onder **Instellingen**: die schrijft een +ZIP met de data van de *ingelogde* gebruiker (`data.json` + `meta.json`) en leest +zo'n ZIP ook weer in. Handig per gebruiker, maar het is geen servercopie — accounts, +wachtwoordhashes en de data van andere gebruikers zitten er niet in. Voor een +volledige backup gebruik je `pg_dump` hieronder. + **Backup maken:** ```bash @@ -407,12 +415,25 @@ docker exec -i vibefinance_postgres psql -U vibefinance -d vibefinance < backup- 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 | +### Rollen + +De rolkeuze in Gebruikersbeheer biedt drie waarden, maar de backend dwingt er op +dit moment één af: + +| Rol | Wat de code ermee doet | |---|---| -| `Admin` | Alles, inclusief gebruikersbeheer | -| `Bewerker` | Data lezen en bewerken | -| `Viewer` | Alleen lezen | +| `Admin` | Enige rol die wordt gecontroleerd: `requireAdmin` in `middleware/auth.js` bewaakt alle routes onder `/api/users` | +| `Bewerker` | Geen eigen rechten — gelijk aan `Viewer` | +| `Viewer` | Standaardrol voor een nieuw account; mag de eigen data lezen én schrijven | + +Dat `Viewer` toch mag schrijven is geen gat in de afscherming: `/api/data` werkt +per gebruiker en gaat altijd over de rij van het eigen token (`req.user.sub`). +Niemand ziet dus data van een ander. Wat ontbreekt is een read-only account — +wil je dat, dan is er een controle op `rol` nodig bij `PUT`/`DELETE /api/data`. + +> De "Gebruikers"-knop in de navigatiebalk staat bij iedereen in beeld; bij een +> niet-Admin antwoordt `/api/users` met `403` en blijft de lijst leeg. De +> afscherming zit dus in de API, niet in de navigatie. --- diff --git a/Changelog.md b/Changelog.md index a2c0ac9..9d4ae8f 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,5 +1,34 @@ # Changelog +## [Niet vrijgegeven] + +### Gewijzigd +- De documentatie is gelijkgetrokken met de code. `README.md`: de bestandsboom + miste `backend/src/logger.js`, `docker/check-updates.mjs`, + `frontend/public/`, `InstellingenModal.jsx`, `LoginBackground.jsx` en de + losse bestanden in `utils/`, en noemde de update-route `update-check` terwijl + het bestand `routes/update.js` heet. De schermentabel gebruikt nu de labels + zoals ze in `constants/index.js` staan ("Schuld", "Voortgang Schuld & EV") en + vermeldt **Instellingen** — thema plus backup/restore via ZIP, dat nergens in + de README stond +- De tabel "wat de app met een verzoek doet" (in beide bestanden) noemde alleen + `/assets/...` en de SPA-fallback. `server.js` kent vier gevallen: `no-store` + op de API en op HTML, een jaar `immutable` op de gehashte bundels, + `must-revalidate` op bestanden met een vaste naam (`favicon.svg`, `icons/*`) + en een echte 404 op een pad mét extensie waar geen bestand achter zit +- `BEHEER.md` beschreef `Bewerker` als "data lezen en bewerken" en `Viewer` als + "alleen lezen". Zo werkt het niet: `requireAdmin` is de enige rolcontrole in + de code en bewaakt alleen `/api/users`. Een `Viewer` mag daardoor gewoon zijn + eigen data schrijven — geen gat in de afscherming, want `/api/data` gaat altijd + over de rij van het eigen token, maar wél iets anders dan er stond. De sectie + zegt nu wat de code doet en wat er nodig is voor een echt read-only account +- `README.md` en `BEHEER.md` wijzen bij backup naar het juiste niveau: de ZIP + onder Instellingen bevat alleen de data van de ingelogde gebruiker, `pg_dump` + is de volledige servercopie +- `DATABASE_URL` staat in de variabelentabel van `README.md`. Hij wordt door + `docker-compose.yml` samengesteld uit de `POSTGRES_*` waarden, dus zelf zetten + is alleen nodig buiten Compose + ## [1.0.4] - 2026-09-10 ### Gewijzigd diff --git a/README.md b/README.md index c417226..b314a1a 100644 --- a/README.md +++ b/README.md @@ -168,14 +168,20 @@ build — anders zou de release met een placeholder als notes online komen. |---|---| | 📊 **Dashboard** | Overzicht van totaal eigen vermogen, schulden en netto vermogen | | 💰 **Eigen vermogen** | Vermogensposten per categorie beheren + geïnvesteerde fiat historiek | -| 📉 **Schulden** | Schulden bijhouden per blok met afbetalingsoverzicht | -| 📈 **Voortgang** | Grafieken en trends van EV en schuld over tijd (apart bij te houden) | +| 📉 **Schuld** | Schulden bijhouden per blok met afbetalingsoverzicht | +| 📈 **Voortgang Schuld & EV** | Grafieken en trends van EV en schuld over tijd (apart bij te houden) | | 👥 **Gebruikers** | Accounts aanmaken, bewerken en beheren (Admin-rol vereist) | +| ⚙️ **Instellingen** | Licht/donker thema, backup downloaden en backup terugzetten | De kolommen in de tabellen op Eigen vermogen en Voortgang zijn versleepbaar: pak de rechterrand van een kolomkop. De breedtes worden per tabel in de browser bewaard; dubbelklik op de greep voor de standaardbreedte. +Backup en restore lopen via **Instellingen** in de navigatiebalk: "Backup maken" +downloadt een ZIP (`data.json` + `meta.json`) met je eigen financiële data, +"Backup terugzetten" leest zo'n ZIP weer in en schrijft hem via `/api/data` weg. +Dat is de gebruikersvariant; een volledige database-dump staat in `BEHEER.md`. + --- ## 🏗️ Architectuur @@ -193,27 +199,33 @@ vibefinance/ ├── release.ps1 / release.sh # Release (test, push, tag, Gitea-release) │ ├── docker/ -│ └── dev-entrypoint.sh # Start API + Vite samen in de dev-container +│ ├── dev-entrypoint.sh # Start API + Vite samen in de dev-container +│ ├── check-updates.mjs # Dependency-check tegen het npm-register +│ └── update-exceptions.json # Pakketten die bewust achterblijven, met reden │ ├── docs/ │ └── screenshot-dashboard.png # Screenshot bovenaan deze README │ ├── frontend/ # React / Vite SPA (build → dist) │ ├── vite.config.js # /api proxy naar de API in dezelfde container +│ ├── index.html # Vite-entry, verwijst naar /favicon.svg +│ ├── public/ # Ongebundeld: favicon.svg + icons/ │ └── src/ │ ├── App.jsx # Root – wiring + idle-logout │ ├── App.css # Reset + losse klassen (o.a. .kolom-grip) │ ├── main.jsx │ ├── version.js # Draaiende versie (__APP_VERSION__ uit de build) │ ├── constants/ # Kleuren, tabs, begindata -│ ├── utils/ # Formatters, helpers +│ ├── utils/ # format.js (bedragen/datums), storage.js │ ├── hooks/ # useTheme, useUpdateCheck, useKolomBreedtes -│ ├── context/ # AppContext (global state + API sync) +│ ├── context/ # AppContext (global state + API sync + backup) │ ├── components/ │ │ ├── ui/ # Primitieve UI (VCard, DonutChart…) │ │ ├── LoginPage.jsx +│ │ ├── LoginBackground.jsx │ │ ├── NavBar.jsx │ │ ├── ProfielPopup.jsx +│ │ ├── InstellingenModal.jsx # Thema + backup/restore │ │ └── GebruikersBeheer.jsx │ └── pages/ │ ├── DashboardTab.jsx @@ -226,10 +238,11 @@ vibefinance/ └── src/ ├── server.js # Entry point: API op /api, SPA op / ├── db.js # PostgreSQL pool + initDb() schema-migraties + ├── logger.js # pino (pino-pretty buiten productie) ├── config/ # Omgevingsvariabelen (incl. STATIC_DIR) ├── constants/ # Begindata (initialData.js) ├── middleware/ # auth.js, errorHandler.js - ├── routes/ # auth, data, users, health, update-check + ├── routes/ # auth, data, users, health, update └── stores/ # userStore, dataStore ``` @@ -245,9 +258,11 @@ frontend en API. | Verzoek | Wat de app doet | |---|---| -| `/api/...` | REST API (rate limited) | -| `/assets/...` | Statische build, 1 jaar `immutable` gecached | -| al het overige | `index.html` — fallback voor React-routing | +| `/api/...` | REST API (rate limited, `Cache-Control: no-store`) | +| `/assets/...` | Gehashte build-bestanden, 1 jaar `immutable` gecached | +| `/favicon.svg`, `/icons/...` | Vaste namen, dus `max-age=0, must-revalidate` | +| pad mét extensie, geen bestand | echte 404 (geen HTML waar een icoon wordt verwacht) | +| al het overige | `index.html` — fallback voor React-routing, niet gecached | --- @@ -295,6 +310,7 @@ Het schema wordt bij het starten van de app aangemaakt/bijgewerkt via | `JWT_SECRET` | — | **Verplicht** — minimaal 64 tekens | | `POSTGRES_USER` | `vibefinance` | Database gebruikersnaam | | `POSTGRES_DB` | `vibefinance` | Database naam | +| `DATABASE_URL` | — | Connectiestring; `docker-compose.yml` stelt hem samen uit de drie `POSTGRES_*` waarden, dus zelf zetten hoeft alleen buiten Compose | | `JWT_EXPIRES` | `7d` | Geldigheidsduur token | | `CORS_ORIGIN` | `http://localhost` | Externe domeinnaam (één origin, dus zelden nodig) | | `APP_PORT` | `3400` | Poort op de host (container luistert op 3001) | @@ -309,6 +325,10 @@ Het schema wordt bij het starten van de app aangemaakt/bijgewerkt via - Wachtwoorden gehasht met bcrypt (cost factor 12) - JWT authenticatie met instelbare vervaltijd +- Data is per gebruiker: `/api/data` leest en schrijft alleen de rij van de + ingelogde gebruiker (`sub` uit het token) +- Van de rollen wordt alleen **Admin** afgedwongen, op `/api/users` — zie de + sectie Rollen in `BEHEER.md` - Frontend en API op één origin — geen interne proxy, geen CORS-uitzonderingen - Content-Security-Policy via Helmet, toegespitst op wat de app laadt - Database bereikbaar alleen binnen het interne Docker netwerk diff --git a/frontend/public/icons/vibefinance-logo.png b/frontend/public/icons/vibefinance-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..309d03fc481e6bfe41ceaa3d9d977c05b5ab3629 GIT binary patch literal 57322 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