Maak DEPLOY_PATH configureerbaar via Gitea Actions variable i.p.v. hardcoded #7

Merged
Sluijsens merged 10 commits from feature/production_deploy_automation into master 2026-07-30 23:58:06 +02:00
4 changed files with 22 additions and 12 deletions
Showing only changes of commit 3af15159fe - Show all commits
+6 -1
View File
@@ -112,7 +112,12 @@ jobs:
- name: Build - name: Build
env: env:
VITE_UMAMI_SCRIPT_URL: ${{ vars.VITE_UMAMI_SCRIPT_URL }} VITE_UMAMI_SCRIPT_URL: ${{ vars.VITE_UMAMI_SCRIPT_URL }}
VITE_UMAMI_WEBSITE_ID: ${{ vars.VITE_UMAMI_WEBSITE_ID }} # Gitea-variable heet VITE_UMAMI_WEBSITE_ID_TEST (niet zonder suffix),
# analoog aan VITE_UMAMI_WEBSITE_ID_PRODUCTION in de build-production
# job hieronder. Linkerkant (VITE_UMAMI_WEBSITE_ID) is wél altijd
# gelijk: dat is de Vite-buildtime-envvar-naam die de app verwacht
# (zie src/components/UmamiAnalytics.tsx), niet aan te passen.
VITE_UMAMI_WEBSITE_ID: ${{ vars.VITE_UMAMI_WEBSITE_ID_TEST }}
# Sentry DSN is niet gevoelig (veilig om in de client-bundle te zitten), # Sentry DSN is niet gevoelig (veilig om in de client-bundle te zitten),
# daarom een Gitea Actions "vars"-waarde i.p.v. een secret. Optioneel: # daarom een Gitea Actions "vars"-waarde i.p.v. een secret. Optioneel:
# als deze niet is ingesteld, wordt Sentry-logging simpelweg overgeslagen # als deze niet is ingesteld, wordt Sentry-logging simpelweg overgeslagen
@@ -86,4 +86,4 @@ Vereist eenmalig vooraf:
## Future Work ## Future Work
- **Van wachtwoord naar SSH-key**: vervang `sshpass -p "${{ secrets.PI_MAIN_PASSWORD }}" scp ...` in `deploy.yaml` door een `scp`-commando met `-i <key-bestand>` (een nieuwe secret `PI_MAIN_SSH_KEY` die je eerst als bestand wegschrijft in de run-stap), en zet de bijbehorende public key in `~/.ssh/authorized_keys` van de `webadmin`-gebruiker op de webserver-Pi. Verwijder daarna het wachtwoord-secret. - **Van wachtwoord naar SSH-key**: vervang `sshpass -p "${{ secrets.PI_MAIN_PASSWORD }}" scp ...` in `deploy.yaml` door een `scp`-commando met `-i <key-bestand>` (een nieuwe secret `PI_MAIN_SSH_KEY` die je eerst als bestand wegschrijft in de run-stap), en zet de bijbehorende public key in `~/.ssh/authorized_keys` van de `webadmin`-gebruiker op de webserver-Pi. Verwijder daarna het wachtwoord-secret.
- **Productie nginx/SSL-configuratie**: de deploy-pipeline ondersteunt productie al (`build-production`/`deploy-production`), maar er is nog geen productie-nginx-voorbeeldconfiguratie — deze is op verzoek van de gebruiker verwijderd totdat er een goed-werkende versie is, en kan later opnieuw opgebouwd worden naar analogie van `nginx/webserver-nginx.conf.example` en `nginx/reverse-proxy-nginx.conf.example`, met domein `slpsoftware.nl`. - **Productie nginx/SSL-configuratie**: de deploy-pipeline ondersteunt productie al (`build-production`/`deploy-production`), maar er is nog geen productie-nginx-voorbeeldconfiguratie — deze is op verzoek van de gebruiker verwijderd totdat er een goed-werkende versie is, en kan later opnieuw opgebouwd worden naar analogie van `nginx/webserver-nginx.conf.example` en `nginx/reverse-proxy-nginx.conf.example`, met domein `slpsoftware.nl`.
- **Aparte productie-Umami-website/Sentry-project**: `build-production` gebruikt momenteel dezelfde `VITE_UMAMI_WEBSITE_ID`/`VITE_SENTRY_DSN` als de testbuild. Overweeg dit te splitsen zodra test- en productieverkeer niet meer door elkaar gemengd mogen worden in dezelfde analytics/Sentry-projecten. - **Apart productie-Sentry-project**: `build-production` gebruikt momenteel dezelfde `VITE_SENTRY_DSN` als de testbuild (Umami heeft al aparte website-ID's per omgeving, zie `umami-setup.md`). Overweeg dit te splitsen zodra test- en productie-events niet meer door elkaar gemengd mogen worden in hetzelfde Sentry-project.
@@ -28,7 +28,7 @@ A combination of:
## Open Action Items ## Open Action Items
1. ~~Decide logging destination~~**Resolved and verified**: Sentry free tier, wired into `ErrorBoundary`/`main.tsx` (see `monitoring-setup.md`), including tracing, environment/release tags, and a tunnel to bypass ad-blocker blocking. The user confirmed errors, logs, and metrics are received correctly, both locally and on the test environment. The Gitea Actions variable `VITE_SENTRY_DSN` still needs to be created by the user with a real Sentry project DSN for the test/production build; until then that build simply skips Sentry initialization and only console-logging is active (local development already has its own DSN via `.env.local`). 1. ~~Decide logging destination~~**Resolved and verified**: Sentry free tier, wired into `ErrorBoundary`/`main.tsx` (see `monitoring-setup.md`), including tracing, environment/release tags, and a tunnel to bypass ad-blocker blocking. The user confirmed errors, logs, and metrics are received correctly, both locally and on the test environment. The Gitea Actions variable `VITE_SENTRY_DSN` still needs to be created by the user with a real Sentry project DSN for the test/production build; until then that build simply skips Sentry initialization and only console-logging is active (local development already has its own DSN via `.env.local`).
2. ~~Pick concrete analytics + uptime tools~~**Resolved**: self-hosted Umami + UptimeRobot (see `monitoring-setup.md` and `umami-setup.md`). Remaining manual follow-ups: actually deploying the Umami containers on the Pi, registering DNS/SSL for `analytics.slpsoftware.nl`, creating the UptimeRobot monitor, and setting the `VITE_UMAMI_SCRIPT_URL`/`VITE_UMAMI_WEBSITE_ID` Gitea repository variables. 2. ~~Pick concrete analytics + uptime tools~~**Resolved**: self-hosted Umami + UptimeRobot (see `monitoring-setup.md` and `umami-setup.md`). Remaining manual follow-ups: actually deploying the Umami containers on the Pi, registering DNS/SSL for `analytics.slpsoftware.nl`, creating the UptimeRobot monitor, and setting the `VITE_UMAMI_SCRIPT_URL`/`VITE_UMAMI_WEBSITE_ID_TEST` (and, once production is set up, `VITE_UMAMI_WEBSITE_ID_PRODUCTION`) Gitea repository variables.
## Rationale ## Rationale
Given this is a simple static marketing site with no backend and no existing monitoring, the aim is lightweight, low/no-cost observability: enough to know if the site is down (uptime) and how it's being used (analytics), plus a documented (if not yet finalized) path for capturing client-side errors. Alerting was deliberately left out to avoid over-engineering a notification pipeline before there's a concrete trigger/audience for it. Given this is a simple static marketing site with no backend and no existing monitoring, the aim is lightweight, low/no-cost observability: enough to know if the site is down (uptime) and how it's being used (analytics), plus a documented (if not yet finalized) path for capturing client-side errors. Alerting was deliberately left out to avoid over-engineering a notification pipeline before there's a concrete trigger/audience for it.
@@ -192,7 +192,7 @@ verschillende domeinen en horen dus niet in dezelfde statistieken te belanden:
- Name: `SLP Software (test)` (of naar keuze) - Name: `SLP Software (test)` (of naar keuze)
- Domain: `test.slpsoftware.nl` - Domain: `test.slpsoftware.nl`
3. Na het opslaan toont Umami een **Website ID** (een UUID) voor deze entry — nodig voor 3. Na het opslaan toont Umami een **Website ID** (een UUID) voor deze entry — nodig voor
`VITE_UMAMI_WEBSITE_ID` in de volgende stap. `VITE_UMAMI_WEBSITE_ID_TEST` in de volgende stap.
4. Herhaal stap 2-3 voor productie zodra die omgeving wordt opgezet: een tweede website- 4. Herhaal stap 2-3 voor productie zodra die omgeving wordt opgezet: een tweede website-
entry met Domain `slpsoftware.nl`, met een eigen Website ID voor entry met Domain `slpsoftware.nl`, met een eigen Website ID voor
`VITE_UMAMI_WEBSITE_ID_PRODUCTION`. `VITE_UMAMI_WEBSITE_ID_PRODUCTION`.
@@ -201,20 +201,25 @@ verschillende domeinen en horen dus niet in dezelfde statistieken te belanden:
De React-app (`src/components/UmamiAnalytics.tsx`) injecteert het Umami tracking-script De React-app (`src/components/UmamiAnalytics.tsx`) injecteert het Umami tracking-script
automatisch, mits de volgende build-time variabelen zijn ingesteld — geen van deze zijn automatisch, mits de volgende build-time variabelen zijn ingesteld — geen van deze zijn
**secrets** (client-side zichtbaar), dus als Gitea Actions **repository variables** **secrets** (client-side zichtbaar), dus als Gitea Actions **repository variables**
(niet secrets), net als `VITE_SENTRY_DSN`: (niet secrets), net als `VITE_SENTRY_DSN`. Omgevingsspecifieke variabelen (die per
omgeving een andere waarde hebben) krijgen consistent een `_TEST`/`_PRODUCTION`-postfix;
gedeelde variabelen (die bewust voor beide omgevingen identiek zijn) niet:
| Variabele | Waarde | | Variabele | Waarde |
|---|---| |---|---|
| `VITE_UMAMI_SCRIPT_URL` | `https://analytics.slpsoftware.nl/script.js` (gedeeld tussen test en productie — zelfde Umami-instance/endpoint voor beide) | | `VITE_UMAMI_SCRIPT_URL` | `https://analytics.slpsoftware.nl/script.js` (gedeeld tussen test en productie — zelfde Umami-instance/endpoint voor beide, geen postfix) |
| `VITE_UMAMI_WEBSITE_ID` | het Website ID van de **test**-website-entry uit stap 4 | | `VITE_UMAMI_WEBSITE_ID_TEST` | het Website ID van de **test**-website-entry uit stap 4 |
| `VITE_UMAMI_WEBSITE_ID_PRODUCTION` | het Website ID van de **productie**-website-entry uit stap 4 (pas nodig vóór de eerste `deploy_production`-run) | | `VITE_UMAMI_WEBSITE_ID_PRODUCTION` | het Website ID van de **productie**-website-entry uit stap 4 (pas nodig vóór de eerste `deploy_production`-run) |
Stel deze in via **Gitea → Repository Settings → Actions → Variables**. Zodra ze bestaan, Stel deze in via **Gitea → Repository Settings → Actions → Variables**. Zodra ze bestaan,
pakt de eerstvolgende build ze automatisch op; zonder deze variabelen slaat de app het pakt de eerstvolgende build ze automatisch op; zonder deze variabelen slaat de app het
inladen van het script gewoon over (geen crash, geen tracking). Let op: inladen van het script gewoon over (geen crash, geen tracking). Let op: dit zijn de
`continuous_integration.yaml`'s `build`-job (test) leest `VITE_UMAMI_WEBSITE_ID`, de namen van de Gitea-variabelen — de app zelf verwacht altijd de envvar-naam
`build-production`-job leest `VITE_UMAMI_WEBSITE_ID_PRODUCTION` — verwissel deze niet, `VITE_UMAMI_WEBSITE_ID` (zie `UmamiAnalytics.tsx`), dus in `continuous_integration.yaml`
anders komt productieverkeer in de teststatistieken terecht (of andersom). wordt bv. `VITE_UMAMI_WEBSITE_ID: ${{ vars.VITE_UMAMI_WEBSITE_ID_TEST }}` gebruikt in de
`build`-job en `VITE_UMAMI_WEBSITE_ID: ${{ vars.VITE_UMAMI_WEBSITE_ID_PRODUCTION }}` in
`build-production` — verwissel deze niet, anders komt productieverkeer in de
teststatistieken terecht (of andersom).
**Lokaal (`pnpm dev`)**: het tracking-script wordt hier bewust nooit geladen (zie **Lokaal (`pnpm dev`)**: het tracking-script wordt hier bewust nooit geladen (zie
`UmamiAnalytics.tsx`), zodat lokaal testen de bezoekersstatistieken niet vervuilt. Wil je `UmamiAnalytics.tsx`), zodat lokaal testen de bezoekersstatistieken niet vervuilt. Wil je
@@ -229,7 +234,7 @@ dit toch lokaal testen, zet dan tijdelijk beide waarden in `.env.local` (zie
- [ ] DNS-record + certbot voor `analytics.slpsoftware.nl` op de reverse-proxy-Pi. - [ ] DNS-record + certbot voor `analytics.slpsoftware.nl` op de reverse-proxy-Pi.
- [ ] Standaard Umami-wachtwoord direct wijzigen na eerste login. - [ ] Standaard Umami-wachtwoord direct wijzigen na eerste login.
- [ ] Website aanmaken in Umami voor de testomgeving en het Website ID overnemen. - [ ] Website aanmaken in Umami voor de testomgeving en het Website ID overnemen.
- [ ] `VITE_UMAMI_SCRIPT_URL` en `VITE_UMAMI_WEBSITE_ID` als Gitea repository variables instellen. - [ ] `VITE_UMAMI_SCRIPT_URL` en `VITE_UMAMI_WEBSITE_ID_TEST` als Gitea repository variables instellen.
- [ ] Zodra productie wordt opgezet: aparte website aanmaken in Umami voor `slpsoftware.nl` en het Website ID als `VITE_UMAMI_WEBSITE_ID_PRODUCTION` instellen (zie stap 4/5 hierboven — vereist vóór de eerste `deploy_production`-run). - [ ] Zodra productie wordt opgezet: aparte website aanmaken in Umami voor `slpsoftware.nl` en het Website ID als `VITE_UMAMI_WEBSITE_ID_PRODUCTION` instellen (zie stap 4/5 hierboven — vereist vóór de eerste `deploy_production`-run).
## Vervolgstappen voor toekomstige self-hosted diensten ## Vervolgstappen voor toekomstige self-hosted diensten