- LoggingService.findLogs(): the `to` date filter compared a date-only
string (e.g. from a date picker) against a timestamp column, which
parses to midnight and silently excludes the entire last day. Widen
it to end-of-day so the range is genuinely inclusive.
- LogRetentionScheduler.cleanupOldLogs(): wrap the delete in try/catch
and log failures via logger.error, matching the existing convention
in CashboxExportScheduler/RecurringTransactionsScheduler. Without
this, a failed nightly cleanup would fail silently - exactly what
this feature exists to prevent.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Global admins couldn't see the app's event log (no read endpoint or UI
existed for it) and had no way to clean up old entries or re-run a
scheduled job without touching the database or server directly.
Backend:
- LoggingService.findLogs() + admin-only LogsController (GET
admin/logs) with level/event/date-range/search filtering and
pagination, mirroring AdminUsersService.findPlayers().
- LogRetentionScheduler deletes log entries older than
LOG_RETENTION_DAYS (default 365, via app.config.ts), following the
existing @Cron scheduler pattern.
- Admin-only POST admin/run endpoints on CashboxExportController and
RecurringTransactionsController that invoke the existing schedulers'
public run methods on demand - both are safe to re-run since their
"due" queries advance nextRunDate only after a successful run.
Frontend:
- New /logs page (global-admin gated, same pattern as /users): AG-Grid
infinite-scroll table with level/event/date-range/search filters,
plus buttons to trigger the two jobs now and see the result land in
the grid immediately.
- LogsApi, and triggerRunNow() added to the existing CashboxExportApi
and RecurringTransactionApi.
- Discoverability link from /users to /logs.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>