docs: approve platform operations specification

This commit is contained in:
2026-08-20 18:54:54 +03:30
parent ec7a7753f6
commit e93eca1384
4 changed files with 66 additions and 47 deletions

View File

@@ -11,7 +11,7 @@ zarinpal-analytics-deployment/ # this repository
├── backend/ # ignored checkout of zarinpal-analytics-backend ├── backend/ # ignored checkout of zarinpal-analytics-backend
├── frontend/ # ignored checkout of zarinpal-analytics-frontend ├── frontend/ # ignored checkout of zarinpal-analytics-frontend
├── docs/ ├── docs/
└── (deployment assets after specification approval) └── (deployment assets only after explicit build authorization)
``` ```
The intended production hostname is `zarinpal.amiirkhl.ir`. The deployment shape will follow the proven Qlockify structure while being reviewed and hardened for this service; it is not a byte-for-byte copy. The intended production hostname is `zarinpal.amiirkhl.ir`. The deployment shape will follow the proven Qlockify structure while being reviewed and hardened for this service; it is not a byte-for-byte copy.
@@ -26,7 +26,7 @@ The intended production hostname is `zarinpal.amiirkhl.ir`. The deployment shape
## Platform operations documents ## Platform operations documents
- `docs/PLATFORM-OPERATIONS-SPEC.md` defines the draft manual Qlockify-style production topology, lifecycle, observability phases, security, backup/restore, acceptance, and operator boundaries. - `docs/PLATFORM-OPERATIONS-SPEC.md` defines the approved manual Qlockify-style production topology, lifecycle, observability phases, security, backup/restore, acceptance, and operator boundaries.
- `docs/runbooks/FIRST-SERVER-BOOTSTRAP.md` defines the safe first-host sequence without implementing a bootstrap script. - `docs/runbooks/FIRST-SERVER-BOOTSTRAP.md` defines the safe first-host sequence without implementing a bootstrap script.
- `docs/runbooks/BACKUP-RESTORE.md` defines logical PostgreSQL backup, encryption/retention, guarded restore, and rehearsal. - `docs/runbooks/BACKUP-RESTORE.md` defines logical PostgreSQL backup, encryption/retention, guarded restore, and rehearsal.
- `tasks/plan.md` and `tasks/todo.md` hold the approval-gated implementation plan. Their presence does not grant implementation authorization. - `tasks/plan.md` and `tasks/todo.md` hold the approval-gated implementation plan. Their presence does not grant implementation authorization.

View File

