Skip to content

Scalability Analysis & Architecture Roadmap

This is the master plan for making Magic e-VERSE scalable. It starts from where we are today, maps out every single project and service, and for each one says exactly what happens to it. The production server is blank — everything described here is built from scratch.


  • 1 home server (Wayne’s) running everything — development AND production
  • ~60 Docker containers serving live client traffic
  • 1 developer (Wayne) working directly on the server via Claude Code
  • 1 co-founder (Michiel) who also works on the server
  • 1 freelance designer
  • No Git workflow — Wayne edits files directly, copies them between folders
  • No dev/prod separation — same server, same machine

Commerce Tenants — 41 containers:

TenantBackendStorefrontRedisMeilisearchNotes
developmentRunningRunningRunningRunningWayne’s dev workspace
brinxxRunningRunningRunningRunningLive client
defaultRunningRunningRunningRunningLive client
logohorlogeRunningRunningRunningRunningHas unique 2D designer + aplt-techniques
bovisalesRunningRunningRunningRunningLive client
demoRunningRunningRunningRunningDemo environment
desluisRunningRunningRunningLive client
jodasignRunningRunningRunningHas extended quotations
mondialRunningRunningRunningRunningSymlink to jodasign — not a real tenant
spranzRunningRunningRunningRunningLive
toolvizionRunningRunningRunningLive

Platform Services — 19 containers:

ContainerWhatNotes
magic_pim_backend_devPIM systemMaster product database
magic_pim_postgres_devPostgreSQLALL databases live here
magic_pim_redis_devPIM Redis
master_magic_backend_dev?Purpose unclear — needs investigation
master_magic_redis_dev?Purpose unclear
magic_agent_redisAgent RedisAI assistants
magic_agent_spranz_redisAgent Spranz RedisSpranz-specific agent
magic_n8nn8n #1Why 4 instances?
magic_n8n_2n8n #2
magic_n8n_3n8n #3
magic_n8n_cleann8n #4
magic_terminal_sshwiftyWeb SSH
mysqlMySQLPortal docs, workflow data
nextcloud_appNextcloudFile sharing
nextcloud_dbNextcloud DB
omada-controllerOmadaNetwork management
onlyoffice_docsOnlyOfficeDocument editing
preflight-servicePreflight?
rembg-serviceBackground removalImage processing
vaultwardenPasswords
ProjectWhat It IsHas Git?Has Docker?Status
Commerce
magic_commerce/magic_developmentDev tenant (source of truth)NoYesActive
magic_commerce/magic_brinxxBrinxx tenant (NVMe symlink)NoYesLive
magic_commerce/magic_defaultDefault tenant (NVMe symlink)NoYesLive
magic_commerce/magic_logohorlogeLogohorloge tenant (NVMe symlink)NoYesLive
magic_commerce/magic_bovisalesBovisales tenant (NVMe symlink)NoYesLive
magic_commerce/magic_demoDemo tenant (NVMe symlink)NoYesLive
magic_commerce/magic_desluisDe Sluis tenant (NVMe symlink)NoYesLive
magic_commerce/magic_jodasignJoDa Sign tenant (NVMe symlink)NoYesLive
magic_commerce/magic_mondialSymlink to jodasignNoYesHack
magic_commerce/magic_spranzSpranz tenant (NVMe symlink)NoYesLive
magic_commerce/magic_toolvizionToolVizion tenant (NVMe symlink)NoYesLive
magic_commerce/master_magicMaster billing?NoYesUnknown
Platform
magic_portalMain portal (Vite + React)NoNoActive
magic_beta_portalBeta portalNoNoUnknown
magic_tenant_portalTenant portalNoNoUnknown
magic_project_portalProject portalNoNoUnknown
magic_managementManagement toolNoNoUnknown
magic_agentAI assistants + flowbuilderYesYesActive
magic_connectorSystem connectorsYes (GitHub)YesActive
magic_docsStarlight documentationNoYesActive
magic_dev_projectsDev project trackingNoNoActive
Design & Media Tools
magic_editorImage/product editorYes (GitHub)NoUnknown
magic_modalLogo designer modal (Spranz/Kie.ai)Yes (GitHub)YesActive
magic_3d3D product viewerNoNoUnknown
magic_3d_mv3D multiviewNoNoUnknown
magic_logoLogo/designer toolsNoNoActive
magic_logo_packagesnpm packages for logo toolsNoNoUnknown
magic_resizeImage resize serviceYes (GitHub)NoUnknown
magic_moodshotProduct moodshot generatorNoNoUnknown
Infrastructure
magic_terminalWeb SSH (sshwifty)Yes (GitHub)YesActive
magic_contactContact systemYes (GitHub)NoUnknown
magic_messageserverMessagingNoNoUnknown
mailerEmail serviceNoNoUnknown
Other / Unknown
magiceverse_evolvedNew Next.js appNoNoUnknown
maw_kalenderCalendar appNoNoUnknown
maw_landingLanding pageNoNoUnknown
maworderingMAW orderingNoNoUnknown
simscanSIM scannerNoNoUnknown
wireframesDesign wireframesNoNoStatic
magic_infrastructure_mapInfra docsNoNoStatic
magic_managerManager toolNoNoUnknown

