# Appspace Webex Alerts Lightweight Node/Express service that bridges **Appspace** device health events to **Cisco Webex** via Adaptive Cards, with optional enrichment from **Workspace ONE MDM**. It also runs an interactive Webex bot (WebSocket mode) for on-demand queries. ## What it does - Listens for Appspace outbound webhooks (`DEVICE.HEALTHSTATUS.*` and `DEVICE.UNREGISTERED`). - Ignores PWA devices. - Enriches alerts with current MDM data (model, OS version, compliance, last sample/seen timestamps in EDT). - Posts formatted Adaptive Cards to a configured Webex room (with direct links to both consoles). - Provides a Webex bot with commands: - `offline [optional filter]` — snapshot of currently offline/lost/failed devices (client-side filter on name or type). - `help` ## Requirements - Node 20+ - Appspace instance with outbound webhook + Application refresh token - Webex bot token + room ID - (Optional but recommended) Workspace ONE MDM OAuth client for enrichment ## Quick Start (Docker - recommended) 1. Copy env: ```bash cp .env.example .env # or .env.dev for the dev profile ``` 2. Fill in the required values (see `.env.example` for descriptions). 3. Run: ```bash # Production profile npm run docker:prod # Development (with live reload + volume mount) npm run docker:dev # Smoke test (builds image + verifies /health responds "healthy" inside container) npm run docker:smoke ``` **Port mapping notes**: The container always listens internally on port 3000 (hardened default). Host port 1889 is used for both dev (`docker compose --profile dev up -d app-dev`) and prod (`docker compose up -d`). The `PORT` env inside the container is forced to 3000 via compose. You cannot run both profiles at the same time due to the shared host port. Direct: ```bash npm install npm start ``` Health check: `GET /health` ## Environment Variables See `.env.example` for the full documented list. Key ones: - `WEBEX_BOT_TOKEN`, `WEBEX_ROOM_ID` - `APPSPACE_INSTANCE_URL`, `APPSPACE_SUBJECT_ID`, `APPSPACE_REFRESH_TOKEN`, `APPSPACE_API_BASE_URL` - `WS1_*` (for MDM enrichment) - `WEBHOOK_SECRET` (recommended for the Appspace webhook) - `DEBUG`, `DEBUG_WEBHOOK` (see below) ## Bot Commands In the Webex space where the bot is added: - `offline` — current problematic devices - `offline tablet` — filter to devices whose name or type contains "tablet" - `help` The bot runs in WebSocket mode (no public webhook required). ## Debugging - `DEBUG=true` — verbose logging for MDM lookups, ignored events, command handling, etc. (very useful in dev, noisy in prod). - `DEBUG_WEBHOOK=true` — log the **full** incoming Appspace webhook payload (contains device details; do **not** leave on in production). - `LOG_FORMAT=json` (or `NODE_ENV=production`) — output structured JSON logs (ideal for Docker/K8s log collectors). You can also set `NODE_ENV=development` for similar verbose behavior. ## Production & Docker Notes - **Graceful shutdown**: The service handles `SIGTERM` (used by `docker stop`, Kubernetes, etc.) and `SIGINT`. It will: 1. Stop the Webex WebSocket framework (important to avoid "excessive device registrations"). 2. Close the HTTP server. 3. Exit cleanly. A hard timeout forces exit after ~8s. - **Healthcheck**: `/health` returns 200 with basic status. Used by Docker and orchestrators. - **Logging**: Logs go to stdout/stderr (12-factor / Docker friendly). Use `LOG_FORMAT=json` or `NODE_ENV=production` for structured JSON. Use `DEBUG=true` in non-prod for detail. Pipe to a collector (Loki, CloudWatch, etc.) as needed. - **Secrets**: Never bake secrets into the image. Use: - `env_file` for compose (dev/staging only) - Docker secrets, Kubernetes Secrets, or a secrets manager (Vault, AWS Secrets Manager) for production. - **Ports**: Container always listens on 3000 internally. Map host ports as needed (see docker-compose.yml). - **Non-root**: Production image runs as the `node` user. - **Resources**: In production, set CPU/memory limits in your orchestrator. The bot command does a full device list scan (limit 500) — monitor for large fleets. ## Architecture Notes - Appspace token uses refresh token + cooldown + safety buffer. - MDM uses 24h serial→ID cache + fresh detail lookup by ID on every alert (for up-to-date compliance/last-seen). - WebSocket mode for the bot avoids restart rate limits. - All enrichment is best-effort; alerts are never blocked by MDM or token issues. ## License / Support Internal tool. Tweak as needed. ## TODO / Future - Server-side filtering for the devices list when the Appspace API supports it reliably. - Metrics / full structured JSON logging. - Support for more Appspace event types. - Multi-stage Dockerfile for even smaller prod images.