Release Notes
Alle Releases auf GitHub Alle Versionen und Änderungen auf GitHub
v0.83.4v0.83.4
## What's Changed
## 🐛 Bug Fixes
- fix: do not pre-fill a stored secret with the manifest default on upgrade @Wiesenwischer (#473)
**Full Changelog**: https://github.com/Wiesenwischer/ReadyStackGo/compare/v0.83.3...v0.83.4
## 🐛 Bug Fixes
- fix: do not pre-fill a stored secret with the manifest default on upgrade @Wiesenwischer (#473)
**Full Changelog**: https://github.com/Wiesenwischer/ReadyStackGo/compare/v0.83.3...v0.83.4
v0.83.3v0.83.3
## What's Changed
## 🐛 Bug Fixes
- fix: keep stored shared variables across a product upgrade @Wiesenwischer (#471)
**Full Changelog**: https://github.com/Wiesenwischer/ReadyStackGo/compare/v0.83.2...v0.83.3
## 🐛 Bug Fixes
- fix: keep stored shared variables across a product upgrade @Wiesenwischer (#471)
**Full Changelog**: https://github.com/Wiesenwischer/ReadyStackGo/compare/v0.83.2...v0.83.3
v0.83.2v0.83.2
## Highlights
### Maintenance mode no longer leaves containers running — #469
Entering maintenance mode could leave product containers up while the deployment reported being in maintenance — and it reported success while doing so. The transition page showed "All containers stopped"; `docker ps` disagreed. Because the surviving containers kept their connection pools, a product update that waits for all database sessions to close waited on containers RSGO believed it had stopped.
This is the counterpart to the observer fix in v0.83.0: that release stopped RSGO from holding a session on a product database itself. It turned out RSGO could still be the reason sessions stayed open — by not stopping the containers that held them.
Four independent causes, each sufficient on its own:
**The container selection only looked for the `running` state.** Docker also reports `restarting`, `paused` and `created`. A container under `restart: always` that is cycling reports `restarting`, so it was never stopped and resumed normal operation once the window began. The selection is now inverted: everything that is not already `exited`, `dead` or `removing` gets stopped, which also means future Docker states default to being stopped rather than silently skipped. Containers marked `rsgo.maintenance=ignore` are exempt exactly as before, so the edge proxy and product-contributed maintenance containers still survive the window.
**A stop that failed was only written to the log.** The container state was never read back, and there was no retry. RSGO now verifies after stopping: it re-reads the actual state, retries the survivors individually, and kills whatever ignores two stop attempts. Each round re-reads the state instead of trusting the previous call, which also catches a container that came up while the transition was running.
**Stacks that were not in `Running` status were skipped wholesale.** A stack is marked `Failed` when a single one of its containers never becomes healthy — the others are up and running. Those stacks were passed over entirely, and because the progress denominator came from the same list, nothing looked missing. `Deploying` and `Failed` stacks are now included. Stacks that were never deployed are still skipped, as they have no containers.
**Success was reported regardless of the outcome.** The terminal update was "All containers stopped" unconditionally, and the result of the stop was discarded. The transition now reports a failure with the names of the containers that are still running — and also when the verification itself could not run, because claiming a stack stopped without having looked is what made this bug invisible in the first place.
### Notes for operators
- **A container that ignores two stop attempts is now killed.** It loses its graceful shutdown. This is deliberate: a maintenance window that never actually starts is worse. If a container legitimately needs to keep running through maintenance, mark it `rsgo.maintenance=ignore`.
- **A partial stop no longer looks like success.** The maintenance transition reports an error naming the containers that survived. Worth checking if you have automation that treats the transition as fire-and-forget.
- **The operation mode is not rolled back when containers survive.** The maintenance flag has already been propagated to the product at that point, so reverting it would be more surprising than reporting the failure. The deployment stays in maintenance and the failure is visible.
- Diagnosing open sessions on a SQL Server: RSGO's own sessions carry the application name `ReadyStackGo-Maintenance` and are non-pooled since v0.83.0, so they exist only for the duration of a single read. A session with that name that persists points at RSGO; sessions carrying a container hostname point at a product container that is still running.
No migration, no manifest change, no configuration change.
**Full changelog:** https://github.com/Wiesenwischer/ReadyStackGo/compare/v0.83.1...v0.83.2
### Maintenance mode no longer leaves containers running — #469
Entering maintenance mode could leave product containers up while the deployment reported being in maintenance — and it reported success while doing so. The transition page showed "All containers stopped"; `docker ps` disagreed. Because the surviving containers kept their connection pools, a product update that waits for all database sessions to close waited on containers RSGO believed it had stopped.
This is the counterpart to the observer fix in v0.83.0: that release stopped RSGO from holding a session on a product database itself. It turned out RSGO could still be the reason sessions stayed open — by not stopping the containers that held them.
Four independent causes, each sufficient on its own:
**The container selection only looked for the `running` state.** Docker also reports `restarting`, `paused` and `created`. A container under `restart: always` that is cycling reports `restarting`, so it was never stopped and resumed normal operation once the window began. The selection is now inverted: everything that is not already `exited`, `dead` or `removing` gets stopped, which also means future Docker states default to being stopped rather than silently skipped. Containers marked `rsgo.maintenance=ignore` are exempt exactly as before, so the edge proxy and product-contributed maintenance containers still survive the window.
**A stop that failed was only written to the log.** The container state was never read back, and there was no retry. RSGO now verifies after stopping: it re-reads the actual state, retries the survivors individually, and kills whatever ignores two stop attempts. Each round re-reads the state instead of trusting the previous call, which also catches a container that came up while the transition was running.
**Stacks that were not in `Running` status were skipped wholesale.** A stack is marked `Failed` when a single one of its containers never becomes healthy — the others are up and running. Those stacks were passed over entirely, and because the progress denominator came from the same list, nothing looked missing. `Deploying` and `Failed` stacks are now included. Stacks that were never deployed are still skipped, as they have no containers.
**Success was reported regardless of the outcome.** The terminal update was "All containers stopped" unconditionally, and the result of the stop was discarded. The transition now reports a failure with the names of the containers that are still running — and also when the verification itself could not run, because claiming a stack stopped without having looked is what made this bug invisible in the first place.
### Notes for operators
- **A container that ignores two stop attempts is now killed.** It loses its graceful shutdown. This is deliberate: a maintenance window that never actually starts is worse. If a container legitimately needs to keep running through maintenance, mark it `rsgo.maintenance=ignore`.
- **A partial stop no longer looks like success.** The maintenance transition reports an error naming the containers that survived. Worth checking if you have automation that treats the transition as fire-and-forget.
- **The operation mode is not rolled back when containers survive.** The maintenance flag has already been propagated to the product at that point, so reverting it would be more surprising than reporting the failure. The deployment stays in maintenance and the failure is visible.
- Diagnosing open sessions on a SQL Server: RSGO's own sessions carry the application name `ReadyStackGo-Maintenance` and are non-pooled since v0.83.0, so they exist only for the duration of a single read. A session with that name that persists points at RSGO; sessions carrying a container hostname point at a product container that is still running.
No migration, no manifest change, no configuration change.
**Full changelog:** https://github.com/Wiesenwischer/ReadyStackGo/compare/v0.83.1...v0.83.2
v0.83.1v0.83.1
## Highlights
### Secret variable values are no longer returned by the API — #467
Variables declared as passwords were shown in clear text on the product deployment detail page. This was not a rendering bug: `GET .../product-deployments/{id}` shipped every stored value verbatim, so the value was in the HTTP response regardless of what the UI drew. Masking in the frontend would have been cosmetic.
**Values of `Password` variables and of every connection-string type are now withheld.** The API returns the variable's name, whether it is secret, and whether a value is stored — never the value itself. The detail page shows `••••••••` for a stored secret and "not stored" when there is none. There is deliberately no reveal affordance: the value is not present in the response at all.
Connection strings count as secrets even though their type is not `Password` — they embed `Password=…`.
### The "save value" opt-out now actually works for product deployments — #467
The deploy form has always offered a per-variable **Save value** toggle, and the client has always sent the opt-out list. But the product deployment endpoint had no field to receive it: the list was discarded during binding and every variable was persisted anyway, including passwords the user explicitly opted out of saving. The toggle was decorative; the filter that existed was only reachable through the single-stack deploy path.
The opt-out now flows through the product **deploy and upgrade** paths and filters both the product-level shared variables and the per-stack variables before they are persisted. Docker still receives the full set — the container needs the value to run.
The upgrade form carries the choice forward and handles stored secrets properly: the field starts empty, leaving it empty keeps the stored value, typing replaces it. Untouched stored secrets are omitted from the request rather than sent as empty strings, which would previously have won during the variable merge and wiped the password.
### Notes for operators
- **A stored password is no longer readable in the UI by anyone, administrators included.** This is intentional. Where a password is needed, it comes from its source of truth, not from a deployment view.
- **A password that was not saved has to be entered again on upgrade.** Also intentional — it only appeared otherwise because it was being stored against the user's choice.
- Deployments created before this release have no recorded classification and fall back to judging by variable name (`*PASSWORD*`, `*SECRET*`, `*TOKEN*`, `*CONNECTIONSTRING*`, …), erring towards withholding. Their next deploy or upgrade records the exact set from the product manifest.
- A database migration (`AddSecretVariableNames`) runs automatically on startup. No manual step, no manifest change.
### API contract change
Despite being a patch release, this changes the shape of two response fields. Anyone consuming the API directly needs to adapt:
```
sharedVariables: Dictionary → DeploymentVariableDto[]
stacks[].variables: Dictionary → DeploymentVariableDto[]
DeploymentVariableDto { name, value (null when secret), isSecret, hasValue }
```
Distributions built on `@rsgo/core` need the same adjustment where they render these fields.
**Documentation:** [Variable types → Password](https://readystackgo.pages.dev/en/reference/variable-types/)
**Full changelog:** https://github.com/Wiesenwischer/ReadyStackGo/compare/v0.83.0...v0.83.1
### Secret variable values are no longer returned by the API — #467
Variables declared as passwords were shown in clear text on the product deployment detail page. This was not a rendering bug: `GET .../product-deployments/{id}` shipped every stored value verbatim, so the value was in the HTTP response regardless of what the UI drew. Masking in the frontend would have been cosmetic.
**Values of `Password` variables and of every connection-string type are now withheld.** The API returns the variable's name, whether it is secret, and whether a value is stored — never the value itself. The detail page shows `••••••••` for a stored secret and "not stored" when there is none. There is deliberately no reveal affordance: the value is not present in the response at all.
Connection strings count as secrets even though their type is not `Password` — they embed `Password=…`.
### The "save value" opt-out now actually works for product deployments — #467
The deploy form has always offered a per-variable **Save value** toggle, and the client has always sent the opt-out list. But the product deployment endpoint had no field to receive it: the list was discarded during binding and every variable was persisted anyway, including passwords the user explicitly opted out of saving. The toggle was decorative; the filter that existed was only reachable through the single-stack deploy path.
The opt-out now flows through the product **deploy and upgrade** paths and filters both the product-level shared variables and the per-stack variables before they are persisted. Docker still receives the full set — the container needs the value to run.
The upgrade form carries the choice forward and handles stored secrets properly: the field starts empty, leaving it empty keeps the stored value, typing replaces it. Untouched stored secrets are omitted from the request rather than sent as empty strings, which would previously have won during the variable merge and wiped the password.
### Notes for operators
- **A stored password is no longer readable in the UI by anyone, administrators included.** This is intentional. Where a password is needed, it comes from its source of truth, not from a deployment view.
- **A password that was not saved has to be entered again on upgrade.** Also intentional — it only appeared otherwise because it was being stored against the user's choice.
- Deployments created before this release have no recorded classification and fall back to judging by variable name (`*PASSWORD*`, `*SECRET*`, `*TOKEN*`, `*CONNECTIONSTRING*`, …), erring towards withholding. Their next deploy or upgrade records the exact set from the product manifest.
- A database migration (`AddSecretVariableNames`) runs automatically on startup. No manual step, no manifest change.
### API contract change
Despite being a patch release, this changes the shape of two response fields. Anyone consuming the API directly needs to adapt:
```
sharedVariables: Dictionary
stacks[].variables: Dictionary
DeploymentVariableDto { name, value (null when secret), isSecret, hasValue }
```
Distributions built on `@rsgo/core` need the same adjustment where they render these fields.
**Documentation:** [Variable types → Password](https://readystackgo.pages.dev/en/reference/variable-types/)
**Full changelog:** https://github.com/Wiesenwischer/ReadyStackGo/compare/v0.83.0...v0.83.1
v0.83.0v0.83.0
## Highlights
### The maintenance observer no longer holds a session on a product database — #464
A product that maintains itself typically follows this sequence: set its maintenance flag, wait until all connections to its database are closed, then take the database exclusively (`SINGLE_USER`, restore). RSGO's SQL observer is a participant in that handshake — it detects the flag and stops the product's containers, whose connections then go away.
But the observer's own connection was **pooled**: `Dispose` only returns it to the ADO.NET pool, and because the next poll refreshed it, the pool's idle cleanup never reclaimed it. The product's wait then never completed — the component that reacts to the flag prevented the effect of its own reaction. Where a product waits without a timeout, its update simply never finishes.
**Connections RSGO opens itself are now non-pooled.** Both SQL observers, the SQL setter and the SQL connection test endpoint: the session exists for the duration of a single read and is gone afterwards. Sessions are tagged with an application name (`ReadyStackGo-Maintenance`, `ReadyStackGo-ConnectionTest`) so they can be identified in `sys.dm_exec_sessions` or `sp_who2`. Product containers are unaffected — RSGO does not build their connection strings, and they keep their pooling.
**RSGO no longer reads a database it must not touch.** The maintenance flag usually lives inside the very database that becomes exclusive, so during that window it cannot be read — and a connect attempt can occupy the single available single-user slot and fail the product's own update with error 924. Before every read, a SQL observer now checks the database's availability in `sys.databases` over a `master` connection derived from the same credentials:
- `master` stays reachable while another database is `SINGLE_USER`, `RESTORING` or `OFFLINE`, and the query takes no lock on the target database.
- While the database is unavailable, the observer reports maintenance with an observed value of `database-exclusive (/)` and leaves the database alone.
- Once it is `ONLINE` and `MULTI_USER` again, the next poll reads the flag normally — the automatic return to normal operation keeps working, however long the product takes.
- If availability cannot be determined (the observer login has no access to `master`), RSGO logs one warning and falls back to the previous behaviour, rather than parking a deployment in maintenance over a permission problem.
**Manual maintenance suspends observer polling.** Trigger ownership means an observer may not end manually activated maintenance, so the read could only ever leave a session behind. Entering maintenance manually is now also a reliable way to keep RSGO off a product entirely.
### Fixed along the way
- **`pollingInterval` was ignored.** Observer state lived on a scoped service while the background service creates a fresh scope every cycle, so every cycle looked like a first check — the effective interval was always 30s. State moved into a singleton store.
- **The observer status endpoint was always empty.** `GET /api/health/deployments/{id}/observer` read the last result from a different scope and therefore always reported `HasObserver=false`.
- **A cached observer survived a config change.** A manifest edit picked up by a redeploy now takes effect without restarting RSGO — while keeping the check timestamp, so a config change cannot be used to read a product database more often than its interval allows.
- **The connection test endpoint** (`POST /api/connections/test/sqlserver`) left an idle session on the product database for the pool's lifetime.
No migration and **no manifest change** required: the availability check derives its `master` connection from the existing observer connection string, so the fix applies to already-deployed manifests as they are. Deployments without a SQL observer are unaffected.
**Documentation:** [Maintenance mode → Database access during maintenance](https://readystackgo.pages.dev/en/docs/monitoring/maintenance-mode/). The docs also described an observer `enabled` field and a `PUT /api/deployments/{id}/maintenance-observer` endpoint — neither exists, both removed.
**Full changelog:** https://github.com/Wiesenwischer/ReadyStackGo/compare/v0.82.0...v0.83.0
### The maintenance observer no longer holds a session on a product database — #464
A product that maintains itself typically follows this sequence: set its maintenance flag, wait until all connections to its database are closed, then take the database exclusively (`SINGLE_USER`, restore). RSGO's SQL observer is a participant in that handshake — it detects the flag and stops the product's containers, whose connections then go away.
But the observer's own connection was **pooled**: `Dispose` only returns it to the ADO.NET pool, and because the next poll refreshed it, the pool's idle cleanup never reclaimed it. The product's wait then never completed — the component that reacts to the flag prevented the effect of its own reaction. Where a product waits without a timeout, its update simply never finishes.
**Connections RSGO opens itself are now non-pooled.** Both SQL observers, the SQL setter and the SQL connection test endpoint: the session exists for the duration of a single read and is gone afterwards. Sessions are tagged with an application name (`ReadyStackGo-Maintenance`, `ReadyStackGo-ConnectionTest`) so they can be identified in `sys.dm_exec_sessions` or `sp_who2`. Product containers are unaffected — RSGO does not build their connection strings, and they keep their pooling.
**RSGO no longer reads a database it must not touch.** The maintenance flag usually lives inside the very database that becomes exclusive, so during that window it cannot be read — and a connect attempt can occupy the single available single-user slot and fail the product's own update with error 924. Before every read, a SQL observer now checks the database's availability in `sys.databases` over a `master` connection derived from the same credentials:
- `master` stays reachable while another database is `SINGLE_USER`, `RESTORING` or `OFFLINE`, and the query takes no lock on the target database.
- While the database is unavailable, the observer reports maintenance with an observed value of `database-exclusive (
- Once it is `ONLINE` and `MULTI_USER` again, the next poll reads the flag normally — the automatic return to normal operation keeps working, however long the product takes.
- If availability cannot be determined (the observer login has no access to `master`), RSGO logs one warning and falls back to the previous behaviour, rather than parking a deployment in maintenance over a permission problem.
**Manual maintenance suspends observer polling.** Trigger ownership means an observer may not end manually activated maintenance, so the read could only ever leave a session behind. Entering maintenance manually is now also a reliable way to keep RSGO off a product entirely.
### Fixed along the way
- **`pollingInterval` was ignored.** Observer state lived on a scoped service while the background service creates a fresh scope every cycle, so every cycle looked like a first check — the effective interval was always 30s. State moved into a singleton store.
- **The observer status endpoint was always empty.** `GET /api/health/deployments/{id}/observer` read the last result from a different scope and therefore always reported `HasObserver=false`.
- **A cached observer survived a config change.** A manifest edit picked up by a redeploy now takes effect without restarting RSGO — while keeping the check timestamp, so a config change cannot be used to read a product database more often than its interval allows.
- **The connection test endpoint** (`POST /api/connections/test/sqlserver`) left an idle session on the product database for the pool's lifetime.
No migration and **no manifest change** required: the availability check derives its `master` connection from the existing observer connection string, so the fix applies to already-deployed manifests as they are. Deployments without a SQL observer are unaffected.
**Documentation:** [Maintenance mode → Database access during maintenance](https://readystackgo.pages.dev/en/docs/monitoring/maintenance-mode/). The docs also described an observer `enabled` field and a `PUT /api/deployments/{id}/maintenance-observer` endpoint — neither exists, both removed.
**Full changelog:** https://github.com/Wiesenwischer/ReadyStackGo/compare/v0.82.0...v0.83.0
v0.82.0v0.82.0
## Highlights
### Changed `edge.mss` now actually takes effect — #461
The VPN-robustness option introduced in v0.81.0 is a **create-time** container setting: kernel sysctls and the edge network MTU cannot be changed on a running container. Because the edge container deliberately survives redeploys (so the maintenance page stays reachable), a changed `edge.mss` never reached a running deployment — and there was no way to tell from the outside.
**Redeploy and upgrade now re-apply it:**
- Both re-read the manifest `edge:` block and compare the configured tuning against the one the live edge container was created with (new container label `rsgo.edge.mss`). On a mismatch the edge container is recreated once, before the product stacks are touched.
- An edge container from a version **before** the option counts as `off` and is switched to the configured mode (`pmtu` by default) on the next redeploy or upgrade.
- The background reconciler still never restarts the front door on its own — recreation only happens on an explicit operator action.
**Verifiable at the customer site.** The edge now logs one line at startup with the values it reads from its own kernel:
```
$ docker logs-edge 2>&1 | head -1
rsgo-edge: client-facing MSS tuning mode=pmtu verdict=ACTIVE (expected: tcp_mtu_probing=1 | tcp_mtu_probing=1 tcp_base_mss=1024 iface_mtu: eth0=1500)
```
`ACTIVE` = in effect · `DISABLED` = `mss: off` · `INACTIVE` = the container does not run the configured tuning (predates it, or a fixed MTU could not be applied to an existing network) → run a redeploy.
### Robustness fixes in the same area
- An `edge:` block that no longer resolves (removed, or unresolved variables) **keeps** the running edge config instead of tearing down the product's front door — on redeploy and when upgrading to a target version whose block does not resolve.
- After the edge container is replaced, the cached Caddy config is invalidated, so the fresh container gets the live config instead of staying on its bootstrap maintenance page.
No migration and no manifest change required; deployments without an `edge:` block are unaffected.
**Documentation:** [Maintenance edge proxy → VPN robustness](https://readystackgo.pages.dev/en/docs/configuration/maintenance-edge-proxy/) — new sections on when a change takes effect and how to verify it.
**Full changelog:** https://github.com/Wiesenwischer/ReadyStackGo/compare/v0.81.0...v0.82.0
### Changed `edge.mss` now actually takes effect — #461
The VPN-robustness option introduced in v0.81.0 is a **create-time** container setting: kernel sysctls and the edge network MTU cannot be changed on a running container. Because the edge container deliberately survives redeploys (so the maintenance page stays reachable), a changed `edge.mss` never reached a running deployment — and there was no way to tell from the outside.
**Redeploy and upgrade now re-apply it:**
- Both re-read the manifest `edge:` block and compare the configured tuning against the one the live edge container was created with (new container label `rsgo.edge.mss`). On a mismatch the edge container is recreated once, before the product stacks are touched.
- An edge container from a version **before** the option counts as `off` and is switched to the configured mode (`pmtu` by default) on the next redeploy or upgrade.
- The background reconciler still never restarts the front door on its own — recreation only happens on an explicit operator action.
**Verifiable at the customer site.** The edge now logs one line at startup with the values it reads from its own kernel:
```
$ docker logs
rsgo-edge: client-facing MSS tuning mode=pmtu verdict=ACTIVE (expected: tcp_mtu_probing=1 | tcp_mtu_probing=1 tcp_base_mss=1024 iface_mtu: eth0=1500)
```
`ACTIVE` = in effect · `DISABLED` = `mss: off` · `INACTIVE` = the container does not run the configured tuning (predates it, or a fixed MTU could not be applied to an existing network) → run a redeploy.
### Robustness fixes in the same area
- An `edge:` block that no longer resolves (removed, or unresolved variables) **keeps** the running edge config instead of tearing down the product's front door — on redeploy and when upgrading to a target version whose block does not resolve.
- After the edge container is replaced, the cached Caddy config is invalidated, so the fresh container gets the live config instead of staying on its bootstrap maintenance page.
No migration and no manifest change required; deployments without an `edge:` block are unaffected.
**Documentation:** [Maintenance edge proxy → VPN robustness](https://readystackgo.pages.dev/en/docs/configuration/maintenance-edge-proxy/) — new sections on when a change takes effect and how to verify it.
**Full changelog:** https://github.com/Wiesenwischer/ReadyStackGo/compare/v0.81.0...v0.82.0
v0.81.0v0.81.0
## Highlights
### VPN-robust edge (configurable client-facing MSS) — #460
Large HTTP responses through the managed edge could stall behind VPN tunnels that lower the path MTU and blackhole ICMP (HTTP 502 / timeout on big pages, login still fine). The edge now sizes its egress TCP segments to fit, controlled by a new manifest option `edge.mss`:
- **`pmtu` (default)** — adaptive kernel path-MTU probing; works out of the box for every hosted product, **no customer VPN change and no elevated container capability**.
- **`` (536–1460)** — a fixed MSS cap (via the edge network MTU).
- **`off`** — previous behaviour, unchanged.
Backward compatible: existing deployments default to `pmtu` on upgrade (no migration).
### Dedicated release-notes page — #459
Product release notes now open on a dedicated, bookmarkable page (`/release-notes/:productId`) reachable from the Stack Catalog and the deployment update badge, with an in-page language selector for localized changelogs and GFM-table rendering.
**Full changelog:** https://github.com/Wiesenwischer/ReadyStackGo/compare/v0.80.0...v0.81.0
### VPN-robust edge (configurable client-facing MSS) — #460
Large HTTP responses through the managed edge could stall behind VPN tunnels that lower the path MTU and blackhole ICMP (HTTP 502 / timeout on big pages, login still fine). The edge now sizes its egress TCP segments to fit, controlled by a new manifest option `edge.mss`:
- **`pmtu` (default)** — adaptive kernel path-MTU probing; works out of the box for every hosted product, **no customer VPN change and no elevated container capability**.
- **`
- **`off`** — previous behaviour, unchanged.
Backward compatible: existing deployments default to `pmtu` on upgrade (no migration).
### Dedicated release-notes page — #459
Product release notes now open on a dedicated, bookmarkable page (`/release-notes/:productId`) reachable from the Stack Catalog and the deployment update badge, with an in-page language selector for localized changelogs and GFM-table rendering.
**Full changelog:** https://github.com/Wiesenwischer/ReadyStackGo/compare/v0.80.0...v0.81.0
v0.80.0v0.80.0
## What's Changed in v0.80.0
### 🚀 Features
- **View product release notes from the Stack Catalog** — a "Release notes" button on a catalog product opens the changelog (with the DE/EN language selector) without needing a deployment or an available update. New `GET /api/products/{productId}/release-notes` endpoint; release notes are now reachable both from the catalog and from the deployment update badge. (#457)
**Full Changelog**: https://github.com/Wiesenwischer/ReadyStackGo/compare/v0.79.0...v0.80.0
### 🚀 Features
- **View product release notes from the Stack Catalog** — a "Release notes" button on a catalog product opens the changelog (with the DE/EN language selector) without needing a deployment or an available update. New `GET /api/products/{productId}/release-notes` endpoint; release notes are now reachable both from the catalog and from the deployment update badge. (#457)
**Full Changelog**: https://github.com/Wiesenwischer/ReadyStackGo/compare/v0.79.0...v0.80.0
v0.79.0v0.79.0
## What's Changed in v0.79.0
### 🚀 Features
- **Localized product release notes** with an in-viewer language selector — RSGO reads `CHANGELOG..md` (e.g. de/en) next to a product manifest and lets the user switch languages; falls back to a language-neutral `CHANGELOG.md`. (#456)
- **Product-level health notifications** — one notification per product overall-health transition instead of per-service spam, and recoveries now surface (direction-aware throttling). (#455)
- **Detailed per-container removal progress during product upgrade** — the upgrade's remove phase streams live "Removing web-1 (2/8)" progress, mirroring redeploy. (#454)
**Full Changelog**: https://github.com/Wiesenwischer/ReadyStackGo/compare/v0.78.0...v0.79.0
### 🚀 Features
- **Localized product release notes** with an in-viewer language selector — RSGO reads `CHANGELOG.
- **Product-level health notifications** — one notification per product overall-health transition instead of per-service spam, and recoveries now surface (direction-aware throttling). (#455)
- **Detailed per-container removal progress during product upgrade** — the upgrade's remove phase streams live "Removing web-1 (2/8)" progress, mirroring redeploy. (#454)
**Full Changelog**: https://github.com/Wiesenwischer/ReadyStackGo/compare/v0.78.0...v0.79.0
v0.78.0v0.78.0
## What's Changed in v0.78.0
### 🐛 Bug Fixes
- **Product upgrade no longer blocks on "Missing required variables"** when the variables were already set at the initial deployment. The upgrade form now pre-fills the stored per-stack values (backend already merged them server-side, but the frontend validated against an empty set). (#452, #453)
### ✨ Features
- **Deployment detail page now shows per-stack variables** in a collapsible "Stack Variables" card, mirroring the existing "Shared Variables" card. (#453)
**Full Changelog**: https://github.com/Wiesenwischer/ReadyStackGo/compare/v0.77.0...v0.78.0
### 🐛 Bug Fixes
- **Product upgrade no longer blocks on "Missing required variables"** when the variables were already set at the initial deployment. The upgrade form now pre-fills the stored per-stack values (backend already merged them server-side, but the frontend validated against an empty set). (#452, #453)
### ✨ Features
- **Deployment detail page now shows per-stack variables** in a collapsible "Stack Variables" card, mirroring the existing "Shared Variables" card. (#453)
**Full Changelog**: https://github.com/Wiesenwischer/ReadyStackGo/compare/v0.77.0...v0.78.0
v0.77.0v0.77.0
## What's Changed
- E2E: assert live per-stack maintenance progress @Wiesenwischer (#451)
## 🚀 Features
- Per-container progress during redeploy stack removal @Wiesenwischer (#450)
- Live maintenance progress + redeploy notification-spam fix @Wiesenwischer (#448)
## 🐛 Bug Fixes
- docs(installation): fix outdated image name and volume mapping @Wiesenwischer (#449)
## 📚 Documentation
- docs(installation): fix outdated image name and volume mapping @Wiesenwischer (#449)
**Full Changelog**: https://github.com/Wiesenwischer/ReadyStackGo/compare/v0.76.1...v0.77.0
- E2E: assert live per-stack maintenance progress @Wiesenwischer (#451)
## 🚀 Features
- Per-container progress during redeploy stack removal @Wiesenwischer (#450)
- Live maintenance progress + redeploy notification-spam fix @Wiesenwischer (#448)
## 🐛 Bug Fixes
- docs(installation): fix outdated image name and volume mapping @Wiesenwischer (#449)
## 📚 Documentation
- docs(installation): fix outdated image name and volume mapping @Wiesenwischer (#449)
**Full Changelog**: https://github.com/Wiesenwischer/ReadyStackGo/compare/v0.76.1...v0.77.0
v0.76.1v0.76.1
## 🐛 Bug Fixes
### Edge / maintenance page shown permanently behind a forward proxy (#446)
In environments with a forward proxy (`HTTP_PROXY`/`HTTPS_PROXY`, e.g. injected into containers by a Docker daemon proxy), the edge-proxy could get **stuck on its maintenance/"deploying" holding page forever** even though the product was healthy: RSGO's container-internal call to the edge's Caddy admin API was routed through the proxy, failed silently, and the edge never switched to proxy mode.
Fix: all HTTP clients whose target is reachable **directly** — edge admin API, HTTP maintenance observer, webhook maintenance setter, HTTP health checks, and the PRTG clients (customer LAN) — now bypass the forward proxy (`UseProxy = false`). Internet-egress clients (registries, GitHub, Cloudflare) keep the default proxy behaviour. No `NO_PROXY` configuration needed.
### Deployment reliability (#444, #445)
- Product removal now reliably removes all containers, with retry and verification passes (no leftover containers).
- A deployment now **fails** on an image-pull failure instead of silently starting from a stale local image.
**Full Changelog**: https://github.com/Wiesenwischer/ReadyStackGo/compare/v0.76.0...v0.76.1
### Edge / maintenance page shown permanently behind a forward proxy (#446)
In environments with a forward proxy (`HTTP_PROXY`/`HTTPS_PROXY`, e.g. injected into containers by a Docker daemon proxy), the edge-proxy could get **stuck on its maintenance/"deploying" holding page forever** even though the product was healthy: RSGO's container-internal call to the edge's Caddy admin API was routed through the proxy, failed silently, and the edge never switched to proxy mode.
Fix: all HTTP clients whose target is reachable **directly** — edge admin API, HTTP maintenance observer, webhook maintenance setter, HTTP health checks, and the PRTG clients (customer LAN) — now bypass the forward proxy (`UseProxy = false`). Internet-egress clients (registries, GitHub, Cloudflare) keep the default proxy behaviour. No `NO_PROXY` configuration needed.
### Deployment reliability (#444, #445)
- Product removal now reliably removes all containers, with retry and verification passes (no leftover containers).
- A deployment now **fails** on an image-pull failure instead of silently starting from a stale local image.
**Full Changelog**: https://github.com/Wiesenwischer/ReadyStackGo/compare/v0.76.0...v0.76.1
v0.76.0v0.76.0
## 🚀 Highlights
**Redesigned default maintenance page** — the page the edge-proxy serves while a product is down is now a self-contained **live status panel** in RSGO's brand colours, instead of a static notice.
- **Live, not static**: it renders the `/__status` contract directly, auto-refreshes every few seconds, and **reloads visitors back into the app automatically** the moment the product reports `running`.
- **State at a glance**: accent colour follows the state — amber for maintenance, brand-blue for a rollout (`deploying`) — with state, reason and deployed version shown in a status panel.
- **Branding & language**: product name, logo and support contact are themeable via `branding`; the on-page language toggle is driven by `branding.locales` (first locale = default, hidden for a single locale). All branding values are HTML/JSON-escaped.
- **Degrades cleanly**: rows without data (e.g. `reason` outside planned maintenance, or `until`) hide automatically, and a correct no-JS fallback is server-rendered.
No configuration change required — existing `edge.maintenancePage.mode: default` products get the new page automatically. The `/__status` contract is unchanged.
## 📚 Documentation
- `configuration/maintenance-edge-proxy.md` (DE + EN) refreshed: new screenshots for the maintenance and deploying states, plus the auto-refresh/auto-reload, accent and language-toggle behaviour.
**Full Changelog**: https://github.com/Wiesenwischer/ReadyStackGo/compare/v0.75.2...v0.76.0
**Redesigned default maintenance page** — the page the edge-proxy serves while a product is down is now a self-contained **live status panel** in RSGO's brand colours, instead of a static notice.
- **Live, not static**: it renders the `/__status` contract directly, auto-refreshes every few seconds, and **reloads visitors back into the app automatically** the moment the product reports `running`.
- **State at a glance**: accent colour follows the state — amber for maintenance, brand-blue for a rollout (`deploying`) — with state, reason and deployed version shown in a status panel.
- **Branding & language**: product name, logo and support contact are themeable via `branding`; the on-page language toggle is driven by `branding.locales` (first locale = default, hidden for a single locale). All branding values are HTML/JSON-escaped.
- **Degrades cleanly**: rows without data (e.g. `reason` outside planned maintenance, or `until`) hide automatically, and a correct no-JS fallback is server-rendered.
No configuration change required — existing `edge.maintenancePage.mode: default` products get the new page automatically. The `/__status` contract is unchanged.
## 📚 Documentation
- `configuration/maintenance-edge-proxy.md` (DE + EN) refreshed: new screenshots for the maintenance and deploying states, plus the auto-refresh/auto-reload, accent and language-toggle behaviour.
**Full Changelog**: https://github.com/Wiesenwischer/ReadyStackGo/compare/v0.75.2...v0.76.0
v0.75.2v0.75.2
Patch release with two fixes for the product catalog/deployment UX.
## What's Changed
## 🐛 Bug Fixes
- fix(catalog): proper SemVer precedence + same-channel update detection — a `-ci` deployment is no longer offered a `-preview` build as an "update"; pre-release versions are ordered per SemVer 2.0.0 @Wiesenwischer (#441)
- fix(deployments): stop per-stack notification spam on product removal — removing a multi-stack product now emits a single aggregated notification @Wiesenwischer (#440)
**Full Changelog**: https://github.com/Wiesenwischer/ReadyStackGo/compare/v0.75.1...v0.75.2
## What's Changed
## 🐛 Bug Fixes
- fix(catalog): proper SemVer precedence + same-channel update detection — a `-ci` deployment is no longer offered a `-preview` build as an "update"; pre-release versions are ordered per SemVer 2.0.0 @Wiesenwischer (#441)
- fix(deployments): stop per-stack notification spam on product removal — removing a multi-stack product now emits a single aggregated notification @Wiesenwischer (#440)
**Full Changelog**: https://github.com/Wiesenwischer/ReadyStackGo/compare/v0.75.1...v0.75.2
v0.75.1v0.75.1
Patch release fixing a v0.75.0 regression where a product manifest using a `${VAR}` placeholder in an edge port field (e.g. `publicPort: ${BFF_PORT}`) failed to load and disappeared from the catalog.
## What's Changed
## 🐛 Bug Fixes
- fix(edge): allow ${VAR} placeholders in edge port fields (catalog-load regression) @Wiesenwischer (#439)
## 📚 Documentation
- docs(plans): add Phase 6 (follow-ups & hardening) to edge-proxy plan @Wiesenwischer (#438)
**Full Changelog**: https://github.com/Wiesenwischer/ReadyStackGo/compare/v0.75.0...v0.75.1
## What's Changed
## 🐛 Bug Fixes
- fix(edge): allow ${VAR} placeholders in edge port fields (catalog-load regression) @Wiesenwischer (#439)
## 📚 Documentation
- docs(plans): add Phase 6 (follow-ups & hardening) to edge-proxy plan @Wiesenwischer (#438)
**Full Changelog**: https://github.com/Wiesenwischer/ReadyStackGo/compare/v0.75.0...v0.75.1
v0.75.0v0.75.0
## Highlights — Maintenance Edge-Proxy
A new opt-in capability: RSGO runs a managed per-product reverse-proxy ("edge", Caddy) that **survives product redeploys** and serves a controlled maintenance page plus a machine-readable status while the product is down — no more connection-refused. Dormant by default (no `edge:` block → behaviour unchanged).
- **Survival & state-driven routing** — proxy when `Running`; a controlled page during redeploy/maintenance; `/hc` & `/liveness` always pass through.
- **TLS termination** at the edge with RSGO-managed certificates, reloaded without an edge restart.
- **Maintenance-page branding** — built-in themeable page, custom HTML bundle, or your own container.
- **Versioned status contract** — stable `GET /__status` (schema 1): `running` | `maintenance` | `deploying`.
- **Optional host-level SNI passthrough router** (off by default).
- Documentation (DE/EN), customization templates (`examples/edge-maintenance/`) and deployable demo stacks (`stacks/examples/edge/`).
See **Configuration → Maintenance Edge-Proxy** in the docs.
---
## What's Changed
## 🚀 Features
- feat(edge): generic maintenance edge-proxy (R2) — phases 1-5 @Wiesenwischer (#431)
## 📚 Documentation
- feat(edge): generic maintenance edge-proxy (R2) — phases 1-5 @Wiesenwischer (#431)
- docs(plans): add maintenance-edge-proxy implementation plan (R2) @Wiesenwischer (#430)
**Full Changelog**: https://github.com/Wiesenwischer/ReadyStackGo/compare/v0.74.0...v0.75.0
A new opt-in capability: RSGO runs a managed per-product reverse-proxy ("edge", Caddy) that **survives product redeploys** and serves a controlled maintenance page plus a machine-readable status while the product is down — no more connection-refused. Dormant by default (no `edge:` block → behaviour unchanged).
- **Survival & state-driven routing** — proxy when `Running`; a controlled page during redeploy/maintenance; `/hc` & `/liveness` always pass through.
- **TLS termination** at the edge with RSGO-managed certificates, reloaded without an edge restart.
- **Maintenance-page branding** — built-in themeable page, custom HTML bundle, or your own container.
- **Versioned status contract** — stable `GET /__status` (schema 1): `running` | `maintenance` | `deploying`.
- **Optional host-level SNI passthrough router** (off by default).
- Documentation (DE/EN), customization templates (`examples/edge-maintenance/`) and deployable demo stacks (`stacks/examples/edge/`).
See **Configuration → Maintenance Edge-Proxy** in the docs.
---
## What's Changed
## 🚀 Features
- feat(edge): generic maintenance edge-proxy (R2) — phases 1-5 @Wiesenwischer (#431)
## 📚 Documentation
- feat(edge): generic maintenance edge-proxy (R2) — phases 1-5 @Wiesenwischer (#431)
- docs(plans): add maintenance-edge-proxy implementation plan (R2) @Wiesenwischer (#430)
**Full Changelog**: https://github.com/Wiesenwischer/ReadyStackGo/compare/v0.74.0...v0.75.0
v0.74.0v0.74.0
## What's Changed
## 🚀 Features
- Active maintenance setter (mirror of the observer) @Wiesenwischer (#429)
- Product updates \& release notes @Wiesenwischer (#428)
## 📚 Documentation
- Active maintenance setter (mirror of the observer) @Wiesenwischer (#429)
- Product updates \& release notes @Wiesenwischer (#428)
## ⬆️ Dependencies
- Active maintenance setter (mirror of the observer) @Wiesenwischer (#429)
- Product updates \& release notes @Wiesenwischer (#428)
**Full Changelog**: https://github.com/Wiesenwischer/ReadyStackGo/compare/v0.73.0...v0.74.0
## 🚀 Features
- Active maintenance setter (mirror of the observer) @Wiesenwischer (#429)
- Product updates \& release notes @Wiesenwischer (#428)
## 📚 Documentation
- Active maintenance setter (mirror of the observer) @Wiesenwischer (#429)
- Product updates \& release notes @Wiesenwischer (#428)
## ⬆️ Dependencies
- Active maintenance setter (mirror of the observer) @Wiesenwischer (#429)
- Product updates \& release notes @Wiesenwischer (#428)
**Full Changelog**: https://github.com/Wiesenwischer/ReadyStackGo/compare/v0.73.0...v0.74.0
v0.73.0v0.73.0
## What's Changed
## 🚀 Features
- Server-side logout via token revocation @Wiesenwischer (#427)
- Unlink OIDC providers from the profile @Wiesenwischer (#426)
- Optional SMTP setup step in the wizard @Wiesenwischer (#425)
- Password reset by email @Wiesenwischer (#424)
- Email-based login, verification, invitations \& OIDC SSO @Wiesenwischer (#422)
## 📚 Documentation
- Email-based login, verification, invitations \& OIDC SSO @Wiesenwischer (#422)
## ⬆️ Dependencies
- Email-based login, verification, invitations \& OIDC SSO @Wiesenwischer (#422)
**Full Changelog**: https://github.com/Wiesenwischer/ReadyStackGo/compare/v0.72.0...v0.73.0
## 🚀 Features
- Server-side logout via token revocation @Wiesenwischer (#427)
- Unlink OIDC providers from the profile @Wiesenwischer (#426)
- Optional SMTP setup step in the wizard @Wiesenwischer (#425)
- Password reset by email @Wiesenwischer (#424)
- Email-based login, verification, invitations \& OIDC SSO @Wiesenwischer (#422)
## 📚 Documentation
- Email-based login, verification, invitations \& OIDC SSO @Wiesenwischer (#422)
## ⬆️ Dependencies
- Email-based login, verification, invitations \& OIDC SSO @Wiesenwischer (#422)
**Full Changelog**: https://github.com/Wiesenwischer/ReadyStackGo/compare/v0.72.0...v0.73.0
v0.72.0 – Catalog: offer only the ams.project Preview channel (remove stable and RC sources)v0.72.0
## What's Changed in v0.72.0
- fix(stack-sources): offer only ams.project Preview channel (remove stable + RC) (#420)
- fix(stack-sources): offer only ams.project Preview channel (remove stable + RC) (#420)
v0.71.0 – Upgrade flow: per-stack remove → deploy with detailed progressv0.71.0
## What's Changed
## 🚀 Features
- feat(upgrade): run upgrade as per-stack remove then deploy with detailed progress @Wiesenwischer (#419)
- Plan upgrade flow as sequential remove then deploy @Wiesenwischer (#418)
## 📚 Documentation
- Plan upgrade flow as sequential remove then deploy @Wiesenwischer (#418)
**Full Changelog**: https://github.com/Wiesenwischer/ReadyStackGo/compare/v0.70.0...v0.71.0
## 🚀 Features
- feat(upgrade): run upgrade as per-stack remove then deploy with detailed progress @Wiesenwischer (#419)
- Plan upgrade flow as sequential remove then deploy @Wiesenwischer (#418)
## 📚 Documentation
- Plan upgrade flow as sequential remove then deploy @Wiesenwischer (#418)
**Full Changelog**: https://github.com/Wiesenwischer/ReadyStackGo/compare/v0.70.0...v0.71.0