# v0.1 Demo — Deployment Guide (for DevOps)

Stand up the **Retail Inward v0.1 demo** on a fresh server. Self-contained: it needs only a broker + a database
(both in one compose file). **The full Garuda Core is NOT required** for the demo.

---

## 1. Prerequisites

| Requirement | Version | Notes |
|---|---|---|
| OS | Linux (Ubuntu 22.04+) or macOS | any Docker host |
| **Docker + Compose** | Docker 24+, Compose v2 | runs EMQX + Postgres |
| **Node.js** | **22 LTS+** | runs the engine, device sim, acceptance, UI generators |
| git | any | clone the repo |
| RAM / disk | ~2 GB / ~2 GB | small |

Open ports (if firewalled): **1883** (MQTT), **5440** (Postgres), **18083** (EMQX dashboard, optional).

---

## 2. Get the code

Private repo `ottlin/garuda-pe` — you need read access (a GitHub PAT, or an SSH deploy key for headless servers).

```bash
git clone https://github.com/ottlin/garuda-pe.git garuda-pe    # or: git@github.com:ottlin/garuda-pe.git
cd garuda-pe
git checkout foundation          # v0.1 lives on the foundation branch (NOT main)
cd platform
```

## 3. Bring up the infra (one command)

```bash
cd deploy && docker compose up -d
docker compose ps                # both healthy: garuda_demo_emqx, garuda_events_db
cd ..
```
This starts **EMQX** (MQTT broker, anonymous OK for demo) and the **garuda_events Postgres** (port 5440).

## 4. Install Node deps + migrate the database

```bash
# deps (only these packages have dependencies)
( cd event-log  && npm install )
( cd ingest     && npm install )
( cd device-cli && npm install )
( cd acceptance && npm install )

# create the event-log schema
( cd event-log && node migrate.js )     # → "✓ migrated garuda_events"
```

## 5. Smoke test (prove it's wired)

```bash
cd acceptance && node src/run.js         # expect: ACCEPTANCE PASSED ✓ — 24/24
cd ..
```
If that prints 24/24, the server is demo-ready. Then follow **`platform/DEMO.md`** for the live 3-beat demo.

---

## 6. Configuration (env vars)

Everything defaults to the compose above; override with env vars if ports/hosts differ:

| Var | Default | Used by |
|---|---|---|
| `MQTT_BROKER` | `mqtt://localhost:1883` | engine consumer, device CLI, acceptance |
| `GARUDA_EVENTS_DB` | `postgres://garuda:garuda_dev_password@localhost:5440/garuda_events` | engine consumer, migrate, acceptance |

Example (broker on another host): `MQTT_BROKER=mqtt://10.0.0.5:1883 node ingest/src/engine-consumer.js`

> **On a machine already running the Core:** skip §3. The Core already runs EMQX (`mqtt://localhost:1883`); just
> stand up the `garuda_events` DB (`cd event-log && docker compose up -d && node migrate.js`) and point the demo at
> the Core's broker. Do **not** run two EMQX on port 1883.

---

## 6b. One-command (re)deploy

After the first-time setup (§3–4), every subsequent deploy is a single script — pull, install, infra, migrate,
regenerate both screens, restart pm2. It **waits for Postgres before migrating** (the manual sequence raced this).

```bash
bash platform/deploy.sh                 # full redeploy
bash platform/deploy.sh --skip-install  # faster when deps are unchanged
bash platform/deploy.sh --no-pull       # deploy current code without git pull
```

**pm2 processes (`platform/deploy/ecosystem.config.js`):** two apps — `garuda-engine` (the engine consumer) and
`garuda-pe` (a zero-dep static server, `serve.mjs`, serving both screens on `:8080`). **`deploy.sh` starts them from
the ecosystem automatically on the first run** and restarts them on every run after — no manual pm2 start needed. To
survive reboots, run `pm2 startup` once and the script's `pm2 save` keeps them. Put nginx/caddy in front to map
`garuda-pe.openturf.dev → :8080` (TLS + domain).

Manual, if ever needed:
```bash
pm2 start platform/deploy/ecosystem.config.js   # start both
pm2 restart garuda-engine garuda-pe             # restart both
pm2 logs garuda-engine                          # tail engine
```

## 7. Run the demo (summary — full script in DEMO.md)

```bash
# Terminal 1 — the engine service (leave running)
cd platform/ingest && node src/engine-consumer.js

# Terminal 2 — scan cartons
cd platform/device-cli
node src/tunnel.js shift                 # whole shipment → inventory 200, 2 held

# Screens
cd platform/runtime-ui && node src/snapshot.js && open runtime-ui.html      # operator
cd platform/customer-view && node snapshot.js && open customer-view.html    # customer/manager
```
**Reset between runs:** `cd platform/event-log && node --input-type=module -e "import {truncateAll} from './src/test-support.js'; await truncateAll(process.env.GARUDA_EVENTS_DB||'postgres://garuda:garuda_dev_password@localhost:5440/garuda_events'); console.log('clean')"`
**Important:** stop the engine consumer (Ctrl-C) **before** running the acceptance harness (they share a broker group).

---

## 8. Troubleshooting

| Symptom | Fix |
|---|---|
| `mqtt error ... ECONNREFUSED 1883` | EMQX not up — `docker compose -f deploy/docker-compose.yml ps`; check port 1883 free |
| `run-pg failed ... ECONNREFUSED 5440` | DB not up or not migrated — `docker compose ps`; re-run `event-log/node migrate.js` |
| acceptance hangs / partial results | an engine consumer is still running — stop it (shares the shared-subscription group) |
| `Cannot find package 'mqtt' / 'pg'` | run the `npm install` in §4 for that package |
| headless server (no `open`) | copy `runtime-ui.html` / `customer-view.html` off the box, or serve the dir: `python3 -m http.server` |

---

## 9. A release package, organized by stakeholder

Once deployed, the same server serves **each stakeholder their own view** — this is the point:

| Stakeholder | What they see | Where |
|---|---|---|
| **DC Operators / staff** | the operator runtime (role-scoped screens, live transaction, device health) | `runtime-ui.html` |
| **Customer / Business / Zonal Mgr** | the inventory dashboard (accepted cartons, stock, exceptions) | `customer-view.html` |
| **QA / Test** | the acceptance harness — 24/24 across all 22 AC-RT, one command | `acceptance/src/run.js` |
| **Product / Leadership** | the plain-language stage-by-stage narrative | `../architecture/STAGE-UPDATES.md` |
| **Architecture (Vivek)** | ADRs, structural model, change-spec, integration plan | `../architecture/` |
| **DevOps** | this guide + the compose | `DEPLOY.md`, `deploy/docker-compose.yml` |
| **Engineers (new joiners)** | the device-sim→HTML trail | `WALKTHROUGH.md` |

*(Deep coexistence — physical device, Solution Studio authoring, shadow-parity-then-cut against the live Core — are
the post-demo tracks; see `../architecture/change-spec/INTEGRATION-PLAN.md`.)*