Backend Code: How Different Are Tenants Really?

Section titled “Backend Code: How Different Are Tenants Really?”

We diffed every tenant backend against magic_development. Result: 95%+ identical.

  • admin/app.tsx — admin customization
  • admin/routes/01-quotations/page.tsx — sync lag
  • admin/routes/02-aplt-orders/page.tsx — sync lag
  • admin/vite.config.ts — build config
  • api/admin/aplt/invoices/pdf/route.ts — PDF branding
  • api/admin/aplt/migrations/route.ts — migration state
  • api/admin/brand-upload/route.ts — brand config
  • api/admin/connectors/medusa-sync/route.ts — sync config
  • api/admin/dev-projects/route.ts — dev tool
  • modules/connectors/database.ts — DB credentials
  • utils/password-sync.ts — DB credentials

Every difference falls into solvable categories:

CategorySolution
Sync lag (development is ahead)One codebase eliminates this
PDF/email branding per tenantRead from aplt_brands / aplt_cms_settings tables
Auth config (logohorloge AUTHENTICATE=false)Environment variable
DB credentials hardcodedEnvironment variables
Tenant-specific features (2D designer, extended quotations)Feature flags in tenant config

Medusa 2.0 is single-tenant by design. Community multi-tenant solutions exist but are immature:

  • Rigby RLS approach — PostgreSQL Row Level Security. Requires monkey-patching Medusa internals. Breaks on upgrades.
  • eventHorizon28 link tables — Early stage, zero adoption.
  • No official plugin — Feature request open, not on Medusa’s roadmap.

Decision: Stay fully isolated. Separate databases, separate containers. Solve the operational pain with one codebase, not with risky framework patches.


Commerce Backends (12 copies → 1 codebase)

Section titled “Commerce Backends (12 copies → 1 codebase)”
CurrentActionResult
magic_development/backendBecomes the single magic-backend repoSource of truth
magic_brinxx/backendDeleted — replaced by magic-backend + TENANT=brinxx env varDeleted
magic_default/backendSameDeleted
magic_logohorloge/backendFeatures merged into magic-backend behind flagsDeleted
magic_jodasign/backendFeatures merged into magic-backend behind flagsDeleted
All other tenant backendsDeployed from magic-backend with env varDeleted
magic_mondial/backendSymlink removed — becomes a real tenant deploymentFixed
master_magic/backendInvestigate purpose first — then merge or killDecide

Commerce Storefronts (12 → template + forks)

Section titled “Commerce Storefronts (12 → template + forks)”
CurrentActionResult
magic_development/storefrontBecomes magic-storefront-base templateTemplate
Each client storefrontGets its own repo, forked from baseOwn repo

Storefronts are genuinely different per client (unique designs). They stay separate.

