From f7356706cd84a2abc9ed4b0a0df713def73deba2 Mon Sep 17 00:00:00 2001 From: saravanakumardb1 Date: Fri, 20 Mar 2026 21:15:40 -0700 Subject: [PATCH] feat(backend): add GET /api/bootstrap route + test - Returns productId, displayName, backendPort for client bootstrapping - Integration test validates response shape and types --- backend/src/diagnostics.test.ts | 19 ++++++++++++++++++- backend/src/server.ts | 9 ++++++++- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/backend/src/diagnostics.test.ts b/backend/src/diagnostics.test.ts index 5429813..23314a7 100644 --- a/backend/src/diagnostics.test.ts +++ b/backend/src/diagnostics.test.ts @@ -4,7 +4,7 @@ import type { FastifyInstance } from 'fastify'; import { getAllFlags } from './lib/feature-flags.js'; import { getBufferedEvents, flushEvents } from './lib/telemetry.js'; import { config } from './lib/config.js'; -import { PRODUCT_ID } from './lib/product-config.js'; +import { PRODUCT_ID, productConfig } from './lib/product-config.js'; let app: FastifyInstance; @@ -29,6 +29,11 @@ beforeAll(async () => { timestamp: new Date().toISOString(), requestId: req.id, })); + app.get('/api/bootstrap', async () => ({ + productId: productConfig.productId, + displayName: productConfig.displayName, + backendPort: config.PORT, + })); await app.ready(); }); @@ -84,4 +89,16 @@ describe('diagnostics routes', () => { expect(body).toHaveProperty('timestamp'); expect(body.timestamp).toMatch(/^\d{4}-\d{2}-\d{2}T/); }); + + it('GET /api/bootstrap returns product identity', async () => { + const res = await app.inject({ method: 'GET', url: '/api/bootstrap' }); + expect(res.statusCode).toBe(200); + const body = res.json(); + expect(body).toHaveProperty('productId'); + expect(body).toHaveProperty('displayName'); + expect(body).toHaveProperty('backendPort'); + expect(typeof body.productId).toBe('string'); + expect(typeof body.displayName).toBe('string'); + expect(typeof body.backendPort).toBe('number'); + }); }); diff --git a/backend/src/server.ts b/backend/src/server.ts index 30106c2..3d40378 100644 --- a/backend/src/server.ts +++ b/backend/src/server.ts @@ -17,7 +17,7 @@ import { initDatastore } from './lib/datastore.js'; import { config } from './lib/config.js'; import { getAllFlags } from './lib/feature-flags.js'; import { getBufferedEvents, flushEvents } from './lib/telemetry.js'; -import { PRODUCT_ID } from './lib/product-config.js'; +import { PRODUCT_ID, productConfig } from './lib/product-config.js'; import { jwtVerify } from 'jose'; import type { JwtPayload } from './lib/request-context.js'; @@ -53,6 +53,13 @@ await app.register(householdRoutes, { prefix: '/api' }); await app.register(sharedTimerRoutes, { prefix: '/api' }); await app.register(webhookRoutes, { prefix: '/api' }); +// ── Bootstrap (no auth) ────────────────────────────────────────── +app.get('/api/bootstrap', async () => ({ + productId: productConfig.productId, + displayName: productConfig.displayName, + backendPort: config.PORT, +})); + // ── Diagnostics routes (no auth) ──────────────────────────────── app.get('/api/diagnostics/flags', async () => getAllFlags()); app.get('/api/diagnostics/telemetry', async () => ({ events: getBufferedEvents() }));