@@ -1,6 +1,6 @@
# Platform Operations Capability Spec # Platform Operations Capability Spec
- Status: Draft revision — confirmed intent, ready for detailed stakeholder review - Status: Approved specification
- Implementation authorization: Not granted - Implementation authorization: Not granted
- Capability: Platform operations - Capability: Platform operations
- Depends on: all deployable backend and frontend capability contracts - Depends on: all deployable backend and frontend capability contracts
@@ -57,19 +57,19 @@ This observability phase must be complete before the AI capability starts. It do
## Approved assumptions and decisions ## Approved assumptions and decisions
1. The target is one supported Ubuntu server. 1. The target is a new dedicated Ubuntu 24.04 LTS server with 2 CPU cores, 2 GB RAM, Docker already installed, user `ubuntu`, and a bootstrap-created 2 GB swap file.
2. A dedicated trusted Ubuntu deployment user belongs to the `docker` group and runs Docker Compose. Docker-group membership is root-equivalent and is restricted to trusted operators. 2. The trusted `ubuntu` user belongs to the `docker` group and runs Docker Compose. Docker-group membership is root-equivalent, so access to this account is restricted to trusted operators.
3. The deployment repository contains ignored nested checkouts of the backend and frontend repositories, matching ADR 0001 and Qlockify. 3. The deployment repository contains ignored nested checkouts of the backend and frontend repositories, matching ADR 0001 and Qlockify.
4. Normal deployment selects the latest protected `main` from all three repositories, then records the exact three commit hashes before building. 4. The operator manually runs `git pull --ff-only origin main` in all three repositories and enters HTTPS credentials interactively. The deployment command performs no pull or credential handling; it verifies and records the three commits before building.
5. Application images are built on the production server from those recorded checkouts. They are not published to a registry. 5. Application images are built on the production server from those recorded checkouts. They are not published to a registry.
6. Rollback checks out the previous recorded hashes and rebuilds. Database rollback remains constrained by migration compatibility. 6. Rollback checks out the previous recorded hashes and rebuilds. Database rollback remains constrained by migration compatibility.
7. Nginx obtains and renews a Let's Encrypt certificate automatically through Certbot using HTTP-01. 7. Nginx obtains and renews a Let's Encrypt certificate automatically through Certbot using HTTP-01.
8. PostgreSQL 18 and Redis 7 Alpine are the initial major versions. Exact patch tags are pinned before implementation. 8. Infrastructure images are pinned to `postgres:18.4-alpine3.24`, `redis:7.4.10-alpine3.21`, `nginx:1.29.8-alpine3.23`, and `certbot/certbot:v5.7.0`.
9. Redis is disposable cache/queue/coordination state and is excluded from backup. PostgreSQL remains authoritative. 9. Redis uses a named volume, AOF `everysec`, and `noeviction` for routine restart continuity. It remains disposable cache/queue/coordination state and is excluded from backup; PostgreSQL remains authoritative.
10. Daily encrypted PostgreSQL backups and tested restores are MVP requirements. 10. Daily encrypted PostgreSQL backups and tested restores are MVP requirements.
11. Qlockify backup/restore/upload scripts are the implementation reference and will receive only necessary project path, service, credential, and safety changes. 11. Qlockify backup/restore/upload scripts are the implementation reference and will receive only necessary project path, service, credential, and safety changes.
12. Production `.env` files, secrets, TLS keys, Redis data, raw CSV, credentials, logs, and font assets are excluded from database backup packages. 12. Production `.env` files, secrets, TLS keys, Redis data, raw CSV, credentials, logs, and font assets are excluded from database backup packages.
13. Prometheus/Grafana are required after MVP readiness and before AI implementation. 13. Prometheus/Grafana are required after MVP readiness and before AI implementation. MVP readiness requires application flows, tenant isolation, migration/import, TLS, manual health/log checks, rollback, encrypted backup, and clean restore to pass.
14. Frontend commit `64f5ac2` owns `static/fonts/IRANYekanXVFaNumVF.woff2` and `static/fonts/FontLicense.txt`; deployment uses the normal frontend build context without another asset path. 14. Frontend commit `64f5ac2` owns `static/fonts/IRANYekanXVFaNumVF.woff2` and `static/fonts/FontLicense.txt`; deployment uses the normal frontend build context without another asset path.
Any change to these decisions requires a spec revision before implementation. Any change to these decisions requires a spec revision before implementation.
@@ -77,7 +77,7 @@ Any change to these decisions requires a spec revision before implementation.
## Repository and server layout ## Repository and server layout
```text ```text
/home/<deploy-user>/zarinpal-analytics-deployment/ /home/ubuntu/zarinpal-analytics-deployment/
├── .git/ deployment repository ├── .git/ deployment repository
├── backend/ ignored checkout of backend repository ├── backend/ ignored checkout of backend repository
│ └── .git/ │ └── .git/
@@ -128,7 +128,7 @@ Nginx is the only public application entry point. The worker is event-driven and
| `backend` | Go API, sessions, authorization, analytics control | `app`, `data` | none | none | | `backend` | Go API, sessions, authorization, analytics control | `app`, `data` | none | none |
| `worker` | On-demand Asynq analytics sections | `data` | none | none | | `worker` | On-demand Asynq analytics sections | `data` | none | none |
| `postgres` | Authoritative database | `data` | `postgres_data` | none | | `postgres` | Authoritative database | `data` | `postgres_data` | none |
| `redis` | Queue, cache, rate-limit, replay coordination | `data` | optional routine AOF volume, excluded from backup | none | | `redis` | Queue, cache, rate-limit, replay coordination | `data` | named AOF volume, excluded from backup | none |
| `migrate` | Versioned schema migration | `data` | none | one-off only | | `migrate` | Versioned schema migration | `data` | none | one-off only |
| `import` | One-time CSV bootstrap/recovery | `data` | exact read-only input bind | one-off profile only | | `import` | One-time CSV bootstrap/recovery | `data` | exact read-only input bind | one-off profile only |
| `admin` | Demo credentials and approved maintenance | `data` | explicit output bind if requested | one-off profile only | | `admin` | Demo credentials and approved maintenance | `data` | explicit output bind if requested | one-off profile only |
@@ -137,7 +137,7 @@ Post-MVP adds `prometheus`, `grafana`, and approved exporters on a separate priv
### Image and build policy ### Image and build policy
- PostgreSQL, Redis, Nginx, Certbot, and later monitoring images use explicit supported tags; no `latest` tag. - PostgreSQL, Redis, Nginx, and Certbot use the exact approved tags above; no `latest` tag.
- Backend and worker build from the same recorded backend commit and deployment Dockerfile/context contract. - Backend and worker build from the same recorded backend commit and deployment Dockerfile/context contract.
- Frontend builds from the recorded frontend commit and normal build context, including its tracked font/license inputs. - Frontend builds from the recorded frontend commit and normal build context, including its tracked font/license inputs.
- The deployment script records resulting local image identifiers and build timestamps for diagnosis, but Git commit hashes are the reproducible source reference. - The deployment script records resulting local image identifiers and build timestamps for diagnosis, but Git commit hashes are the reproducible source reference.
@@ -152,15 +152,28 @@ Post-MVP adds `prometheus`, `grafana`, and approved exporters on a separate priv
- CPU, memory, PID, database-pool, and log limits are explicit. Initial values are validated against the actual server and import/load tests. - CPU, memory, PID, database-pool, and log limits are explicit. Initial values are validated against the actual server and import/load tests.
- Docker logs use bounded rotation so a noisy service cannot fill the server disk. - Docker logs use bounded rotation so a noisy service cannot fill the server disk.
Initial runtime limits for the 2-GB server are:
| Service | Memory limit |
|---|---:|
| PostgreSQL | 512 MB |
| Redis | 256 MB container limit; 192 MB `maxmemory` target to leave process/AOF overhead |
| Backend API | 256 MB |
| Worker | 512 MB |
| Frontend | 96 MB |
| Nginx | 96 MB |
Certbot is one-shot/periodic rather than continuously memory-resident. Worker concurrency remains 16 globally and 4 per merchant. If measured load exceeds this server, upgrade server capacity rather than silently lowering the approved concurrency.
## Manual deployment and release records ## Manual deployment and release records
### Normal deployment ### Normal deployment
1. Confirm exact server, deployment root, environment, available disk, recent backup, Docker health, and operator identity. 1. Confirm exact server, deployment root, environment, available disk, recent backup, Docker health, and operator identity.
2. Acquire a deployment lock so backup/restore/import/deploy operations cannot conflict unsafely. 2. Acquire a deployment lock so backup/restore/import/deploy operations cannot conflict unsafely.
3. Verify all three repositories exist at their exact expected paths, use approved remotes, and contain no unexplained local changes. 3. Before running the deployment command, the operator manually executes `git pull --ff-only origin main` in each repository and enters HTTPS credentials interactively; no Git credential is stored by deployment.
4. Fetch and fast-forward each repository to its latest `origin/main`. Do not discard local/user changes automatically. 4. Verify all three repositories exist at their exact expected paths, use the approved HTTPS remotes, are on `main`, match `origin/main`, and contain no unexplained local changes.
5. Record the deployment, backend, and frontend commit hashes before building. 5. Record the deployment, backend, and frontend commit hashes under the ignored `releases/` directory before building.
6. Validate required configuration/secret files without printing values. 6. Validate required configuration/secret files without printing values.
7. Render and validate Docker Compose configuration. 7. Render and validate Docker Compose configuration.
8. Build candidate application/Nginx images on the server. 8. Build candidate application/Nginx images on the server.
@@ -223,10 +236,12 @@ Compose health/dependency conditions prevent common startup races, but the manua
### One-time CSV import ### One-time CSV import
- Import is an explicit operator command/profile, never normal startup, cron, a scheduler, watcher, or deploy trigger. - Import is an explicit operator command/profile, never normal startup, cron, a scheduler, watcher, or deploy trigger.
- On the first server release only, tracked `scripts/first-start.sh` orchestrates PostgreSQL/Redis readiness, the one-off migration, the importer profile, reconciliation, and then public application startup. Later ordinary deploys/restarts never invoke it.
- The operator provides an exact resolved path outside Git; only that file is mounted read-only. - The operator provides an exact resolved path outside Git; only that file is mounted read-only.
- Import cannot overlap migration, restore, or another import. - Import cannot overlap restore, backup, or another import and starts only after migration succeeds.
- The backend importer validates checksum/schema, streams data, reconciles counts, and records incomplete failure safely according to the Data Foundation spec. - The backend importer pins the approved checksum/schema/filename/counts, enforces resource caps, streams data, reconciles counts, removes temporary raw staging, and records incomplete failure safely according to the approved backend import specifications.
- An identical completed import is idempotent and does not duplicate business rows. - An identical completed import is idempotent and does not duplicate business rows.
- Import failure prevents the first public application activation. Recovery restarts from the immutable archive; it never resumes guessed partial CSV/database state.
- Demo credential generation is a separate one-time `admin` job whose plaintext output never enters Compose logs, Git, backups, or shell history by default. - Demo credential generation is a separate one-time `admin` job whose plaintext output never enters Compose logs, Git, backups, or shell history by default.
### Graceful shutdown ### Graceful shutdown
@@ -256,7 +271,7 @@ Initial health timing target is 10-second interval, 3-second timeout, 30-second
### Routing ### Routing
- Port 80 serves `/.well-known/acme-challenge/` and redirects everything else to `https://zarinpal.amiirkhl.ir$request_uri`. - Port 80 serves `/.well-known/acme-challenge/` and redirects everything else to `https://zarinpal.amiirkhl.ir$request_uri`.
- Alternate approved hostnames redirect to the canonical hostname. Unknown hosts are rejected by a default server. - The certificate and application serve only `zarinpal.amiirkhl.ir`; there is no `www` or alternate domain. Unknown hosts are rejected by a default server.
- `/api/` proxies only to the backend with host, scheme, safe client-address chain, and request id. - `/api/` proxies only to the backend with host, scheme, safe client-address chain, and request id.
- `/` serves/proxies the frontend; SPA fallback never captures API errors. - `/` serves/proxies the frontend; SPA fallback never captures API errors.
- Fingerprinted assets receive long immutable caching; HTML/mutable manifests revalidate. - Fingerprinted assets receive long immutable caching; HTML/mutable manifests revalidate.
@@ -282,11 +297,11 @@ Initial health timing target is 10-second interval, 3-second timeout, 30-second
## Configuration and secrets ## Configuration and secrets
- A committed safe example names required variables and contains placeholders only. - A committed safe example names required variables and contains placeholders only.
- Real production `.env` and secret files live outside public Git with mode 0600 or stricter. - Follow the Qlockify environment layout: deployment `.env` in the deployment root plus backend/frontend `.env` files in their nested repository roots. All are Git-ignored, mode 0600, and excluded from backups.
- Secrets are mounted only into the services that need them and never passed in command-line arguments or embedded in images. - Secrets are mounted only into the services that need them and never passed in command-line arguments or embedded in images.
- Frontend receives no production secret. - Frontend receives no production secret.
- Compose validation and diagnostics must not print resolved secret values. - Compose validation and diagnostics must not print resolved secret values.
- Backup object-store credentials and encryption passphrase are read from protected server configuration, following the Qlockify script interface with renamed ZarinPal variables/paths as needed. - Backup object-store credentials and encryption passphrase are read from the protected deployment `.env`, following the Qlockify script interface with ZarinPal-specific ParsPack bucket/prefix and separate credentials.
- If a secret reaches Git/logs, rotate/revoke it first, then clean history/evidence as a separate incident action. - If a secret reaches Git/logs, rotate/revoke it first, then clean history/evidence as a separate incident action.
### Licensed font ### Licensed font
@@ -362,19 +377,19 @@ Necessary changes include deployment root, archive/prefix names, Compose service
### Backup contract ### Backup contract
- Daily PostgreSQL logical dump using a matching PostgreSQL 18 client. - Daily at `02:00 UTC`, create a PostgreSQL plain-SQL logical dump using the matching PostgreSQL 18 client, following Qlockify's `pg_dump` flow.
- Backup package contains database archive plus non-secret manifest/checksums only. - Backup package contains database archive plus non-secret manifest/checksums only.
- Encrypt before durable local/remote storage using the approved Qlockify-compatible mechanism. - Encrypt before durable local/remote storage using Qlockify's OpenSSL AES-256-CBC with PBKDF2 and 200,000 iterations; pair it with recorded SHA-256 checksums because CBC encryption is not itself authenticated.
- Upload to private S3-compatible storage over TLS and verify the remote object. - Upload to private S3-compatible storage over TLS and verify the remote object.
- Retain the latest three verified encrypted local backups and seven verified encrypted remote backups. - Retain the latest three verified encrypted local backups and seven verified encrypted remote backups.
- Delete stale backups only after a new remote backup is verified; never delete the last known-good copy. - Delete stale backups only after a new remote backup is verified; never delete the last known-good copy.
- Exclude `.env`, secrets, Redis, TLS keys, raw CSV, credentials, logs, monitoring state, font binary, and `FontLicense.txt`. - Exclude `.env`, secrets, Redis, TLS keys, raw CSV, credentials, logs, monitoring state, font binary, and `FontLicense.txt`.
- A dump is successful only after archive listing/checksum, encryption, upload, remote verification, and manifest completion. - A dump is successful only after plain-SQL header/size/checksum validation, package-content inspection, encryption, upload, remote verification, and manifest completion.
### Restore contract ### Restore contract
- Default restore target is a new empty non-production database. - Default restore target is a new empty non-production database; plain SQL is restored with `psql -X --set ON_ERROR_STOP=on` and a reviewed transaction strategy.
- Validate explicit backup id, checksums, manifest, archive listing, PostgreSQL compatibility, free space, and exact resolved destination before mutation. - Validate explicit backup id, checksums, manifest, package contents, plain-SQL header, PostgreSQL compatibility, free space, and exact resolved destination before mutation.
- Production restore additionally requires environment, host, database, backup id, typed confirmation, maintenance mode, exclusive lock, and named operator. - Production restore additionally requires environment, host, database, backup id, typed confirmation, maintenance mode, exclusive lock, and named operator.
- Never pipe an unchecked dump into the active database or restore over a running destination in place. - Never pipe an unchecked dump into the active database or restore over a running destination in place.
- Restore into an empty database/cluster, validate counts/invariants/tenant isolation/login/cold Redis analytics/SSE, then switch/reopen traffic. - Restore into an empty database/cluster, validate counts/invariants/tenant isolation/login/cold Redis analytics/SSE, then switch/reopen traffic.
@@ -386,13 +401,13 @@ Necessary changes include deployment root, archive/prefix names, Compose service
2. Prove two key-only operator logins and provider console recovery before disabling root/password SSH. 2. Prove two key-only operator logins and provider console recovery before disabling root/password SSH.
3. Configure default-deny firewall: operator-allowlisted SSH plus public 80/443 only. 3. Configure default-deny firewall: operator-allowlisted SSH plus public 80/443 only.
4. Patch the OS, enable time sync/security updates/log rotation/disk monitoring, and reboot-test access. 4. Patch the OS, enable time sync/security updates/log rotation/disk monitoring, and reboot-test access.
5. Install Docker Engine/Compose from the approved source and add only the dedicated trusted deploy user to the `docker` group. 5. Verify the preinstalled Docker Engine/Compose installation, record its source/version, and ensure only the trusted `ubuntu` user has the required Docker-group access.
6. Clone the deployment repository and backend/frontend nested repositories into exact validated paths. 6. Clone the deployment repository and backend/frontend nested repositories into exact validated paths.
7. Create protected configuration/secret paths outside Git and validate permissions. 7. Create protected configuration/secret paths outside Git and validate permissions.
8. Validate Compose and local builds without starting public traffic. 8. Validate Compose and local builds without starting public traffic.
9. Point DNS, test ACME staging, issue production TLS, and verify canonical routing. 9. Point DNS, test ACME staging, issue production TLS, and verify canonical routing.
10. Start data services, run migration, then API/worker/frontend/Nginx and health checks. 10. Run tracked `scripts/first-start.sh`: start data services, migrate, import/reconcile the pinned archive, then start API/worker/frontend/Nginx and run health checks.
11. Run the explicit one-time CSV import and separate credential generation only after the platform is healthy. 11. Run separate demo credential generation, authenticate as at least two merchants, and verify tenant isolation.
12. Complete encrypted remote backup and clean restore rehearsal before handoff. 12. Complete encrypted remote backup and clean restore rehearsal before handoff.
## Threats and failure behavior ## Threats and failure behavior
@@ -433,7 +448,7 @@ Necessary changes include deployment root, archive/prefix names, Compose service
- Expose a new port, hostname, admin/debug/docs/metrics route, or third-party endpoint. - Expose a new port, hostname, admin/debug/docs/metrics route, or third-party endpoint.
- Change PostgreSQL/Redis major version, backup provider/encryption, retention, RPO/RTO, or restore behavior. - Change PostgreSQL/Redis major version, backup provider/encryption, retention, RPO/RTO, or restore behavior.
- Run a destructive/non-compatible migration, production restore, or replacement import. - Run a destructive/non-compatible migration, production restore, or replacement import.
- Change the manual latest-`main` deployment rule, repository topology, deploy-user privilege, or TLS/HSTS scope. - Change the manual latest-`main` deployment rule, repository topology, deploy-user privilege, resource limits, exact image tags, or TLS/HSTS scope.
- Add Prometheus/Grafana before MVP is ready or start AI before the observability phase is accepted. - Add Prometheus/Grafana before MVP is ready or start AI before the observability phase is accepted.
- Change frontend ownership/location of the licensed assets. - Change frontend ownership/location of the licensed assets.
@@ -484,17 +499,16 @@ Necessary changes include deployment root, archive/prefix names, Compose service
- MVP can be operated through health, logs, release records, disk/certificate/backup checks without Prometheus/Grafana. - MVP can be operated through health, logs, release records, disk/certificate/backup checks without Prometheus/Grafana.
- Prometheus/Grafana/exporters/dashboards/alerts are implemented and accepted after MVP readiness and before any AI implementation begins. - Prometheus/Grafana/exporters/dashboards/alerts are implemented and accepted after MVP readiness and before any AI implementation begins.
## Remaining decisions before implementation approval ## Remaining implementation inputs
1. Confirm server provider, Ubuntu version, CPU/RAM/disk, public IP/DNS owner, and deployment username/path. No stakeholder-level Platform Operations decisions remain. Implementation still consumes these concrete inputs without reopening the approved design:
2. Approve exact PostgreSQL 18, Redis 7 Alpine, Nginx, Certbot, and base-image tags after compatibility/security checks.
3. Approve initial CPU, memory, PID, database-pool, log-rotation, and disk thresholds for the selected server. - the new server's public IP and DNS access
4. Confirm exact backend/frontend repository URLs, build contexts, commands, health endpoints, migration/import/admin commands, and SSE path. - actual ZarinPal ParsPack endpoint/bucket/prefix credentials and separately protected encryption passphrase
5. Confirm S3-compatible endpoint/bucket/prefix, new ZarinPal credentials, encryption passphrase custody, and cron time. - backend/frontend build commands, health endpoints, migration/import/admin commands, and exact SSE path from their approved implementation contracts
6. Confirm whether Redis uses an AOF named volume for routine restart continuity or starts fully disposable; it remains excluded from backup either way. - the named operators allowed to perform deployment/restore and the off-server secret/configuration escrow location
7. Approve the exact deployment release-record location/format and the safe behavior for a dirty or divergent server checkout.
8. Confirm who may deploy/restore and where off-server copies of production configuration/secrets are escrowed. If an input would change an approved behavior rather than fill in a value/interface, amend this spec first.
9. Define the explicit “MVP ready” gate that starts the Prometheus/Grafana phase and the observability acceptance gate that permits AI work.
## References ## References

