Scaffold homelab-monitor: Fastify API + React dashboard + CI
Vertical slice for Phase 1 (v1-dashboard milestone): Proxmox collector, SQLite storage, local auth, and a dashboard UI showing host/container status cards. Config-driven collector registry so future data sources (SSH-based hosts, Zabbix, network discovery) plug in without rewiring. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,66 @@
|
||||
import "dotenv/config";
|
||||
import Fastify from "fastify";
|
||||
import fastifyCookie from "@fastify/cookie";
|
||||
import fastifySession from "@fastify/session";
|
||||
import { loadConfig } from "./config/index.js";
|
||||
import { openDb, upsertSnapshots, pruneOldSnapshots } from "./db/index.js";
|
||||
import { seedAdminUser } from "./auth/local.js";
|
||||
import { ProxmoxCollector } from "./collectors/proxmox.js";
|
||||
import type { Collector } from "./collectors/types.js";
|
||||
import { registerAuthRoutes } from "./routes/auth.js";
|
||||
import { registerHostRoutes } from "./routes/hosts.js";
|
||||
|
||||
const HOSTS_CONFIG_PATH = process.env.HOSTS_CONFIG_PATH ?? "../../config/hosts.yaml";
|
||||
|
||||
async function main() {
|
||||
const cfg = loadConfig(HOSTS_CONFIG_PATH);
|
||||
const db = openDb(cfg.dbPath);
|
||||
|
||||
if (cfg.adminPassword) {
|
||||
seedAdminUser(db, cfg.adminUsername, cfg.adminPassword);
|
||||
}
|
||||
|
||||
const collectors: Collector[] = [
|
||||
new ProxmoxCollector({
|
||||
host: cfg.proxmox.host,
|
||||
node: cfg.proxmox.node,
|
||||
tokenId: cfg.proxmox.tokenId,
|
||||
tokenSecret: cfg.proxmox.tokenSecret,
|
||||
}),
|
||||
];
|
||||
|
||||
async function pollOnce() {
|
||||
for (const collector of collectors) {
|
||||
try {
|
||||
const snapshots = await collector.collect();
|
||||
upsertSnapshots(db, snapshots);
|
||||
} catch (err) {
|
||||
app.log.error({ err, collector: collector.id }, "collector failed");
|
||||
}
|
||||
}
|
||||
pruneOldSnapshots(db, cfg.snapshotRetentionHours);
|
||||
}
|
||||
|
||||
const app = Fastify({ logger: true });
|
||||
|
||||
await app.register(fastifyCookie);
|
||||
await app.register(fastifySession, {
|
||||
secret: cfg.sessionSecret,
|
||||
cookie: { secure: process.env.NODE_ENV === "production", maxAge: 1000 * 60 * 60 * 12 },
|
||||
});
|
||||
|
||||
registerAuthRoutes(app, db);
|
||||
registerHostRoutes(app, db);
|
||||
|
||||
await pollOnce();
|
||||
setInterval(() => {
|
||||
void pollOnce();
|
||||
}, cfg.pollIntervalSeconds * 1000);
|
||||
|
||||
await app.listen({ port: cfg.port, host: "0.0.0.0" });
|
||||
}
|
||||
|
||||
main().catch((err) => {
|
||||
console.error(err);
|
||||
process.exit(1);
|
||||
});
|
||||
Reference in New Issue
Block a user