Files
NextChair/README.md
T
Stefan Lazic 4763b50e62
CI / ci (push) Canceled after 0s
Dockge Removal
Removed dockge from the app as it is not required due to the manager page picking up most of its abilities.
2026-09-06 18:33:01 +01:00

234 lines
8.4 KiB
Markdown

# NextChair
Booking app as an alternative to Booksy
## VPS deployment (multi-business)
Everything below runs on a fresh VPS with Docker and the Compose plugin
already installed — no other prerequisite (no host Node.js/npm needed;
every command either uses Docker itself or plain shell tools). Every code
block is meant to be pasted as-is, in order.
### 0. One-time: clone the repo and generate your secrets
```bash
# STACKS_DIR later on must be this exact absolute path — every stack
# shells `docker compose` back out to the HOST's dockerd via a mounted
# socket, so the path only resolves to the same thing on both sides if
# it's cloned here and never moved.
git clone <your-repo-url> /opt/nextchair
cd /opt/nextchair
```
Generate the secrets you'll paste into the `.env` files in the steps
below. Run these now and keep the output somewhere safe (a password
manager) — you'll need each value again in a moment.
```bash
# MYSQL_ROOT_PASSWORD — goes into BOTH stacks/infra/.env and manager/.env
# (the same value in both places).
echo "MYSQL_ROOT_PASSWORD=$(openssl rand -hex 24)"
# MANAGER_SESSION_SECRET — manager/.env only.
echo "MANAGER_SESSION_SECRET=$(openssl rand -hex 32)"
# MANAGER_SETTINGS_ENCRYPTION_KEY — manager/.env only. Encrypts the
# SMTP/VAPID secrets you'll enter in the Manager's Settings page later.
# Losing/rotating this makes any already-saved secret there undecryptable,
# so store it as carefully as the other secrets on this page.
echo "MANAGER_SETTINGS_ENCRYPTION_KEY=$(openssl rand -hex 32)"
```
```bash
# MANAGER_PASSWORD_HASH — manager/.env only. Replace "your-password" with
# your chosen Manager login password first. Run via a throwaway container
# so this works with nothing but Docker installed on the host.
docker run --rm node:22-alpine sh -c \
"mkdir -p /tmp/gen && cd /tmp/gen && npm install bcryptjs --no-audit --no-fund >/dev/null 2>&1 && \
node -e \"const h=require('/tmp/gen/node_modules/bcryptjs').hashSync('your-password',12); console.log('MANAGER_PASSWORD_HASH=\\\"'+h.replace(/\\$/g,'\\$\\$')+'\\\"')\""
```
### 1. Shared infrastructure — network, MySQL and Caddy
```bash
docker network create next-chair-edge
cp .env.infra.example stacks/infra/.env
```
Edit `stacks/infra/.env`:
- `MYSQL_ROOT_PASSWORD` — the first secret you generated above.
- `MYSQL_HOST_PORT` — set this to `127.0.0.1:3306` so MySQL is only exposed on the VPS loopback interface, not publicly. You can still connect to it remotely through an SSH tunnel.
- `ACME_EMAIL` — a real address you check (Let's Encrypt renewal notices).
```bash
docker compose -f stacks/infra/compose.yaml --env-file stacks/infra/.env up -d
```
### 2. Build the shared application image
Every business (and no other step in this guide) runs this same image —
you only rebuild it here, once, and again whenever you ship a code
update (see "Updating" below).
```bash
docker build -t nextchair-app:latest .
```
### 3. The management UI (Manager)
This is what you'll use to add every business from here on.
```bash
cp manager/.env.example stacks/manager/.env
```
Edit `stacks/manager/.env`:
- `MANAGER_EMAIL` — the email you'll log in with.
- `MANAGER_PASSWORD_HASH` — the bcrypt hash generated in step 0.
- `MANAGER_SESSION_SECRET` and `MANAGER_SETTINGS_ENCRYPTION_KEY` — the two
other values generated in step 0.
- `MANAGER_PUBLIC_URL` — `https://` + the domain you'll point at this app
in the next step.
- `MYSQL_ROOT_PASSWORD` — same value as `stacks/infra/.env`.
- `STACKS_DIR` — same absolute path as step 1.
```bash
docker compose -f stacks/manager/compose.yaml --env-file stacks/manager/.env up -d --build
```
Point your chosen Manager domain's DNS (A/AAAA record) at the VPS, then
give it a Caddy site and reload:
```bash
cat > stacks/infra/sites/manager.caddy << 'EOF'
manager.example.com {
reverse_proxy next-chair-manager:3000
}
EOF
docker exec next-chair-caddy caddy reload --config /etc/caddy/Caddyfile
```
(Replace `manager.example.com` with your real domain — Caddy issues its
TLS certificate automatically on first request.)
### 4. Configure platform-wide settings (once)
Log into the Manager at `https://<your-manager-domain>` and open
**Settings**. Both sections are optional to fill in now, but doing it
before adding your first business means that business never needs its
own SMTP/push setup:
- **Email / SMTP** — your SMTP relay's host/port/username/password and a
from-address. Use **Send Test Email** to confirm it before saving for
real, then **Save Changes** to apply it to every business.
- **Push Notifications** — click **Generate VAPID Keys** once (a contact
email is enough to start). This is a one-time, platform-wide key pair —
see that section's own copy for what happens if you ever regenerate it.
### 5. Add your first business
Still in the Manager: **Add Business** → name, slug, domain. This creates
its database, generates its secrets, starts its container, and runs its
migrations for you — no manual per-business `.env` editing needed.
Point that business's own domain's DNS at the VPS (the Manager doesn't do
this for you), then finish its setup by visiting
`https://<business-domain>/install`.
Repeat this step for each additional business, whenever you want one.
## Updating after a code change
For an existing NextChair server, **do not re-run the fresh VPS setup above** and do not overwrite your production `.env` files.
First pull the latest code:
```bash
cd /opt/nextchair
git pull
```
Before rebuilding, check whether either example environment file has gained new settings since your last deployment:
```bash
# Review only — do not copy these files over your existing production .env files.
diff -u stacks/infra/.env .env.infra.example || true
diff -u stacks/manager/.env manager/.env.example || true
```
If a new variable has been added, copy **only that variable** into the corresponding production `.env` and give it an appropriate value. Keep all existing passwords, secrets and generated values unchanged.
Then rebuild the one shared image every business uses:
```bash
cd /opt/nextchair
docker build -t nextchair-app:latest .
```
Then, for **each** business: use its **Update** button in the Manager UI,
or run this directly:
```bash
cd /opt/nextchair/stacks/<slug>
docker compose --env-file .env up -d --force-recreate
```
Either way this recreates that business's container against the freshly
built image — and its own startup automatically runs
`prisma migrate deploy`, so any new database migration is applied on the
same step. No separate migration command needed.
If the code change touched the **Manager app itself** (anything under
`manager/`), rebuild/recreate the Manager too:
```bash
cd /opt/nextchair
docker compose -f stacks/manager/compose.yaml --env-file stacks/manager/.env up -d --build
```
If both the business app and Manager changed, do both update steps.
## Upgrading from a version that included Dockge (one-time)
Dockge used to run alongside NextChair Manager as a separate stack
management UI. It's no longer part of the shared infrastructure stack —
Manager is the only tool needed to provision and manage business stacks,
so the two were redundant. If your server was set up before this change,
existing tenant databases, tenant containers, business Compose files, and
the global SMTP/VAPID settings are all unaffected — this only removes the
old Dockge container.
Pull the change, then re-apply the infra stack with `--remove-orphans` so
Docker removes the container that's no longer defined in
`stacks/infra/compose.yaml`:
```bash
cd /opt/nextchair
git pull
docker compose \
-f stacks/infra/compose.yaml \
--env-file stacks/infra/.env \
up -d --remove-orphans
```
`--remove-orphans` only removes containers Compose no longer recognizes
(the old `next-chair-dockge` container) — it does not touch Caddy, MySQL,
or their volumes.
This does **not** delete Dockge's own data volume
(`next-chair-dockge-data`) — Docker never removes volumes on its own, and
this command has no reason to either. Once you've confirmed Caddy, MySQL
and every business are still healthy, you can remove that now-unused
volume by hand:
```bash
docker volume rm next-chair-dockge-data
```
Finally, `STACKS_DIR` and `DOCKGE_HOST_PORT` in `stacks/infra/.env` were
only ever used by Dockge and are safe to delete from that file — nothing
else in the infra stack reads them. (Manager keeps its own separate
`STACKS_DIR` in `stacks/manager/.env`; leave that one alone.)