View File

@@ -60,8 +60,12 @@ Framework decisions remain subordinate to capability requirements. SvelteKit is
- Nginx TLS module: <https://nginx.org/en/docs/http/ngx_http_ssl_module.html> - Nginx TLS module: <https://nginx.org/en/docs/http/ngx_http_ssl_module.html>
- PostgreSQL backup and restore: <https://www.postgresql.org/docs/current/backup.html> - PostgreSQL backup and restore: <https://www.postgresql.org/docs/current/backup.html>
- PostgreSQL SQL dumps: <https://www.postgresql.org/docs/current/backup-dump.html> - PostgreSQL SQL dumps: <https://www.postgresql.org/docs/current/backup-dump.html>
- PostgreSQL official image tags: <https://hub.docker.com/_/postgres/tags>
- Redis official image tags: <https://hub.docker.com/_/redis/tags>
- Nginx official image tags: <https://hub.docker.com/_/nginx/tags>
- Certbot official image tags: <https://hub.docker.com/r/certbot/certbot/tags>
Applied in `PLATFORM-OPERATIONS-SPEC.md` through health-gated Compose startup, isolated networks and secrets, bounded container logs, TLS/SSE proxy behavior, and logical PostgreSQL backup with guarded restore. Exact product versions and server resource limits remain explicit approval decisions rather than assumptions. Applied in `PLATFORM-OPERATIONS-SPEC.md` through health-gated Compose startup, isolated networks and secrets, bounded container logs, TLS/SSE proxy behavior, logical PostgreSQL backup with guarded restore, and the approved exact image tags and resource limits.
## Qlockify deployment reference ## Qlockify deployment reference

View File

@@ -15,18 +15,19 @@ The platform still needs to answer which source is running and how to return to
Use manual Qlockify-style deployment on the production server. Use manual Qlockify-style deployment on the production server.
For a normal release, a trusted deployment user: For a normal release, the trusted `ubuntu` user:
1. verifies the exact deployment/backend/frontend repository paths, remotes, branches, and clean working trees; 1. verifies the exact deployment/backend/frontend repository paths, remotes, branches, and clean working trees;
2. fetches and fast-forwards each checkout to the latest `origin/main`; 2. manually runs `git pull --ff-only origin main` in each checkout, entering the source-forge username/password interactively when prompted;
3. records the exact three resulting Git commit hashes; 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. builds application images locally with Docker Compose; 4. records the exact three resulting Git commit hashes under the ignored `/home/ubuntu/zarinpal-analytics-deployment/releases/` directory;
5. runs the dedicated migration and health/smoke checks; and 5. builds application images locally with Docker Compose;
6. records the release as active only after validation passes. 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. 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 it must not unconditionally `git reset --hard`. A dirty or divergent checkout stops for operator resolution so user changes are not destroyed. 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. There is no CI/CD workflow, Actions runner, automated cross-repository event, private image registry, or direct automated production mutation.