← back to Professional Directory
agents/enrich-agent/server.js
69 lines
#!/usr/bin/env node
/**
* Enrich agent — HTTP control plane for geocoding + future enrichers.
*
* GET /health — { ok, agent, geocode_pending, enrichers }
* POST /run/geocode — async-fire geocode.js with optional { limit }
*/
const fs = require('node:fs');
const path = require('path');
const { spawn } = require('node:child_process');
require('dotenv').config({ path: path.resolve(__dirname, '../../.env') });
const express = require('express');
const { pool, query } = require('../shared/db');
const PORT = Number(process.env.PORT_ENRICH || process.env.PORT || 9872);
const ENRICHERS_DIR = path.join(__dirname);
const app = express();
app.use(express.json());
// LAN/tailnet auth gate (skip /health for watchdog probes)
const BASIC_AUTH = process.env.BASIC_AUTH || 'admin:DWSecure2024!';
const AUTH_HEADER = 'Basic ' + Buffer.from(BASIC_AUTH).toString('base64');
app.use((req, res, next) => {
if (req.path === '/health' || req.path === '/healthz') return next();
if (req.get('authorization') === AUTH_HEADER) return next();
res.set('WWW-Authenticate', 'Basic realm="mac2-pm2"');
res.status(401).send('auth required');
});
function listEnrichers() {
return fs.readdirSync(ENRICHERS_DIR)
.filter(f => f.endsWith('.js') && f !== 'server.js')
.map(f => f.replace(/\.js$/, ''));
}
app.get('/health', async (_req, res) => {
try {
const r = await query(`
SELECT
(SELECT COUNT(*) FROM organizations WHERE lat IS NULL AND address IS NOT NULL) AS geocode_pending,
(SELECT COUNT(*) FROM organizations WHERE lat IS NOT NULL) AS geocoded
`, []);
res.json({ ok: true, agent: 'pd-enrich', enrichers: listEnrichers(), ...r.rows[0] });
} catch (e) {
res.status(500).json({ ok: false, error: e.message });
}
});
app.post('/run/:enricher', (req, res) => {
const id = String(req.params.enricher);
if (!listEnrichers().includes(id)) {
return res.status(404).json({ error: `unknown enricher '${id}'`, available: listEnrichers() });
}
const env = { ...process.env };
if (req.body?.limit) env.LIMIT = String(req.body.limit);
const child = spawn('node', [path.join(ENRICHERS_DIR, `${id}.js`)], {
cwd: path.resolve(__dirname, '../..'),
env,
detached: true,
stdio: 'ignore',
});
child.unref();
res.json({ ok: true, started: id, pid: child.pid });
});
app.listen(PORT, '0.0.0.0', () => {
console.log(`[pd-enrich] listening on http://127.0.0.1:${PORT}`);
});