Add automated test-environment deploy via SCP with nginx reverse proxy, domain names and SSL (certbot) setup

Co-authored-by: Junie <junie@jetbrains.com>
This commit is contained in:
2026-07-24 15:52:16 +02:00
co-authored by Junie
parent a437bad95b
commit 1ffe884eba
9 changed files with 273 additions and 61 deletions
@@ -336,3 +336,27 @@
**Feature Status**: Complete
---
## Post-Completion Follow-up: Automated Test-Environment Deploy
**Timestamp**: 2026-07-24T15:20:00Z
**User Input**: "Ik wil de voorgestelde vervolgstappen uitvoeren beginnend bij de deployment. Voor nu wil ik in ieder geval kunnen deployen naar een testomgeving. Die testomgeving is een web-server gehost op mijn eigen raspberry pi achter andere raspberry pi met een nginx reversed proxy" — followed by clarification on auth (password for now), connection details (internal IP `192.168.1.103`, port `2224`, user `webadmin`), deploy path (`/html/test/slpsoftware`), nginx setup needed, and trigger (keep existing manual + auto-on-merge-to-master trigger).
**AI Response**: "Implemented the previously open 'automatic deploy' follow-up from `deployment-plan.md`, for a test environment only. Fixed the CI push trigger (`main` -> `master`, matching the actual default branch). Extended `.gitea/workflows/deploy.yaml` with a real `appleboy/scp-action` upload step (password-based SSH auth via new secrets `PI_TEST_HOST`/`PI_TEST_PORT`/`PI_TEST_USERNAME`/`PI_TEST_PASSWORD`) uploading `dist/` to `/html/test/slpsoftware`. Renamed/reconfigured the calling job to `deploy-test` (`environment: test`, `secrets: inherit`). Added example nginx configs (`operations/deployment/nginx/webserver-nginx.conf.example` and `reverse-proxy-nginx.conf.example`) for the two-Pi setup. Rewrote `deployment-plan.md`, `deployment-instructions.md`, and `rollback-plan.md` to describe the new automated test deploy, required secrets, and manual nginx/Pi setup steps."
**Context**: Post-workflow follow-up (feature already marked Complete); addresses the "Open Item — Automatic Deploy Not Yet Implemented" from the original `deployment-plan.md`. Changes not yet committed/pushed; production deploy remains a separate open item.
---
## Post-Completion Follow-up: Domain Names & SSL for Test/Production
**Timestamp**: 2026-07-24T15:48:00Z
**User Input**: "Het was misschien handiger geweest als je om onduidelijkheden had gevraagd zoals domeinnaam en hoe het zit met ssl-certificaat. De reverse-proxy Pi heeft de certificaten. Die vroeg ik altijd aan met certbot van LetsEncrypt. Die leid het verkeer door naar de webhost en de webhost handelt verder http af. domeinnaam voor de productiewebsite wordt: slpsoftware.nl. Voor de testomgeving wordt dat test.slpsoftware.nl"
**AI Response**: "Updated `nginx/reverse-proxy-nginx.conf.example` (test) to use `test.slpsoftware.nl` as `server_name`, with an HTTP server block for the Let's Encrypt ACME challenge + redirect to HTTPS, and an HTTPS server block referencing certbot-managed certificate paths (`/etc/letsencrypt/live/test.slpsoftware.nl/...`) — matching the user's existing certbot/Let's Encrypt workflow on the reverse-proxy Pi, which terminates SSL before forwarding plain HTTP to the webserver Pi. Added a new `nginx/reverse-proxy-nginx-production.conf.example` documenting the future production reverse-proxy config for `slpsoftware.nl`/`www.slpsoftware.nl` (not yet wired up, since production deploy automation is still an open item). Updated `deployment-plan.md` and `deployment-instructions.md` with the domain/DNS/certbot setup steps for both environments."
**Context**: Post-workflow follow-up (feature already marked Complete); addresses the user's feedback that domain name and SSL certificate handling should have been clarified during the earlier deployment follow-up. Changes not yet committed/pushed.
---
@@ -1,36 +1,52 @@
# Deployment Instructions
## Overview
Deployment is currently a **manually-triggered Gitea Actions pipeline**: `.gitea/workflows/deploy.yml`. You start it yourself from the Gitea Actions UI; it runs the build/test/lint gate and then packages the `dist/` build as a downloadable artifact. There is no automatic upload to a host yet — you upload the artifact yourself for now.
Deployment gebeurt via Gitea Actions, opgesplitst in twee bestanden:
- `.gitea/workflows/continuous_integration.yaml` — build/test/lint-gate, plus de `deploy-test` job.
- `.gitea/workflows/deploy.yaml` — herbruikbare workflow die `dist/` via SCP naar een omgeving uploadt.
## Pipeline File
`.gitea/workflows/deploy.yml` — triggered by `workflow_dispatch` only (no automatic trigger on push/tag). Two jobs:
- `build-and-test` — install, lint, unit tests, build; uploads `dist/` as the `dist` artifact
- `deploy` — downloads that artifact and republishes it as `release-dist` (placeholder for a future automatic upload step)
Sinds deze stap wordt er automatisch gedeployed naar een **testomgeving**: een Raspberry Pi die de site serveert via nginx, bereikbaar achter een tweede Raspberry Pi met een nginx reverse proxy.
## How to Prepare and Run a Release
## Pipeline Files
- `continuous_integration.yaml` — getriggerd door `pull_request` (build/test/lint-gate), `push` naar `master`, en handmatig via `workflow_dispatch`.
- `prepare``build` (uploadt `dist` artifact) → `test` (lint + unit tests)
- `deploy-test` (alleen bij `workflow_dispatch` of een push naar `master`) roept `deploy.yaml` aan met `environment: test` en `deploy_path: /html/test/slpsoftware`
- `deploy.yaml` — download de `dist`-artifact en upload de inhoud via `appleboy/scp-action` naar de opgegeven `deploy_path` op de host uit de meegegeven secrets.
### 1. Create a release branch (manual, your own git flow)
```bash
git checkout master
git pull
git checkout -b release/1.0.0
git push origin release/1.0.0
```
## Eenmalige Setup — Gitea Secrets
Voeg deze secrets toe in Gitea: **Repository → Settings → Actions → Secrets**:
### 2. Trigger the pipeline manually
1. In Gitea, open the repository's **Actions** tab.
2. Select the **Build, Test and Package Release** workflow.
3. Click **Run workflow**, choose the `release/1.0.0` branch (or whichever ref you want to build), and start it.
| Secret | Waarde |
|---|---|
| `PI_TEST_HOST` | Intern IP-adres van de webserver-Pi (`192.168.1.103`) |
| `PI_TEST_PORT` | SSH-poort (`2224`) |
| `PI_TEST_USERNAME` | SSH-gebruikersnaam (`webadmin`) |
| `PI_TEST_PASSWORD` | Het SSH-wachtwoord van deze gebruiker |
### 3. Download and upload the artifact
1. Once the run finishes successfully, open the run's summary page in Gitea Actions.
2. Download the **release-dist** artifact (a zip of the `dist/` folder).
3. Upload its contents to your host manually (e.g. via your FTP/SFTP client), using whatever hosting setup you finalize with mijnhostingpartner.nl.
## Eenmalige Setup — Domeinnaam & DNS
- **Test**: `test.slpsoftware.nl` → moet als DNS A-record wijzen naar het publieke IP van de reverse-proxy-Pi.
- **Productie** (nog niet automatisch gedeployed, maar domein al bekend): `slpsoftware.nl` (en `www.slpsoftware.nl`) → zelfde reverse-proxy-Pi, zodra productie wordt opgezet.
## Eenmalige Setup — nginx & SSL op de Raspberry Pi's
1. Kopieer `operations/deployment/nginx/webserver-nginx.conf.example` naar `/etc/nginx/sites-available/` op de webserver-Pi, maak een symlink in `sites-enabled/`, en herlaad nginx.
2. Kopieer `operations/deployment/nginx/reverse-proxy-nginx.conf.example` naar `/etc/nginx/sites-available/slpsoftware-test.conf` op de reverse-proxy-Pi, maak een symlink in `sites-enabled/`, en herlaad nginx. Dit bestand gebruikt al `test.slpsoftware.nl` als `server_name`.
3. Vraag op de reverse-proxy-Pi een SSL-certificaat aan met certbot (Let's Encrypt), nadat het DNS-record klopt: `sudo certbot --nginx -d test.slpsoftware.nl`. Certbot regelt automatisch de HTTPS-configuratie en de HTTP→HTTPS-redirect (net zoals je gewend bent van certbot).
4. Zorg dat de map `/html/test/slpsoftware` bestaat op de webserver-Pi en schrijfbaar is voor de gebruiker `webadmin` (bijv. `sudo mkdir -p /html/test/slpsoftware && sudo chown webadmin:webadmin /html/test/slpsoftware`).
5. Voor later, wanneer productie wordt opgezet: zie `operations/deployment/nginx/reverse-proxy-nginx-production.conf.example` (domein `slpsoftware.nl`, certbot-commando alvast gedocumenteerd).
## How to Deploy to Test
### Automatisch
Merge een pull request naar `master` — de `deploy-test` job draait dan automatisch na een groene build/test-run.
### Handmatig
1. In Gitea, open de repository's **Actions** tab.
2. Selecteer de **Continuous Integration** workflow.
3. Klik **Run workflow**, kies de gewenste branch/ref, en start.
## Verifying a Deployment
1. Confirm the Gitea Actions run completed successfully (`build-and-test` and `deploy` both green).
2. After manually uploading the artifact contents, open the live site in a browser and confirm it loads correctly (check the browser console for errors, per the manual smoke test in `construction/build-and-test/integration-test-instructions.md`).
1. Bevestig dat de Gitea Actions run succesvol is (alle jobs groen, inclusief `deploy-test`).
2. Open de testomgeving in de browser (via het adres/IP dat je bij de reverse-proxy hebt ingesteld) en controleer dat de site correct laadt (check de browserconsole op fouten, zoals in de handmatige smoke test in `construction/build-and-test/integration-test-instructions.md`).
## Future Work — Automatic Upload
Once the hosting setup is finalized (FTP/SFTP details, and whether this frontend shares a domain/app with a future back-end and CMS front-end — see `deployment-plan.md`'s "Open Item"), replace the placeholder step in the `deploy` job with an actual upload step (e.g. an FTP/SFTP action, or a shell-based upload using `lftp`/`curl`), using Gitea Actions Secrets for credentials and Variables for host/paths. At that point, decide whether the trigger should stay manual or become automatic (e.g. on push to `release/*` or on tag).
## Future Work
- **Van wachtwoord naar SSH-key**: vervang `password: ${{ secrets.PI_TEST_PASSWORD }}` in `deploy.yaml` door `key: ${{ secrets.PI_TEST_SSH_KEY }}` (een nieuwe secret met de private key-inhoud), en zet de bijbehorende public key in `~/.ssh/authorized_keys` van de `webadmin`-gebruiker op de webserver-Pi. Verwijder daarna het wachtwoord-secret.
- **Productie-omgeving**: voeg een `deploy-production`-job toe zodra de definitieve productiehosting bekend is (zie `deployment-plan.md`'s "Open Item"), en pas `nginx/reverse-proxy-nginx-production.conf.example` (domein `slpsoftware.nl`) toe zodra de webserver-locatie voor productie vastligt.
@@ -1,30 +1,41 @@
# Deployment Plan
## Chosen Method
**A manually-triggered Gitea Actions pipeline** (`workflow_dispatch`) that runs the build/test/lint gate and then packages the `dist/` build as a downloadable artifact. This is an interim setup, deliberately simplified per user feedback after the initial plan: no automatic upload to a host yet — that will be added later once the hosting details are finalized (see "Open Item" below).
**Gitea Actions**, opgesplitst in twee workflow-bestanden:
- `.gitea/workflows/continuous_integration.yaml` — draait de build/test/lint-gate, automatisch bij elke pull request en bij elke push/merge naar `master`, of handmatig via `workflow_dispatch`.
- `.gitea/workflows/deploy.yaml` — een herbruikbare (`workflow_call`) job die de `dist/` build via SCP (over SSH) uploadt naar de webroot van een omgeving.
Sinds deze stap is er een echte, geautomatiseerde upload naar een **testomgeving**: een Raspberry Pi die de statische site serveert via nginx, achter een tweede Raspberry Pi die als nginx reverse proxy fungeert.
## How It Works
1. You manually create a `release/*` branch when you want to cut a release (e.g. `release/1.0.0`), following your own git flow.
2. You manually trigger the pipeline (`Build, Test and Package Release`) from Gitea's Actions UI, picking the branch/ref to run it against (typically the release branch).
3. The pipeline always runs `build-and-test` first (install, lint, unit tests, build) as a gate.
4. If that succeeds, the `deploy` job downloads the build and republishes it as a `release-dist` artifact, ready to download and upload to the host by hand for now.
1. Bij elke pull request draait automatisch de build/test/lint-gate (`prepare``build``test`), zodat merge requests direct gevalideerd worden.
2. Zodra een pull request naar `master` gemerged wordt (of de workflow handmatig via `workflow_dispatch` gestart wordt), draait aanvullend de `deploy-test` job.
3. `deploy-test` roept de herbruikbare `deploy.yaml` workflow aan met `environment: test` en `deploy_path: /html/test/slpsoftware`, en geeft via `secrets: inherit` de Pi-inloggegevens door.
4. `deploy.yaml` downloadt de `dist`-artifact en uploadt de inhoud via SCP (wachtwoord-login) naar de webserver-Pi op het interne netwerk (`192.168.1.103`, poort `2224`).
5. nginx op de webserver-Pi serveert de bestanden vanaf `/html/test/slpsoftware`; de reverse-proxy-Pi stuurt binnenkomend verkeer door naar deze webserver-Pi. Voorbeeldconfiguraties staan in `operations/deployment/nginx/`.
6. De reverse-proxy-Pi is ook verantwoordelijk voor SSL: certificaten worden net als voorheen aangevraagd via certbot (Let's Encrypt) en HTTP-verkeer wordt doorverwezen naar HTTPS.
## Environments
Simplified to a single flow for now (superseding the earlier dev/staging/production proposal, which is dropped per user feedback — **the staging/production auto-deploy jobs have been removed**):
- No automated environment deployments exist yet.
- Releases are prepared manually via `release/*` branches; the artifact produced by the pipeline is uploaded to the host manually until an automatic deploy step is added.
- **Test** (nieuw, geautomatiseerd): zoals hierboven beschreven — de enige omgeving die op dit moment daadwerkelijk automatisch gedeployed wordt. Domeinnaam: `test.slpsoftware.nl` (SSL via certbot op de reverse-proxy-Pi).
- **Productie**: nog niet geautomatiseerd. Zodra de definitieve productiehosting bekend is, kan een vergelijkbare `deploy-production`-job worden toegevoegd die `deploy.yaml` aanroept met `environment: production` en de productie-secrets/pad. Domeinnaam ligt al vast: `slpsoftware.nl` (SSL eveneens via certbot; zie `nginx/reverse-proxy-nginx-production.conf.example`).
## Automation Level
Partially automated (intentionally, for now): build/test/lint and artifact packaging are automated once triggered, but **triggering itself is manual** (`workflow_dispatch`), and the actual upload to the host is also manual (download the `release-dist` artifact from the Gitea Actions run, then upload it yourself, e.g. via an FTP client). This is a deliberate interim step until the hosting setup is finalized.
Volledig geautomatiseerd voor de testomgeving: build, test, lint én upload naar de test-Pi gebeuren zonder handmatige tussenstap, zodra er gemerged wordt naar `master` (of handmatig getriggerd wordt). Alleen productie is nog niet geautomatiseerd.
## Rollback Strategy
Version control via git branches/releases: keep `release/*` branches (or tag them) so a previous release's artifact can be regenerated by re-running the pipeline against that branch/tag. See `rollback-plan.md`.
Zie `rollback-plan.md` — voor de testomgeving kan een eerdere commit/branch opnieuw gebouwd en geüpload worden door de workflow opnieuw te triggeren.
## Secrets & Configuration
Not yet needed — there is no automated upload step, so no host credentials are configured in Gitea Actions at this stage. When automatic deployment is added later, credentials should be stored as Gitea Actions Secrets (never committed to the repo), consistent with the original decision.
Voor de testomgeving zijn de volgende Gitea Actions Secrets (repository-niveau) vereist:
- `PI_TEST_HOST``192.168.1.103` (intern IP van de webserver-Pi)
- `PI_TEST_PORT``2224`
- `PI_TEST_USERNAME``webadmin`
- `PI_TEST_PASSWORD` — het SSH-wachtwoord van deze gebruiker
## Open Item — Automatic Deploy Not Yet Implemented
The `deploy` job currently only re-publishes the build as an artifact. Once you decide on the final hosting setup (FTP/SFTP details, and whether this frontend shares a domain/app with a future back-end and CMS front-end), the `deploy` job in `.gitea/workflows/deploy.yml` should be extended to actually upload `dist/` to the host (e.g. via an FTP/SFTP action or a shell-based upload step), reusing Gitea Actions Secrets/Variables for credentials and paths.
Dit is bewust wachtwoord-authenticatie (voor nu, zoals gekozen), zodat de testomgeving snel werkend is. Zie "Future Work" in `deployment-instructions.md` voor de overstap naar SSH-key-authenticatie.
## Open Item — Productie-deploy Nog Niet Geautomatiseerd
Zodra de definitieve productiehosting bekend is (en of dit dezelfde soort Raspberry Pi-opstelling is, of een externe hostingpartij), voeg een `deploy-production`-job toe aan `continuous_integration.yaml` die `deploy.yaml` aanroept met `environment: production`, en configureer de bijbehorende secrets (`PI_PROD_*` of vergelijkbaar). Domeinnaam (`slpsoftware.nl`) en SSL-aanpak (certbot/Let's Encrypt op de reverse-proxy-Pi) liggen al vast, zie `nginx/reverse-proxy-nginx-production.conf.example`.
## Verified Build Prerequisite
This plan relies on the Build and Test stage already being verified (`construction/build-and-test/build-and-test-summary.md`): `pnpm run build` produces a static `dist/` bundle with no server-side requirements.
Dit plan bouwt voort op de Build and Test-stage (`construction/build-and-test/build-and-test-summary.md`): `pnpm run build` produceert een statische `dist/`-bundel zonder server-side vereisten, geschikt om direct door nginx geserveerd te worden.
@@ -0,0 +1,55 @@
# Voorbeeldconfiguratie voor de nginx reverse proxy op de Raspberry Pi voor de
# PRODUCTIEOMGEVING, bereikbaar via het domein slpsoftware.nl.
#
# LET OP: dit bestand is nog niet in gebruik — de productie-deploy is nog niet
# geautomatiseerd (zie deployment-plan.md's "Open Item — Productie-deploy Nog
# Niet Geautomatiseerd"). Dit voorbeeld ligt hier alvast klaar zodat het
# domein en SSL-certificaat (net als bij de testomgeving via certbot) bekend
# zijn wanneer de productie-deploy wordt opgezet. Vervang <PROD_WEBSERVER_IP>
# en <PROD_WEBSERVER_POORT> door de daadwerkelijke waarden zodra die bekend
# zijn (mogelijk dezelfde webserver-Pi op een ander poortnummer/pad, of een
# aparte Pi/host).
#
# Kopieer dit bestand handmatig naar bijvoorbeeld
# /etc/nginx/sites-available/slpsoftware-production.conf op de reverse-proxy-Pi,
# maak een symlink in sites-enabled, en herlaad nginx.
#
# SSL-certificaat aanvragen met certbot (Let's Encrypt), nadat het DNS-record
# voor slpsoftware.nl naar het publieke IP van deze Pi wijst:
# sudo certbot --nginx -d slpsoftware.nl -d www.slpsoftware.nl
server {
listen 80;
listen [::]:80;
server_name slpsoftware.nl www.slpsoftware.nl;
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
location / {
return 301 https://$host$request_uri;
}
}
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name slpsoftware.nl www.slpsoftware.nl;
ssl_certificate /etc/letsencrypt/live/slpsoftware.nl/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/slpsoftware.nl/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
location / {
proxy_pass http://<PROD_WEBSERVER_IP>:<PROD_WEBSERVER_POORT>;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
@@ -0,0 +1,56 @@
# Voorbeeldconfiguratie voor de nginx reverse proxy op de andere Raspberry Pi
# (degene die wél vanaf het internet bereikbaar is en het binnenkomende verkeer
# doorstuurt naar de webserver-Pi op 192.168.1.103:8080) — voor de TESTOMGEVING,
# bereikbaar via het domein test.slpsoftware.nl.
#
# Kopieer dit bestand handmatig naar bijvoorbeeld
# /etc/nginx/sites-available/slpsoftware-test.conf op de reverse-proxy-Pi,
# maak een symlink in sites-enabled, en herlaad nginx.
#
# SSL-certificaat: net als voor de productiesite wordt dit aangevraagd met
# certbot (Let's Encrypt) rechtstreeks op deze reverse-proxy-Pi, bijvoorbeeld:
# sudo certbot --nginx -d test.slpsoftware.nl
# Zorg dat het DNS-record voor test.slpsoftware.nl al naar het publieke IP van
# deze Pi wijst voordat je certbot draait. Certbot vult automatisch het
# onderstaande `listen 443 ssl` server-block aan (of maakt het aan) en
# schrijft de HTTP-server hieronder om naar een 301-redirect. Het onderstaande
# is dus vooral illustratief voor de eindsituatie.
# HTTP: alleen gebruikt voor de Let's Encrypt ACME-challenge en om door te
# verwijzen naar HTTPS. Na het draaien van certbot ziet dit block er zo uit.
server {
listen 80;
listen [::]:80;
server_name test.slpsoftware.nl;
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
location / {
return 301 https://$host$request_uri;
}
}
# HTTPS: het daadwerkelijke reverse-proxy-verkeer naar de webserver-Pi.
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name test.slpsoftware.nl;
ssl_certificate /etc/letsencrypt/live/test.slpsoftware.nl/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/test.slpsoftware.nl/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
location / {
proxy_pass http://192.168.1.103:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
@@ -0,0 +1,39 @@
# Voorbeeldconfiguratie voor de nginx server op de Raspberry Pi die de
# gebouwde react-frontend (dist/) daadwerkelijk serveert.
#
# Deze Pi is NIET rechtstreeks vanaf het internet bereikbaar; de andere
# Raspberry Pi (met de nginx reverse proxy, zie reverse-proxy-nginx.conf.example)
# stuurt inkomend verkeer door naar deze server op het interne netwerk.
#
# Kopieer dit bestand handmatig naar bijvoorbeeld
# /etc/nginx/sites-available/slpsoftware-test.conf op de webserver-Pi,
# maak een symlink in sites-enabled, en herlaad nginx (`sudo nginx -t && sudo systemctl reload nginx`).
server {
# Alleen luisteren op het interne (LAN) IP-adres van deze Pi, niet op 0.0.0.0,
# zodat deze poort niet per ongeluk vanaf buiten het netwerk bereikbaar is.
listen 192.168.1.103:8080;
listen [::]:8080;
server_name _;
root /html/test/slpsoftware;
index index.html;
# De React-app gebruikt client-side routing (React Router), dus onbekende
# paden moeten terugvallen op index.html in plaats van een 404 te geven.
location / {
try_files $uri $uri/ /index.html;
}
# Statische assets mogen langer gecachet worden.
location ~* \.(?:css|js|svg|png|jpg|jpeg|gif|ico|woff2?)$ {
try_files $uri =404;
expires 7d;
add_header Cache-Control "public";
}
# Doorgeven van het echte client-IP en protocol, afkomstig van de reverse proxy.
set_real_ip_from 192.168.1.0/24;
real_ip_header X-Forwarded-For;
}
@@ -1,24 +1,23 @@
# Rollback Plan
## Strategy
Since there is no automated upload step yet (deployment is manual — see `deployment-instructions.md`), "rollback" today means re-uploading a previous known-good build to the host by hand, rather than the pipeline reverting anything automatically.
Sinds deze stap wordt de testomgeving automatisch gedeployed door de `deploy-test` job (zie `deployment-instructions.md`). "Rollback" betekent hier: de workflow opnieuw laten draaien tegen een eerdere, bekend-goede commit/branch, zodat die build automatisch opnieuw naar de test-Pi wordt geüpload en de huidige (foutieve) bestanden overschrijft.
## Rolling Back the Live Site
1. Identify the previous good `release/*` branch (or its last commit) that was actually uploaded to the host.
2. Re-run the **Build, Test and Package Release** workflow manually against that branch/commit in Gitea Actions.
3. Download the resulting `release-dist` artifact.
4. Upload its contents to the host manually, overwriting the current (bad) files — the same manual step used for a normal deployment.
5. Verify the live site reflects the rolled-back version.
## Rolling Back the Live Site (Test-omgeving)
1. Identificeer de laatste bekend-goede commit op `master` (of een eerdere `release/*`-branch/tag) die succesvol gedeployed was.
2. Trigger de **Continuous Integration** workflow handmatig (`workflow_dispatch`) tegen die commit/branch/tag in Gitea Actions.
3. De `deploy-test` job uploadt automatisch de resulterende `dist/`-build naar `/html/test/slpsoftware` op de webserver-Pi, en overschrijft daarmee de huidige (foutieve) bestanden.
4. Verify de live testomgeving reflecteert de teruggedraaide versie (via het adres achter de reverse proxy).
## Keeping Rollback Possible
- Do not delete `release/*` branches after they've been deployed; keep them (or tag them, e.g. `release/1.0.0``v1.0.0`) so you can always re-run the pipeline against a known-good point.
- Optionally keep a local/manual copy of the last few uploaded `dist/` artifacts as an extra safety net, since Gitea Actions artifacts expire after the configured retention period (currently 30 days, see `.gitea/workflows/deploy.yml`).
- Do not delete `release/*` branches (or tags) after they've been deployed, so you can always re-run the pipeline against a known-good point.
- Optionally keep a local/manual copy of the last few uploaded `dist/` artifacts as an extra safety net, since Gitea Actions artifacts expire after the configured retention period (currently 1 day, see `.gitea/workflows/continuous_integration.yaml`).
## Database / Stateful Rollback Considerations
Not applicable — this unit (`react-frontend-app`) is a static marketing site with no database and no server-side state. There is nothing to roll back beyond the static files themselves.
## Future Work
Once an automatic upload step is added (see `deployment-plan.md`'s "Open Item"), this rollback plan should be revisited: at that point, rollback can likely be automated too (e.g. re-triggering the pipeline for a previous branch/tag and letting it redeploy automatically, instead of a manual file upload).
Zodra ook productie geautomatiseerd wordt (zie `deployment-plan.md`'s "Open Item"), moet dit rollback-plan uitgebreid worden met een vergelijkbare procedure voor de `deploy-production`-job.
## Post-Rollback Checklist
- [ ] Confirm the Gitea Actions run for the rollback build completed successfully