Skip to content

PLAN: Monorepo + Coolify Deployment

+======================================================================+
| |
| ███╗ ███╗ ██████╗ ███╗ ██╗ ██████╗ |
| ████╗ ████║██╔═══██╗████╗ ██║██╔═══██╗ |
| ██╔████╔██║██║ ██║██╔██╗ ██║██║ ██║ |
| ██║╚██╔╝██║██║ ██║██║╚██╗██║██║ ██║ |
| ██║ ╚═╝ ██║╚██████╔╝██║ ╚████║╚██████╔╝ |
| ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═══╝ ╚═════╝ |
| |
| R E P O + C O O L I F Y D E P L O Y M E N T |
| |
| Magic e-VERSE Commerce Platform |
| Monorepo + Feature Flags + Automated Deployments |
| |
| Status: IN PROGRESS (Phase 2b Complete) |
| Prioriteit: Hoog |
| Impact: Alle commerce tenants |
| |
+======================================================================+

Dit plan migreert de Magic Commerce multi-tenant omgeving van 8+ losse tenant-kopieën met handmatige code-distributie naar een single Git monorepo met feature flags en geautomatiseerde deployments via Coolify op een dedicated Hostinger KVM 4 server.


┌──────────────────────────────────────────────────────────────────┐
│ HUIDIGE ARCHITECTUUR │
│ Handmatige Copy/Paste │
├──────────────────────────────────────────────────────────────────┤
│ │
│ magic_development/ ──── cp ────► magic_brinxx/ │
│ │ magic_default/ │
│ │ (handmatig) magic_jodasign/ │
│ │ magic_logohorloge/ │
│ └── bestanden kopiëren ──► magic_bovisales/ │
│ magic_demo/ │
│ magic_desluis/ │
│ │
│ Problemen: │
│ ✗ Geen versiegeschiedenis │
│ ✗ Geen rollback mogelijk │
│ ✗ Handmatig kopiëren = foutgevoelig │
│ ✗ Geen preview van wijzigingen │
│ ✗ Tenant-specifieke code moeilijk te beheren │
│ ✗ Geen CI/CD pipeline │
│ │
└──────────────────────────────────────────────────────────────────┘
┌──────────────────────────────────────────────────────────────────┐
│ NIEUWE ARCHITECTUUR │
│ Monorepo + Coolify │
├──────────────────────────────────────────────────────────────────┤
│ │
│ GitHub: magic-commerce (1 repo) │
│ │ │
│ ├── push to main ──► Coolify auto-deploy ──► Production │
│ ├── open PR ───────► Coolify preview ──────► Preview URL │
│ │ │
│ ▼ │
│ Hostinger KVM 4 (Coolify) │
│ ┌────────────────────────────────────────────────────────────┐ │
│ │ Coolify Dashboard │ │
│ │ ├── Traefik (auto-SSL, auto-routing) │ │
│ │ ├── PostgreSQL (shared, per-tenant databases) │ │
│ │ ├── Project: Brinxx (backend + storefront + redis) │ │
│ │ ├── Project: Default (backend + storefront + redis) │ │
│ │ ├── Project: Jodasign (backend + storefront + redis) │ │
│ │ └── ... (1 project per tenant) │ │
│ └────────────────────────────────────────────────────────────┘ │
│ │
│ Voordelen: │
│ ✓ Volledige versiegeschiedenis │
│ ✓ Instant rollback naar elke versie │
│ ✓ Auto-deploy bij push naar main │
│ ✓ Preview URLs bij pull requests │
│ ✓ Feature flags = licentiesysteem │
│ ✓ Nieuwe klant = nieuw Coolify project + env vars │
│ │
└──────────────────────────────────────────────────────────────────┘

Het hart van het nieuwe systeem is één Git repository die alle tenant-code bevat:

