feat(health): add external URL column, backfill domains, thread through repo
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
17
lib/db/migrations/022_monitored_services_external.sql
Normal file
17
lib/db/migrations/022_monitored_services_external.sql
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
-- 022_monitored_services_external.sql
|
||||||
|
-- Optional external/domain URL for a service, used by the dashboard tile when the
|
||||||
|
-- owner is browsing remotely. LAN `url` stays the source of truth for health checks.
|
||||||
|
ALTER TABLE monitored_services ADD COLUMN external text;
|
||||||
|
|
||||||
|
-- Backfill curated domains by id (the live instance is already seeded, so adding the
|
||||||
|
-- column alone wouldn't populate them). No-op for ids that don't exist.
|
||||||
|
UPDATE monitored_services SET external = 'https://void.hynesy.com' WHERE id = 'void-server';
|
||||||
|
UPDATE monitored_services SET external = 'https://gramps.hynesy.com' WHERE id = 'gramps';
|
||||||
|
UPDATE monitored_services SET external = 'https://plex.hynesy.com' WHERE id = 'plex';
|
||||||
|
UPDATE monitored_services SET external = 'https://tdarr.hynesy.com' WHERE id = 'tdarr';
|
||||||
|
UPDATE monitored_services SET external = 'https://sonarr.hynesy.com' WHERE id = 'sonarr';
|
||||||
|
UPDATE monitored_services SET external = 'https://radarr.hynesy.com' WHERE id = 'radarr';
|
||||||
|
UPDATE monitored_services SET external = 'https://bookstack.hynesy.com' WHERE id = 'bookstack';
|
||||||
|
-- Two services previously stored their domain in `url`; normalise to LAN url + external.
|
||||||
|
UPDATE monitored_services SET url = 'http://192.168.1.230:8096', external = 'https://jellyfin.hynesy.com' WHERE id = 'jellyfin';
|
||||||
|
UPDATE monitored_services SET url = 'http://192.168.1.230:8789', external = 'https://chaptarr.hynesy.com' WHERE id = 'chaptarr';
|
||||||
@@ -1,12 +1,12 @@
|
|||||||
import { pool } from '../pool.js';
|
import { pool } from '../pool.js';
|
||||||
|
|
||||||
const COLS = 'id, name, category, host, url, icon, check_cfg, source, enabled';
|
const COLS = 'id, name, category, host, url, icon, external, check_cfg, source, enabled';
|
||||||
|
|
||||||
// Map a DB row to the service shape the registry/checker expect (check_cfg -> check).
|
// Map a DB row to the service shape the registry/checker expect (check_cfg -> check).
|
||||||
function toSvc(r) {
|
function toSvc(r) {
|
||||||
return {
|
return {
|
||||||
id: r.id, name: r.name, category: r.category, host: r.host, url: r.url,
|
id: r.id, name: r.name, category: r.category, host: r.host, url: r.url,
|
||||||
icon: r.icon, check: r.check_cfg || {}, source: r.source, enabled: r.enabled
|
icon: r.icon, external: r.external ?? null, check: r.check_cfg || {}, source: r.source, enabled: r.enabled
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -42,15 +42,15 @@ export async function count() {
|
|||||||
|
|
||||||
export async function create(svc) {
|
export async function create(svc) {
|
||||||
const { id, name, category = 'other', host = null, url, icon = null,
|
const { id, name, category = 'other', host = null, url, icon = null,
|
||||||
check = {}, source = 'manual', enabled = true } = svc;
|
external = null, check = {}, source = 'manual', enabled = true } = svc;
|
||||||
const { rows: [r] } = await pool.query(
|
const { rows: [r] } = await pool.query(
|
||||||
`INSERT INTO monitored_services (id, name, category, host, url, icon, check_cfg, source, enabled)
|
`INSERT INTO monitored_services (id, name, category, host, url, icon, external, check_cfg, source, enabled)
|
||||||
VALUES ($1,$2,$3,$4,$5,$6,$7::jsonb,$8,$9) RETURNING ${COLS}`,
|
VALUES ($1,$2,$3,$4,$5,$6,$7,$8::jsonb,$9,$10) RETURNING ${COLS}`,
|
||||||
[id, name, category, host, url, icon, JSON.stringify(check), source, enabled]);
|
[id, name, category, host, url, icon, external, JSON.stringify(check), source, enabled]);
|
||||||
return toSvc(r);
|
return toSvc(r);
|
||||||
}
|
}
|
||||||
|
|
||||||
const PATCHABLE = ['name', 'category', 'host', 'url', 'icon', 'enabled'];
|
const PATCHABLE = ['name', 'category', 'host', 'url', 'icon', 'external', 'enabled'];
|
||||||
export async function update(id, patch) {
|
export async function update(id, patch) {
|
||||||
const sets = [], vals = [];
|
const sets = [], vals = [];
|
||||||
for (const k of PATCHABLE) {
|
for (const k of PATCHABLE) {
|
||||||
@@ -75,8 +75,8 @@ export async function remove(id) {
|
|||||||
export async function upsertDiscovered(svc) {
|
export async function upsertDiscovered(svc) {
|
||||||
const { id, name, category = 'other', host = null, url, icon = null, check = {} } = svc;
|
const { id, name, category = 'other', host = null, url, icon = null, check = {} } = svc;
|
||||||
const { rows: [r] } = await pool.query(
|
const { rows: [r] } = await pool.query(
|
||||||
`INSERT INTO monitored_services (id, name, category, host, url, icon, check_cfg, source, enabled)
|
`INSERT INTO monitored_services (id, name, category, host, url, icon, external, check_cfg, source, enabled)
|
||||||
SELECT $1,$2,$3,$4,$5,$6,$7::jsonb,'discovered',false
|
SELECT $1,$2,$3,$4,$5,$6,NULL,$7::jsonb,'discovered',false
|
||||||
WHERE NOT EXISTS (SELECT 1 FROM monitored_services WHERE url=$5)
|
WHERE NOT EXISTS (SELECT 1 FROM monitored_services WHERE url=$5)
|
||||||
ON CONFLICT (id) DO NOTHING
|
ON CONFLICT (id) DO NOTHING
|
||||||
RETURNING ${COLS}`,
|
RETURNING ${COLS}`,
|
||||||
|
|||||||
@@ -30,4 +30,12 @@ describe('registry', () => {
|
|||||||
expect(after.every(s => s.source === 'manual' && s.enabled)).toBe(true);
|
expect(after.every(s => s.source === 'manual' && s.enabled)).toBe(true);
|
||||||
expect(await seedFromConfig()).toBe(0); // table not empty → no-op
|
expect(await seedFromConfig()).toBe(0); // table not empty → no-op
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('persists and returns external on create/get/update', async () => {
|
||||||
|
const id = 'ext-test';
|
||||||
|
await services.create({ id, name: 'Ext', url: 'http://10.0.0.1', external: 'https://ext.example.com' });
|
||||||
|
expect((await services.get(id)).external).toBe('https://ext.example.com');
|
||||||
|
const upd = await services.update(id, { external: 'https://ext2.example.com' });
|
||||||
|
expect(upd.external).toBe('https://ext2.example.com');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user