Skip to content

PROJ: GitHub Integration Plan

╔══════════════════════════════════════════════════════════════════════╗
║ ║
║ ██████╗ ██╗████████╗██╗ ██╗██╗ ██╗██████╗ ║
║ ██╔════╝ ██║╚══██╔══╝██║ ██║██║ ██║██╔══██╗ ║
║ ██║ ███╗██║ ██║ ███████║██║ ██║██████╔╝ ║
║ ██║ ██║██║ ██║ ██╔══██║██║ ██║██╔══██╗ ║
║ ╚██████╔╝██║ ██║ ██║ ██║╚██████╔╝██████╔╝ ║
║ ╚═════╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═════╝ ║
║ ║
║ I N T E G R A T I O N P L A N ║
║ ║
║ Magic e-VERSE ──► GitHub Repositories ║
║ Multi-Tenant Version Control & Code Distribution ║
║ ║
╚══════════════════════════════════════════════════════════════════════╝

The Magic e-VERSE platform currently manages 9 commerce tenants, a PIM system, a Portal, and multiple supporting services. Code is distributed manually by copying files from magic_development to all tenants using rsync and cp commands.

This plan migrates the entire ecosystem to GitHub-hosted repositories with proper version control, branching, commit history, and a structured code distribution workflow — eliminating manual file copying and introducing traceability, rollback capability, and team collaboration.


What is Git & GitHub? — High-Level Overview

Section titled “What is Git & GitHub? — High-Level Overview”

Git is a distributed version control system that tracks every change ever made to your codebase. Think of it as an unlimited “undo history” for your entire project, where every save point (called a commit) records exactly what changed, when, and by whom.

Your Code Over Time
═══════════════════
Commit 1 Commit 2 Commit 3 Commit 4
┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
│ Initial │─────►│ Add cart │─────►│ Fix bug │─────►│ New CMS │
│ project │ │ feature │ │ in login │ │ module │
└──────────┘ └──────────┘ └──────────┘ └──────────┘
│ │ │ │
Jan 15 Jan 22 Jan 25 Feb 3
by Michiel by Michiel by Claude by Michiel
◄──── You can go back to ANY of these points at any time ────►

Key Git concepts:

ConceptWhat it meansAnalogy
Repository (repo)A project folder tracked by GitA project folder with infinite undo
CommitA saved snapshot of changesA save point in a video game
BranchA parallel version of your codeA copy you can experiment on safely
MergeCombining changes from one branch into anotherBringing your experiment back into the main project
PullDownload changes from GitHub to your serverSyncing your local copy with the team
PushUpload changes from your server to GitHubPublishing your work for the team
CloneCreate a full copy of a repositoryDownloading the project for the first time

GitHub is a cloud platform that hosts Git repositories and adds collaboration features on top:

  • Central source of truth — One place where the “official” code lives
  • Pull Requests (PRs) — Propose changes, review them, discuss, then merge
  • History & blame — See who changed what line and when
  • Issues — Track bugs and feature requests
  • Releases — Tag and distribute specific versions
  • Access control — Control who can read/write to each repository
  • Backup — Your code is safely stored in the cloud, not just on one server

Branches are what make Git powerful for a multi-tenant setup like Magic e-VERSE:

main (stable, production-ready)
────●────●────●────●────●────●────●────●────●────►
\ \ /
\ \ / ◄── merge back when done
\ \ /
●────●────● ●───●
feature/ fix/cart-
new-cms calculation
● = commit (saved change)
  • main branch always contains stable, tested code
  • New features and fixes are developed on separate branches
  • Changes are merged back into main only after review and testing
  • If something goes wrong on a branch, main is never affected

Why Git for Magic e-VERSE? — Benefits for Multi-Tenant

Section titled “Why Git for Magic e-VERSE? — Benefits for Multi-Tenant”
┌──────────────────────────────────────────────────────────────────────┐
│ CURRENT WORKFLOW (Manual Copy) │
├──────────────────────────────────────────────────────────────────────┤
│ │
│ 1. Developer changes files in magic_development │
│ 2. Manually copy changed files to 8 other tenants (cp / rsync) │
│ 3. Rebuild Docker containers for each tenant │
│ 4. Hope nothing was missed │
│ │
│ PROBLEMS: │
│ ✗ No history — "What changed last week?" → Unknown │
│ ✗ No rollback — "Something broke, go back" → Impossible (no │
│ snapshots unless manual backup was made) │
│ ✗ No traceability — "Who changed this file?" → Unknown │
│ ✗ No safety net — Accidentally copy tenant-specific config → │
│ Tenant breaks │
│ ✗ No collaboration — Two people working = conflicts and chaos │
│ ✗ No code review — Changes go live without any review process │
│ ✗ Drift — Tenants slowly diverge from each other over time │
│ │
└──────────────────────────────────────────────────────────────────────┘
┌──────────────────────────────────────────────────────────────────────┐
│ FUTURE WORKFLOW (Git + GitHub) │
├──────────────────────────────────────────────────────────────────────┤
│ │
│ 1. Developer creates a branch for their change │
│ 2. Makes changes, commits with descriptive message │
│ 3. Opens a Pull Request → visible diff, review, discussion │
│ 4. After approval, merge into main │
│ 5. Pull on server → all tenants get the update automatically │
│ │
│ BENEFITS: │
│ ✓ Full history — Every change recorded with timestamp & author │
│ ✓ Instant rollback — "git revert" undoes any change safely │
│ ✓ Full traceability — "git blame" shows who changed each line │
│ ✓ Safety — Tenant-specific files in .gitignore, can't be │
│ accidentally overwritten │
│ ✓ Collaboration — Branches isolate work, merges combine it │
│ ✓ Code review — Pull Requests enforce review before deploy │
│ ✓ Consistency — All tenants pull from the same source branch │
│ │
└──────────────────────────────────────────────────────────────────────┘