CurrentActionResult
magic_portalKeep — this is the main oneLives on
magic_beta_portalMerge into main portal or deleteMerged/deleted
magic_tenant_portalMerge into main portal or deleteMerged/deleted
magic_project_portalMerge into main portal or deleteMerged/deleted
magic_managementMerge into main portal or deleteMerged/deleted
CurrentActionNew Repo
magic_pimKeep, already has GitHub repoMagic-PIM (exists)
magic_agentKeep, push to GitHubNew repo
magic_connectorKeep, already has GitHub repoMagic-Connector (exists)
magic_docsKeep, push to GitHubNew repo
CurrentActionResult
magic_modalKeep, has GitHub repoLives on
magic_editorKeep if active, has GitHub repoKeep or archive
magic_3d / magic_3d_mvIf active push to GitHub, if dead archiveDecide
magic_logoKeep, push to GitHubKeep
magic_resizeKeep, has GitHub repoKeep
magic_moodshotIf active keep, if dead archiveDecide
rembg-serviceKeepKeep
CurrentActionResult
12× Redis instances1 shared Redis with key prefix per tenant11 removed
10× Meilisearch instances1 shared Meilisearch with tenant indices9 removed

Investigate why there are 4. Keep 1, kill the rest.

Delete all .bak_*, .pre_merge_backup, .current_backup, .pre_restore files once Git is in place.


Part 3: Every Deployable Service — The Complete Map

Section titled “Part 3: Every Deployable Service — The Complete Map”

Before talking about servers or pipelines, here’s EVERY service that needs to run in production, where its code comes from, how Wayne works on it, and what domain it serves.

Wayne currently works in one big directory (/mnt/data/magic_omniverse/). If we split everything into 20 separate Git repos, his workflow breaks — he’d need to know which repo to open Claude Code in, navigate between them, make separate commits. That’s a non-starter for someone who doesn’t use Git.

Decision: One monorepo for all backend services and tools. Separate repos only for storefronts (because each client has a unique design).

Wayne opens Claude Code in one directory. He can work on the backend, the portal, the agent, PIM — whatever. One commit, one push. GitHub Actions figures out what changed and only builds the affected images.

magic-everse/ # ONE repo — Wayne works here
├── services/
│ ├── commerce-backend/ # Medusa backend (deployed 12× with diff env vars)
│ │ ├── src/
│ │ ├── tenants/
│ │ │ ├── brinxx.json
│ │ │ ├── logohorloge.json # features: ["2d-designer"]
│ │ │ └── jodasign.json # features: ["extended-quotations"]
│ │ └── Dockerfile
│ │
│ ├── pim/ # Product Information Management
│ │ ├── backend/
│ │ ├── storefront/
│ │ └── Dockerfile
│ │
│ ├── portal/ # Main portal (consolidated from 4+ portals)
│ │ ├── src/
│ │ └── Dockerfile
│ │
│ ├── agent/ # AI customer assistants
│ │ ├── agents/ # Agent configs (brinxx, jodasign, spranz, etc.)
│ │ ├── agents-portal/ # Agent admin UI
│ │ ├── escalation-server/
│ │ ├── flowbuilder/
│ │ └── Dockerfile
│ │
│ ├── connector/ # System connectors between services
│ │ ├── src/
│ │ └── Dockerfile
│ │
│ ├── logo-designer/ # Logo tools (spranz designer, logohorloge)
│ │ ├── spranz/
│ │ │ ├── backend/ # Spranz designer backend
│ │ │ └── frontend/ # Spranz designer frontend
│ │ ├── logohorloge/
│ │ │ ├── backend/
│ │ │ └── frontend/
│ │ └── Dockerfile
│ │
│ ├── modal/ # Logo designer modal widget (Kie.ai)
│ │ ├── src/
│ │ └── Dockerfile
│ │
│ ├── 3d-viewer/ # 3D product visualization
│ │ ├── spranz-3d/
│ │ ├── default-3d/
│ │ └── Dockerfile
│ │
│ ├── editor/ # Image/product editor
│ │ ├── src/
│ │ └── Dockerfile
│ │
│ ├── resize/ # Image resize service
│ │ ├── src/
│ │ └── Dockerfile
│ │
│ ├── moodshot/ # Product moodshot generator
│ │ ├── src/
│ │ └── Dockerfile
│ │
│ ├── rembg/ # Background removal service
│ │ └── Dockerfile
│ │
│ ├── mailer/ # Email service
│ │ ├── src/
│ │ └── Dockerfile
│ │
│ ├── docs/ # Starlight documentation (this site)
│ │ ├── src/
│ │ └── Dockerfile
│ │
│ └── n8n/ # n8n automation (config only — uses official image)
│ └── config/
├── infra/ # Production server config
│ ├── docker-compose.traefik.yml
│ ├── docker-compose.infra.yml # postgres, redis, meilisearch
│ ├── docker-compose.tenants.yml # all tenant backends
│ ├── docker-compose.storefronts.yml # all storefronts
│ ├── docker-compose.platform.yml # pim, portal, agent, etc.
│ ├── docker-compose.tools.yml # editor, resize, 3d, logo, etc.
│ ├── docker-compose.monitoring.yml # uptime-kuma, watchtower
│ ├── .env.example
│ └── backup.sh
└── .github/
└── workflows/
└── build.yml # Builds ONLY what changed