magic-commerce/
├── backend/ # Medusa v2 backend (één codebase)
│ ├── Dockerfile
│ ├── medusa-config.ts # Configuratie via environment variables
│ ├── package.json
│ └── src/
│ ├── features/ # Feature flag systeem
│ │ ├── flags.ts # Feature definities + tier levels
│ │ └── index.ts # isFeatureEnabled(), featureGuard()
│ ├── admin/routes/ # Admin panel routes (gedeeld)
│ ├── api/ # API routes (gedeeld)
│ ├── modules/ # Medusa modules
│ ├── utils/ # Utilities
│ └── workflows/ # Business workflows
├── storefront/ # Next.js storefront (één codebase)
│ ├── Dockerfile
│ ├── package.json
│ └── src/
│ ├── lib/features.ts # Client-side feature checks
│ └── themes/ # Theme systeem
│ ├── base/ # Gedeelde basis CSS
│ ├── brinxx/ # Brinxx override CSS
│ ├── default/ # Default override CSS
│ └── ...
├── tenants/ # Referentie-configuratie per tenant
│ ├── brinxx/tenant.json
│ ├── default/tenant.json
│ ├── jodasign/tenant.json
│ └── ...
├── docker-compose.yml # Lokale development
└── .gitignore

Het feature flag systeem doet dubbel dienst: het controleert welke features actief zijn per tenant én functioneert als licentiesysteem.

┌─────────────────────────────────────────────────────────────┐
│ LICENTIE TIERS │
├─────────────────────────────────────────────────────────────┤
│ │
│ STARTER │
│ ├── Offertes (quotations) │
│ ├── Orders │
│ ├── Klanten │
│ ├── Producten │
│ └── CMS │
│ │
│ PROFESSIONAL (alles van Starter +) │
│ ├── Facturen (invoices) │
│ ├── Creditnota's │
│ ├── Betalingen │
│ └── Rapportages │
│ │
│ ENTERPRISE (alles van Professional +) │
│ ├── CRM │
│ ├── Abonnementen │
│ ├── Merk Wizard │
│ ├── Vertalingen (i18n) │
│ └── Leverancier Connectors │
│ │
│ ADD-ONS (los in te schakelen per tenant) │
│ ├── 2D Designer (logohorloge) │
│ ├── Externe Designer (spranz) │
│ ├── Offerte Bronfilter (jodasign) │
│ ├── Techniek Prijzen │
│ ├── Pagina Manager │
│ └── Menu Manager │
│ │
└─────────────────────────────────────────────────────────────┘
backend/src/features/flags.ts
export enum Feature {
// Core (alle tiers)
QUOTATIONS = 'quotations',
ORDERS = 'orders',
INVOICES = 'invoices',
CUSTOMERS = 'customers',
PRODUCTS = 'products',
CMS = 'cms',
// Professional
CREDIT_NOTES = 'credit_notes',
PAYMENTS = 'payments',
REPORTS = 'reports',
// Enterprise
CRM = 'crm',
SUBSCRIPTIONS = 'subscriptions',
BRAND_WIZARD = 'brand_wizard',
TRANSLATIONS = 'translations',
CONNECTORS = 'connectors',
// Add-ons
QUOTATION_SOURCE_FILTER = 'quotation_source_filter',
DESIGNER_2D = 'designer_2d',
DESIGNER_EXTERNAL = 'designer_external',
TECHNIQUE_PRICING = 'technique_pricing',
PAGE_MANAGER = 'page_manager',
MENU_MANAGER = 'menu_manager',
}
export type Tier = 'starter' | 'professional' | 'enterprise';
const TIER_FEATURES: Record<Tier, Feature[]> = {
starter: [
Feature.QUOTATIONS, Feature.ORDERS, Feature.CUSTOMERS,
Feature.PRODUCTS, Feature.CMS,
],
professional: [
// ...starter features included automatically
Feature.INVOICES, Feature.CREDIT_NOTES,
Feature.PAYMENTS, Feature.REPORTS,
],
enterprise: [
// ...professional features included automatically
Feature.CRM, Feature.SUBSCRIPTIONS, Feature.BRAND_WIZARD,
Feature.TRANSLATIONS, Feature.CONNECTORS,
],
};
backend/src/features/index.ts
const tier = (process.env.TENANT_TIER || 'starter') as Tier;
const extraFeatures = (process.env.TENANT_FEATURES || '')
.split(',')
.filter(Boolean);
export function isFeatureEnabled(feature: Feature): boolean {
const tierFeatures = getTierFeatures(tier);
if (tierFeatures.includes(feature)) return true;
return extraFeatures.includes(feature);
}
export function featureGuard(feature: Feature) {
return (req, res, next) => {
if (!isFeatureEnabled(feature)) {
return res.status(403).json({ message: 'Feature not available in current license' });
}
next();
};
}
// Voor admin sidebar: geeft lijst van actieve features
export function getEnabledFeatures(): Feature[] {
return Object.values(Feature).filter(f => isFeatureEnabled(f));
}
storefront/src/lib/features.ts
const enabledFeatures = (process.env.NEXT_PUBLIC_TENANT_FEATURES || '').split(',');
export function hasFeature(feature: string): boolean {
return enabledFeatures.includes(feature);
}
// Backend: API route beschermen
app.use('/admin/aplt/credit-notes',
featureGuard(Feature.CREDIT_NOTES),
creditNotesRouter
);
// Backend: Admin sidebar items conditioneel tonen
if (isFeatureEnabled(Feature.DESIGNER_2D)) {
registerAdminRoute('designer-2d', Designer2DPage);
}
// Storefront: Component conditioneel renderen
{hasFeature('designer_2d') && <Mini2DPreview product={product} />}