In a multi-tenant architecture like Magic e-VERSE, Git is particularly valuable:

  1. Single source of truth — Shared code lives in one repository. No more 9 copies drifting apart.
  2. Tenant-specific configuration safely separateddocker-compose.yml, .env, and medusa-config.ts are in .gitignore (or in a separate config directory), so they are never accidentally overwritten during sync.
  3. Feature branches per tenant — If Brinxx needs a custom feature, it can live on a dedicated branch without affecting other tenants.
  4. Deployment visibility — Commit history shows exactly which features have been deployed to which tenants and when.
  5. Disaster recovery — If the server dies, the full codebase (with history) is safely on GitHub. Clone and you’re back.

ComponentGit StatusRemoteNotes
magic_omniverse/Local git repoLocal bare repo only8,524 tracked files, master branch
magic_pim/Local git repoNo remoteIsolated, 8,478 tracked files
magic_brinxx/Local git repoLocal bare repo8,524 tracked files
magic_development/Local git repoLocal bare repoSource/basis for all tenants
magic_commerce.gitBare repositoryN/ACentral local repo for commerce tenants
Other tenantsMixedLocal bare repoSome empty (no commits)
IssueImpactPriority
No .gitignore filesSensitive files (.env, credentials) could be trackedCritical
No GitHub remoteSingle point of failure — code only on this serverCritical
No branch strategyEverything on master, no feature isolationHigh
No PR workflowChanges go live without reviewHigh
Tenant configs in sourceRisk of overwriting tenant-specific files during syncHigh
PIM has no remoteComplete isolation, no backupHigh
safe.directory = *Bypasses Git’s security protectionsMedium

Section titled “Option A: Monorepo (Recommended for teams < 10)”

One single repository contains all shared code. Tenant-specific configuration lives in a dedicated config/tenants/ directory within the same repo.

GitHub Organization: magiceverse
═══════════════════════════════
┌────────────────────────────────────────────────────────────────┐
│ Repository: magiceverse/magic-commerce │
│ │
│ main branch │
│ ├── backend/ │
│ │ ├── src/ ◄── Shared code (all tenants) │
│ │ │ ├── api/admin/aplt/ │
│ │ │ ├── admin/routes/ │
│ │ │ ├── modules/ │
│ │ │ └── ... │
│ │ ├── Dockerfile │
│ │ └── package.json │
│ ├── storefront/ │
│ │ ├── src/ ◄── Shared code (all tenants) │
│ │ │ ├── themes/ │
│ │ │ │ ├── base/ ◄── Shared base theme │
│ │ │ │ ├── brinxx/ ◄── Tenant-specific theme │
│ │ │ │ ├── default/ ◄── Tenant-specific theme │
│ │ │ │ └── .../ │
│ │ ├── Dockerfile │
│ │ └── package.json │
│ ├── config/ │
│ │ └── tenants/ ◄── Tenant configs (tracked!) │
│ │ ├── magic_development/ │
│ │ │ ├── docker-compose.yml │
│ │ │ ├── medusa-config.ts │
│ │ │ └── .env.example ◄── Template only, no secrets │
│ │ ├── magic_brinxx/ │
│ │ │ ├── docker-compose.yml │
│ │ │ ├── medusa-config.ts │
│ │ │ └── .env.example │
│ │ └── .../ │
│ ├── scripts/ │
│ │ ├── deploy-tenant.sh ◄── Automated deployment │
│ │ ├── deploy-all.sh ◄── Deploy to all tenants │
│ │ └── new-tenant.sh ◄── Create new tenant setup │
│ ├── .gitignore │
│ └── README.md │
│ │
└────────────────────────────────────────────────────────────────┘
┌────────────────────────────────────────────────────────────────┐
│ Repository: magiceverse/magic-pim │
│ (Separate repo — different codebase, different lifecycle) │
└────────────────────────────────────────────────────────────────┘
┌────────────────────────────────────────────────────────────────┐
│ Repository: magiceverse/magic-portal │
│ (Separate repo — React/Vite app, independent deployment) │
└────────────────────────────────────────────────────────────────┘
┌────────────────────────────────────────────────────────────────┐
│ Repository: magiceverse/magic-docs │
│ (Separate repo — Starlight documentation site) │
└────────────────────────────────────────────────────────────────┘

Pros:

  • Simple — one repo to manage, one place to search code
  • Atomic commits — a change that affects backend + storefront is one commit
  • Easy code review — one Pull Request for all related changes
  • No dependency management between repos
  • Tenant themes are versioned alongside the code that uses them

Cons:

  • Larger repository size (but Git handles this well)
  • All developers see all tenant configs (mitigated by GitHub access controls)

Option B: Core + Tenant Config Repos (Better for teams > 10)

Section titled “Option B: Core + Tenant Config Repos (Better for teams > 10)”

Shared code lives in a core repository. Each tenant has a tiny config-only repository.

