5.1 KiB
ZarinPal Merchant Analytics — Deployment
This repository is the operational control plane for the hackathon project. It will own Docker Compose, Nginx, environment templates, deployment automation, backup/restore scripts, and cross-repository release orchestration. Product code belongs in the backend and frontend repositories.
The production stack is Docker Compose based and connects to the existing shared Caddy deployment. This repository does not publish host ports and does not run a second TLS proxy.
For direct Windows development without Docker Compose, see docs/LOCAL-DEVELOPMENT.md. This helper is deliberately separate from the production Compose contract.
Repository topology
zarinpal-analytics-deployment/ # this repository
├── backend/ # ignored checkout of zarinpal-analytics-backend
├── frontend/ # ignored checkout of zarinpal-analytics-frontend
├── docs/
└── (deployment assets created through the authorized task list)
The production hostname is zarinpal.amiirkhl.ir. Caddy routes /api/* and /healthz to the Go API and every other path to the static frontend. PostgreSQL, Redis, the worker, and all one-off commands remain on the private Compose data network; the worker additionally joins a dedicated bridge network for outbound AI-provider access without joining the shared Caddy proxy network.
Required server layout
/home/ubuntu/zarinpal-analytics-deployment/
├── .env
├── backend/
│ └── .env
└── frontend/
└── .env
Clone the backend and frontend as ordinary ignored repositories, not submodules. Copy the three tracked examples to their ignored runtime names:
cp .env.example .env
cp backend/.env.production.example backend/.env
cp frontend/.env.production.example frontend/.env
chmod 600 .env backend/.env frontend/.env
Replace every change-me value. Generate URL-safe secrets with openssl rand -hex 32. The root file owns the PostgreSQL and Redis passwords; Compose injects their connection settings into the Go containers. The frontend file contains public build-time switches only.
First production start
Before adding/reloading the Caddy route, validate and build the stack, import the immutable dataset, create the demo account, and only then start the public upstreams:
docker compose config --quiet
docker compose build backend frontend
docker compose up -d postgres redis
docker compose --profile tools run --rm migrate
docker compose --profile import run --rm importer
docker compose --profile tools run --rm admin
docker compose up -d backend worker frontend
docker compose ps
After every service reports healthy, validate and reload Caddy from the separate Caddy deployment. This order prevents the first public activation from serving an empty or partially imported database.
Normal later deployments
Pull each repository manually, then run the guarded deploy script. It rejects dirty, non-main, or non-origin/main checkouts and never performs a fetch, reset, or checkout itself.
git pull --ff-only origin main
git -C backend pull --ff-only origin main
git -C frontend pull --ff-only origin main
bash scripts/deploy.sh
Normal deploys run migrations but never run the importer or admin command.
Re-running one-off tools
IMPORT_FILE in the root .env is the absolute host path of the immutable challenge_data.csv.gz. If recovery requires the idempotent importer or the demo account must be reset, run them explicitly:
docker compose --profile import run --rm importer
docker compose --profile tools run --rm admin
Both commands are explicit one-offs. Re-running the importer relies on the backend's checksum-based idempotency guard.
Operations
docker compose ps
docker compose logs --tail=200 backend worker frontend postgres redis
docker compose restart backend worker frontend
docker compose down
Do not use docker compose down -v in production; -v deletes the PostgreSQL and Redis volumes. Caddy is managed from its own repository and must already provide the external caddy_proxy network.
Documentation workflow
CAPABILITY-MAP.mdis the approved Phase 0 decomposition.- Each capability receives a spec before implementation.
- Surprising or hard-to-reverse decisions receive an ADR in
docs/decisions/. - Raw datasets and database state are never committed.
- Every material change is a small Conventional Commit.
Platform operations documents
docs/PLATFORM-OPERATIONS-SPEC.mddefines the production topology and is amended by ADR 0006 for the shared Caddy ingress.docs/QLOCKIFY-ADAPTATION-CONTRACT.mdmaps Qlockify's tracked deployment files and environment layout to the planned ZarinPal artifacts without requiring real server values during planning.docs/runbooks/FIRST-SERVER-BOOTSTRAP.mddefines the safe first-host sequence without implementing a bootstrap script.docs/runbooks/BACKUP-RESTORE.mddefines logical PostgreSQL backup, encryption/retention, guarded restore, and rehearsal.tasks/plan.mdandtasks/todo.mdhold the approved implementation plan and dependency-ordered Phase 4 tasks.