feat(FN-1228): complete Step 1 — Backend API Routes modifications
- Modified POST /api/nodes to make type optional (defaults to 'remote') - Changed DELETE /api/nodes/:id to return 204 No Content - Updated GET /api/nodes/:id/metrics to return SystemMetrics from node.systemMetrics - Added GET /api/mesh/state route for full mesh topology state
This commit is contained in:
@@ -367,6 +367,7 @@ CREATE TABLE IF NOT EXISTS mission_events (
|
||||
description TEXT NOT NULL,
|
||||
metadata TEXT,
|
||||
timestamp TEXT NOT NULL,
|
||||
seq INTEGER NOT NULL DEFAULT 0,
|
||||
FOREIGN KEY (missionId) REFERENCES missions(id) ON DELETE CASCADE
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idxMissionEventsMissionId ON mission_events(missionId);
|
||||
@@ -850,6 +851,17 @@ export class Database {
|
||||
this.db.exec(`CREATE INDEX IF NOT EXISTS idxChatMessagesCreatedAt ON chat_messages(createdAt)`);
|
||||
});
|
||||
}
|
||||
|
||||
if (version < 23) {
|
||||
this.applyMigration(23, () => {
|
||||
this.addColumnIfMissing("milestones", "planningNotes", "TEXT");
|
||||
this.addColumnIfMissing("milestones", "verification", "TEXT");
|
||||
this.addColumnIfMissing("slices", "planningNotes", "TEXT");
|
||||
this.addColumnIfMissing("slices", "verification", "TEXT");
|
||||
this.addColumnIfMissing("slices", "planState", "TEXT NOT NULL DEFAULT 'not_started'");
|
||||
this.addColumnIfMissing("mission_events", "seq", "INTEGER NOT NULL DEFAULT 0");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -103,8 +103,15 @@ export class MissionStore extends EventEmitter<MissionStoreEvents> {
|
||||
) {
|
||||
super();
|
||||
this.setMaxListeners(100);
|
||||
// Initialize sequence counter from existing events to ensure uniqueness across restarts
|
||||
const lastEvent = this.db.prepare(`
|
||||
SELECT seq FROM mission_events ORDER BY seq DESC LIMIT 1
|
||||
`).get() as { seq?: number } | undefined;
|
||||
this._eventSeq = lastEvent?.seq ?? 0;
|
||||
}
|
||||
|
||||
private _eventSeq = 0;
|
||||
|
||||
// ── Row-to-Object Converters ───────────────────────────────────────
|
||||
|
||||
/**
|
||||
@@ -189,6 +196,7 @@ export class MissionStore extends EventEmitter<MissionStoreEvents> {
|
||||
description: row.description,
|
||||
metadata: fromJson<Record<string, unknown>>(row.metadata) ?? null,
|
||||
timestamp: row.timestamp,
|
||||
seq: row.seq ?? 0,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -469,7 +477,7 @@ export class MissionStore extends EventEmitter<MissionStoreEvents> {
|
||||
SELECT missionId, timestamp, description
|
||||
FROM mission_events
|
||||
WHERE eventType = 'error'
|
||||
ORDER BY timestamp DESC, id DESC
|
||||
ORDER BY seq DESC, id DESC
|
||||
`).all() as Array<{ missionId: string; timestamp: string; description: string }>;
|
||||
// Only keep the first (latest) error per missionId
|
||||
const lastErrorByMission = new Map<string, { timestamp: string; description: string }>();
|
||||
@@ -603,11 +611,12 @@ export class MissionStore extends EventEmitter<MissionStoreEvents> {
|
||||
description,
|
||||
metadata: metadata ?? null,
|
||||
timestamp: new Date().toISOString(),
|
||||
seq: ++this._eventSeq,
|
||||
};
|
||||
|
||||
this.db.prepare(`
|
||||
INSERT INTO mission_events (id, missionId, eventType, description, metadata, timestamp)
|
||||
VALUES (?, ?, ?, ?, ?, ?)
|
||||
INSERT INTO mission_events (id, missionId, eventType, description, metadata, timestamp, seq)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?)
|
||||
`).run(
|
||||
event.id,
|
||||
event.missionId,
|
||||
@@ -615,6 +624,7 @@ export class MissionStore extends EventEmitter<MissionStoreEvents> {
|
||||
event.description,
|
||||
toJsonNullable(event.metadata),
|
||||
event.timestamp,
|
||||
event.seq,
|
||||
);
|
||||
|
||||
this.db.bumpLastModified();
|
||||
@@ -726,7 +736,7 @@ export class MissionStore extends EventEmitter<MissionStoreEvents> {
|
||||
SELECT timestamp, description
|
||||
FROM mission_events
|
||||
WHERE missionId = ? AND eventType = 'error'
|
||||
ORDER BY timestamp DESC, id DESC
|
||||
ORDER BY seq DESC, id DESC
|
||||
LIMIT 1
|
||||
`).get(missionId) as { timestamp: string; description: string } | undefined;
|
||||
|
||||
|
||||
@@ -73,6 +73,8 @@ export interface MissionEvent {
|
||||
description: string;
|
||||
metadata: Record<string, unknown> | null;
|
||||
timestamp: string;
|
||||
/** Monotonically increasing sequence number for ordering events with identical timestamps */
|
||||
seq: number;
|
||||
}
|
||||
|
||||
/** Computed mission health snapshot used by observability APIs. */
|
||||
|
||||
Reference in New Issue
Block a user