Ronni Baslund 861212831d
ci / typecheck (map[dir:apps/booking name:booking]) (push) Has been cancelled
ci / typecheck (map[dir:apps/portal name:portal]) (push) Has been cancelled
ci / typecheck (map[dir:apps/website name:website]) (push) Has been cancelled
ci / typecheck (map[dir:services/platform-api name:platform-api]) (push) Has been cancelled
ci / test (push) Has been cancelled
fix(infra): restic→Storage Box backups working end-to-end
Three fixes found bringing up backups on node1:
- restic.env wrote BACKUP_PATHS/RETENTION unquoted → sourcing ran a path as a
  command ("Is a directory"); now quoted.
- ssh config was written to $BACKUP_HOME/.ssh/config, but restic runs as root
  and its ssh resolves ~ from the passwd db (not $HOME), so it reads
  /root/.ssh/config — write the Storage Box block there. Also
  StrictHostKeyChecking=no + UserKnownHostsFile=/dev/null (safe: restic encrypts
  before upload; fixes flaky Storage Box host-key verification).
- Storage Box SFTP lands in /home, so the repo path needs the /home prefix
  (absolute /dezky hit the root-owned chroot parent → SSH_FX_FAILURE).

Verified: repo initialized, nightly snapshot of mail store + Stalwart config +
etcd snapshots + dumps dir, `restic check` clean, retention applied.
2026-06-08 21:46:49 +02:00

Dezky

Sovereign workspace platform for European businesses. Mail, files, calendar, video meetings — all EU-hosted, all open source.

Quick start (local development)

# 1. Clone and enter
git clone <repo-url> dezky
cd dezky

# 2. Run bootstrap (handles everything)
./scripts/bootstrap.sh

# 3. Open the portal
open https://app.dezky.local

The bootstrap script:

  • Checks prerequisites (Docker, mkcert, openssl)
  • Generates wildcard TLS certificate via mkcert
  • Adds /etc/hosts entries (with your permission)
  • Generates secure random secrets in .env
  • Pulls Docker images
  • Starts all services in correct order
  • Prints next-step instructions

Service URLs (local development)

Service URL Purpose
Portal https://app.dezky.local Customer-facing landing & launcher
Authentik https://auth.dezky.local Identity provider (OIDC/SAML)
Files (OCIS) https://files.dezky.local File storage & sharing
Mail (Stalwart) https://mail.dezky.local Mail server admin UI
Office https://office.dezky.local Collabora Online editor
Traefik https://traefik.dezky.local Reverse proxy dashboard

What's in this repo

dezky/
├── apps/portal/                Nuxt 3 customer portal
├── services/platform-api/      NestJS service · tenants, partners, users, provisioning orchestration
├── packages/                   Shared TypeScript libraries
├── infrastructure/
│   └── docker-compose/         Local development stack
├── scripts/                    Setup, reset, helpers
└── docs/                       Service references & guides

Prerequisites

  • macOS or Linux (Windows users: use WSL2)
  • Docker Desktop 24+ or OrbStack
  • mkcert (brew install mkcert)
  • pnpm 9+ (brew install pnpm)
  • Node.js 20+
  • 16 GB RAM recommended

Common commands

# Start everything
docker compose -f infrastructure/docker-compose/docker-compose.yml up -d

# View logs
docker compose -f infrastructure/docker-compose/docker-compose.yml logs -f [service]

# Stop everything (keeps data)
docker compose -f infrastructure/docker-compose/docker-compose.yml down

# Nuke and restart (DESTROYS DATA)
./scripts/reset.sh

Architecture

This is a multi-tenant SaaS platform. Each tenant gets:

  • Isolated Authentik OIDC tenant
  • Custom subdomain (e.g. customer-name.dezky.local)
  • Mail domain in Stalwart with auto-generated DKIM
  • Dedicated OCIS space hierarchy
  • Branded launcher in the portal

All components are Apache 2.0 / MIT licensed — no per-seat fees, full whitelabel rights.

Production

The production target is a single Hetzner AX41-NVMe server (€39/mo) with:

  • Stalwart on bare-metal
  • k3s for all other services
  • Hetzner Object Storage (€5/mo) as OCIS S3 backend
  • Storage Box BX11 (€3.20/mo) for Restic backups
  • Storage Box BX11 in Helsinki (€3.20/mo) for DR

See docs/PRODUCTION-DEPLOYMENT.md (TBD) for migration plan.

Stack rationale

These choices are deliberate after extensive license/architecture research. See CLAUDE.md for the full reasoning.

Component License Why this one
Stalwart Mail Apache 2.0 Modern Rust, ActiveSync built-in, JMAP support
OCIS Apache 2.0 Cleaner license than Nextcloud (AGPL+trademark)
Zulip Apache 2.0 Only truly open-core-free chat option
Authentik MIT Better multi-tenancy than Keycloak
Hetzner N/A 100% EU sovereignty — core to business

License

Application code: MIT (own code) Third-party services: see individual service licenses in stack.

S
Description
No description provided
Readme 3.4 MiB
Languages
Vue 53.5%
TypeScript 42%
Shell 2.4%
CSS 0.5%
PHP 0.5%
Other 1.1%