feat(assets): track physical QR label assignment - #2717
Draft
ChaddBrenner wants to merge 1 commit into
Draft
Conversation
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 changed
Adds a nullable
Asset.qrLabelAppliedAttimestamp and an organization/timestamp index. The new "Has ID Assigned" state is available in the asset overview, advanced index columns and filters, asset queries, and CSV exports.The timestamp is set when an existing QR is assigned during asset creation, linked to an asset, or relinked to an asset. Creating from an existing QR and the other assignment paths re-read QR ownership in serializable transactions with bounded retries when PostgreSQL reports a write conflict.
Why this matters
Having a generated QR in the database does not necessarily mean someone applied a physical label. Tracking the assignment separately makes it possible to find assets that still need labels without treating every auto-generated QR as applied.
How it works
The normal and advanced asset queries both project
qrLabelAppliedAt, so the overview, filters, sorting, columns, and exports use the same value. Sorting puts null values last.The migration uses the relationship between asset and QR timestamps to infer historical assignments. It excludes QRs created at the same time as their assets, since those are the normal auto-generated records. A linked QR is backfilled only when its creation timestamp differs from the asset and it was updated after it was created. A database trigger records assignments made by an older application process during a rolling deploy. Cross-organization and asset-plus-kit legacy links are excluded from both paths.
Migration notes
The migration backfills the earliest qualifying QR update timestamp for each asset. Fresh auto-generated, replacement, and import-created QR rows remain null when their timestamps do not show a later assignment.
This is intentionally a conservative inference. The database cannot prove every historical physical action, but it can distinguish the existing-then-linked pattern from asset and QR rows created together.
The change is split into schema/trigger, backfill, and index migrations. I rehearsed the public migration history on PostgreSQL 15 with 50,007 assets and 55,844 QRs. The three phases took 9 ms, 152 ms, and 28 ms. Expected auto-generated, pre-generated, replacement, secondary, unclaimed, cross-organization, and dual-linked cases were checked individually, and hashes of every pre-existing column matched afterward.
During the migration rehearsal, 89,393 concurrent asset updates completed without failures, serialization errors, or deadlocks. The slowest observed update took 58.6 ms.
Tests run
pnpm db:generatepnpm --filter @shelf/webapp typecheckgit diff --check origin/main...chaddb/qr-label-assignmentI also ran
pnpm webapp:validate. The branch tests and typecheck pass separately, but the combined command still exits on the existing import-order error inapps/webapp/app/components/list/list-title.tsx, which this branch does not modify.Review notes
Generating or downloading a QR file does not set this timestamp. It changes only on an assignment or linking write path.