From c9db5287568377d567569feda9618c8b3536444f Mon Sep 17 00:00:00 2001 From: Wanja Krah Date: Tue, 3 Nov 2026 13:30:47 +0100 Subject: [PATCH] refinement of spec S6 --- .../S6_Deployment-gitea-action-to-production | 3 - ...6_deployment-gitea-action-to-production.md | 177 ++++++++++++++++++ 2 files changed, 177 insertions(+), 3 deletions(-) delete mode 100644 specs/S6_Deployment-gitea-action-to-production create mode 100644 specs/refined/S6_deployment-gitea-action-to-production.md diff --git a/specs/S6_Deployment-gitea-action-to-production b/specs/S6_Deployment-gitea-action-to-production deleted file mode 100644 index cefc1bc..0000000 --- a/specs/S6_Deployment-gitea-action-to-production +++ /dev/null @@ -1,3 +0,0 @@ -As developer -I want a succeeded branch on main to be deployed to a production environment -so that the latest succesfull build is always running and accissasible at the Synology server \ No newline at end of file diff --git a/specs/refined/S6_deployment-gitea-action-to-production.md b/specs/refined/S6_deployment-gitea-action-to-production.md new file mode 100644 index 0000000..1bf322d --- /dev/null +++ b/specs/refined/S6_deployment-gitea-action-to-production.md @@ -0,0 +1,177 @@ +# S6 — Manual versioned production deployment through Gitea + +Status: REFINED + +Agreed after the grill-me interview; shared understanding confirmed. + +## User story + +As a developer, I want to manually release a verified main-branch build from +Gitea to the Synology, choosing a semantic version increment, so that I control +when the launching partner receives a new production version and can recover +the previous working version when necessary. + +This replaces the original automatic-deployment story. Build, test and image +publication remain automatic; production deployment requires a deliberate action. + +## Existing foundation and scope + +- Extend the implemented S4 pipeline, which verifies builds and publishes matching + frontend/backend images with immutable full commit SHA tags for successful main + builds. Deploy those existing images without rebuilding them. +- Target one production Docker Compose stack on the Synology (`linux/amd64`). + The existing Gitea runner triggers deployment over SSH. +- Keep one active backend. A brief restart interruption is acceptable, including + interruption of a scheduling calculation; the user may restart the calculation. +- Production is private to the LAN or existing VPN. A configurable Synology + hostname/IP and port provide access without an application login. +- Publish only the frontend port. Keep the backend reachable within the Compose + network; route browser API requests through the frontend proxy. +- Actual server addresses, ports, paths and account configuration must be + established and documented during implementation, without committing secrets. + +## Manual release interface + +Provide a separate **Deploy production** workflow using Gitea's native manual +workflow trigger (`workflow_dispatch`). Its Run workflow popup offers: + +- **New release** or **Retry release** mode. +- For a new release: a release-type choice of **patch**, **minor** or **major**. +- For a retry: the existing release version tag. + +Provide a manual rollback action for the previous successful production release. +The native Gitea button need not be renamed or embedded into an existing build +run. Gitea 1.25.4 supports the required modal and choice inputs. + +### New release eligibility and ordering + +- Run the release workflow from main. Branch builds cannot deploy production. +- Pin the current main SHA at workflow start. Require successful build checks and + image publication for that exact SHA; missing or failed verification leaves + production unchanged. Both images must be retrievable before replacement. +- Recheck main immediately before changing production. If it has advanced, abort + without changing production. Once replacement starts, finish deployment or + recovery using the pinned SHA; later commits require another manual release. +- Serialize deployment, recovery, rollback, version allocation and tag creation. + Prevent stale runs from replacing newer successful production releases. +- Reject a new release for an already release-tagged commit and direct the + operator to retry or rollback instead. Repeated clicks must not create extra + versions or deploy out of order. + +## Semantic versioning and Git tags + +- Use one shared application version for frontend and backend, represented by + an immutable annotated Git tag `vMAJOR.MINOR.PATCH` on the verified SHA. +- The first release is `v1.0.0`. Inspect remote tags before initialization and + fail visibly on conflicting existing history instead of overwriting it. +- Subsequent releases increment the highest existing release version tag, + including tags belonging to failed deployments. A rollback does not lower the + version baseline. Patch increments PATCH; minor increments MINOR and resets + PATCH; major increments MAJOR and resets MINOR and PATCH. +- For example, from `v1.2.3`, the choices produce `v1.2.4`, `v1.3.0` or `v2.0.0`. +- After checking eligibility and image availability, create the tag before + changing production. This establishes tag-writing access before replacement. + Never move a release tag or reuse its version for different code. +- Retain a tag if deployment subsequently fails or aborts. Record the outcome so + a tag is not mistaken for proof of successful production deployment. +- A retry reuses the existing tag and exact SHA without allocating a version. + Require successful build verification and matching available images. Retrying + an older release must not supersede a newer successful release. Retrying an + existing release is an explicit exception to the current-main requirement. +- Rollback restores an existing release and creates no new version. It is an + explicit exception to the prohibition on replacing newer code with older code. +- Continue using SHA-tagged container images; the Git release tag and deployment + record map the semantic version to that SHA and image pair. +- Maven/npm version fields and automated changelog generation are outside S6. + Do not introduce a version-bump commit and rebuild into the release path. + +## Deployment checks and recovery + +- Retrieve the candidate images and validate prerequisites before replacing the + running release. Frontend and backend must use the same selected commit SHA. +- Within five minutes of starting the replacement, require all of: + - Backend readiness succeeds. + - The frontend page is served. + - A read-only API request succeeds through the frontend proxy. + - Both running containers match the selected SHA/image pair. +- Checks must not create or modify user data. Log the selected SHA/version and + final outcome. +- A failed candidate automatically restores the previous successful image pair + and checks its health. The workflow remains failed even if recovery succeeds. +- Retain references to the current and previous successful releases and ensure + their images remain available. A manual rollback targets that previous release; + fail before modifying production if its required images cannot be retrieved. +- If the first deployment fails with no previous release, or recovery itself + fails, stop with a clear failure report and manual recovery instructions. + Preserve diagnostics; do not enter an endless deployment/recovery loop. +- Record successful production release state separately from allocated Git tags, + so failed attempts do not become the rollback target. + +## Data policy and S16/S17 boundaries + +S16 is **not a prerequisite** for S6. Until S16 is implemented, application state +is held in memory and may be lost during deployment, rollback or recovery. The +launching-partner phase explicitly accepts this limitation. Restoring old images +does not restore lost data. + +- State the temporary data-loss limitation in the workflow description and + deployment runbook. The operator is responsible for informing the launching + partner; do not add a further approval step to each deployment. +- After S16 is implemented, deployments and rollbacks must preserve saved data. + Keep persistent storage outside replaceable containers and do not delete it + during deployment or recovery. +- After S16, ordinary release and rollback paths require database compatibility + with the previous application version. Incompatible migrations require a + separately planned maintenance procedure; image rollback cannot undo them. +- Database backup and restore remain separate S17 work. S6 does not promise + recovery of data lost before persistence or through storage loss. + +## Credentials and operational documentation + +- Use a dedicated Synology deployment account with SSH key authentication and a + pinned server host key. Document the narrowly required deployment permissions. +- Use a separate registry credential with pull access for production and a + credential with the required repository permission for release-tag creation. +- Store deployment secrets in Gitea Actions secrets, provision server-side + credentials securely where needed, and keep secret values out of Git and logs. +- Document initial provisioning, configuration, release/retry/rollback operation, + credential setup, health checks, release records and manual recovery. +- Retain deployment diagnostics for fourteen days, including failed deployment + and recovery outcomes, without exposing credentials. + +## Acceptance criteria + +- [ ] Successful main builds still automatically verify and publish matching SHA + images; publishing does not automatically change production. +- [ ] Gitea's manual workflow form provides new/retry mode and the appropriate + release-type or existing-tag inputs; invalid combinations fail clearly. +- [ ] The first release and subsequent patch/minor/major releases allocate the + agreed versions and immutable annotated remote Git tags on verified SHAs. +- [ ] Duplicate new releases, tag conflicts, concurrent attempts, stale main + snapshots and older pending deployments cannot overwrite release identity + or replace a newer successful release. +- [ ] An unverified release or missing image is rejected before production changes; + branch builds cannot deploy production. +- [ ] A real Synology deployment serves the frontend and proxied API over the + private endpoint, with both containers running the selected image pair. +- [ ] Readiness, frontend, proxied read-only API and image-identity checks establish + success within five minutes or trigger recovery. +- [ ] A deliberately failed release restores the previous successful version, + while the workflow reports failure. Failed first deployment and failed + recovery produce actionable diagnostics and manual recovery instructions. +- [ ] A failed release can be retried with its existing tag/SHA without allocating + another version or superseding a newer successful release. +- [ ] Manual rollback demonstrably restores the previous successful release with + no new version, and required retained images are available. +- [ ] The temporary pre-S16 data-loss policy is visible in workflow documentation + and the runbook. Once S16 applies, demonstrate saved data surviving both + deployment and rollback, including the migration compatibility requirement. +- [ ] Server setup and operational recovery documentation are usable; diagnostics + and release outcomes are retained for fourteen days without secrets. + +## Implementation handoff + +This specification records the confirmed design. Implementing workflows, release +automation, Compose configuration, Synology provisioning and collecting actual +deployment/recovery evidence are subsequent work. Configuration alone does not +complete S6.