GitHub Organization: magiceverse
═══════════════════════════════
┌────────────────────────────────────────────────────────────────┐
│ Repository: magiceverse/magic-commerce-core │
│ │
│ Contains ONLY shared code: │
│ ├── backend/src/ ◄── All API routes, modules │
│ ├── storefront/src/ ◄── All storefront code │
│ ├── backend/Dockerfile │
│ ├── storefront/Dockerfile │
│ ├── backend/package.json │
│ ├── storefront/package.json │
│ └── storefront/src/themes/ ◄── All tenant themes │
└────────────────────────────────────────────────────────────────┘
┌───────────────────┐ ┌───────────────────┐ ┌───────────────────┐
│ magic-tenant- │ │ magic-tenant- │ │ magic-tenant- │
│ development │ │ brinxx │ │ default │
│ │ │ │ │ │
│ docker-compose │ │ docker-compose │ │ docker-compose │
│ medusa-config │ │ medusa-config │ │ medusa-config │
│ .env.example │ │ .env.example │ │ .env.example │
└───────────────────┘ └───────────────────┘ └───────────────────┘
...and 6 more tenant config repos

Pros:

  • Clean separation of concerns
  • Tenant-specific access control (client could see only their config)
  • Smaller repos, faster clones

Cons:

  • More repositories to manage (10+ repos instead of 1)
  • Changes spanning core + config require coordinated commits
  • More complex deployment orchestration
  • Harder to keep everything in sync

FactorOption A (Monorepo)Option B (Multi-Repo)
Setup complexityLowHigh
Ongoing maintenanceLowMedium
Team size fit1-10 developers10+ developers
Code review workflowSimple (1 PR)Complex (multiple PRs)
Deployment automationSimpleRequires orchestration
Tenant isolationMediumHigh
Current team sizeBest fitOverkill for now

The migration is divided into 6 phases, designed to be executed safely with minimal downtime. Each phase is independent — if something goes wrong, you can pause and resume later.

┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
│ PHASE 1 │───►│ PHASE 2 │───►│ PHASE 3 │───►│ PHASE 4 │
│ GitHub │ │ Clean & │ │ Push to │ │ Branch │
│ Setup │ │ Prepare │ │ GitHub │ │ Strategy │
└──────────┘ └──────────┘ └──────────┘ └──────────┘
┌──────────┐ ┌──────────┐ │
│ PHASE 6 │◄───│ PHASE 5 │◄────────────────────────┘
│ New Code │ │ Tenant │
│ Workflow │ │ Deploy │
└──────────┘ └──────────┘
┌──────────────────────────────────────────────────────────────┐
│ FUTURE: Phase 7 — CI/CD with GitHub Actions │
│ (Automated testing, building, and deployment on merge) │
└──────────────────────────────────────────────────────────────┘

Phase 1 — GitHub Organization & Repository Setup

Section titled “Phase 1 — GitHub Organization & Repository Setup”

Goal: Create the GitHub organization and empty repositories.

Time estimate: 30 minutes

  1. Create GitHub Organization

    Go to github.com/organizations/new and create:

    • Organization name: magiceverse (or magic-everse)
    • Plan: Free (sufficient for private repos with small team)
    • Owner email: admin@magiceverse.nl
  2. Create Repositories

    Create the following repositories (all private):

    RepositoryDescriptionVisibility
    magic-commerceMulti-tenant B2B e-commerce platform (Medusa 2.x)Private
    magic-pimProduct Information Management systemPrivate
    magic-portalCentral dashboard & tenant manager (React/Vite)Private
    magic-docsDeveloper documentation (Starlight/Astro)Private
    Terminal window
    # Using GitHub CLI (install first if needed: apt install gh)
    gh auth login
    # Create organization
    gh api orgs -X POST -f login=magiceverse -f billing_email=admin@magiceverse.nl
    # Create repositories
    gh repo create magiceverse/magic-commerce --private --description "Multi-tenant B2B e-commerce (Medusa 2.x)"
    gh repo create magiceverse/magic-pim --private --description "Product Information Management"
    gh repo create magiceverse/magic-portal --private --description "Central dashboard & tenant manager"
    gh repo create magiceverse/magic-docs --private --description "Developer documentation (Starlight)"
  3. Set up SSH access on the server

    Terminal window
    # Generate SSH key for the server
    ssh-keygen -t ed25519 -C "server@magiceverse.online" -f ~/.ssh/github_magiceverse
    # Add to SSH config
    cat >> ~/.ssh/config << 'EOF'
    Host github.com
    IdentityFile ~/.ssh/github_magiceverse
    IdentitiesOnly yes
    EOF
    # Copy public key and add to GitHub organization
    cat ~/.ssh/github_magiceverse.pub
    # → Add this key at: github.com/organizations/magiceverse/settings/keys
  4. Install GitHub CLI on the server

    Terminal window
    # Install gh CLI
    curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | \
    sudo dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg
    echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | \
    sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null
    sudo apt update && sudo apt install gh
    gh auth login

Goal: Add .gitignore files, clean up tracked files, ensure no secrets are committed.

