Two bugs in the attendance admin print (Tisk on Správa docházky):
1. Viewer-timezone date shift: day rows are built from date-only strings
('2026-06-01'), which new Date() parses as UTC midnight per spec; local
formatting then rendered the PREVIOUS day for any viewer west of UTC —
a June print opened with '31. 5. Neděle' (a May row holding June 1's
punches) and every weekday name + weekend tint shifted by one. Czech
viewers were unaffected (UTC+1/+2), US viewers always hit it.
formatDate / getCzechWeekday / isWeekendDate now parse the calendar day
from the string parts — identical output in every timezone.
2. Every time cell carried a bogus date prefix ('1.6. 08:00'): the
overnight-only guard compared the extracted date part against the raw
wire shift_date ('2026-06-01T02:00:00') — never equal. Now compares
normalized date parts; the prefix fires only for true overnight punches.
Verified end-to-end against the production June payload; +8 regression
tests (timezone-proof by construction — parts-based, no UTC parse).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Fixes every CRITICAL/HIGH finding from the 2026-06-09 full-codebase audit
(REVIEW_FINDINGS.md); each fix went through independent spec + code-quality
review. Plan and per-task log: docs/superpowers/plans/2026-06-10-audit-high-fix-pass.md
- attendance: schemas accept the combined local datetimes the forms/service
use (new dateTimeString helpers in schemas/common.ts), breaks persist on
create, AttendanceCreate submit rebuilt — every submit 400'd since 519edce
- 2fa: backup codes wired to /totp/backup-verify (+ remember-me parity),
enrollment QR generated locally via qrcode (CSP-blocked external service
also leaked the secret), dashboard shows per-user enrollment, not policy
- invoices/orders: per-line VAT survives re-saves (numberOr 0-respecting
coercion in formatters.ts), billing_text persists on update, issued-order
status transitions update UI gates
- trips: real pagination on all 3 pages, GET /trips/stats server aggregate
(shared buildTripsWhere + legacy distance coalesce), vehicle_id applies on
PUT with both-vehicle odometer recompute, print rebuilt (sync window.open,
escaped template, server totals)
- orders api: attachment_data PDF blob excluded from all non-binary reads
- warehouse: unit field is a Select over UnitEnum, receipt attachments
downloadable via new authenticated GET route
- downloads: shared RFC 5987 contentDisposition helper — Czech filenames no
longer 500 (warehouse, received-invoices, orders endpoints)
- misc: block-env hook actually blocks (exit 2 + stderr), project create
works with empty dates, NaN filter guards on trips endpoints
- deps: remove unused concurrently (clears both critical advisories), pin
@hono/node-server >=1.19.13 via overrides (clears the 3 moderates without
the Prisma 6 downgrade), drop deprecated @types stubs
Gates: tsc -b clean - vitest 30 files / 342 tests (31 new) - eslint 0 errors
- build OK
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- base.css: var(--danger-color) (undefined, no fallback -> inherited color) -> var(--danger)
- attendanceHelpers: re-export formatDate from formatters instead of a byte-identical copy
- dashboard.ts: remove dead duplicate require2FAOptions (canonical copy is in settings.ts)
- settings.ts: remove unused @deprecated systemSettingsOptions alias
- PlanWork: drop redundant per-page plan.css import (loaded globally in AdminApp)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Times in the database are stored as local time (CET). JavaScript's
Date constructor treated them as UTC, then toLocaleTimeString added
+1 hour for CET timezone.
Fix: extract hours/minutes directly from the datetime string via regex
instead of going through Date object. No timezone conversion applied.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>