feat(facility): track badge prints and report yearly gaps#962
Open
jee7s wants to merge 1 commit into
Open
Conversation
Add a durable record of physical ID badge prints and a Facility Ops report answering "who has / hasn't had a badge printed in year X". - New BadgePrint model (personId, printedAt, printedById, optional note), sibling of RawBadgeLog. Append-only; reprints/yearly refresh add rows. - POST /api/facility/badge-prints marks people printed (single + bulk, same call). GET returns the calendar-year report: printed (grouped per person with last date, recorder, count) and the gap list (people who visited that year with no print). Both sysadmin/board gated. - New "Badge Prints" tab under Facility Ops with a year picker, gap list with per-row + bulk mark-printed, and the printed list. - Additive migration (new table only). Calendar-year (UTC) window; membership- year/timezone boundary deferred. See docs/designs/BADGE_PRINT_TRACKING.md. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What & why
Physical ID badges get printed for people, but nothing recorded that a badge
was printed, when, or by whom — so reprints and the yearly badge refresh
were tracked by memory. This adds a durable record of badge prints and a Facility
Ops report answering "who has / hasn't had a badge printed in year X?"
Design:
checkin-app/docs/designs/BADGE_PRINT_TRACKING.md.Decisions (from the product interview)
scans. Recording a print is a deliberate human act, decoupled from generating a
badge PDF (which already exists on Print ID Badges). Both alternatives are
written up as rejected in the design doc.
BadgePrintmodel (personId,printedAt,printedById, optionalnote) — a sibling ofRawBadgeLog. Append-only; multiple rows per person arenormal (reprints, yearly refresh). The report de-dupes to one row per person
with the most recent date + a count.
physical-facility concern and a direct sibling of the existing Raw Badge Events
/ Print ID Badges tabs, same
isSysadmin|isBoardMembergate. (Rationale in thedoc.)
Visit) that year.Defensible from existing data (came to the facility → should have a badge; never
came → doesn't need one). Read only as a
wherefilter, so noVisitrows arereturned and the route auth drift-guard's edge rule doesn't apply.
boundary is written up as the deferred alternative.
Changes
BadgePrintmodel + additive migration20260709020000_badge_print_tracking(new table only — two FKs to
Person, two indexes; no data change).GET/POST /api/facility/badge-prints(sysadmin/board): POST marks peopleprinted (single + bulk in one call); GET returns the yearly report (printed +
gap lists).
and bulk mark-printed, and the printed list.
security/generated/classifications.ts(BadgePrint field tiers);new page/route registered in
pageRegistry+authzRegistry.Testing
badgePrints.test.ts— year-window boundaries (half-open, adjacentyears, in/out of range).
badge-prints/__tests__/page.test.tsx— renders printed + gap lists,single and bulk mark POST the right body.
badge-prints/__tests__/route.integration.test.ts(7 tests) —authz 401/403 (GET + POST), single + bulk mark with the caller as actor, report
printed/gap correctness across the 2025↔2026 boundary, and reprint/duplicate
behavior (two rows, one report row, count 2).
tsc --noEmitandeslint --max-warnings 0clean.Deferred
Membership-year/timezone-aware boundary, editing/deleting a print row,
registering the report route through the security registry, per-person print
history UI. All noted in the design doc.
🤖 Generated with Claude Code