Files
zarinpal-analytics-deployment/docs/decisions/0002-manual-server-build-releases.md

3.7 KiB

ADR 0002: Manual server-build releases

  • Status: Accepted
  • Date: 2026-08-20

Context

The project has three repositories but one small hackathon server. The Qlockify reference already proves a simple operational model: the deployment repository contains ignored backend/frontend checkouts, a trusted operator pulls source on the server, and Docker Compose builds and starts the stack there.

An earlier proposed design used CI/CD, a private image registry, immutable image digests, and cross-repository candidate events. The stakeholder explicitly rejected that complexity for this project. No CI/CD pipeline is needed.

The platform still needs to answer which source is running and how to return to the previous version.

Decision

Use manual Qlockify-style deployment on the production server.

For a normal release, the trusted ubuntu user:

  1. verifies the exact deployment/backend/frontend repository paths, remotes, branches, and clean working trees;
  2. manually runs git pull --ff-only origin main in each checkout, entering the source-forge username/password interactively when prompted;
  3. invokes the deployment command, which verifies that all three checkouts are clean, on main, and equal to origin/main without performing any Git pull;
  4. records the exact three resulting Git commit hashes under the ignored /home/ubuntu/zarinpal-analytics-deployment/releases/ directory;
  5. builds application images locally with Docker Compose;
  6. runs the dedicated migration and health/smoke checks; and
  7. records the release as active only after validation passes.

Rollback selects the previous release record, checks out its three hashes, rebuilds locally, and repeats the checks. Database down-migration is never automatic; migrations follow expand/contract compatibility.

The deploy flow may adapt Qlockify's deploy.sh, but Git pulling is a separate operator prerequisite and the deployment command must not store source-forge credentials. It must not unconditionally git reset --hard. A dirty or divergent checkout stops for operator resolution so user changes are not destroyed.

There is no CI/CD workflow, Actions runner, automated cross-repository event, private image registry, or direct automated production mutation.

Alternatives considered

CI/CD plus private registry

  • Pros: build-once artifacts, automated checks, stronger image provenance.
  • Cons: more services, credentials, runner maintenance, workflow coordination, and implementation effort than the hackathon needs.
  • Rejected: stakeholder chose the simpler manual Qlockify model.

Per-service manual deployment

  • Pros: each repository can be changed independently.
  • Cons: services could be built from incompatible revisions and migration/config changes could race.
  • Rejected: the deployment repository remains the single manual operational entry point.

Git submodules

  • Pros: deployment commits can pin service revisions.
  • Cons: conflicts with accepted ADR 0001 and the Qlockify-style ignored checkout layout.
  • Rejected: server release records provide the required three-hash provenance.

Consequences

  • The trusted deployment user and production server contain the source/build toolchain.
  • Deployment is slower and less artifact-reproducible than build-once registry delivery, but exact Git hashes and build records preserve practical traceability.
  • Source forge availability is required for new deployment and usually for rollback unless the target commits remain locally available.
  • Manual quality commands and health checks are essential because no pipeline enforces them.
  • Dirty/diverged checkout handling must fail safely rather than destroying changes.
  • The server stores active and previous non-secret release records.
  • Any future CI/CD or registry introduction requires a new approved ADR.