Shaheer Sarfaraz c4749b4211
feat: opinionated public DEMO_MODE with simulated/blocked actions, resets, and demo toasts (#87)
* feat(demo): add DEMO_MODE runtime helpers and /api/demo/info endpoint

* feat(demo): enforce simulated and blocked API actions under DEMO_MODE

* feat(demo): add deterministic seed dataset and 6-hour auto-reset

* feat(demo-ui): add demo banner and custom sonner toasts for simulated/blocked actions

* test+docs(demo): add demo mode coverage, behavior matrix, and operator docs

* formatting

* tests

* feat(demo): seed resets from typed baseline defaults

* formatting

* feat(demo): enrich baseline seed data and demo project catalog

* feat(demo): expand seeded applications and chart time ranges

* refactor(demo): split demo seed data from generation logic

* feat(demo): cap generated application history to 30 days

* feat(demo): rebalance generated job status distribution

* feat(demo-ui): make demo banner fixed and topmost

* minor fixes

* formatting

* duration revert

* durations

* feat(demo): share demo info hook, brighten demo toasts, and enforce webhook auth

* comment explaning

* formatting

* comments

* deadline builder comment
2026-02-05 16:04:04 +00:00

211 lines
5.9 KiB
TypeScript

import { okWithMeta } from "@infra/http";
import { getSetting } from "@server/repositories/settings";
import { LlmService } from "@server/services/llm-service";
import { RxResumeClient } from "@server/services/rxresume-client";
import {
getResume,
RxResumeCredentialsError,
} from "@server/services/rxresume-v4";
import { resumeDataSchema } from "@shared/rxresume-schema";
import { type Request, type Response, Router } from "express";
import { isDemoMode } from "../../config/demo";
export const onboardingRouter = Router();
type ValidationResponse = {
valid: boolean;
message: string | null;
};
async function validateLlm(options: {
apiKey?: string | null;
provider?: string | null;
baseUrl?: string | null;
}): Promise<ValidationResponse> {
const llm = new LlmService({
apiKey: options.apiKey,
provider: options.provider ?? undefined,
baseUrl: options.baseUrl ?? undefined,
});
return llm.validateCredentials();
}
/**
* Validate that a base resume is configured and accessible via RxResume v4 API.
*/
async function validateResumeConfig(): Promise<ValidationResponse> {
try {
// Check if rxresumeBaseResumeId is configured
const rxresumeBaseResumeId = await getSetting("rxresumeBaseResumeId");
if (!rxresumeBaseResumeId) {
return {
valid: false,
message:
"No base resume selected. Please select a resume from your RxResume account in Settings.",
};
}
// Verify the resume is accessible and valid
try {
const resume = await getResume(rxresumeBaseResumeId);
if (!resume.data || typeof resume.data !== "object") {
return {
valid: false,
message: "Selected resume is empty or invalid.",
};
}
// Validate against schema
const result = resumeDataSchema.safeParse(resume.data);
if (!result.success) {
const issue = result.error.issues[0];
const path = issue?.path?.join(".") || "";
const baseMessage =
issue?.message ?? "Resume does not match the expected schema.";
const details = path ? `Field "${path}": ${baseMessage}` : baseMessage;
return { valid: false, message: details };
}
return { valid: true, message: null };
} catch (error) {
if (error instanceof RxResumeCredentialsError) {
return {
valid: false,
message: "RxResume credentials not configured.",
};
}
const message =
error instanceof Error
? error.message
: "Failed to fetch resume from RxResume.";
return { valid: false, message };
}
} catch (error) {
const message =
error instanceof Error ? error.message : "Resume validation failed.";
return { valid: false, message };
}
}
async function validateRxresume(
email?: string | null,
password?: string | null,
): Promise<ValidationResponse> {
const rxEmail = email?.trim() || process.env.RXRESUME_EMAIL || "";
const rxPassword = password?.trim() || process.env.RXRESUME_PASSWORD || "";
if (!rxEmail || !rxPassword) {
return { valid: false, message: "RxResume credentials are missing." };
}
const result = await RxResumeClient.verifyCredentials(rxEmail, rxPassword);
if (result.ok) {
return { valid: true, message: null };
}
const normalizedMessage = result.message?.toLowerCase() ?? "";
if (
result.status === 401 ||
normalizedMessage.includes("invalidcredentials")
) {
return {
valid: false,
message:
"Invalid RxResume credentials. Check your email and password and try again.",
};
}
const message =
result.message || `RxResume validation failed (HTTP ${result.status})`;
return { valid: false, message };
}
onboardingRouter.post(
"/validate/openrouter",
async (req: Request, res: Response) => {
if (isDemoMode()) {
return okWithMeta(
res,
{
valid: true,
message:
"Demo mode: OpenRouter validation is simulated and always succeeds.",
},
{ simulated: true },
);
}
const apiKey =
typeof req.body?.apiKey === "string" ? req.body.apiKey : undefined;
const result = await validateLlm({ apiKey, provider: "openrouter" });
res.json({ success: true, data: result });
},
);
onboardingRouter.post("/validate/llm", async (req: Request, res: Response) => {
if (isDemoMode()) {
return okWithMeta(
res,
{
valid: true,
message: "Demo mode: LLM validation is simulated.",
},
{ simulated: true },
);
}
const apiKey =
typeof req.body?.apiKey === "string" ? req.body.apiKey : undefined;
const provider =
typeof req.body?.provider === "string" ? req.body.provider : undefined;
const baseUrl =
typeof req.body?.baseUrl === "string" ? req.body.baseUrl : undefined;
const result = await validateLlm({ apiKey, provider, baseUrl });
res.json({ success: true, data: result });
});
onboardingRouter.post(
"/validate/rxresume",
async (req: Request, res: Response) => {
if (isDemoMode()) {
return okWithMeta(
res,
{
valid: true,
message: "Demo mode: RxResume validation is simulated.",
},
{ simulated: true },
);
}
const email =
typeof req.body?.email === "string" ? req.body.email : undefined;
const password =
typeof req.body?.password === "string" ? req.body.password : undefined;
const result = await validateRxresume(email, password);
res.json({ success: true, data: result });
},
);
onboardingRouter.get(
"/validate/resume",
async (_req: Request, res: Response) => {
if (isDemoMode()) {
return okWithMeta(
res,
{
valid: true,
message: "Demo mode: resume validation is simulated.",
},
{ simulated: true },
);
}
const result = await validateResumeConfig();
res.json({ success: true, data: result });
},
);