-- 011_opnfwd.sql — wire panel into opnfwd's port-forward HTTP API. -- -- Three changes: -- 1. agents.lan_ip — operator-set LAN IP for this agent. opnfwd's `target` -- field needs the LAN-side IP of the host running the game container. -- Defaulted blank; the dashboard's agent edit modal lets the operator -- fill it in. Without it, the opnfwd integration silently no-ops for -- instances on that agent (loud log line, no destructive failure). -- -- 2. panel_settings — singleton key/value table for instance-wide knobs. -- Today: opnfwd_enabled / opnfwd_url / opnfwd_token. Future: anything -- else that's "global, operator-edited, doesn't fit elsewhere." -- -- 3. instance_forwards — what the panel believes it owns in opnfwd. We -- persist the {nat_uuid, filter_uuid} returned by `POST /api/forwards` -- so we can target opnfwd's bulk-delete on instance delete. Composite -- PK on (instance_id, port_name) — every public port gets one row. ALTER TABLE agents ADD COLUMN IF NOT EXISTS lan_ip TEXT NOT NULL DEFAULT ''; CREATE TABLE IF NOT EXISTS panel_settings ( key TEXT PRIMARY KEY, value TEXT NOT NULL DEFAULT '', updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); INSERT INTO panel_settings (key, value) VALUES ('opnfwd_enabled', 'false'), ('opnfwd_url', ''), ('opnfwd_token', '') ON CONFLICT (key) DO NOTHING; CREATE TABLE IF NOT EXISTS instance_forwards ( instance_id TEXT NOT NULL, port_name TEXT NOT NULL, nat_uuid TEXT NOT NULL DEFAULT '', filter_uuid TEXT NOT NULL DEFAULT '', target_ip TEXT NOT NULL, host_port INTEGER NOT NULL, proto TEXT NOT NULL, descr TEXT NOT NULL DEFAULT '', created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), PRIMARY KEY (instance_id, port_name) ); CREATE INDEX IF NOT EXISTS instance_forwards_instance_id_idx ON instance_forwards(instance_id);