Here’s every service that runs in production, its source in the monorepo, its Docker image, its domain, and what triggers a rebuild:

Tenant Backends — 12 containers, 1 Docker image

ServiceImageDomainEnv Vars
backend-brinxxghcr.io/midego1/magic-everse/commerce-backend:mainadmin-brinxx.magiceverse.onlineTENANT=brinxx
backend-defaultsame imageadmin-default.magiceverse.onlineTENANT=default
backend-logohorlogesame imageadmin-logohorloge.magiceverse.onlineTENANT=logohorloge FEATURES=2d-designer,aplt-techniques
backend-bovisalessame imageadmin-bovisales.magiceverse.onlineTENANT=bovisales
backend-demosame imageadmin-demo.magiceverse.onlineTENANT=demo
backend-desluissame imageadmin-desluis.magiceverse.onlineTENANT=desluis
backend-jodasignsame imageadmin-jodasign.magiceverse.onlineTENANT=jodasign FEATURES=extended-quotations
backend-mondialsame imageadmin-mondial.magiceverse.onlineTENANT=mondial (real tenant, not symlink)
backend-spranzsame imageadmin-spranz.magiceverse.onlineTENANT=spranz
backend-toolvizionsame imageadmin-toolvizion.magiceverse.onlineTENANT=toolvizion
backend-stagingsame image :dev tagstaging.magiceverse.onlineTENANT=staging

Tenant Storefronts — 12 containers, 12 separate repos

ServiceImage (separate repo)Domain
sf-brinxxghcr.io/midego1/magic-sf-brinxx:mainbrinxx.magiceverse.online
sf-logohorlogeghcr.io/midego1/magic-sf-logohorloge:mainlogohorloge.magiceverse.online
sf-jodasignghcr.io/midego1/magic-sf-jodasign:mainjodasign.magiceverse.online
each storefront has its own repo

Storefronts are separate repos because each client has a unique design. They’re forked from a base template.

Total production containers: ~42 (vs ~60 today, but properly organized and on a real server)

WhatWhy Separate
Storefronts (magic-sf-brinxx, etc.)Each client has unique design. Different release cadence. Designer works on these independently.
Infrastructure config for Wayne’s home serverHis dev setup is personal and shouldn’t be in the shared repo
CurrentReason
magic_beta_portalMerged into main portal
magic_tenant_portalMerged into main portal
magic_project_portalMerged into main portal
magic_management / magic_managerMerged into main portal
magic_n8n_2, magic_n8n_3, magic_n8n_cleanKeep 1 n8n, kill the rest
magic_messageserverMerged into mailer (or killed if redundant)
magic_infrastructure_mapStatic docs, move into services/docs/
11× Redis instancesReplaced by 1 shared Redis
9× Meilisearch instancesReplaced by 1 shared Meilisearch