Features worden geconfigureerd via environment variables in Coolify — niet in code:

# Coolify → Project: Brinxx → Service: Backend → Environment Variables
TENANT_ID=brinxx
TENANT_TIER=enterprise
TENANT_FEATURES=technique_pricing,brand_wizard

De tenants/brinxx/tenant.json in de repo dient als referentie/documentatie:

{
"id": "brinxx",
"name": "Brinxx",
"domain": "brinxx.magiceverse.online",
"adminDomain": "admin-brinxx.magiceverse.online",
"theme": "brinxx",
"tier": "enterprise",
"features": {
"technique_pricing": true,
"brand_wizard": true,
"designer_2d": false
}
}

Coolify is een open-source, self-hosted Platform-as-a-Service (PaaS) — vergelijkbaar met Vercel/Heroku maar op je eigen server. Het vervangt handmatige DevOps met een visueel dashboard.

HandmatigCoolify
GitHub Actions workflows schrijvenIngebouwde auto-deploy bij push
Traefik/Nginx configuratie beherenIngebouwde Traefik, automatisch geconfigureerd
Let’s Encrypt scriptsAutomatische SSL-certificaten
SSH deploy scriptsDocker deployment via UI
Preview omgeving scriptsIngebouwde PR preview deployments
Docker Compose op VPS beherenCoolify beheert Docker Compose stacks
.env bestanden op serverEnvironment variables in Coolify UI
Log bestanden doorzoekenIngebouwde log viewer
Monitoring opzettenIngebouwde health checks & notificaties
┌──────────────────────────────────────────────────────────────────┐
│ COOLIFY DASHBOARD │
├──────────────────────────────────────────────────────────────────┤
│ │
│ Project: "Shared Infrastructure" │
│ ├── PostgreSQL 16 (gedeeld door alle tenants) │
│ └── Auth Service (centraal, fase 2) │
│ │
│ Project: "Brinxx" tier: enterprise │
│ ├── Backend (magic-commerce repo, /backend) │
│ │ └── Domain: admin-brinxx.magiceverse.online │
│ ├── Storefront (magic-commerce repo, /storefront) │
│ │ └── Domain: brinxx.magiceverse.online │
│ ├── Redis 7 │
│ └── Meilisearch │
│ │
│ Project: "Default" tier: starter │
│ ├── Backend (zelfde repo, andere env vars) │
│ ├── Storefront (zelfde repo, ander thema) │
│ ├── Redis 7 │
│ └── Meilisearch │
│ │
│ Project: "Jodasign" tier: professional │
│ ├── Backend (+ add-on: quotation_source_filter) │
│ ├── Storefront │
│ ├── Redis 7 │
│ └── Meilisearch │
│ │
│ ... (1 project per tenant) │
│ │
└──────────────────────────────────────────────────────────────────┘

