Files
mivanchenko 156166b4e5 Add booking stack, client deploys, and back-office updates
- 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>
2026-07-14 16:10:15 +02:00

47 lines
2.3 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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.