Time estimate: 1-2 hours

  1. Create comprehensive .gitignore for magic-commerce

    Terminal window
    cat > /mnt/data/magic_omniverse/magic_commerce/magic_development/.gitignore << 'GITIGNORE'
    # ══════════════════════════════════════════════════════
    # Magic e-VERSE Commerce — .gitignore
    # ══════════════════════════════════════════════════════
    # ── Dependencies ──────────────────────────────────────
    node_modules/
    .pnp/
    .pnp.js
    # ── Build Output ──────────────────────────────────────
    dist/
    build/
    .next/
    .medusa/
    .cache/
    # ── Environment & Secrets ─────────────────────────────
    .env
    .env.local
    .env.*.local
    backend/.env
    storefront/.env
    # ── Tenant-Specific Configuration ─────────────────────
    # These files MUST differ per tenant and should never
    # be synced. They live in config/tenants/ instead.
    docker-compose.yml
    docker-compose.override.yml
    backend/medusa-config.ts
    # ── Database & Data Dumps ─────────────────────────────
    *.sql
    *.dump
    *.bak
    *_export.*
    # ── Runtime & Logs ────────────────────────────────────
    *.log
    logs/
    tmp/
    uploads/
    backend/public/uploads/
    # ── OS & IDE ──────────────────────────────────────────
    .DS_Store
    ._.DS_Store
    Thumbs.db
    .vscode/
    .idea/
    *.swp
    *.swo
    # ── Backups ───────────────────────────────────────────
    *.bak-*
    src.bak-*/
    backups/
    # ── Package Lock (optional — uncomment to track) ─────
    # package-lock.json
    GITIGNORE
  2. Create .gitignore for magic-pim

    Terminal window
    cat > /mnt/data/magic_pim/.gitignore << 'GITIGNORE'
    # Magic PIM — .gitignore
    node_modules/
    dist/
    build/
    .next/
    .medusa/
    .cache/
    .env
    .env.local
    .env.*.local
    backend/.env
    storefront/.env
    docker-compose.yml
    docker-compose.override.yml
    *.sql
    *.dump
    *.log
    uploads/
    .DS_Store
    ._.DS_Store
    .vscode/
    .idea/
    GITIGNORE
  3. Audit for secrets currently tracked in git

    Terminal window
    # Check if any .env files are tracked
    cd /mnt/data/magic_omniverse
    git ls-files | grep -E '\.env|password|secret|credential|docker-compose\.yml'
    # If files with secrets are tracked, remove them from tracking
    # (this removes from git but keeps the file on disk)
    git rm --cached path/to/secret-file
  4. Clean up untracked files

    Terminal window
    # Review what's untracked (DO NOT auto-delete)
    cd /mnt/data/magic_omniverse
    git status
    # Move backups to a safe location outside the repo
    mv backups/ /mnt/data/backups_archive/
  5. Create the config/tenants/ directory structure

    Terminal window
    BASE="/mnt/data/magic_omniverse/magic_commerce/magic_development"
    mkdir -p "$BASE/config/tenants"
    TENANTS="magic_development magic_brinxx magic_default magic_demo magic_jodasign magic_logohorloge magic_bovisales magic_desluis magic_spranz"
    for tenant in $TENANTS; do
    mkdir -p "$BASE/config/tenants/$tenant"
    TENANT_DIR="/mnt/data/magic_omniverse/magic_commerce/$tenant"
    # Copy tenant-specific files to config directory
    [ -f "$TENANT_DIR/docker-compose.yml" ] && \
    cp "$TENANT_DIR/docker-compose.yml" "$BASE/config/tenants/$tenant/"
    [ -f "$TENANT_DIR/backend/medusa-config.ts" ] && \
    cp "$TENANT_DIR/backend/medusa-config.ts" "$BASE/config/tenants/$tenant/"
    # Create .env.example (stripped of actual secrets)
    if [ -f "$TENANT_DIR/backend/.env" ]; then
    sed 's/=.*/=CHANGE_ME/' "$TENANT_DIR/backend/.env" \
    > "$BASE/config/tenants/$tenant/.env.example"
    fi
    echo " Prepared config for $tenant"
    done
  6. Commit the clean state

    Terminal window
    cd /mnt/data/magic_omniverse
    git add .gitignore config/
    git commit -m "chore: add .gitignore and tenant config structure
    - Add comprehensive .gitignore to exclude secrets, build artifacts,
    and tenant-specific runtime files
    - Create config/tenants/ directory with per-tenant configuration
    - Prepare for GitHub migration"

Goal: Push the existing repositories (with full commit history) to GitHub.

Time estimate: 30-60 minutes (depends on upload speed)

  1. Connect magic_development to GitHub

    Terminal window
    cd /mnt/data/magic_omniverse/magic_commerce/magic_development
    # Rename local remote for clarity
    git remote rename origin local-bare
    # Add GitHub as the new origin
    git remote add origin git@github.com:magiceverse/magic-commerce.git
    # Verify remotes
    git remote -v
    # Should show:
    # local-bare /mnt/data/magic_omniverse/magic_commerce.git (fetch)
    # local-bare /mnt/data/magic_omniverse/magic_commerce.git (push)
    # origin git@github.com:magiceverse/magic-commerce.git (fetch)
    # origin git@github.com:magiceverse/magic-commerce.git (push)
  2. Rename master to main (GitHub standard)

    Terminal window
    git branch -m master main
  3. Push to GitHub

    Terminal window
    # Push main branch with full history
    git push -u origin main
    # Push all existing feature/fix branches
    git push origin --all
  4. Repeat for Magic PIM

    Terminal window
    cd /mnt/data/magic_pim
    git remote add origin git@github.com:magiceverse/magic-pim.git
    git branch -m master main # or main already
    git push -u origin main
  5. Repeat for Magic Portal

    Terminal window
    cd /mnt/data/magic_omniverse/magic_portal
    git remote add origin git@github.com:magiceverse/magic-portal.git
    git branch -m master main
    git push -u origin main
  6. Repeat for Magic Docs

    Terminal window
    cd /mnt/data/magic_omniverse/magic_docs/starlight
    git remote add origin git@github.com:magiceverse/magic-docs.git
    git branch -m master main
    git push -u origin main
  7. Verify on GitHub

    Visit github.com/magiceverse and confirm:

    • All 4 repositories are visible
    • Commit history is intact
    • No .env or secret files are visible
    • .gitignore is present

