156166b4e5
- deploy/booking: shared Easy!Appointments stack with brand-matched wizard (flatpickr recolor, single-tenant provider hide, iframe auto-fit height reporter) - deploy/clients: per-client isolated nginx compose stacks with _template scaffold, new-client.sh, and happynails live site - deploy/backup: smb-db backup script - n8n: booking-sync workflow; onboarding tweaks - playbooks: lead-to-customer lifecycle + outreach - templates: nail-studio landing previews - backoffice: app/db/init/compose updates Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
47 lines
2.3 KiB
Markdown
47 lines
2.3 KiB
Markdown
# clients/ — one isolated stack per business client
|
||
|
||
Each signed client gets their **own Compose project** (`smb-client-<slug>`) running a
|
||
single lightweight `nginx:alpine` container that serves *their* static site on *their*
|
||
domain. Clients are fully separated: independent lifecycle, logs, and removal; no shared
|
||
container or state. Booking and lead data still flow into the **shared CRM** (Postgres
|
||
source of truth) via the n8n webhooks baked into each client's page.
|
||
|
||
## Why a container per client (not one shared host)
|
||
- **Isolation** — update / restart / remove one client without touching any other.
|
||
- **Clean billing & offboarding** — `docker compose down` removes exactly that client.
|
||
- **Cheap** — static nginx idles at a few MB; capped at 64 MB each, so dozens fit the 16 GB box.
|
||
|
||
## Layout
|
||
```
|
||
deploy/clients/
|
||
├── _template/ # DON'T deploy — the source template
|
||
│ ├── docker-compose.yml (name: smb-client-${CLIENT_SLUG})
|
||
│ ├── .env.example
|
||
│ └── site/index.html
|
||
├── new-client.sh # scaffolds a client folder from _template/
|
||
└── <slug>/ # one folder per real client (created by the script)
|
||
├── docker-compose.yml
|
||
├── .env (CLIENT_SLUG, CLIENT_DOMAIN)
|
||
└── site/ (the client's branded page)
|
||
```
|
||
|
||
## Add a client
|
||
```bash
|
||
cd deploy/clients
|
||
./new-client.sh happynails happynails.de ../../templates/landing/preview-happynails
|
||
```
|
||
Then follow the printed steps: add the Caddy block + reload, point DNS, and `docker compose up -d`
|
||
on the homelab. Each client lives at `/home/mivanchenko/clients/<slug>/` on the box.
|
||
|
||
## How this fits the whole system (compose groups)
|
||
```
|
||
edge/ caddy → TLS, routing, basic-auth (one, shared)
|
||
automation/ n8n (+ postgres, redis) → n8n.mivanchenko.de (one, shared)
|
||
crm/ smb-db + smb-crm → onboard.mivanchenko.de/crm (one, shared)
|
||
demos/ smb-demos → demos.mivanchenko.de (prospect previews)
|
||
clients/ smb-client-<slug> × N → each client's domain (one per client) ← this dir
|
||
```
|
||
Shared infra (edge / automation / crm) stays single; only the client-facing sites multiply,
|
||
one isolated stack each. Previews for *prospects* stay in `demos/` until they sign — then
|
||
scaffold them a real isolated stack here.
|