login, register, forgot-password, reset-password, confirm-email, users,
and logs all commit to at least one full viewport tall via
min-height:100dvh. Without compensation, the env banner's 28px pushes
their content past body's fixed one-viewport box, creating a phantom
scrollbar in the dev environment on exactly the routes where confusing
dev with prod matters most.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Shell and the public pages commit to exactly one viewport tall; without
this, the new dev-environment banner would push their bottom edge (and
Shell's bottom nav) past the visible viewport, the same overflow-leak
bug fixed earlier today.
Renders the banner once at the app root so every route picks it up,
and exposes its height as a CSS custom property so fixed-viewport
layouts (Shell, public pages) can compensate for it.
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>
- Reject dates that are not strict YYYY-MM-DD (was accepting full ISO
datetimes, which silently produced empty exports instead of a 400)
and reject from > to with a 400 before touching the team/DB.
- Emit the cashbox_export_download and cashbox_export_subscription_update
audit log events that were declared but never fired, matching the
audit trail every sibling feature already has.
- Restore full type checking on the pdfkit import via `import = require()`
instead of an untyped require() with an eslint-disable.
- Tighten a cashbox.spec.ts assertion to check the exact dialog class
instead of expect.anything(), so it can't pass with the wrong dialog
wired to the Export button.
- Style and announce the export dialogs' error messages using this
codebase's established error-message/role=alert pattern.
openExportDialog()/openExportSubscriptionDialog() only guarded on teamId
truthiness, relying solely on the template @if for permission gating.
Every other permission-gated method in Cashbox (submitPlayerBooking,
reverseBooking) re-checks the permission internally too. Add the same
guard here, plus a test asserting direct invocation without booking
rights does not call dialog.open.
Adds an Export button (opens CashboxExportDialog directly) plus a
secondary menu (opens CashboxExportSubscriptionDialog) to the journal
toolbar, gated by the existing canBook permission signal.
Lets treasurers/captains/coaches define recurring fee/levy dues that
are automatically booked for all active players on a monthly,
quarterly, or yearly schedule via a daily cron job, instead of having
to book them manually every cycle.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- teams.service.spec.ts: pick a checkpoint older than the adjustment's own
month so the exclusion test actually fails without the exclusion filter
- teams.service.ts: only negate fine/levy/fee amounts when positive,
matching TeamMembersService.recomputeBalance and Transaction.setBalance()
exactly, instead of negating unconditionally
- teams.service.ts: outstanding-history helper now returns a positive
value when players owe money, matching the house convention already
established by getOverview()'s team.outstanding
- overview.spec.ts: assert the balance chart's legend becomes visible
- teams.service.spec.ts: add coverage for inactive-player exclusion and
a positive-balance (prepaid credit) case
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Adds a second, dashed line to the existing balance-history chart that
includes currently open player dues, so managers can see at a glance
how far the actual cash balance lags behind what has been pledged.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The vi.mock('chart.js', ...) MockChart class was copy-pasted verbatim
between chart-canvas.spec.ts and overview.spec.ts. Extract it to
shared/chart-canvas/testing/mock-chart.ts and import it via
vi.hoisted(async () => import(...)) in each spec, since vi.mock's
factory is hoisted above regular imports and can't reference a
plain top-level import.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Adds three chart.js-backed KPI cards (Kassenstand-Verlauf, Einnahmen &
Ausgaben, Top-10 offene Beitraege) to the existing Uebersicht page,
consuming the new GET teams/:id/overview/stats endpoint via a new
TeamStatsApi service. Introduces a small reusable ChartCanvas shared
component that wraps the Chart.js instance lifecycle via @Input()/
ngOnChanges, following this codebase's existing input-decorator
convention rather than effect().
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Adds a catalog picker to the member-booking form in the cashbox (prefills
amount/note/type, stays editable) and a "Buchen" button on each penalty
catalog entry that jumps to the cashbox with that entry preselected via a
penaltyId query param. No backend changes — reuses the existing POST
/transactions flow, the catalog only supplies starting values.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Team managers (captain and above) can now deactivate/reactivate a player and
change their team-role from the player detail page. Deactivation zeroes the
open balance via an auditable adjustment transaction instead of overwriting
the balance field, and both actions are blocked if they would leave a team
without an active treasurer. Also hardens the existing PUT teams/:id/players
endpoint down to profile-only fields, fixing a typo bug and closing a gap
where any authenticated user could mutate a player's active/role/balance in
any team.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>