Backend service (per tenant):

SettingWaarde
SourceGitHub repo magic-commerce
Build Path/backend
Dockerfile/backend/Dockerfile
Domainadmin-{tenant}.magiceverse.online
Auto-deployAan (bij push naar main)
PreviewAan (bij PR)

Environment variables (per tenant in Coolify):

# Database
DATABASE_URL=postgres://postgres:xxx@postgres:5432/magic_b2b_{tenant}
REDIS_URL=redis://redis:6379
# Tenant configuratie
TENANT_ID={tenant}
TENANT_TIER={starter|professional|enterprise}
TENANT_FEATURES={comma-separated add-ons}
# Security (unieke secrets per tenant!)
JWT_SECRET={gegenereerd-uniek-secret}
COOKIE_SECRET={gegenereerd-uniek-secret}
COOKIE_SECURE=true
COOKIE_SAMESITE=none
# Medusa
MEDUSA_BACKEND_URL=https://admin-{tenant}.magiceverse.online
STORE_CORS=https://{tenant}.magiceverse.online
ADMIN_CORS=https://admin-{tenant}.magiceverse.online
AUTH_CORS=https://admin-{tenant}.magiceverse.online

Storefront service (per tenant):

# Build-time arguments (Coolify → Build Settings)
NEXT_PUBLIC_THEME={tenant-theme}
NEXT_PUBLIC_MEDUSA_BACKEND_URL=https://admin-{tenant}.magiceverse.online
NEXT_PUBLIC_TENANT_FEATURES={comma-separated features}
NEXT_PUBLIC_BASE_URL=https://{tenant}.magiceverse.online

Developer pusht naar main
Coolify detecteert push (webhook)
├── Bouwt backend Docker image (per tenant)
├── Bouwt storefront Docker image (per tenant)
Containers worden vervangen (zero-downtime)
Database migraties draaien automatisch
✓ Live op production domain
Developer opent PR #42
Coolify detecteert PR (webhook)
├── Bouwt preview images
├── Maakt preview database (kopie van productie)
Preview beschikbaar op:
Admin: pr-42.preview.magiceverse.online
Store: store-pr-42.preview.magiceverse.online
PR gesloten → Coolify ruimt preview op