Goal: Establish a clear branching model for development and releases.

BRANCHING MODEL
═══════════════
main ─────●─────●─────●─────●─────●─────●─────●─────►
│ ↑ │ ↑ │
│ merge │ │merge│ │
│ │ │ │ │
feature/ └───●───●───┘ │ │ └───●───●── ...
PROJ-0025 add test │ │ new
invoice it │ │ feature
│ │
fix/ ──────────────────────└──●──┘
FIX-0003 quick
fix
hotfix/ (for urgent production fixes — branch from main, merge back immediately)

Branch naming conventions:

Branch PatternPurposeExample
mainStable, production-ready codeAlways deployable
feature/PROJ-XXXX-descriptionNew featuresfeature/PROJ-0025-invoice-module
fix/FIXNNNN-descriptionBug fixesfix/FIX0003-cart-calculation
hotfix/descriptionUrgent production fixeshotfix/login-crash
tenant/nameTenant-specific customizations (if needed)tenant/brinxx-custom-pricing

Rules:

  1. Never commit directly to main — always use a branch + Pull Request
  2. Delete branches after merge — keeps the repo clean
  3. Write meaningful commit messages — explain why, not just what
  4. Use the existing PROJ-XXXX numbering from the Dev Projects system
  1. Protect the main branch on GitHub

    Terminal window
    # Using GitHub CLI
    gh api repos/magiceverse/magic-commerce/branches/main/protection \
    -X PUT \
    -f required_pull_request_reviews='{"required_approving_review_count":1}' \
    -F enforce_admins=false \
    -f required_status_checks='null' \
    -f restrictions='null'

    Or in GitHub web UI:

    • Go to Settings → Branches → Add branch protection rule
    • Branch name pattern: main
    • Enable: “Require a pull request before merging”
    • Enable: “Require approvals” (at least 1)
  2. Set up commit message template

    Terminal window
    # Create commit message template
    cat > /mnt/data/magic_omniverse/magic_commerce/magic_development/.gitmessage << 'EOF'
    # Format: type(scope): description
    #
    # Types: feat, fix, refactor, docs, chore, style, test
    # Scope: backend, storefront, admin, api, config, theme
    #
    # Examples:
    # feat(admin): add invoice PDF export
    # fix(api): correct cart total calculation
    # refactor(backend): simplify order processing module
    # chore(config): update Docker ports for spranz tenant
    EOF
    git config commit.template .gitmessage

Goal: Replace the manual cp/rsync workflow with a Git-based deployment to all tenants.

Time estimate: 2-3 hours

This is the most impactful phase — it replaces the current manual copy workflow with a clean, repeatable, Git-based approach.

