mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-13 14:32:03 +00:00
The weekly pass can stop and leave no trace where anyone looks. The handler's own error never runs when the job is killed rather than thrown; `recordError()` increments an unnamed counter; and the admin status page's failing-queue panel looks back 72 hours, which for a weekly queue means a permanent failure is on screen three days in seven. The backups page itself showed an ordinary row with an ordinary timestamp, because a copy made six weeks ago reads exactly like Sunday's until somebody subtracts the dates. The listing now carries two facts that fail at different times: the age of the newest scheduled copy, which never leaves any retention window, and the terminal state of the last scheduled run, which is the only place the reason is written down. `readLastQueueRun` takes the newest run rather than a window, so a weekly queue's outcome stays readable until the next one replaces it, and it unwraps the value pg-boss stores a thrown error under, so the page says "job timed out" instead of raw JSON. The failing-queue reader gets the same unwrap. Manual uploads are excluded from the cadence judgement by the shape of the input, so an ad-hoc upload cannot make a dead cron look alive, and a fresh instance is not called overdue for having no copy yet. The listing also stops reading every blob into the web process to measure it; `octet_length` answers that in the database, which on an instance with large records was its own way of running out of memory.
44 lines
1.6 KiB
TypeScript
44 lines
1.6 KiB
TypeScript
/**
|
|
* v1.4.41 W-ORG (org-audit rec #2) — DTOs for `/api/admin/backups`.
|
|
*
|
|
* Pre-v1.4.41 these interfaces lived inside the route handler at
|
|
* `src/app/api/admin/backups/route.ts` and were imported directly from
|
|
* the route module by `src/components/admin/backups-section.tsx`. That
|
|
* was a textbook layer violation (component → route handler) and the
|
|
* only one of its kind in the codebase. Hoisting the shapes here gives
|
|
* both sides a route-handler-independent shared type home; the route
|
|
* keeps owning the HTTP contract, the component keeps owning the UI.
|
|
*/
|
|
import type { BackupScheduleStatus } from "@/lib/jobs/backup-schedule-status";
|
|
|
|
export interface BackupRow {
|
|
id: string;
|
|
userId: string;
|
|
username: string;
|
|
type: string;
|
|
/**
|
|
* Size of the encrypted blob in bytes — useful for capacity planning.
|
|
* The blob itself is never returned.
|
|
*/
|
|
sizeBytes: number;
|
|
createdAt: string;
|
|
}
|
|
|
|
export interface BackupsList {
|
|
rows: BackupRow[];
|
|
/**
|
|
* Whether the weekly schedule is still producing copies, and how the last
|
|
* scheduled run ended. A row's own timestamp cannot answer that — a copy
|
|
* made six weeks ago and one made on Sunday look identical in a table.
|
|
*/
|
|
schedule: BackupScheduleStatus;
|
|
/**
|
|
* Soft retention hint — the worker is configured for weekly backups
|
|
* (see `DATA_BACKUP_CRON` in `src/lib/jobs/reminder-worker.ts`), and
|
|
* the model upserts in-place per (userId, type), so each user has
|
|
* exactly one current snapshot. The frontend uses this to label the
|
|
* grid; no server-side enforcement.
|
|
*/
|
|
retentionDays: number;
|
|
}
|