Part 4: The Production Server — Built From Scratch

Section titled “Part 4: The Production Server — Built From Scratch”

No platform, no orchestration tool. Just proven, boring infrastructure:

ComponentToolWhy
Reverse proxy + SSLTraefikAuto-discovers Docker containers, auto-SSL via Let’s Encrypt, routes domains. Zero config per new service.
ContainersDocker + Docker ComposeYou already know it. Battle-tested.
Container registryGitHub Container Registry (ghcr.io)Free for private repos. Images built by GitHub Actions.
CI/CDGitHub ActionsOn push: detect what changed, build only affected images, push to ghcr.io.
Auto-deployWatchtowerWatches ghcr.io for new images. Pulls and restarts automatically.
DatabasePostgreSQL 16One instance, separate database per tenant + PIM + portal.
SearchMeilisearchOne instance, tenant-prefixed indices.
CacheRedisOne instance, key prefix per tenant.
MonitoringUptime KumaChecks all URLs every minute, alerts via email/Telegram.
BackupsCron + pg_dump + offsiteDaily dumps to Backblaze B2/S3.
/opt/magic/
├── docker-compose.traefik.yml # Reverse proxy + SSL
├── docker-compose.infra.yml # PostgreSQL, Redis, Meilisearch
├── docker-compose.tenants.yml # ALL tenant backends (same image, diff env vars)
├── docker-compose.storefronts.yml # ALL storefronts (diff images)
├── docker-compose.platform.yml # PIM, Portal, Agent, Connector, Docs
├── docker-compose.tools.yml # Logo designer, Modal, 3D, Editor, Resize, Rembg
├── docker-compose.monitoring.yml # Watchtower, Uptime Kuma, n8n
├── .env # All secrets (POSTGRES_PASSWORD, MEILI_KEY, etc.)
├── backups/
│ └── backup.sh # Daily cron job
└── letsencrypt/ # SSL certificates (auto-managed by Traefik)

All compose files share a single Docker network (magic-network) so services can talk to each other by container name.

docker-compose.traefik.yml
services:
traefik:
image: traefik:v3
command:
- --providers.docker=true
- --providers.docker.exposedByDefault=false
- --entrypoints.web.address=:80
- --entrypoints.websecure.address=:443
- --certificatesresolvers.le.acme.httpchallenge.entrypoint=web
- --certificatesresolvers.le.acme.email=admin@magiceverse.online
- --certificatesresolvers.le.acme.storage=/letsencrypt/acme.json
ports:
- "80:80"
- "443:443"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./letsencrypt:/letsencrypt
networks:
- magic-network
restart: always
networks:
magic-network:
name: magic-network

Part 5: The Development Pipeline — Every Service

Section titled “Part 5: The Development Pipeline — Every Service”

How It Works For ALL Services (not just the backend)

Section titled “How It Works For ALL Services (not just the backend)”
┌────────────────────────────────────────────────────────┐
│ WAYNE'S HOME SERVER │
│ │
│ ~/magic-everse/ ← ONE directory │
│ ├── services/commerce-backend/ ← works on backend │
│ ├── services/portal/ ← works on portal │
│ ├── services/agent/ ← works on agent │
│ ├── services/logo-designer/ ← works on designer │
│ └── ... everything in one place │
│ │
│ Wayne makes changes anywhere │
│ Claude Code: "commit and push" │
└──────────────────────┬─────────────────────────────────┘
│ git push
┌────────────────────────────────────────────────────────┐
│ GITHUB ACTIONS │
│ │
│ Detects WHAT changed using path filters: │
│ │
│ services/commerce-backend/ changed? │
│ → Build ghcr.io/midego1/magic-everse/commerce-backend│
│ │
│ services/portal/ changed? │
│ → Build ghcr.io/midego1/magic-everse/portal │
│ │
│ services/agent/ changed? │
│ → Build ghcr.io/midego1/magic-everse/agent │
│ │
│ services/logo-designer/ changed? │
│ → Build ghcr.io/midego1/magic-everse/logo-designer │
│ │
│ Only changed services get rebuilt. Others untouched. │
└──────────────────────┬─────────────────────────────────┘
│ pushes new image(s) to ghcr.io
┌────────────────────────────────────────────────────────┐
│ PRODUCTION SERVER │
│ │
│ Watchtower detects new image(s) │
│ Restarts ONLY the affected containers: │
│ │
│ commerce-backend changed? │
│ → Restarts ALL 12 tenant backends (same image) │
│ │
│ portal changed? │
│ → Restarts portal container only │
│ │
│ agent changed? │
│ → Restarts agent container only │
│ │
│ Other containers untouched. │
└────────────────────────────────────────────────────────┘

