--- name: Wild Dragon MAM platform description: Self-hosted media asset management replacing Grass Valley AMPP FramelightX. Deployed on zampp1 (primary) and zampp2 (worker w/ DeckLink Duo 2). Repo at forge.wilddragon.net/zgaetano/wild-dragon. type: project originSessionId: 544a289a-0493-4194-9fbd-112ed250e221 --- Self-hosted MAM platform under active development. Stack: Node.js/Express, vanilla HTML/CSS/JS frontend, PostgreSQL 16, Redis 7 + BullMQ, S3-compatible (RustFS), FFmpeg, Blackmagic DeckLink SDK, Docker Compose. Repo: `forge.wilddragon.net/zgaetano/wild-dragon` (HTTPS only, no SSH). **Why:** Replacing Grass Valley AMPP FramelightX with an in-house alternative. Test deployment is the production deployment — the user authorizes pushing directly to `main` and deploying to zampp1 + zampp2 for continued testing. **How to apply:** Treat zampp1/zampp2 as authorized targets for MeshCentral / live deploy. Push to `main` directly when changes are validated. The repo's `deploy/onboard-node.sh` is the canonical worker provisioning path. ## Cluster topology - **zampp1** — primary; runs `mam-api`, `db`, `redis`, `web-ui`, `worker`, `capture` containers via `docker-compose.yml` - **zampp2** — worker; runs `node-agent` (host-network) + on-demand `capture` sidecars via `docker-compose.worker.yml`; has a **DeckLink Duo 2** (4 BNC ports at `/dev/blackmagic/io0..io3`) - Workers heartbeat to `POST /api/v1/cluster/heartbeat` with hostname, IP, GPU/DeckLink capabilities - Cluster registry: unique index on `cluster_nodes.hostname` (migration 007); `pickIp()` in `routes/cluster.js` rejects 172.16/12 docker bridge IPs in favor of request source IP ## Codec selection (recorders) Per-recorder columns added in migration 008 (`recording_*` and `proxy_*` for video bitrate, framerate, audio codec/bitrate/channels, container). `services/capture/src/capture-manager.js` exports `VIDEO_CODECS`, `AUDIO_CODECS`, `CONTAINER_FMT`, `CONTAINER_EXT` catalogs. `routes/recorders.js` `RECORDER_FIELDS` whitelist passes settings as env vars to the capture sidecar via `bootstrapAutoStart()`. ## DeckLink port picker `services/web-ui/public/js/bmd-card.js` (window.BMDCards) renders an SVG diagram of the card with click-to-select ports. Models registered: Duo 2, Quad 2, Mini Recorder 4K, Mini Monitor 4K, UltraStudio 4K Mini. Backed by `GET /api/v1/cluster/devices/blackmagic` which flattens every node's DeckLink capabilities. **The `recorders.html` rewrite that consumes this was lost** in a context-compaction event — file on zampp1 still matches the old (pre-tabs, pre-SVG) version. ## Pending work (as of 2026-05-21) 1. Re-do `services/web-ui/public/recorders.html` rewrite — tabbed codec settings (Video/Audio/Container) for both master & proxy, node selector + BMD card SVG picker for SDI source. The previous attempt was transferred to zampp1 mid-session but the chunked b64 assembly never completed. 2. Deploy on zampp1: `cd /opt/wild-dragon && git pull && docker compose up -d --build` to pick up migrations 007/008 and codec changes. 3. Deploy on zampp2: `git pull`, update `.env.worker` with `BMD_COUNT=4`, `BMD_MODEL='DeckLink Duo 2'`, `NODE_IP=`, then `docker compose -f docker-compose.worker.yml up -d --build`. 4. Run `deploy/test-cluster.sh` on zampp1 to validate. 5. GUI polish pass with flyonui MCP (explicitly the LAST priority). ## Pushed commits (already on `main`) - `3b4af6e` node-agent: prefer host LAN IP, NODE_IP override - `0efef0d` cluster route: pickIp() + /devices/blackmagic endpoint - `a39c983` migration 007: dedupe hostnames + unique index - `049beb8` migration 008: expanded codec columns - `40a66ba` worker compose: network_mode: host for node-agent - `f4a83ee` capture-manager: dynamic ffmpeg args - `485af25` capture index.js: bootstrap reads codec env vars - `4c65753` recorders route: full codec field whitelist - `0ebb3cf` onboard-node: auto-detect host LAN IP - `d39f86d` web-ui: bmd-card.js - `97628bb` chore: remove cloudflare rate-limit probe (.touchtest) - `8aa3783` deploy: test-cluster.sh + .touchtest cleanup (rebased onto 97628bb and pushed from zampp1 using a Forgejo PAT written to /root/.git-credentials) ## Git creds on zampp1 `/root/.git-credentials` holds the Forgejo PAT for user `zgaetano`. `credential.helper=store` is set in `/root/.gitconfig`. Future pushes from zampp1 just need `HOME=/root` exported (the MeshCentral agent's default $HOME is `/usr/local/mesh_services/Mesh Dragon/MeshDragon`). Rotate the PAT by overwriting that one file.