# BMS — Data Centre Infrastructure Management A full-stack DCIM platform with live sensor dashboards, alarm management, power/cooling monitoring, and simulated sensor bots. **Stack:** Next.js 16 · FastAPI · PostgreSQL + TimescaleDB · MQTT (Mosquitto) · Docker Compose --- ## Table of Contents 1. [Prerequisites](#prerequisites) 2. [Quick Start — Docker Compose](#quick-start--docker-compose) 3. [Environment Variables](#environment-variables) 4. [Verify Everything Is Running](#verify-everything-is-running) 5. [Accessing the App](#accessing-the-app) 6. [Ports Reference](#ports-reference) 7. [Local Development (without Docker)](#local-development-without-docker) 8. [Project Structure](#project-structure) 9. [Stopping & Resetting](#stopping--resetting) --- ## Prerequisites | Requirement | Minimum version | Check | |---|---|---| | Docker | 24+ | `docker --version` | | Docker Compose | v2 (bundled with Docker Desktop / Engine) | `docker compose version` | | Git | any | `git --version` | That's it for the Docker path — Node and Python are **not** needed on the host. --- ## Quick Start — Docker Compose ### 1. Clone the repo ```bash git clone https://git.rdx4.com/youruser/bms.git cd bms ``` ### 2. Create the environment files ```bash cp backend/.env.example backend/.env cp frontend/.env.local.example frontend/.env.local ``` The defaults work as-is — they already match the service names in `docker-compose.yml`. **The app runs in demo mode with authentication disabled**, so there are no keys to obtain before the first run. See [Environment Variables](#environment-variables) below. ### 3. Start all services ```bash docker compose up --build ``` The first run downloads base images and builds the containers — this takes a few minutes. On subsequent starts it is much faster: ```bash docker compose up ``` ### 4. Done Open your browser at **http://your-server:5646** --- ## Environment Variables > **Authentication is disabled.** The app runs in demo mode: `frontend/proxy.ts` passes every > request through and there is no auth provider in `app/layout.tsx`. Deploy it on a trusted > network (LAN, VPN, or behind an authenticating reverse proxy) — every route is open. > > To turn auth back on: reinstall `@clerk/nextjs`, wrap the tree in `` in > `app/layout.tsx`, restore `` in `components/layout/topbar.tsx`, re-add the > `sign-in` / `sign-up` route groups, and swap `proxy.ts` for `clerkMiddleware`. ### `backend/.env` ```env # Database — matches the db service in docker-compose.yml, no change needed DATABASE_URL=postgresql+asyncpg://dcim:dcim_pass@db:5432/dcim # MQTT broker — matches the mqtt service, no change needed MQTT_HOST=mqtt MQTT_PORT=1883 # CORS — add your frontend origin if you expose the backend directly # Leave empty when using the built-in Next.js proxy (recommended) CORS_ORIGINS=[] DEBUG=true ``` ### `frontend/.env.local` ```env # API path — leave as-is, Next.js proxies /api/backend/* to the backend internally NEXT_PUBLIC_API_URL=/api/backend # Backend internal URL (used by the Next.js server-side proxy, not sent to the browser) # In Docker: http://backend:8000 In local dev: http://localhost:8000 BACKEND_INTERNAL_URL=http://backend:8000 ``` --- ## Verify Everything Is Running ```bash docker compose ps ``` All five services should show `healthy` or `running`: ``` NAME STATUS dcim_mqtt running (healthy) dcim_db running (healthy) dcim_backend running (healthy) dcim_simulators running dcim_frontend running ``` Check individual logs if something looks wrong: ```bash docker compose logs backend # FastAPI logs docker compose logs frontend # Next.js logs docker compose logs db # PostgreSQL logs docker compose logs simulators # Sensor bot logs ``` Test the backend API directly: ```bash curl http://localhost:8000/api/health # Expected: {"status":"ok"} ``` --- ## Accessing the App | What | URL | |---|---| | Dashboard | http://your-server:5646 | | API docs (Swagger) | http://your-server:5646/api/backend/docs | | API docs (ReDoc) | http://your-server:5646/api/backend/redoc | > **Reverse proxy tip:** The frontend is the only service that needs to be publicly reachable. Point Nginx / Caddy / Traefik at port **5646**. The backend, database, and MQTT broker communicate only on the internal Docker network. ``` Browser → Reverse Proxy → :5646 (Next.js) ↓ server-side rewrite :8000 (FastAPI) — internal only ``` --- ## Ports Reference | Service | Host port | Container port | Notes | |---|---|---|---| | Frontend (Next.js) | 5646 | 5646 | Public-facing | | Backend (FastAPI) | 8000 | 8000 | Internal; exposed for dev/debugging | | Database (PostgreSQL) | 5433 | 5432 | Mapped to 5433 to avoid conflicts with any local Postgres | | MQTT (Mosquitto) | 1883 | 1883 | Internal | --- ## Deploying to the Unraid Server The live instance runs on the Unraid Docker host at `192.168.1.249` as the Portainer stack **`bms`** — reachable at **http://192.168.1.249:5646/dashboard**. ```bash python3 ops/deploy.py # build all four images + deploy/update the stack python3 ops/deploy.py --no-build # redeploy the stack using the existing images ``` There is no `docker` CLI in WSL and no SSH to the Unraid box, so `ops/deploy.py` ships each service's build context to the remote daemon's `/build` endpoint over the Portainer API (token at `~/.portainer-token`), then pushes `docker-compose.prod.yml` as a Portainer stack. The script is idempotent — rerun it after any code change. `docker-compose.prod.yml` differs from the dev `docker-compose.yml`: images instead of build contexts, no source bind mounts, no `--reload`, and only the frontend publishes a host port. Postgres data is bind-mounted to `/mnt/user/appdata/bms/db` so it lands on the Unraid array instead of growing inside `docker.img`, and it survives redeploys. ## Local Development (without Docker) Useful if you want hot-reload on the frontend or backend without rebuilding containers. ### Database only via Docker ```bash docker compose up db mqtt ``` ### Backend Requires Python 3.12+. ```bash cd backend python -m venv .venv source .venv/bin/activate # Windows: .venv\Scripts\activate pip install -r requirements.txt uvicorn main:app --reload --port 8000 ``` ### Frontend Requires Node 22+ and pnpm. ```bash # Install pnpm if you don't have it npm install -g pnpm cd frontend pnpm install pnpm dev ``` Frontend dev server runs on http://localhost:3000 by default. ### Simulators ```bash cd simulators pip install -r requirements.txt python main.py ``` --- ## Project Structure ``` bms/ ├── frontend/ Next.js 16 app (TypeScript, Tailwind, shadcn/ui, Recharts) │ ├── app/ Pages (dashboard, cooling, power, alarms, floor-map, …) │ ├── components/ Shared UI components │ └── lib/ API client, contexts, utilities │ ├── backend/ FastAPI app │ ├── api/routes/ REST endpoints (alarms, cooling, power, env, …) │ ├── core/ DB connection, config │ ├── models/ SQLAlchemy models │ └── services/ MQTT subscriber, alarm engine, WebSocket manager │ ├── simulators/ Python sensor bots — publish fake DCIM telemetry over MQTT │ └── bots/ Per-device bots: CRAC, UPS, generator, PDU, env, … │ ├── infra/ │ └── mosquitto/ Mosquitto broker config │ └── docker-compose.yml Orchestrates all services ``` --- ## Stopping & Resetting ```bash # Stop all containers (data is preserved) docker compose down # Stop and delete the database volume (full reset — all data lost) docker compose down -v # Rebuild images after code changes docker compose up --build ```