One workflow file that builds only what changed:

.github/workflows/build.yml
name: Build & Deploy
on:
push:
branches: [main, dev]
jobs:
detect-changes:
runs-on: ubuntu-latest
outputs:
commerce-backend: ${{ steps.changes.outputs.commerce-backend }}
pim-backend: ${{ steps.changes.outputs.pim-backend }}
pim-storefront: ${{ steps.changes.outputs.pim-storefront }}
portal: ${{ steps.changes.outputs.portal }}
agent: ${{ steps.changes.outputs.agent }}
connector: ${{ steps.changes.outputs.connector }}
logo-designer: ${{ steps.changes.outputs.logo-designer }}
modal: ${{ steps.changes.outputs.modal }}
3d-viewer: ${{ steps.changes.outputs.3d-viewer }}
editor: ${{ steps.changes.outputs.editor }}
resize: ${{ steps.changes.outputs.resize }}
moodshot: ${{ steps.changes.outputs.moodshot }}
mailer: ${{ steps.changes.outputs.mailer }}
docs: ${{ steps.changes.outputs.docs }}
steps:
- uses: actions/checkout@v4
- uses: dorny/paths-filter@v3
id: changes
with:
filters: |
commerce-backend:
- 'services/commerce-backend/**'
pim-backend:
- 'services/pim/backend/**'
pim-storefront:
- 'services/pim/storefront/**'
portal:
- 'services/portal/**'
agent:
- 'services/agent/**'
connector:
- 'services/connector/**'
logo-designer:
- 'services/logo-designer/**'
modal:
- 'services/modal/**'
3d-viewer:
- 'services/3d-viewer/**'
editor:
- 'services/editor/**'
resize:
- 'services/resize/**'
moodshot:
- 'services/moodshot/**'
mailer:
- 'services/mailer/**'
docs:
- 'services/docs/**'
build-service:
needs: detect-changes
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
strategy:
matrix:
include:
- service: commerce-backend
context: services/commerce-backend
changed: ${{ needs.detect-changes.outputs.commerce-backend }}
- service: pim-backend
context: services/pim/backend
changed: ${{ needs.detect-changes.outputs.pim-backend }}
- service: pim-storefront
context: services/pim/storefront
changed: ${{ needs.detect-changes.outputs.pim-storefront }}
- service: portal
context: services/portal
changed: ${{ needs.detect-changes.outputs.portal }}
- service: agent
context: services/agent
changed: ${{ needs.detect-changes.outputs.agent }}
- service: connector
context: services/connector
changed: ${{ needs.detect-changes.outputs.connector }}
- service: logo-designer
context: services/logo-designer
changed: ${{ needs.detect-changes.outputs.logo-designer }}
- service: modal
context: services/modal
changed: ${{ needs.detect-changes.outputs.modal }}
- service: 3d-viewer
context: services/3d-viewer
changed: ${{ needs.detect-changes.outputs.3d-viewer }}
- service: editor
context: services/editor
changed: ${{ needs.detect-changes.outputs.editor }}
- service: resize
context: services/resize
changed: ${{ needs.detect-changes.outputs.resize }}
- service: docs
context: services/docs
changed: ${{ needs.detect-changes.outputs.docs }}
steps:
- if: matrix.changed == 'true'
uses: actions/checkout@v4
- if: matrix.changed == 'true'
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- if: matrix.changed == 'true'
uses: docker/build-push-action@v5
with:
context: ${{ matrix.context }}
push: true
tags: ghcr.io/midego1/magic-everse/${{ matrix.service }}:${{ github.ref_name }}

