Same pgx v5 binary protocol issue as admin service — created_at
in transactions cannot be scanned into *string.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
pgx v5 uses binary protocol for timestamptz and cannot scan it
directly into *string. Scan into time.Time and format as RFC3339.
Fixes /admin/users internal server error and broken grant search.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
router.push() can reuse a cached middleware redirect that was
issued before the cookie was set, sending the user back to /login.
window.location.href forces a fresh browser request that carries
the newly set access_token cookie.
Also changed SameSite=Strict -> SameSite=Lax so the cookie is
included in all same-site navigation patterns.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Partner flow: QR scanner component (html5-qrcode) with camera
permission/not-found handling, 3-step spend flow (scan → amount
entry with auto-filled max → success/error result).
Admin dashboard: stats overview, grant points with debounced
student search, paginated transactions table with type filters,
paginated students table.
Tests: comprehensive unit tests for points and auth packages —
service (all paths including error branches, RS256 wrong-method),
handler (all HTTP status codes via httptest), JWT round-trip,
repository constructors. Auth coverage: 72.9%, points service
coverage: 100%.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>