feat(platform-service): add GET /settings/kill-switch public endpoint

- No auth required — mobile apps call this at launch before login
- Reads kill_switch feature flag from Cosmos DB
- If flag enabled=true → returns disabled:true with maintenance message
- Fail-open: DB errors allow app to run normally
- Response: { enabled: bool, disabled: bool, message: string }

Used by iOS KillSwitchService.swift and Android KillSwitchService.kt
This commit is contained in:
saravanakumardb1 2026-02-15 21:30:03 -08:00
parent 5622499575
commit 7524c4d29e

View File

@ -1,6 +1,7 @@
/**
* User settings REST endpoints.
*
* GET /settings/kill-switch public kill switch check (no auth)
* GET /settings get user settings
* PUT /settings merge global settings
* GET /settings/device/:deviceId get resolved settings for a device
@ -13,6 +14,7 @@ import { getRequestProductId } from '../../lib/request-context.js';
import { BadRequestError, UnauthorizedError } from '../../lib/errors.js';
import * as repo from './repository.js';
import { UpdateSettingsSchema, SetDeviceOverridesSchema, type UserSettingsDoc } from './types.js';
import * as flagRepo from '../flags/repository.js';
function getRequestUserId(req: FastifyRequest): string {
const userId = req.jwtPayload?.sub;
@ -34,6 +36,32 @@ function buildDefaultDoc(productId: string, userId: string): UserSettingsDoc {
}
export async function settingsRoutes(app: FastifyInstance) {
// Public kill switch endpoint — no auth required.
// Mobile apps call this at launch to check if the app is disabled.
// Reads the `kill_switch` feature flag: if enabled=true → app is disabled.
app.get('/settings/kill-switch', async req => {
const productId =
(req.query as { productId?: string }).productId ||
(req.headers['x-product-id'] as string) ||
process.env.PRODUCT_ID ||
'';
if (!productId) return { enabled: true, disabled: false, message: '' };
try {
const flag = await flagRepo.getByKey('kill_switch', productId);
if (flag && flag.enabled) {
return {
enabled: false,
disabled: true,
message: flag.description || 'LysnrAI is temporarily unavailable for maintenance.',
};
}
} catch {
// DB error — fail open (allow app to run)
}
return { enabled: true, disabled: false, message: '' };
});
app.get('/settings', async req => {
const productId = getRequestProductId(req);
const userId = getRequestUserId(req);