Add customer service dashboard component

This commit is contained in:
2026-07-18 12:09:56 -04:00
parent e9894c893b
commit cde8148196
14 changed files with 1190 additions and 24 deletions
+28
View File
@@ -7,6 +7,7 @@
// /api/meta/* → routes/meta (was meta-server :3005)
// /api/dashboard-analytics/* → routes/google (was google-server :3007 via Caddy /api/analytics rewrite)
// /api/typeform/* → routes/typeform (was typeform-server :3008)
// /api/freescout/* → routes/freescout (FreeScout + acot_phone CS report, new)
//
// Shared infrastructure (Phase 2 + Phase 6):
// - shared/auth/middleware.js authenticate() guards /api/* (Phase 6.1/6.2 — second line of defense)
@@ -39,6 +40,7 @@ import { createKlaviyoRouter } from './routes/klaviyo/index.js';
import { createMetaRouter } from './routes/meta/index.js';
import { createGoogleRouter } from './routes/google/index.js';
import { createTypeformRouter } from './routes/typeform/index.js';
import { createFreescoutRouter } from './routes/freescout/index.js';
const __dirname = path.dirname(fileURLToPath(import.meta.url));
@@ -76,6 +78,25 @@ const pool = createPool('DB');
// if Redis is temporarily unavailable, and aligns with shared/db/redis.js defaults.
const redis = createRedis();
// Read-only pools for the FreeScout CS section. The .env keys use USERNAME /
// DATABASE where createPool() reads USER / NAME, hence the overrides. Both are
// optional: without FREESCOUT_DB_* the route isn't mounted; without
// ACOT_PHONE_DB_* the report's phone block is null.
const freescoutPool = process.env.FREESCOUT_DB_HOST
? createPool('FREESCOUT_DB', {
user: process.env.FREESCOUT_DB_USERNAME,
database: process.env.FREESCOUT_DB_DATABASE,
max: 5,
})
: null;
const phonePool = process.env.ACOT_PHONE_DB_HOST
? createPool('ACOT_PHONE_DB', {
user: process.env.ACOT_PHONE_DB_USERNAME,
database: process.env.ACOT_PHONE_DB_DATABASE,
max: 3,
})
: null;
app.use(requestLog());
app.use(cors(corsOptions));
app.use(express.json({ limit: '10mb' }));
@@ -91,6 +112,11 @@ app.use('/api/meta', createMetaRouter());
// Caddy can drop the rewrite — see Caddyfile.proposed.
app.use('/api/dashboard-analytics', createGoogleRouter({ redis }));
app.use('/api/typeform', createTypeformRouter({ redis }));
if (freescoutPool) {
app.use('/api/freescout', createFreescoutRouter({ redis, freescoutPool, phonePool }));
} else {
logger.warn('FREESCOUT_DB_* not set — /api/freescout not mounted');
}
app.get('/health', (req, res) => {
res.json({
@@ -118,6 +144,8 @@ const shutdown = async (signal) => {
server.close();
try { await redis.quit(); } catch { /* ignore */ }
try { await pool.end(); } catch { /* ignore */ }
try { await freescoutPool?.end(); } catch { /* ignore */ }
try { await phonePool?.end(); } catch { /* ignore */ }
process.exit(0);
};
process.on('SIGTERM', () => shutdown('SIGTERM'));