Paste the content below the line into Docker Hub → <DOCKER_USER>/caissemanager-prod →
Repository overview. It is written for whoever deploys the stack, not for us, so it
says nothing about CI, the frontend repos or how the artifact is built.
Keep it in step with CI-CD.md — the settings table here mirrors the runtime variables documented there.
This repository does not hold a container image. It holds the entire Caisse Manager
backend as a single OCI Compose artifact: one docker compose file, with every image
reference and setting already resolved, published under one tag. One command brings the
whole stack up on a clean host — no repository checkout, no .env to assemble.
docker compose -f oci://docker.io/amineessadiki/caissemanager-prod:latest up -d
docker pull on this repository will not do anything useful. Use -f oci://….
docker compose version;
if oci:// is not recognised, the plugin is too old.docker login first./opt/caissemanager
on first start./dev/bus/usb present — the printing worker binds it for USB receipt printers.| Tag | Meaning |
|---|---|
latest | Newest build from the release branch. Convenient, moves under you. |
<40-char commit sha> | One exact build. Pin production to this. |
<environment> | Newest build for a named per-site environment. |
<environment>-<sha> | One exact build for that environment. |
pr-<number> | Preview built from an open pull request. Never deploy. |
| Service | Container | Port (host → container) | Role |
|---|---|---|---|
app | cm-api | 8000 → 8000, 8001 → 8001 | REST API and the socket server |
mongo | cm-mongo | 27017 → 27017 | MongoDB, single-node replica set (transactions need it) |
redis | cm-redis | 6379 → 6379 | Queues and cache |
html-renderer | cm-html-renderer | 5000 → 5000 | Renders receipts and labels to image/PDF |
printing-worker | cm-printing-worker | — | Drives USB receipt printers |
log-archiver | cm-log-archiver | — | Rotates the API logs daily into dated .gz |
host-dirs-init | — | — | One-shot: creates the host folders before anything mounts them, then exits |
The POS and back-office frontends are appended to this same artifact by their own
pipelines, so a complete latest also carries a front and a backoffice service.
Every service that mounts a host folder waits for host-dirs-init to finish, so a first
run on a clean host needs no manual mkdir.
Four folders, bind-mounted so they survive docker compose down and image upgrades:
| Path | Holds | Override with |
|---|---|---|
/opt/caissemanager/mongo-data | MongoDB data files | MONGO_DATA_PATH |
/opt/caissemanager/uploads | Product images and other uploads | UPLOADS_PATH |
/opt/caissemanager/logs | API logs, rotated daily | LOGS_PATH |
/opt/caissemanager/cache | Redis dump | REDIS_DATA_PATH |
Point these at your own disk when /opt is small:
MONGO_DATA_PATH=/srv/cm/mongo UPLOADS_PATH=/srv/cm/uploads \
docker compose -f oci://docker.io/amineessadiki/caissemanager-prod:latest up -d
Changing a path on a running install does not move the data — stop the stack, copy the folder, then start with the new value.
The artifact already carries a complete configuration, so a plain up -d works. These are
the ones worth overriding at deploy time:
| Variable | Default | Purpose |
|---|---|---|
LICENCE_KEY | — | Licence for a brand-new database. On the first healthy start the API registers it and provisions the install — admin user, settings, one POS per licensed seat. An existing licence is never overwritten, so leaving it set across restarts is safe. |
ADMIN_EMAIL | set | Login of the Default Admin the seeder creates on a fresh install. |
ADMIN_PASSWORD | set | That user's password. Change it before going live. |
API_KEY | set | Guards /api/admin/*, sent as Authorization: Api-Key <key>. |
HOST_API_PORT | 8000 | REST API on the host. |
HOST_SOCKET_PORT | 8001 | Socket server on the host. |
HOST_MONGO_PORT | 27017 | MongoDB on the host. |
HOST_REDIS_PORT | 6379 | Redis on the host. |
HOST_RENDERER_PORT | 5000 | HTML renderer on the host. |
Rather than booting half-configured, cm-api checks every required setting first and
exits listing whatever is missing:
[entrypoint] refusing to start — missing required settings (env_files/.env):
ADMIN_PASSWORD
If you see this, the value is missing from the environment you started the stack with —
supply it and start again. LICENCE_KEY is the one exception: an install may come up
unlicensed and wait to be licensed later.
Pass the licence on the first start:
LICENCE_KEY=<key> docker compose -f oci://docker.io/amineessadiki/caissemanager-prod:latest up -d
Or register it against a running stack at any time:
curl -X PUT http://localhost:8000/api/admin/sync \
-H "Authorization: Api-Key $API_KEY" \
-H 'Content-Type: application/json' \
-d '{"token":"<licence-key>"}'
The same call renews a licence and reconciles the POS count against a new seat quantity. Check the current state with:
curl -H "Authorization: Api-Key $API_KEY" http://localhost:8000/api/admin/subscription
STACK=oci://docker.io/amineessadiki/caissemanager-prod:latest
docker compose -f $STACK ps # what is running
docker compose -f $STACK logs -f app # follow the API
docker compose -f $STACK down # stop, keep the data
docker compose -f $STACK config # the resolved stack — output is sensitive
Upgrade — start the newer tag; the host folders are reused, so data carries over:
docker compose -f oci://docker.io/amineessadiki/caissemanager-prod:<new-sha> up -d
Roll back — start the previous SHA tag the same way. Database migrations run forward only, so rolling back across a schema change needs a data restore too.
Health — curl http://localhost:8000/health.
docker compose config
prints as sensitive.mongod.