From d576f103c54333cf8a2b1a311a86ca411eba5c20 Mon Sep 17 00:00:00 2001 From: jtricerolph Date: Wed, 8 Jul 2026 11:57:42 +0000 Subject: [PATCH] =?UTF-8?q?Add=20cache-bust=20endpoint=20=E2=80=94=20inval?= =?UTF-8?q?idates=20workforce=20+=20smtp=20creds=20on=20demand?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Settings service calls POST /api/auth/internal/cache-bust (Bearer SETTINGS_SECRET) after saving workforce or smtp integrations, so location/credential changes take effect immediately without waiting for the 5-minute TTL or restarting the container. Co-Authored-By: Claude Sonnet 4.6 --- src/email.js | 5 +++++ src/routes/internal.js | 16 ++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/src/email.js b/src/email.js index 8c8da72..e560266 100644 --- a/src/email.js +++ b/src/email.js @@ -33,6 +33,11 @@ async function getTransporter() { return _transporter } +export function invalidateCache() { + _smtpCache = null + _transporter = null +} + export async function sendPinEmail(to, name, pin) { const config = await getSmtpConfig() const transport = await getTransporter() diff --git a/src/routes/internal.js b/src/routes/internal.js index 5271052..0f49183 100644 --- a/src/routes/internal.js +++ b/src/routes/internal.js @@ -1,5 +1,7 @@ import { pool } from '../db.js' import { syncAllWorkforceUsers } from '../sync.js' +import { invalidateCache as invalidateWorkforceCache } from '../workforce.js' +import { invalidateCache as invalidateSmtpCache } from '../email.js' function isAuthorised(request) { const auth = request.headers.authorization || '' @@ -7,6 +9,12 @@ function isAuthorised(request) { return secret && auth === `Bearer ${secret}` } +function isSettingsAuthorised(request) { + const auth = request.headers.authorization || '' + const secret = process.env.SETTINGS_SECRET || '' + return secret && auth === `Bearer ${secret}` +} + // Service-to-service endpoints — no user cookie, Bearer token = CENTRAL_AUTH_SECRET. export async function internalRoutes(app) { app.get('/registry', async (request, reply) => { @@ -29,4 +37,12 @@ export async function internalRoutes(app) { return reply.status(502).send({ error: e.message }) } }) + + // Called by settings service after saving workforce/smtp integrations + app.post('/cache-bust', async (request, reply) => { + if (!isSettingsAuthorised(request)) return reply.status(401).send({ error: 'Unauthorized' }) + invalidateWorkforceCache() + invalidateSmtpCache() + return { ok: true } + }) }