feat(messages): extraction des messages importants APT (tâche 5 backlog)

- extractImportantMessages (TDD) : E:/dpkg error → error, W:/GPG → warning,
  déprecations/EOL → future_major_change ; nettoyage des secrets dans les URLs
- recordImportantMessages : dédup par (machine, source, message) non acquitté →
  maj lastSeenAt, sinon insert (firstSeen/lastSeen) dans important_messages
- branché dans refreshMachine (sortie APT) avec snapshotId
- routes GET /machines/:id/messages + POST .../:msgId/ack
- UI : carte « Messages importants » (badge sévérité + ack) dans le panneau détail

tsc 0 · 118 tests · build OK.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-06 19:30:07 +02:00
parent ff9cfaa9e1
commit a93a43e1c8
6 changed files with 208 additions and 0 deletions
+2
View File
@@ -9,6 +9,7 @@ import { runScriptSudo } from "../ssh/client.js";
import { buildAptSnapshotDetail } from "./aptParse.js";
import { outputHub } from "../ws/outputHub.js";
import { deriveAptState, upsertMachineState, recordEvent } from "./machineState.js";
import { extractImportantMessages, recordImportantMessages } from "./importantMessages.js";
import type { UpdateSnapshot, MachineStatus, AptSnapshotDetail } from "@shared/types.js";
/** Extrait la section entre deux marqueurs ===SU:X=== d'une sortie de script. */
@@ -82,6 +83,7 @@ export async function refreshMachine(machineId: string): Promise<UpdateSnapshot>
db.update(schema.machines).set({ status, lastCheckedAt: checkedAt }).where(eq(schema.machines.id, machineId)).run();
upsertMachineState(machineId, deriveAptState(snapshot));
recordImportantMessages(machineId, extractImportantMessages(raw, "apt"), { snapshotId });
recordEvent({
machineId,
eventType: "apt_refresh",