┌──────────────────────────────────────────────────────────────────┐
│ Huidige Auth: Verspreid │
├──────────────────────────────────────────────────────────────────┤
│ │
│ Portal → MySQL sessions + bcrypt + WhatsApp 2FA │
│ Medusa Tenant → JWT + cookie (JWT_SECRET=supersecret) ⚠️ │
│ Password Sync → Direct PostgreSQL UPDATE op alle databases │
│ │
│ Problemen: │
│ ✗ Elke tenant heeft eigen user tabel │
│ ✗ JWT_SECRET is overal hetzelfde ("supersecret") │
│ ✗ Password sync via directe DB queries │
│ ✗ Geen single sign-on │
│ │
└──────────────────────────────────────────────────────────────────┘
┌──────────────────────────────────────────────────────────────────┐
│ Nieuwe Auth: Gecentraliseerd │
├──────────────────────────────────────────────────────────────────┤
│ │
│ Auth Service (auth.magiceverse.online) │
│ ├── magic_auth database │
│ │ ├── auth_users (master user tabel) │
│ │ ├── auth_user_tenants (user ↔ tenant mapping) │
│ │ └── auth_sessions (sessie beheer) │
│ ├── Login + 2FA (WhatsApp) │
│ ├── Password management │
│ └── Session/JWT uitgifte │
│ │ │
│ ▼ │
│ Medusa Custom Auth Provider │
│ └── Valideert credentials tegen Auth Service │
│ │
│ Voordelen: │
│ ✓ Eén login voor alle tenants │
│ ✓ Unieke JWT secrets per tenant │
│ ✓ Wachtwoord wijziging werkt overal │
│ ✓ 2FA centraal beheerd │
│ ✓ User ↔ tenant permissies │
│ │
└──────────────────────────────────────────────────────────────────┘

  1. Fase 0: Documentatie

    Documentatiepagina geschreven en gepubliceerd.

  2. Fase 1: Monorepo + Git Setup

    • ✅ Nieuwe GitHub repo magic-commerce aangemaakt (privé, github.com/midego1/magic-commerce)
    • ✅ Code gekopieerd vanuit magic_development (huidige server niet aangeraakt)
    • medusa-config.ts gerefactord: hardcoded waarden → environment variables
    • ✅ Feature flag systeem geïmplementeerd (backend/src/features/)
    • ✅ Tenant referentie-configuraties aangemaakt
    • ✅ Eerste commit gepusht
  3. Fase 2: Coolify + Eerste Tenant (Brinxx)

    • ✅ Coolify geïnstalleerd op Contabo VPS (159.195.68.41, 12 cores, 32 GB RAM, 1 TB)
    • ✅ GitHub repo gekoppeld aan Coolify (via PAT)
    • ✅ PostgreSQL 16 gedeployed via Coolify
    • ✅ Brinxx database hersteld (pg_dump/pg_restore van huidige server)
    • ✅ Brinxx project aangemaakt: backend + storefront + Redis
    • ✅ Domeinen geconfigureerd: admin-brinxx.magicomniverse.online + brinxx.magicomniverse.online
    • ✅ Product images (28 GB) en uploads (3.8 GB) gemigreerd via bind mounts
    • ✅ Verificatie: admin panel, storefront, orders, APLT endpoints operationeel
  4. Fase 2b: Security & Monitoring

    • Magic Access gedeployed als Docker container met Traefik forwardAuth
    • ✅ IP whitelist (26 IPs), device tokens (14), en users (19) gemigreerd van oude server
    • ✅ WhatsApp 2FA blijft werken (MessageBird API)
    • ✅ Alle MySQL queries herschreven naar PostgreSQL — nul afhankelijkheid van oude server
    • ✅ Geblokkeerde pagina toont branded HTML met IP adres
    • Netdata monitoring geïnstalleerd met basicAuth login (monitor.magicomniverse.online)
    • ✅ PostgreSQL en Redis monitoring geconfigureerd
    • ✅ Per-container CPU/memory/network/disk tracking (alle 11 containers)
  5. Fase 3: Feature FlagsVOLGENDE STAP

    • Audit alle tenant-specifieke code paths in backend (custom API routes, admin extensions)
    • Flags integreren in admin sidebar (hide/show menu items)
    • Flags integreren in API routes (featureGuard middleware)
    • Flags integreren in storefront (conditionele componenten)
    • Testen: zelfde code met verschillende TENANT_TIER → verschillende features
    • Tenant configuraties valideren voor alle 8 tenants
  6. Fase 4: Remaining Tenants Deployen (week 4-5)

    • Overige tenants toevoegen als Coolify projecten (zelfde repo, andere env vars):
      • Default, Demo, Desluis, Bovisales
      • Jodasign (+ quotation_source_filter add-on)
      • Logohorloge (+ designer_2d add-on)
      • Spranz (+ designer_external add-on)
    • Per tenant: database restore, env vars, domein configuratie
    • Auto-deploy on push to main inschakelen
    • PR preview deployments inschakelen
  7. Fase 5: Productie Cutover

    • Finale data sync van oude server naar nieuwe server
    • DNS cutover per domein (oude server als fallback)
    • SSL certificaten automatisch via Let’s Encrypt/Traefik
    • Smoke test alle tenants
    • Geautomatiseerde backups opzetten (database dumps + image snapshots)
    • 1 week monitoren
    • Oude server uitfaseren

