docs: define Qlockify adaptation contract
This commit is contained in:
134
docs/QLOCKIFY-ADAPTATION-CONTRACT.md
Normal file
134
docs/QLOCKIFY-ADAPTATION-CONTRACT.md
Normal file
@@ -0,0 +1,134 @@
|
||||
# Qlockify deployment adaptation contract
|
||||
|
||||
- Status: Approved planning baseline
|
||||
- Source: `D:/Programing/Scripts/Qlockify/qlockify-deployment` (read-only)
|
||||
- Target: `/home/ubuntu/zarinpal-analytics-deployment`
|
||||
- Implementation authorization: Not granted
|
||||
- Last updated: 2026-08-20
|
||||
|
||||
## Purpose
|
||||
|
||||
Use Qlockify's proven single-server deployment shape and environment-file layout for ZarinPal Analytics without requiring production IPs, credentials, or operator names during planning. Real values are supplied on the server when deployment occurs; they are not planning blockers and never enter public Git.
|
||||
|
||||
## Repository layout
|
||||
|
||||
```text
|
||||
/home/ubuntu/zarinpal-analytics-deployment/
|
||||
├── .env ignored deployment/TLS/backup values
|
||||
├── backend/ ignored backend Git checkout
|
||||
│ └── .env ignored backend/runtime values
|
||||
├── frontend/ ignored frontend Git checkout
|
||||
│ └── .env ignored public build values only
|
||||
├── data/incoming/ ignored one-time CSV input
|
||||
├── data/reports/ ignored import reports
|
||||
├── releases/ ignored non-secret release records
|
||||
└── backups/ ignored encrypted local backups
|
||||
```
|
||||
|
||||
This deliberately simplifies Qlockify's extra application subdirectory layer. Each service checkout is directly under the deployment root and keeps an independent `.git` directory.
|
||||
|
||||
## File adaptation matrix
|
||||
|
||||
| Qlockify source | Planned ZarinPal artifact | Adaptation |
|
||||
|---|---|---|
|
||||
| `.env.sample` | `.env.example` | Keep TLS and ParsPack variable names; use the ZarinPal domain/prefix; remove alternate-domain and duplicate database values. |
|
||||
| `backend/.env.sample` | backend-owned `.env.example`, consumed as `backend/.env` | Replace Django, JWT, Celery, OAuth, SMS, and demo-cleanup variables with the Go API/worker/import contracts. |
|
||||
| `frontend/.env.sample` | frontend-owned `.env.example`, consumed as `frontend/.env` | Keep only public same-origin build configuration; never place a secret here. |
|
||||
| `docker-compose.yml` | `compose.yaml` | Keep single-host orchestration and nested build contexts; replace Django/Celery/media services with API, worker, migrate, importer, and admin boundaries. |
|
||||
| `backend/Dockerfile` | deployment backend image definition | Build the backend checkout once and select API/worker/migrate/import/admin commands from the same recorded backend revision. |
|
||||
| `frontend/Dockerfile` | deployment frontend image definition | Build the ordinary frontend checkout, including its tracked font and license. |
|
||||
| `nginx/*` | `nginx/*` | Keep HTTP-01, automatic renewal, temporary bootstrap certificate, and reload flow; use only `zarinpal.amiirkhl.ir` and ZarinPal routes. |
|
||||
| `scripts/deploy.sh` | `scripts/deploy.sh` plus release-record helper | Keep manual Compose build/start structure; Git pulls happen interactively before the script; remove fetch/reset and partial-repository release selection. |
|
||||
| `scripts/backup.sh` | `scripts/backup.sh` | Keep plain-SQL `pg_dump` and temporary archive structure; include PostgreSQL plus non-secret manifest/checksums only. |
|
||||
| `scripts/backup-upload-s3.sh` | same filename | Keep root `.env` loading, OpenSSL/rclone flow, ParsPack support, and 3/7 retention; retain encrypted local artifacts. |
|
||||
| `scripts/restore.sh` | same filename | Keep plain-SQL restore basis; remove env/media restore and add empty-target plus production guards. |
|
||||
| `scripts/restore-from-s3.sh` | same filename | Keep rclone/decrypt handoff; require an explicit object id for production and validate it before restore. |
|
||||
| `.gitea/workflows/*` | none | Do not port. ZarinPal deployment is manual and has no CI/CD pipeline or runner. |
|
||||
|
||||
## Environment layout
|
||||
|
||||
Future tracked examples contain placeholders or safe public defaults only. Production files are Git-ignored, owned by `ubuntu`, mode `0600`, excluded from backup, and loaded without printing resolved values.
|
||||
|
||||
### Deployment root `.env`
|
||||
|
||||
The future `.env.example` uses this deployment-owned contract:
|
||||
|
||||
```dotenv
|
||||
COMPOSE_PROJECT_NAME=zarinpal_analytics
|
||||
|
||||
SSL_CERT_MODE=letsencrypt
|
||||
LETSENCRYPT_EMAIL=
|
||||
PRIMARY_DOMAIN=zarinpal.amiirkhl.ir
|
||||
CERTBOT_STAGING=0
|
||||
|
||||
S3_BACKUP_BUCKET=
|
||||
S3_BACKUP_PREFIX=backup/zarinpal-analytics
|
||||
S3_BACKUP_ENDPOINT_URL=
|
||||
S3_BACKUP_ACCESS_KEY_ID=
|
||||
S3_BACKUP_SECRET_ACCESS_KEY=
|
||||
BACKUP_ENCRYPTION_PASSPHRASE=
|
||||
BACKUP_LOCAL_KEEP_LATEST=3
|
||||
BACKUP_REMOTE_KEEP_LATEST=7
|
||||
```
|
||||
|
||||
There is no `ALT_DOMAINS`, runner, registry, deploy-host, SSH-key, or CI variable. The endpoint, bucket, email, access keys, and passphrase may remain blank in the tracked example; the future validation command requires them only for the operation that consumes them.
|
||||
|
||||
### Backend `backend/.env`
|
||||
|
||||
The backend repository owns the complete Go application example. Deployment requires these semantic groups and consumes their eventual exact backend-owned names without maintaining a second competing template:
|
||||
|
||||
- production mode and structured-log level
|
||||
- API listen address and public origin `https://zarinpal.amiirkhl.ir`
|
||||
- `POSTGRES_HOST=postgres`, port `5432`, database/user/password
|
||||
- `REDIS_HOST=redis`, port `6379`, password, and database selection required by the backend/Asynq contract
|
||||
- session/cookie secrets and secure same-origin cookie settings
|
||||
- analytics TTL, rate limits, worker concurrency `16`, per-merchant concurrency `4`, 60-second attempt timeout, and retry policy
|
||||
- import source/report paths, schema version, readiness timeout, and bounded batch/resource settings
|
||||
|
||||
The same protected file supplies PostgreSQL, Redis, API, worker, migrate, importer, and admin services only with the variables each service needs. Qlockify-only Django, JWT, Celery, Google OAuth, SMS, demo-environment, media, and scheduled-cleanup variables are not carried over.
|
||||
|
||||
### Frontend `frontend/.env`
|
||||
|
||||
The frontend repository owns its exact public variable name. Its production value is the same-origin API prefix, initially `/api/v1`. No database, Redis, session, backup, AvalAI, or other secret is allowed in this file or the browser bundle.
|
||||
|
||||
## Manual deployment flow
|
||||
|
||||
1. The operator manually runs `git pull --ff-only origin main` in deployment, backend, and frontend checkouts and enters source-forge credentials interactively.
|
||||
2. The future deploy command acquires the operation lock and verifies exact paths, remotes, `main`, equality with `origin/main`, and clean trees. It performs no Git fetch, pull, checkout, or reset.
|
||||
3. It records all three commit hashes and validates the root/backend/frontend environment contracts without printing values.
|
||||
4. It validates Compose, builds from the three recorded revisions, starts data services, runs the one-off migration, and replaces application services only after the required gates pass.
|
||||
5. It validates private readiness plus public TLS/routing/font/SSE behavior, observes for 15 minutes, then marks the release active.
|
||||
6. Rollback selects the prior release's three hashes, rebuilds, and re-runs the same checks. It never automatically reverses a migration.
|
||||
|
||||
The ordinary deployment path never invokes CSV import or credential generation. The first server uses the separately planned `first-start.sh` path after migration and before the first public activation.
|
||||
|
||||
## Always / Ask / Never
|
||||
|
||||
### Always
|
||||
|
||||
- Adapt from the named tracked Qlockify source file and record intentional differences.
|
||||
- Keep all three real `.env` files ignored, mode `0600`, and out of backups/logs.
|
||||
- Validate only the variables needed by the requested operation.
|
||||
- Preserve exact-path guards before any mutation, cleanup, restore, or retention action.
|
||||
|
||||
### Ask first
|
||||
|
||||
- Rename a deployment-owned variable after implementation begins.
|
||||
- Add a public origin/domain, external provider, persistent data class, or secret consumer.
|
||||
- Change the manual three-repository release rule or Qlockify-derived backup encryption/retention contract.
|
||||
|
||||
### Never
|
||||
|
||||
- Port Qlockify's Gitea workflows, runner/deploy-key variables, or automated deployment.
|
||||
- Port Qlockify's destructive `git reset --hard` synchronization.
|
||||
- Copy Qlockify credentials, domains, database names, service names, or secret values.
|
||||
- Back up or restore `.env` files, Redis, TLS keys, raw CSV, credentials, logs, or frontend assets.
|
||||
- Create a second font path or private asset-injection workflow.
|
||||
|
||||
## Planning acceptance
|
||||
|
||||
- Every future deployment artifact maps to a named Qlockify source or a documented ZarinPal-only requirement.
|
||||
- Root/backend/frontend environment ownership is unambiguous and has no duplicate secret source.
|
||||
- Tracked examples can be committed with blank secret placeholders and useful safe defaults.
|
||||
- Planning and local validation do not require a server IP, real DNS access, real ParsPack values, or named operators.
|
||||
- Real values are required only at the first-server or operation-specific execution gate.
|
||||
Reference in New Issue
Block a user