GitHub (magiceverse/magic-commerce)
┌──────────────────────────────────┐
│ main branch │
│ (shared backend + storefront) │
└───────────────┬──────────────────┘
│ git pull origin main
Server: /mnt/data/magic_commerce_shared/
┌──────────────────────────────────┐
│ Single checkout of shared code │
│ ├── backend/src/ │
│ ├── storefront/src/ │
│ └── config/tenants/ │
└───────────────┬──────────────────┘
│ deploy-tenant.sh (symlinks or rsync)
┌────────────┼────────────┬────────────┐
│ │ │ │
▼ ▼ ▼ ▼
┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐
│ dev │ │ brinxx │ │default │ │ ... │
│tenant │ │ tenant │ │ tenant │ │tenants │
│(Docker)│ │(Docker)│ │(Docker)│ │(Docker)│
└────────┘ └────────┘ └────────┘ └────────┘
  1. Create the shared code directory

    Terminal window
    # Clone from GitHub into a new shared location
    cd /mnt/data
    git clone git@github.com:magiceverse/magic-commerce.git magic_commerce_shared
    # This becomes the SINGLE SOURCE for all tenant deployments
  2. Create the deployment script

    cat > /mnt/data/magic_commerce_shared/scripts/deploy-tenant.sh << 'SCRIPT'
    #!/bin/bash
    # ══════════════════════════════════════════════════════
    # Magic e-VERSE — Deploy shared code to a tenant
    # ══════════════════════════════════════════════════════
    set -e
    SHARED="/mnt/data/magic_commerce_shared"
    COMMERCE="/mnt/data/magic_omniverse/magic_commerce"
    TENANT="${1:?Usage: deploy-tenant.sh <tenant_name>}"
    TENANT_DIR="$COMMERCE/$TENANT"
    DATE=$(date +%Y%m%d-%H%M)
    if [ ! -d "$TENANT_DIR" ]; then
    echo "ERROR: Tenant directory not found: $TENANT_DIR"
    exit 1
    fi
    echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
    echo " Deploying to: $TENANT"
    echo " Source: $SHARED ($(cd $SHARED && git log --oneline -1))"
    echo " Date: $DATE"
    echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
    # Step 1: Sync backend source code
    echo "[1/5] Syncing backend source code..."
    rsync -av --delete \
    --exclude='node_modules' \
    --exclude='.medusa' \
    --exclude='dist' \
    "$SHARED/backend/src/" "$TENANT_DIR/backend/src/"
    # Step 2: Sync storefront source code
    echo "[2/5] Syncing storefront source code..."
    rsync -av --delete \
    --exclude='node_modules' \
    --exclude='.next' \
    --exclude='dist' \
    "$SHARED/storefront/src/" "$TENANT_DIR/storefront/src/"
    # Step 3: Sync package files (if changed)
    echo "[3/5] Syncing package files..."
    cp "$SHARED/backend/package.json" "$TENANT_DIR/backend/package.json"
    cp "$SHARED/storefront/package.json" "$TENANT_DIR/storefront/package.json"
    cp "$SHARED/backend/Dockerfile" "$TENANT_DIR/backend/Dockerfile"
    cp "$SHARED/storefront/Dockerfile" "$TENANT_DIR/storefront/Dockerfile"
    # Step 4: Apply tenant-specific config (if exists in config/tenants/)
    TENANT_CONFIG="$SHARED/config/tenants/$TENANT"
    if [ -d "$TENANT_CONFIG" ]; then
    echo "[4/5] Applying tenant config from config/tenants/$TENANT..."
    [ -f "$TENANT_CONFIG/docker-compose.yml" ] && \
    cp "$TENANT_CONFIG/docker-compose.yml" "$TENANT_DIR/docker-compose.yml"
    [ -f "$TENANT_CONFIG/medusa-config.ts" ] && \
    cp "$TENANT_CONFIG/medusa-config.ts" "$TENANT_DIR/backend/medusa-config.ts"
    else
    echo "[4/5] No tenant config found, skipping..."
    fi
    # Step 5: Rebuild Docker containers
    echo "[5/5] Rebuilding Docker containers..."
    cd "$TENANT_DIR"
    docker compose build backend storefront
    docker compose up -d backend storefront
    echo ""
    echo "$TENANT deployed successfully"
    echo " Commit: $(cd $SHARED && git log --oneline -1)"
    echo ""
    SCRIPT
    chmod +x /mnt/data/magic_commerce_shared/scripts/deploy-tenant.sh
  3. Create the deploy-all script

    cat > /mnt/data/magic_commerce_shared/scripts/deploy-all.sh << 'SCRIPT'
    #!/bin/bash
    # ══════════════════════════════════════════════════════
    # Magic e-VERSE — Deploy to ALL tenants
    # ══════════════════════════════════════════════════════
    set -e
    SHARED="/mnt/data/magic_commerce_shared"
    SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
    # Pull latest from GitHub first
    echo "╔══════════════════════════════════════════╗"
    echo "║ Magic e-VERSE — Full Deployment ║"
    echo "╚══════════════════════════════════════════╝"
    echo ""
    echo "Pulling latest from GitHub..."
    cd "$SHARED"
    git pull origin main
    echo "Current commit: $(git log --oneline -1)"
    echo ""
    TENANTS="magic_development magic_brinxx magic_default magic_demo magic_jodasign magic_logohorloge magic_bovisales magic_desluis magic_spranz"
    FAILED=""
    for tenant in $TENANTS; do
    echo ""
    echo "┌─── Deploying: $tenant ─────────────────────"
    if "$SCRIPT_DIR/deploy-tenant.sh" "$tenant"; then
    echo "└─── ✓ $tenant complete ────────────────────"
    else
    echo "└─── ✗ $tenant FAILED ──────────────────────"
    FAILED="$FAILED $tenant"
    fi
    done
    echo ""
    echo "╔══════════════════════════════════════════╗"
    if [ -z "$FAILED" ]; then
    echo "║ ✓ ALL TENANTS DEPLOYED SUCCESSFULLY ║"
    else
    echo "║ ⚠ SOME TENANTS FAILED: ║"
    echo "║ $FAILED"
    fi
    echo "║ ║"
    echo "║ Commit: $(git log --oneline -1) ║"
    echo "╚══════════════════════════════════════════╝"
    SCRIPT
    chmod +x /mnt/data/magic_commerce_shared/scripts/deploy-all.sh
  4. Create the git-pull-and-deploy workflow

    cat > /mnt/data/magic_commerce_shared/scripts/update.sh << 'SCRIPT'
    #!/bin/bash
    # Quick update: pull latest code and deploy to specified tenants
    # Usage: ./update.sh [tenant1 tenant2 ...] or ./update.sh --all
    SHARED="/mnt/data/magic_commerce_shared"
    SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
    cd "$SHARED"
    echo "Pulling latest from GitHub..."
    git pull origin main
    echo "Latest commit: $(git log --oneline -1)"
    echo ""
    if [ "$1" = "--all" ]; then
    "$SCRIPT_DIR/deploy-all.sh"
    elif [ $# -gt 0 ]; then
    for tenant in "$@"; do
    "$SCRIPT_DIR/deploy-tenant.sh" "$tenant"
    done
    else
    echo "Usage:"
    echo " ./update.sh --all Deploy to all tenants"
    echo " ./update.sh magic_brinxx Deploy to specific tenant(s)"
    echo " ./update.sh magic_brinxx magic_demo"
    fi
    SCRIPT
    chmod +x /mnt/data/magic_commerce_shared/scripts/update.sh

Goal: Establish the day-to-day workflow for making changes using Git.

NEW DEVELOPMENT WORKFLOW
═══════════════════════
Developer (on server or local machine)
──────────────────────────────────────
1. git pull origin main ◄── Get latest code
2. git checkout -b feature/PROJ-XXXX ◄── Create feature branch
3. ... make changes ... ◄── Write code
4. git add -p ◄── Stage changes (review each)
5. git commit -m "feat(admin): ..." ◄── Commit with clear message
6. git push origin feature/PROJ-XXXX ◄── Push branch to GitHub
7. Open Pull Request on GitHub ◄── Request review
8. Review & approve ◄── Team reviews the diff
9. Merge into main ◄── PR merged
10. Deploy to tenants ◄── Run update.sh
┌─────────────────────────────────────────────────────────────┐
│ KEY RULE: All changes flow through Pull Requests. │
│ No direct pushes to main. No more manual file copying. │
└─────────────────────────────────────────────────────────────┘
  1. Starting new work

    Terminal window
    cd /mnt/data/magic_commerce_shared
    # Make sure you're up to date
    git checkout main
    git pull origin main
    # Create a new branch for your work
    git checkout -b feature/PROJ-0030-credit-notes
  2. Making changes and committing

    Terminal window
    # After making changes...
    git status # See what changed
    git diff # Review the actual changes
    git add backend/src/api/admin/aplt/credit-notes/ # Stage specific files
    git commit -m "feat(admin): add credit note generation
    - Add POST /admin/aplt/credit-notes endpoint
    - Add credit note PDF template
    - Add admin UI route for credit note management"
  3. Push and create Pull Request

    Terminal window
    git push origin feature/PROJ-0030-credit-notes
    # Create PR using GitHub CLI
    gh pr create \
    --title "feat: Add credit note generation (PROJ-0030)" \
    --body "## Changes
    - New credit note API endpoint
    - PDF generation with template
    - Admin UI for management
    ## Testing
    - [ ] Create credit note from order
    - [ ] Generate PDF
    - [ ] View in admin panel"
  4. After PR is merged — deploy to tenants

    Terminal window
    # Pull the merged changes
    cd /mnt/data/magic_commerce_shared
    git checkout main
    git pull origin main
    # Deploy to specific tenant for testing first
    ./scripts/deploy-tenant.sh magic_development
    # Test on development tenant...
    # If everything works, deploy to all
    ./scripts/deploy-all.sh

Phase 7 (Future) — CI/CD with GitHub Actions

Section titled “Phase 7 (Future) — CI/CD with GitHub Actions”

Goal: Automate testing and deployment using GitHub Actions.

CI/CD PIPELINE (Future)
═══════════════════════
Push to branch Open Pull Request Merge to main
───────────── ────────────────── ─────────────
│ │ │
▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────┐
│ Lint & │ │ Build │ │ Deploy │
│ Type │ │ Check │ │ to all │
│ Check │ │ (Docker) │ │ tenants │
└──────────┘ └──────────┘ └──────────┘
│ │ │
▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────┐
│ Unit │ │ Preview │ │ Health │
│ Tests │ │ Comment │ │ Check │
│ (if any) │ │ on PR │ │ (curl) │
└──────────┘ └──────────┘ └──────────┘

Example GitHub Actions Workflow (for reference)

Section titled “Example GitHub Actions Workflow (for reference)”
.github/workflows/deploy.yml
name: Deploy to Tenants
on:
push:
branches: [main]
jobs:
deploy:
runs-on: self-hosted # Runs on your server
steps:
- name: Pull latest code
run: |
cd /mnt/data/magic_commerce_shared
git pull origin main
- name: Deploy to development (canary)
run: |
/mnt/data/magic_commerce_shared/scripts/deploy-tenant.sh magic_development
- name: Health check development
run: |
sleep 10
curl -f https://admin-development.magiceverse.online/health || exit 1
- name: Deploy to all tenants
run: |
/mnt/data/magic_commerce_shared/scripts/deploy-all.sh
- name: Notify on success
run: echo "Deployment complete for commit ${{ github.sha }}"
Terminal window
# Install GitHub Actions runner on your server
mkdir /opt/actions-runner && cd /opt/actions-runner
curl -o actions-runner-linux-x64.tar.gz -L \
https://github.com/actions/runner/releases/download/v2.XXX/actions-runner-linux-x64-2.XXX.tar.gz
tar xzf actions-runner-linux-x64.tar.gz
./config.sh --url https://github.com/magiceverse --token YOUR_TOKEN
sudo ./svc.sh install
sudo ./svc.sh start

┌────────────────────────────────────────────────────────────────────┐
│ PRE-MIGRATION CHECKLIST │
├────────────────────────────────────────────────────────────────────┤
│ │
│ PREPARATION │
│ [ ] Full server backup completed (all /mnt/data/) │
│ [ ] Database backups completed for all tenant databases │
│ [ ] Disk space verified (df -h — need ~5GB free) │
│ [ ] No active development in progress │
│ [ ] All tenants are currently stable and running │
│ [ ] Team has been informed of the migration │
│ │
│ ACCOUNTS & ACCESS │
│ [ ] GitHub account created / available │
│ [ ] Credit card on file (if using paid features) │
│ [ ] SSH key generated for server │
│ [ ] GitHub CLI installed on server │
│ │
│ CODE AUDIT │
│ [ ] No .env files or secrets in git history │
│ [ ] .gitignore created and tested │
│ [ ] docker-compose.yml files are NOT tracked │
│ [ ] medusa-config.ts tenant-specific values identified │
│ [ ] All tenant configurations backed up to config/tenants/ │
│ │
└────────────────────────────────────────────────────────────────────┘
┌────────────────────────────────────────────────────────────────────┐
│ POST-MIGRATION CHECKLIST │
├────────────────────────────────────────────────────────────────────┤
│ │
│ GITHUB VERIFICATION │
│ [ ] All 4 repositories visible on github.com/magiceverse │
│ [ ] Commit history is complete and intact │
│ [ ] No secrets visible in any repository │
│ [ ] Branch protection rules enabled on main branches │
│ [ ] SSH access from server to GitHub works (ssh -T git@github.com)│
│ │
│ REPOSITORY VERIFICATION │
│ [ ] magic-commerce: all backend/src files present │
│ [ ] magic-commerce: all storefront/src files present │
│ [ ] magic-commerce: config/tenants/ contains all 9 tenant configs │
│ [ ] magic-pim: all files present │
│ [ ] magic-portal: all files present │
│ [ ] magic-docs: documentation site builds correctly │
│ │
│ DEPLOYMENT VERIFICATION │
│ [ ] deploy-tenant.sh works for magic_development │
│ [ ] deploy-tenant.sh works for magic_brinxx │
│ [ ] deploy-all.sh completes without errors │
│ [ ] All 9 tenant admin UIs are accessible │
│ [ ] All 9 tenant storefronts are accessible │
│ [ ] PIM system is unaffected and running │
│ [ ] beta.brinxx.nl is accessible and functional │
│ │
│ WORKFLOW VERIFICATION │
│ [ ] Can create branch, commit, push, and open PR │
│ [ ] Can merge PR and pull changes on server │
│ [ ] Deploy scripts correctly sync code after pull │
│ [ ] Old local bare repo preserved as backup (do not delete yet) │
│ │
└────────────────────────────────────────────────────────────────────┘

If the migration causes issues, every phase is individually reversible:

Phase 1-3 Rollback (GitHub push failed or secrets exposed)

Section titled “Phase 1-3 Rollback (GitHub push failed or secrets exposed)”
Terminal window
# If secrets were accidentally pushed — delete the repo and recreate
gh repo delete magiceverse/magic-commerce --yes
# Then fix the issue and re-push
# Local repos are untouched — GitHub is just a copy
# Remove the GitHub remote if needed:
git remote remove origin
# Re-add the original local bare repo:
git remote add origin /mnt/data/magic_omniverse/magic_commerce.git

Phase 5 Rollback (Deployment script broke a tenant)

Section titled “Phase 5 Rollback (Deployment script broke a tenant)”
Terminal window
# The original tenant directories still exist with their code
# The deploy script only overwrites src/ directories
# Option 1: Restore from git history
cd /mnt/data/magic_omniverse/magic_commerce/magic_brinxx
git checkout HEAD -- backend/src/ storefront/src/
docker compose build backend storefront
docker compose up -d backend storefront
# Option 2: Restore from the local bare repo
cd /mnt/data/magic_omniverse/magic_commerce/magic_brinxx
git fetch local-bare
git checkout local-bare/master -- backend/src/
docker compose build backend && docker compose up -d backend
Terminal window
# The old workflow still works — nothing was deleted
# Simply stop using GitHub and go back to manual copy workflow
# Remove GitHub remotes from all repos:
for dir in magic_development magic_brinxx magic_pim; do
cd "/mnt/data/magic_omniverse/magic_commerce/$dir" 2>/dev/null || \
cd "/mnt/data/$dir" 2>/dev/null
git remote remove origin 2>/dev/null
git remote rename local-bare origin 2>/dev/null
echo "Restored: $dir"
done

For daily use after migration:

Terminal window
# ── Status & Information ──────────────────────
git status # What files changed?
git log --oneline -10 # Last 10 commits
git diff # See unstaged changes
git diff --staged # See staged changes
# ── Branching ─────────────────────────────────
git checkout main # Switch to main branch
git pull origin main # Get latest from GitHub
git checkout -b feature/name # Create new branch
git branch -d feature/name # Delete merged branch
# ── Committing ────────────────────────────────
git add path/to/file # Stage specific file
git add -p # Stage interactively (review each change)
git commit -m "type: message" # Commit staged changes
git push origin branch-name # Push branch to GitHub
# ── Pull Requests (via GitHub CLI) ────────────
gh pr create --title "..." # Create PR from current branch
gh pr list # List open PRs
gh pr merge 42 # Merge PR #42
gh pr view 42 --web # Open PR in browser
# ── Deployment ────────────────────────────────
./scripts/update.sh --all # Pull + deploy all
./scripts/update.sh magic_brinxx # Pull + deploy one
./scripts/deploy-tenant.sh magic_brinxx # Deploy without pull
# ── Emergency ─────────────────────────────────
git revert HEAD # Undo last commit (creates new commit)
git stash # Temporarily shelve changes
git stash pop # Restore shelved changes

PhaseDescriptionEffortRiskDependencies
Phase 1GitHub org & repos30 minLowGitHub account
Phase 2Clean & .gitignore1-2 hoursMediumPhase 1
Phase 3Push to GitHub30-60 minMediumPhase 2
Phase 4Branch strategy30 minLowPhase 3
Phase 5Deployment scripts2-3 hoursMediumPhase 3
Phase 6New workflowOngoingLowPhase 4+5
Phase 7CI/CD (future)4-8 hoursLowPhase 6 stable

Total initial effort: ~5-7 hours (Phases 1-6)