┌──────────────────────────────────────────────────────────────────┐
│ Contabo VPS — 159.195.68.41 │
│ Debian 13 | 12 cores | 32 GB RAM | 1 TB disk │
├──────────────────────────────────────────────────────────────────┤
│ │
│ Coolify Dashboard → http://159.195.68.41:8000 │
│ │
│ ┌── Traefik (coolify-proxy) ──────────────────────────────┐ │
│ │ :80 / :443 — auto-SSL via Let's Encrypt │ │
│ │ forwardAuth → magic-access (IP/token/session check) │ │
│ │ basicAuth → Netdata (separate login) │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │
│ Protected by Magic Access: │
│ ├── admin-brinxx.magicomniverse.online → Backend (:9000) │
│ ├── brinxx.magicomniverse.online → Storefront (:3000) │
│ └── access.magicomniverse.online → Login portal (:3334) │
│ │
│ Protected by basicAuth: │
│ └── monitor.magicomniverse.online → Netdata (:19999) │
│ │
│ Internal services: │
│ ├── PostgreSQL 16 (magic_b2b_brinxx + magic_access DBs) │
│ ├── Redis 7 (session cache) │
│ ├── Coolify app (deployment management) │
│ ├── Coolify Redis (Coolify internal) │
│ ├── Coolify DB (Coolify PostgreSQL) │
│ └── Coolify Realtime (websocket updates) │
│ │
│ Storage: │
│ ├── /data/magic-commerce/brinxx/static-products/ (28 GB) │
│ └── /data/magic-commerce/brinxx/uploads/ (3.8 GB) │
│ │
└──────────────────────────────────────────────────────────────────┘
WasNuStatus
MySQL users tabel op 83.86.98.93PostgreSQL magic_access.users op 159.195.68.41✅ Volledig gemigreerd
IP whitelist in Magic Access configGemigreerd naar nieuwe server✅ 26 IPs
Device tokensGemigreerd naar nieuwe server✅ 14 tokens
WhatsApp 2FA (MessageBird)Werkt onafhankelijk via API✅ Geen server dependency
Product imagesGekopieerd naar /data/magic-commerce/brinxx/✅ 28 GB
Databasepg_dump/pg_restore naar nieuwe PostgreSQL✅ Volledig

Conclusie: De nieuwe server is 100% zelfstandig. Geen enkele dependency op de oude server (83.86.98.93).


Na het opzetten van het systeem is een nieuwe klant toevoegen eenvoudig:

  1. Coolify: Nieuw project aanmaken met naam van de klant

  2. Services toevoegen: Backend + Storefront (beide vanuit dezelfde magic-commerce repo) + Redis + Meilisearch

  3. Environment variables instellen: TENANT_ID, TENANT_TIER, TENANT_FEATURES, DATABASE_URL, domeinen

  4. Database aanmaken: CREATE DATABASE magic_b2b_klantnaam;

  5. DNS instellen: klantnaam.magiceverse.online → Hostinger VPS IP

  6. Deploy — Coolify bouwt en deployt automatisch vanuit de repo


Na elke implementatiefase:

CheckBeschrijving
Admin PanelInloggen, alle menu items navigeren, order aanmaken/bewerken
StorefrontProducten browsen, winkelwagen, checkout flow
APIAPLT endpoints testen (orders, offertes, facturen, PDF generatie)
Feature FlagsUitgeschakelde features retourneren 403 / verbergen UI elementen
Auto-deployCode wijziging pushen, verifieer dat Coolify automatisch deployt
PreviewPR openen, verifieer dat Coolify preview omgeving aanmaakt
AuthEenmaal inloggen, toegang verifiëren over tenants (fase 4)

SpecificatieWaarde
vCPU4 cores
RAM8 GB
Storage200 GB NVMe SSD
OSUbuntu 24.04 LTS
SoftwareCoolify (beheert Docker, Traefik, SSL)
ServiceRAM per instancePer tenant
Medusa Backend~500 MB1x
Next.js Storefront~300 MB1x
Redis~50 MB1x
Meilisearch~200 MB1x
Totaal per tenant~1050 MB

Met 8 GB RAM: comfortabel 3-4 tenants + PostgreSQL + Coolify overhead. Voor alle 8 tenants is een upgrade naar 16-32 GB nodig.

ItemWaarde
Repositorymagic-commerce (privé)
HostingGitHub
Branch strategiemain = production, feature branches voor ontwikkeling
Container RegistryCoolify-managed (lokaal op VPS)