What this means: Wayne changes 3 lines in the portal and pushes. Only the portal image gets rebuilt. The 12 tenant backends, PIM, agent, everything else — completely untouched.

Each storefront repo has its own simple workflow (same 20-line GitHub Actions from before). The designer or Wayne pushes a storefront change → only that one storefront rebuilds.

Wayne pushes to "dev" branch (default)
→ GitHub Actions builds images tagged :dev
→ Watchtower restarts staging containers only
→ Wayne/Michiel verify on staging.magiceverse.online
Michiel merges dev → main (via GitHub or Claude Code)
→ GitHub Actions builds images tagged :main
→ Watchtower restarts all production containers
→ All tenants updated

Wayne never pushes directly to main. Claude Code is configured to always push to dev. Michiel reviews and merges.


Part 6: Wayne’s Home Server — Development Setup

Section titled “Part 6: Wayne’s Home Server — Development Setup”

Wayne’s server keeps running, but ONLY for development. No more production traffic.

~/magic-everse/ ← Git clone of the monorepo
├── services/
│ ├── commerce-backend/ ← Wayne works here most of the time
│ ├── portal/
│ ├── agent/
│ └── ...
~/storefronts/ ← Separate storefront repos
├── magic-sf-brinxx/
├── magic-sf-logohorloge/
└── ...
Docker containers (dev only):
├── development-backend ← Runs from local code, not ghcr.io
├── development-storefront ← For testing
├── postgres-dev ← Local dev databases
├── redis-dev
└── meilisearch-dev

Wayne’s development docker-compose mounts local code for hot-reloading — changes appear instantly without rebuilding. This is exactly how he works today, just organized.


Part 7: Wayne’s Workflow — Before & After

Section titled “Part 7: Wayne’s Workflow — Before & After”

Before (11 steps, touches 12+ directories)

