feat(logs): app log store — backend pino DB sink + frontend error collection
Add a third data stream (app_logs), distinct from the signed ledger and device telemetry, for operational/diagnostic logs — an offline appliance has no Sentry to ship to, so the host is the log store. Backend: a pino stream tees warn/error/fatal into app_logs (info/debug stay stdout-only) with no call-site change; the DB is built before Fastify so the logger has its sink. Frontend (lib/logger.ts): ships failed API requests (minus 401 churn), window.onerror, unhandledrejection, and a top-level React ErrorBoundary; console warn/error forwarded only at debug/trace. Batched/throttled POST, sendBeacon on pagehide, loop-safe (never logs the /api/logs call), best-effort everywhere. POST /api/logs (any signed-in user, CSRF, tolerant) + GET /api/logs gated by a new log:read permission (new `log` RBAC resource; admin holds it). Retention: pruned by age + row cap, hourly + at startup. UI: a Logs screen under /setup (filter level/source/since, expand to context+stack), sq+en. Migration 0009_app_logs. Verified end-to-end via app.inject: login -> POST 204 -> GET 200 with the record; backend warn/error persisted, info dropped; non-admin GET 403 / POST 204. Claude-Session: https://claude.ai/code/session_01Xcm6ikLgGoCxxHrxtjkk5V
This commit is contained in:
@@ -51,6 +51,7 @@ export const sq = {
|
||||
users: "Përdoruesit",
|
||||
roles: "Rolet",
|
||||
shifts: "Turnet",
|
||||
logs: "Regjistrat",
|
||||
},
|
||||
status: {
|
||||
live: "LIVE",
|
||||
@@ -495,6 +496,24 @@ export const sq = {
|
||||
cashRemoved: "Para të hequra",
|
||||
loadFailed: "Ngarkimi i turneve dështoi.",
|
||||
},
|
||||
logs: {
|
||||
title: "Regjistrat e sistemit",
|
||||
refresh: "Rifresko",
|
||||
level: "Niveli",
|
||||
source: "Burimi",
|
||||
since: "Që nga",
|
||||
apply: "Apliko",
|
||||
clear: "Pastro",
|
||||
allLevels: "Të gjitha nivelet",
|
||||
allSources: "Të gjitha burimet",
|
||||
frontend: "Ndërfaqja",
|
||||
backend: "Serveri",
|
||||
time: "Koha",
|
||||
message: "Mesazhi",
|
||||
status: "Statusi",
|
||||
path: "Rruga",
|
||||
empty: "Asnjë regjistër.",
|
||||
},
|
||||
pay: {
|
||||
ticket: "Bileta",
|
||||
entry: "Hyrja",
|
||||
|
||||
Reference in New Issue
Block a user