Checkpoint: Préparation recette : ajout du journal classification_errors, exposition de la cause technique des fallbacks IA, enregistrement non bloquant depuis le moteur RSS, écran d’administration Erreurs IA, route protégée et migration 0013. Validation locale : 28 tests, TypeScript et build de production réussis.

This commit is contained in:
Manus
2026-08-18 07:49:11 +00:00
parent e4a389cc67
commit 9acc52da7d
15 changed files with 1432 additions and 5 deletions

View File

@@ -16,9 +16,11 @@ import {
rssSettings,
processedDedupKeys,
articleReads,
classificationErrors,
type InsertRssFeed,
type InsertRssSettings,
type ImportLog,
type ClassificationError,
type RssFeed,
type RssSettings,
} from "../drizzle/schema";
@@ -489,6 +491,49 @@ export async function getImportStats() {
};
}
// ─── Rapport d'erreurs de classification RSS ──────────────────────────────────
export interface ClassificationErrorInput {
feedId: number | null;
feedName: string;
feedType: "veille" | "aap";
articleTitle: string;
articleUrl: string | null;
errorMessage: string;
}
/**
* Enregistre un fallback IA sans interrompre le traitement du flux RSS.
* La collecte reste opérationnelle : l'erreur est visible dans l'administration
* tandis que l'article est classé par la règle de repli prévue.
*/
export async function recordClassificationError(input: ClassificationErrorInput): Promise<void> {
const db = await getDb();
if (!db) {
console.error("[Classification errors] Base indisponible : erreur non journalisée");
return;
}
try {
await db.insert(classificationErrors).values(input);
} catch (error) {
console.error("[Classification errors] Échec de journalisation :", error);
}
}
/** Liste paginée des fallbacks IA, réservée aux administrateurs via le routeur. */
export async function getClassificationErrors(page: number, pageSize: number): Promise<{ errors: ClassificationError[]; total: number }> {
const db = await getDb();
if (!db) return { errors: [], total: 0 };
const offset = (page - 1) * pageSize;
const [errors, totals] = await Promise.all([
db.select().from(classificationErrors).orderBy(desc(classificationErrors.occurredAt)).limit(pageSize).offset(offset),
db.select({ total: count() }).from(classificationErrors),
]);
return { errors, total: Number(totals[0]?.total ?? 0) };
}
// ─── Boîte à idées ────────────────────────────────────────────────────────────
export async function createIdea(data: InsertIdea) {