Section titled “Before (11 steps, touches 12+ directories)”
1. SSH into home server
2. Open Claude Code in magic_development/backend/
3. Build feature
4. Test against development tenant
5. Manually copy changed files to 11 other tenant folders
6. Remember not to overwrite storefront files
7. Remember jodasign needs sudo
8. Remember logohorloge has unique files
9. Rebuild each tenant's Docker container one by one
10. Check nothing broke on each tenant
11. If also changing portal/agent/tools: repeat in those directories
1. SSH into home server
2. Open Claude Code in ~/magic-everse/
3. Build feature (backend, portal, agent, whatever — it's all here)
4. Say "commit and push" — done

What happens automatically after step 4:

  • Claude Code commits and pushes to dev branch
  • GitHub Actions detects what changed, builds only those images
  • Watchtower on production restarts only affected staging containers
  • Michiel verifies staging, merges to main
  • All production containers update

Wayne’s world is ONE directory. He works on anything — backend, portal, agent, logo designer, 3D viewer, docs — it’s all there. One commit captures everything. No syncing. No copying. No remembering rules.


Clone directories, modify configs, set up Nginx, SSL certs, create database, build containers, add to sync script, update guardrails doc…

  1. Create database

    Terminal window
    docker exec postgres createdb -U postgres magic_b2b_newtenant
  2. Add tenant config — create services/commerce-backend/tenants/newtenant.json:

    { "name": "New Tenant", "features": [], "domain": "newtenant.magiceverse.online" }
  3. Add to compose — 15 lines in docker-compose.tenants.yml:

    backend-newtenant:
    image: ghcr.io/midego1/magic-everse/commerce-backend:main
    environment:
    TENANT: newtenant
    DATABASE_URL: postgres://...newtenant
    labels:
    - "traefik.http.routers.be-newtenant.rule=Host(`admin-newtenant.magiceverse.online`)"
    - "traefik.http.routers.be-newtenant.tls.certresolver=le"
    - "com.centurylinklabs.watchtower.enable=true"
    networks: [magic-network]
    restart: always
  4. Fork the storefront — clone magic-sf-base, customize branding

  5. Point DNS — add CNAME records for admin-newtenant and newtenant

  6. docker compose up -d — Traefik handles SSL automatically

  7. Done. New tenant live.


Part 9: Container Count — Before & After

Section titled “Part 9: Container Count — Before & After”
EnvironmentBeforeAfter
Wayne’s home server~60 (dev + prod mixed)~5 (dev only)
Production server0 (doesn’t exist)~42 (organized)
Total~60 on one home server~47 across two servers, properly separated

  • Answer all open questions (portals, n8n, dead projects)
  • Archive dead projects to _archive/
  • Delete .bak_* files everywhere
  • Consolidate n8n to 1 instance
  • Consolidate portals into 1
  • Resolve mondialjodasign symlink
  • Create magic-everse repo on GitHub
  • Move magic_development/backend/services/commerce-backend/
  • Merge logohorloge/jodasign unique features behind feature flags
  • Move magic_pim/services/pim/
  • Move magic_portal/services/portal/
  • Move magic_agent/services/agent/
  • Move magic_connector/services/connector/
  • Move magic_logo/services/logo-designer/
  • Move magic_modal/services/modal/
  • Move magic_3d/services/3d-viewer/
  • Move magic_editor/services/editor/
  • Move magic_resize/services/resize/
  • Move magic_docs/starlight/services/docs/
  • Move remaining active services
  • Ensure every service has a working Dockerfile
  • Set up GitHub Actions workflow (path-based builds)
  • Test every image builds successfully
  • Create magic-sf-base from development storefront
  • Fork per client, preserve customizations
  • Set up GitHub Actions per storefront repo
  • Ensure each builds and runs
  • Install Docker
  • Create magic-network
  • Deploy Traefik
  • Deploy PostgreSQL + Redis + Meilisearch
  • Migrate all databases from home server
  • Deploy tenant backends (from ghcr.io images)
  • Deploy storefronts
  • Deploy platform services (PIM, portal, agent, etc.)
  • Deploy tools (logo designer, editor, resize, 3d, etc.)
  • Set up Watchtower
  • Set up Uptime Kuma
  • Set up backup cron
  • Deploy staging tenant on dev branch
  • Point DNS to production server
  • Verify ALL services work (not just backends — portal, PIM, agents, designer, 3d, etc.)
  • Stop production containers on home server
  • Home server = dev only

  • Mondial is a new customer — gets its own database, tenant config, and deployment. The current symlink to jodasign is temporary and will be replaced with a proper tenant setup.
  • Everything gets migrated into the monorepo as-is. Dead projects sit quietly in services/ and never get built unless touched. Active projects get Dockerfiles and deploy automatically. No need to audit what’s alive before starting.

Part 10: Open Questions (Must Answer Before Starting)

Section titled “Part 10: Open Questions (Must Answer Before Starting)”
#QuestionWhy It Matters
1What are the 4 portals and are they all active?Determines merge scope
2Why 4 n8n instances?Can we kill 3?
3What is master_magic?Running with unclear purpose
4What is magiceverse_evolved?New app — replacing something?
5Is mondialjodasign intentional long-term?Needs real tenant
6magic_3d vs magic_3d_mv — both needed?Potential dead project
7magic_management vs magic_manager — both needed?Overlap
9magic_messageserver vs mailer — both needed?Overlap
10What is preflight-service?Running, unknown purpose
11Are maw_* projects active?3 MAW-related projects
12What is simscan?Unknown purpose

Last updated: 2026-03-31 Generated by platform scalability analysis