import { HttpError } from "@batch-cooking/error-tools"; import { wrapAsyncHandler } from "@batch-cooking/express-tools"; import { ErrorCode, listCorrectionsQuerySchema, listSuggestionsQuerySchema, retrainRequestSchema, trainingDataSnippetQuerySchema, updateTrainingSuggestionSchema, } from "@batch-cooking/shared"; import { Router } from "express"; import { requireAdmin } from "../../middlewares/require-admin.js"; import { getTrainingDataSnippet, listCorrections, listSuggestions, runRetrain, updateSuggestion, } from "./admin-tech-steps.service.js"; /** Router mounted at `/admin/tech-steps` (via `admin.routes.ts`) — every route behind {@link requireAdmin}. Correction/suggestion triage + the retrain trigger. */ export const adminTechStepsRouter = Router(); adminTechStepsRouter.get( "/suggestions", requireAdmin, wrapAsyncHandler(async (req, res) => { res.status(200).json(await listSuggestions(listSuggestionsQuerySchema.parse(req.query))); }), ); adminTechStepsRouter.get( "/corrections", requireAdmin, wrapAsyncHandler(async (req, res) => { res.status(200).json(await listCorrections(listCorrectionsQuerySchema.parse(req.query))); }), ); adminTechStepsRouter.get( "/training-data-snippet", requireAdmin, wrapAsyncHandler(async (req, res) => { res .status(200) .json(await getTrainingDataSnippet(trainingDataSnippetQuerySchema.parse(req.query))); }), ); adminTechStepsRouter.patch( "/suggestions/:id", requireAdmin, wrapAsyncHandler(async (req, res) => { const id = Number(req.params.id); if (!Number.isInteger(id) || id <= 0) { throw new HttpError( 400, ErrorCode.VALIDATION_ERROR, `Not a valid suggestion id: ${req.params.id}`, ); } const input = updateTrainingSuggestionSchema.parse(req.body); res.status(200).json(await updateSuggestion(id, input)); }), ); /** * Runs the F1 regression gate then (if it passes) the full step backfill, * and marks the given suggestion ids — see {@link runRetrain}. Long-running * and process-locked: `409 RETRAIN_ALREADY_RUNNING` if one is already * underway. */ adminTechStepsRouter.post( "/retrain", requireAdmin, wrapAsyncHandler(async (req, res) => { const input = retrainRequestSchema.parse(req.body); res.status(200).json(await runRetrain(input)); }), );