Demo

Deployment

Bootstrap the host with ./install.sh (or installation/installation.sh), run Quan ERP with Docker Compose, ship plugins from build → available → installed, and harden staging / production.

Overview

Quark ERP / Quan ERP deploys as a base stack (Postgres, Redis, backend, frontend) plus versioned plugins. On a fresh server, use the install script to prepare Docker, Nginx, and start compose. You develop plugins under plugins/, build them into available-plugins/, then activate them through the ERP UI into installed-plugins/. The base images and @quan-erp/* packages must stay on the same version line.

  • installation/ — ./install.sh (or installation.sh) for host bootstrap + compose start/stop
  • docker-compose.yaml — Postgres, Redis, backend, frontend
  • plugins/ — source; quan-erp CLI builds into available-plugins/
  • ERP UI install — copies / activates into installed-plugins/
  • Never SQL-seed the module table against UAT or production

1. Host bootstrap (./install.sh)

Server deployments ship an installation helper next to the production docker-compose.yaml (folder installation/). Run it as a normal user — not with sudo / as root. The script installs Docker Engine, the Compose plugin, and Nginx, then can start or stop the stack.

  • Commands: install | start | stop (see ./install.sh --help)
  • Do not run as root — the script uses sudo only where needed (packages, systemctl, docker group)
  • install — detects Ubuntu/Debian or RHEL-family, installs Docker + Compose plugin + Nginx, enables services, adds your user to the docker group
  • start — docker compose up -d for the stack next to installation/
  • stop — docker compose stop for the same compose file
  • Supported OS: Ubuntu, Debian, RHEL, CentOS, Fedora, Rocky, AlmaLinux
  • After install, you may need a new shell (or re-login) so the docker group membership applies without sudo
SHTerminal
1cd installation 2chmod +x ./install.sh # or ./installation.sh 3 4# One-time host setup (Docker + Compose + Nginx) 5./install.sh install 6 7# Start compose services 8./install.sh start 9 10# Stop compose services 11./install.sh stop

2. Base stack (Docker Compose)

For local template work, start under base/ with compose directly. On a server prepared with ./install.sh, prefer ./install.sh start so host helpers run before up -d. The example stack is four services on a shared bridge network: db (Postgres), redis, backend, and frontend. Backend talks to Postgres and Redis by compose service name.

  • Inside containers, hosts are compose service names (db, redis) — never localhost for cross-service traffic
  • Typical volumes: ./data (db / redis / app data), ./available-plugins, ./backend/installed-plugins, ./backend/logs
  • Match BASE_VERSION / image tags (base-backend, base-frontend) with plugin @quan-erp/* versions
  • Template passwords and token secrets are for local/dev only — rotate before any shared environment
SHLocal template
cd base docker compose up -d docker compose ps
SHServer (via install script)
cd installation ./install.sh start ./install.sh stop

2b. Example docker-compose.yaml

Copy this local/dev template, then replace every change-me value, set VITE_BACKEND_API to a browser-reachable URL, and point image tags / BASE_VERSION at your release line. Backend connects directly to Postgres (db:5432).

  • DATABASE_HOST / DB_HOST=db and DB_PORT=5432 — direct Postgres, no pooler in this template
  • Optional: OPENAI_* / FIREBASE_CONFIG — set only when those integrations are required; never commit real private keys
YAMLdocker-compose.yaml
1services: 2 db: 3 image: postgres:17 4 container_name: postgres 5 restart: always 6 environment: 7 POSTGRES_USER: postgres 8 POSTGRES_PASSWORD: change-me 9 POSTGRES_DB: quan-erp 10 ports: 11 - "5432:5432" 12 volumes: 13 - ./data/db-data:/var/lib/postgresql/data 14 networks: 15 - app-network 16 17 redis: 18 image: redis:7 19 container_name: quanerp-redis 20 restart: unless-stopped 21 ports: 22 - "6379:6379" 23 command: > 24 redis-server 25 --requirepass "change-me" 26 --appendonly yes 27 volumes: 28 - ./data/redis:/data 29 networks: 30 - app-network 31 healthcheck: 32 test: ["CMD", "redis-cli", "ping", "-a", "change-me"] 33 interval: 5s 34 timeout: 2s 35 retries: 5 36 37 backend: 38 build: 39 context: ./backend 40 dockerfile: Dockerfile 41 image: theparadance/quan-erp-base-backend:1.0.0 42 restart: unless-stopped 43 platform: linux/amd64 44 container_name: backend 45 ports: 46 - "8080:8080" 47 - "8081:8081" 48 environment: 49 NODE_ENV: production 50 MODE: dev 51 BASE_VERSION: 1.0.0 52 ORGANIZATION_ID: quan-erp 53 54 FRONTEND_URL: http://localhost 55 BACKEND_URL: http://localhost:8080 56 DEV_TOOL_URL: http://localhost:8081 57 PLUGIN_SERVER_URL: http://localhost:8082 58 59 ACCESS_TOKEN_SECRET: change-me 60 ACCESS_TOKEN_SECRET_EXPIRATION_TIME: 15m 61 REFRESH_TOKEN_SECRET: change-me 62 REFRESH_TOKEN_SECRET_EXPIRATION_TIME: 30d 63 64 DATABASE_HOST: db 65 DB_HOST: db 66 DB_USERNAME: postgres 67 DB_PASSWORD: change-me 68 DB_PORT: 5432 69 DB_SCHEMA: quan-erp 70 DB_SYNC: true 71 72 REDIS_HOST: redis 73 REDIS_PORT: 6379 74 REDIS_PASSWORD: change-me 75 76 CLUSTER_MODE: false 77 CLUSTER_MAX_COUNT: 2 78 ENV_ENCRYPTION_KEY: change-me-32-char-hex-or-secret 79 FIREBASE_CONFIG: '' 80 81 OPENAI_BASE_URL: https://api.deepseek.com 82 OPENAI_API_KEY: <sk-key> 83 84 CORS_ALLOWED_ORIGINS: http://localhost:3000,http://127.0.0.1:3000,http://localhost,https://localhost 85 86 AVAILABLE_PLUGINS_FOLDER: /app/available-plugins 87 INSTALLED_PLUGINS_FOLDER: /app/installed-plugins 88 APP_DATA_FOLDER: /app/data/data/ 89 UPLOAD_FILE_TEMP_FOLDER: /app/data/temp 90 UPLOAD_FILE_FOLDER: /app/data/data/ 91 PLUGINS_ENV_FILE: /app/data/data/plugin.env.json 92 RUNNER_FLOW_FILE: /app/data/data/workflows/ 93 94 ROOT_ADMIN_USERNAME: admin 95 ROOT_ADMIN_PASSWORD: change-me 96 DEVELOPER_CONFIG_PASSWORD: change-me 97 98 MAX_USER_LIMIT: 5 99 MAX_ACTIVE_USER_LIMIT: 5 100 MAX_USER_SESSION_LIMIT_PER_USER: 1 101 MAX_ORGANIZATION_BRANCH: 1 102 MAX_ROLE_LIMIT: 5 103 MAX_SUBSCRIPTION_GRACE_PERIOD_DAYS: 14 104 SUBSCRIPTION_END_DATE: '2099-01-01' 105 volumes: 106 - ./backend/installed-plugins:/app/installed-plugins 107 - ./data:/app/data 108 - ./backend/logs:/app/logs 109 - ./available-plugins:/app/available-plugins 110 depends_on: 111 - db 112 - redis 113 networks: 114 - app-network 115 dns: 116 - 1.1.1.1 117 - 8.8.8.8 118 119 frontend: 120 build: 121 context: ./frontend 122 dockerfile: Dockerfile 123 image: theparadance/quan-erp-base-frontend:1.0.0 124 restart: unless-stopped 125 platform: linux/amd64 126 container_name: frontend 127 environment: 128 VITE_BACKEND_API: http://localhost:8080 129 VITE_MODE: dev 130 ports: 131 - "80:80" 132 volumes: 133 - ./data/frontend/web-env.json:/usr/share/nginx/html/web-env.json 134 networks: 135 - app-network 136 137networks: 138 app-network: 139 driver: bridge

3. Services & ports

Default template wiring (adjust for your host / reverse proxy). Prefer not publishing db / redis to the public internet on real servers.

  • db (postgres:17) — host 5432 → container 5432; backend sets DATABASE_HOST / DB_HOST=db and DB_PORT=5432; POSTGRES_DB / schema quan-erp; volume ./data/db-data
  • redis — host 6379 → 6379; REDIS_HOST=redis with REDIS_PASSWORD; volume ./data/redis
  • backend — :8080 (BACKEND_URL / API), :8081 (DEV_TOOL_URL); volumes for available-plugins, installed-plugins, ./data, logs
  • frontend — :80; set VITE_BACKEND_API to a URL the browser can reach (LAN IP or public hostname, not only localhost inside Docker)
  • Nginx on the host — installed by ./install.sh install for TLS / reverse proxy in front of frontend (and optionally API)

4. Deploy plugins

Plugins are not baked into the base images. Build them, stage them as available, then install through the product UI (or distribute a pack archive).

  • Build output → available-plugins/<name>/<version>/ (or base/available-plugins/ in the Node template)
  • After UI install → installed-plugins/<name>/ (or base/backend/installed-plugins/)
  • Backend loads installed plugins whose module row is marked installed
  • Frontend loads each installed plugin’s module.js and calls register(AppRegistry)
  • Local/dev only: insert a module row so the plugin appears in the UI — never against UAT/prod
TSBuild & stage
1# From repo root 2quan-erp build:prod sample-es 3# Continuous during development 4quan-erp watch sample-es 5 6# Distributable zip (frontend + backend + metadata) 7quan-erp pack:prod sample-es 8quan-erp pack:prod sample-es ./dist-archives

5. Version alignment

Keep the platform and plugins on one version line to avoid runtime breaks.

  • All @quan-erp/* deps in plugin package.json share the same version as the base images
  • docker-compose image tags (base-backend, base-frontend) and BASE_VERSION stay in sync
  • module.metadata.json pluginVersion / requiredBasedVersion must match what you built and install
  • After upgrading base images, rebuild plugins against the matching @quan-erp/* packages

6. Environment configuration

Infrastructure settings come from compose environment blocks (and optional .env). Plugin-specific operator settings use @InjectEnv and should not require a redeploy when changed from the ERP UI. See Documentation → Backend → Environment variables for the full key list.

  • DB_* / DATABASE_HOST — use db (port 5432) in the example stack; DB_SCHEMA matches POSTGRES_DB (e.g. quan-erp)
  • REDIS_HOST / REDIS_PORT / REDIS_PASSWORD — must match the redis service requirepass
  • ACCESS_TOKEN_* / REFRESH_TOKEN_* / ENV_ENCRYPTION_KEY — rotate away from template values
  • CORS_ALLOWED_ORIGINS — comma-separated browser origins (include http://LAN-IP and https://hostname as needed)
  • FRONTEND_URL / BACKEND_URL / DEV_TOOL_URL / VITE_BACKEND_API — URLs browsers and peers can actually reach
  • AVAILABLE_PLUGINS_FOLDER / INSTALLED_PLUGINS_FOLDER / APP_DATA_FOLDER / PLUGINS_ENV_FILE — paths inside the backend container, backed by host volumes
  • BASE_VERSION + image tags — keep aligned with plugin @quan-erp/* versions
  • DB_SYNC — fine for early local/dev; use migrations for staging/production schema changes
  • MODE — template often uses dev; production deployments should use the intended production mode

7. Staging & production checklist

Treat the template compose file as a starting point, not a finished production config.

  • Run ./install.sh install on a clean Linux host before first start
  • Change all default passwords (Postgres, Redis, ROOT_ADMIN_*, DEVELOPER_CONFIG_PASSWORD) and token / encryption secrets
  • Do not publish Postgres or Redis ports publicly; terminate TLS on Nginx (or another reverse proxy)
  • Persist ./data, installed-plugins, available-plugins, and logs on durable volumes / backups
  • Disable unsafe defaults (example secrets, open CORS, DB_SYNC=true, weak mem_limit on production workloads) before go-live
  • Ship plugins via pack / available-plugins + UI install — do not SQL-seed modules on prod
  • Run TypeORM migrations for schema changes; do not rely on synchronize in production
  • Confirm FRONTEND_URL, BACKEND_URL, and VITE_BACKEND_API match the public hostnames (not a private LAN IP unless that is intentional)
  • Align base image tags and plugin @quan-erp/* versions before upgrading
  • Never commit real FIREBASE_CONFIG private keys, npm tokens, or production passwords into compose files checked into git

8. Day-2 operations

  • Start / stop stack: cd installation && ./install.sh start|stop
  • Update base: pull/build new base-backend / base-frontend tags → recreate containers
  • Update a plugin: quan-erp build:prod|pack:prod → place under available-plugins → install / upgrade in UI
  • Health: docker compose ps; check backend logs
  • Data: back up Postgres volume and APP_DATA_FOLDER regularly
  • Rollback: keep previous plugin version folders and image tags until the new release is verified
YAMLUseful compose commands
1cd installation # or cd base for the Node template 2docker compose logs -f backend 3docker compose restart backend frontend 4docker compose down 5./install.sh start

Troubleshooting

  • ./install.sh install fails — unsupported OS, missing sudo, or Docker repo not reachable; install Docker manually if needed
  • docker: permission denied — log out/in after install so the docker group applies
  • start fails — ensure POSTGRES_* / REDIS_* and image tags exist in docker-compose.yaml
  • Backend cannot reach DB — DATABASE_HOST / DB_HOST must be db, DB_PORT=5432; not localhost
  • Frontend cannot call API — VITE_BACKEND_API must be a browser-reachable host (LAN IP / public URL), not only an in-compose hostname
  • Plugin missing in UI — not in available-plugins, wrong version folder, or module row missing (local only)
  • Installed but UI blank — frontend dist / module.js not copied; rebuild and reinstall
  • Auth / CORS failures — FRONTEND_URL and CORS_ALLOWED_ORIGINS must include the browser origin
  • Version errors after upgrade — base image tag and plugin @quan-erp/* packages out of sync

Need help with deployment?

If you run into trouble deploying Quark ERP, you can get support from The Paradance. Help may be free or billed as an additional charge depending on the case — scope, urgency, and environment.

  • Include BASE_VERSION / image tags, OS, compose logs, and steps to reproduce
  • Simple guidance may be free; hands-on setup, production hardening, or custom ops work may be charged
  • We confirm free vs paid before starting paid work