# ATAPOLY CBT — Docker Setup

The whole stack (Node app + Postgres database) ships as Docker images. The
target machine only needs **Docker** installed — no Node, no Postgres, no
manual config.

---

## 1. Build & save the bundle (on your dev machine)

Make sure the frontend is already built into `backend/public/` (run
`bash deploy.sh` or `cd frontend && npm run build && cp -r dist/* ../backend/public/`).

Then from the `backend/` folder:

**Linux / macOS:**
```bash
bash docker-build-and-save.sh
```

**Windows:**
```bat
.\docker-build-and-save.bat
```

This produces:

```
backend/DockerImages/
├── atapoly-cbt-images.tar   ← both images (app + postgres)
├── docker-compose.yml       ← the stack definition
└── README.txt               ← target-machine instructions
```

Copy the **entire `DockerImages/` folder** to any other machine.

---

## 2. Run on the target machine (Docker only)

```bash
cd DockerImages
docker load -i atapoly-cbt-images.tar
docker compose up -d
```

Open: **http://&lt;machine-ip&gt;:3001**

That's it. The database is created automatically on first boot, the schema is
applied, migrations run, and data persists in a Docker volume across restarts.

---

## 3. Common commands

| Action | Command |
|---|---|
| View logs | `docker compose logs -f app` |
| Restart | `docker compose restart` |
| Stop (keep data) | `docker compose down` |
| Stop & **delete database** | `docker compose down -v` |
| Update to a new bundle | `docker compose down` → `docker load -i atapoly-cbt-images.tar` → `docker compose up -d` |

---

## 4. Notes

- **Database port is not exposed** to the host — only the app container can
  reach it. This is intentional (security + no port conflicts).
- **Persistent data** lives in named volumes: `cbt_db_data`, `cbt_uploads`,
  `cbt_backups`, `cbt_license`. They survive `docker compose down` but are
  wiped by `docker compose down -v`.
- **Sync mode (optional):** to make a copy act as a lab-PC node that syncs to
  a hub, edit `docker-compose.yml` and set `ONLINE_SERVER_URL` and
  `SYNC_TOKEN`, then `docker compose up -d`.
- **License:** activate the license through the UI on first launch — the
  cached license is stored in the `cbt_license` volume and survives restarts.
