Files
system_update/server/services/machineState.ts
T
gilles fa73ab07b0 feat(events): timeline d'événements machine (tâche 5 backlog)
- listMachineEvents (machine_events, 30 derniers, desc) + route GET /machines/:id/events
- api machineEvents ; section repliable « Timeline » dans le panneau détail
  (badge sévérité + horodatage), exploite les events déjà enregistrés par recordEvent

tsc 0 · 118 tests · build OK.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 19:36:06 +02:00

76 lines
2.3 KiB
TypeScript

// server/services/machineState.ts
import { randomUUID } from "node:crypto";
import { desc, eq } from "drizzle-orm";
import { db, schema } from "../db/client.js";
import type { UpdateSnapshot } from "@shared/types.js";
/** Derniers événements d'une machine (timeline), du plus récent au plus ancien. */
export function listMachineEvents(machineId: string, limit = 30) {
return db
.select()
.from(schema.machineEvents)
.where(eq(schema.machineEvents.machineId, machineId))
.orderBy(desc(schema.machineEvents.createdAt))
.limit(limit)
.all();
}
export interface AptDerivedState {
status: string;
aptStatus: string;
aptUpdatesCount: number;
aptRebootRequired: number;
aptLastAnalyzeAt: string;
}
/** Dérive le bloc APT de l'état courant depuis un snapshot (fonction pure). */
export function deriveAptState(snapshot: UpdateSnapshot): AptDerivedState {
return {
status: snapshot.status,
aptStatus: snapshot.status,
aptUpdatesCount: snapshot.apt.count,
aptRebootRequired: snapshot.apt.rebootRequired ? 1 : 0,
aptLastAnalyzeAt: snapshot.checkedAt,
};
}
type MachineStateInsert = typeof schema.machineState.$inferInsert;
/** Insère ou met à jour les champs fournis de machine_state pour une machine. */
export function upsertMachineState(
machineId: string,
fields: Partial<Omit<MachineStateInsert, "machineId" | "updatedAt" | "status">> & { status: string },
): void {
const now = new Date().toISOString();
db.insert(schema.machineState)
.values({ machineId, updatedAt: now, ...fields })
.onConflictDoUpdate({
target: schema.machineState.machineId,
set: { ...fields, updatedAt: now },
})
.run();
}
/** Ajoute une ligne à la timeline machine_events. */
export function recordEvent(input: {
machineId: string;
eventType: string;
severity: "info" | "warning" | "error";
actorType?: string;
snapshotId?: string;
executionId?: string;
message?: string;
}): void {
db.insert(schema.machineEvents).values({
id: randomUUID(),
machineId: input.machineId,
eventType: input.eventType,
severity: input.severity,
createdAt: new Date().toISOString(),
actorType: input.actorType ?? "system",
snapshotId: input.snapshotId,
executionId: input.executionId,
message: input.message,
}).run();
}