- db-backup sidecar: pg_dump -Fc of procurement+casdoor every BACKUP_INTERVAL_SECONDS into BACKUP_DIR, retention via BACKUP_KEEP_DAYS - audit_log table (migration.sql + runtime ensure_audit_table) with model + transactional helper (utils/audit.record) — wired into user create/role-change and inventory transaction creation - get_actor: quote_events.actor now stores the VERIFIED user's display name instead of the raw bearer token
Deploy webhook receiver (push-to-deploy, hardened)
Every push to the production branch triggers a rebuild on the VPS through
this receiver (host port 9000). The receiver must verify the Gitea
webhook signature — an open deploy endpoint is effectively remote code
execution on the production server.
VPS setup (one time)
# 1) Files live here:
sudo mkdir -p /srv/erp && sudo chown $USER /srv/erp
# copy the repo to /srv/erp (the receiver runs docker compose in this dir)
# 2) Secrets — add to /srv/erp/.env (git-ignored):
# GITEA_WEBHOOK_SECRET=<long random string>
# 3) Install as a systemd service:
sudo cp infra/deploy-webhook/erp-deploy-webhook.service /etc/systemd/system/
# adjust User= and paths inside, then:
sudo systemctl daemon-reload
sudo systemctl enable --now erp-deploy-webhook
curl http://127.0.0.1:9000/ping # → {"status":"ok"}
Gitea webhook
Repo → Settings → Webhooks → Add webhook → Gitea:
- Target URL:
http://<server-ip>:9000/deploy - Method:
POST— Secret: same value asGITEA_WEBHOOK_SECRET - Trigger: Push Events, Branch filter:
production
Behavior
- Verifies
X-Gitea-Signature(HMAC-SHA256) — rejects everything else with 401. - Only pushes to
refs/heads/productiondeploy; other branches are acknowledged and ignored. - Deploys are serialized with a lock (concurrent pushes don't race).
- Runs
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d --buildin/srv/erp. - After a successful build, polls the API
/health/readyendpoint and logs a failed post-deploy check (surfaced by the monitoring stack). - Logs to journald (
journalctl -u erp-deploy-webhook -f).