# infra R&D infrastructure stacks for Waterschap Brabantse Delta. Hub-and-spoke deployment: one **cloud** central hub + per-plant **edge** sites. ## Layout ``` infra/ ├── stacks/ # reusable, runnable stack defs (kebab-case) ├── cloud/ # the single central hub ├── sites/ # per-plant edge deployments └── docs/ # architecture + conventions ``` Stacks are pulled into the cloud and site composes via the Compose Spec `include:` directive. Each stack is also runnable standalone for testing. ## Quick start ```bash # Cloud hub (run on the central server) cd cloud cp .env.example .env # fill in real secrets ./deploy.sh # one-shot bring-up + Let's Encrypt + smoke test # A plant edge (run on the edge gateway at the plant) cd sites/ cp .env.example .env docker compose up -d ``` After `deploy.sh` finishes, see [`cloud/README.md`](cloud/README.md) for the one-time Keycloak realm bootstrap that wires every app to Keycloak SSO. ## Stacks | Stack | Purpose | Cloud | Edge | |---|---|:---:|:---:| | node-red | Flow-based automation | ✓ | ✓ | | influxdb | Time-series database | ✓ | ✓ | | grafana | Dashboards / SCADA | ✓ | ✓ | | keycloak | Identity / SSO | ✓ | ✓ | | portainer | Container management UI | ✓ | ✓ | | nginx-proxy | Stock nginx + certbot sidecar | ✓ | ✓ | | rabbitmq | General-purpose broker (AMQP + MQTT plugin) | ✓ | ✓ | | postfix | Outbound mail relay | ✓ | ✓ | | wireguard-server | VPN server | ✓ | — | | wireguard-client | VPN client | — | ✓ | | gitea | Git server (HTTPS-only) | ✓ | — | | jenkins | CI/CD | ✓ | — | | sql | Config DB (postgres 16) | ✓ | — | | mlflow | ML experiment tracking + registry | ✓ | — | | jupyterhub | Multi-user notebook server | ✓ | — | | frost | OGC SensorThings API (postgis + dedicated bus) | ✓ | — | | oauth2-proxy | Keycloak SSO gate (auth_request sidecar) for apps without native OIDC | ✓ | — | ## Sites | Site | Status | |---|---| | gemaal1 | Scaffolded — awaiting hardware provisioning | ## Design See [`docs/architecture.md`](docs/architecture.md) for the hub-and-spoke topology, 4-network model, ingress table, and the reasoning behind each choice. ## Conventions - kebab-case folder names - `compose.yml` (Compose Spec), not `docker-compose.yml` - Stack composes pulled into cloud/site via `include:` - Secrets in `.env` files (gitignored); `.env.example` committed with placeholders - OT layer (OPCUA, PLCs) is **out of scope** for this repo