Skip to content

v2.0 — Multi-tenant + Docker deploy 🚀

Choose a tag to compare

@dripips dripips released this 12 May 22:18

v2.0 — Multi-tenant foundation + Docker deploy story

Major architectural shift: foundation for hosting multiple companies on one HRMS instance + production-grade Docker deployment.

🏢 Multi-tenant routing

  • Each company can have a subdomain (e.g. `acme`)
  • HRMS at `https://acme.hrms.example.com\` → `Current.company = Company.find_by(subdomain: "acme")`
  • `https://hrms.example.com\` → falls back to first company (single-tenant compatibility)
  • Subdomain `acme.hrms.example.com` with no matching company → 404 (JSON for API, HTML for browser)
  • `IGNORED_SUBDOMAINS = [www, api, app]` → marketing pages keep working

Setting up: superadmin sets the subdomain in Settings → Коммуникации → 🏢 Subdomain компании. Validation: `[a-z0-9-]{1,50}`.

Migration path: 6 hot files (introduced in v1.6+) now use `Current.company` / `current_company` helper. 14 legacy callsites still use `Company.kept.first` — they work via fallback and will migrate incrementally in v2.1.

🐳 Docker deploy

  • `scripts/update.sh` — zero-downtime upgrade:
    1. Backup DB + storage (auto-calls `scripts/backup.sh`)
    2. `git checkout` to target tag (or latest master)
    3. `docker compose build` new image
    4. Migrations run on new image BEFORE container swap (no broken intermediate state)
    5. Rolling restart of `app` + `worker`
    6. Healthcheck loop on `/up` for 60s
    7. On failure: prints rollback command
  • `docker-compose.prod.yml` override:
    • Pre-built image (`APP_IMAGE=ghcr.io/...`) instead of local build
    • Healthcheck on app container
    • PostgreSQL tuning: shared_buffers 512MB, work_mem 16MB
    • JSON-file logging with rotation
    • Puma: 3 workers × 10 threads

Run with: `docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d`

Migration

  • `companies.subdomain` (unique partial index, nullable)

i18n

  • +6 keys × 3 locales

Quality

  • Zeitwerk: clean
  • 120 specs, 0 failures
  • Rubocop: 0 offenses on 255 files

Next: v2.1 (incremental tenant refactor)

  • Replace remaining 14 legacy `Company.kept.first` callsites
  • Test multi-tenant flow end-to-end with two real tenants
  • Per-tenant settings ownership (one company can't read another's AppSetting)