Skip to content

Add barcode scan handler - #16

Open
spenfeld wants to merge 4 commits into
mainfrom
3-barcode-scan-handler
Open

spenfeld wants to merge 4 commits into
mainfrom
3-barcode-scan-handler

Conversation

@spenfeld

Copy link
Copy Markdown
Collaborator

Pull Request

Description

Adds handleBarcodeScan in packages/backend/src/barcode-scan-handler.ts, which handles a member scanning their barcode at the kiosk and adds barcode-scan-handler.test.ts using an in-memory fake of Firestore.

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation update
  • Refactoring (no functional changes)
  • Performance improvement
  • Other (please describe):

Related Issues (put task name here from notion)

Screenshots (If it is a front end feature screenshot is required)

Additional Notes

Current visit fields: personId, visitTypeId, checkedInAt, checkedOutAt, durationMs.

normalizeBarcode() isn't on main yet, so I used trim().toUpperCase() for now and will swap it in later.

Tests use a fake Firestore, so they don't cover two scans at the same time.

@coderabbitai

coderabbitai Bot commented Oct 24, 2026 •

Copy link
Copy Markdown

Important

  • Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

Run configuration

  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 49a02fa4-c904-4f1b-a478-43dad8a15a15
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Tip

🎯 Customize your risk assessments

Guide how CodeRabbit assesses merge risk and security architecture risk. Highlight sensitive changes and explain your security boundaries using Merge Risk Instructions and Security Risk Instructions in your review settings. Security architecture risk assessments require the Advanced plan or above.

✅ Automatic approvals, with your rules

Let CodeRabbit approve pull requests once required threads are resolved, pre-merge checks pass, and your risk limits are met. Enable Automatic approvals in review settings, with overrides for teams or file paths.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share

@amanuelabiy amanuelabiy left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work on the core logic. The transaction is solid. We just need a few of these changes before merging.

Also for testing please add a test that calls visits.scan through createCaller (see routers/index.test.ts), including one that checks a call without a session is rejected with UNAUTHORIZED. Your existing tests can stay. Just pass the fake db in directly instead of mocking the module.

import { COLLECTIONS } from "@repo/common";
import type { Person } from "@repo/common";

type ScanInput = { barcode: string; visitTypeId?: string };

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As per the task, the input schema should live in packages/common/src/schemas.ts as arktype schema, so its checked at runtime and shared with the frontend.

Remove this local type. And add something like this to packages/common/src/schemas.ts :

export const scanInput = type({
  barcode: "string >= 1",
  "visitTypeId?": "string",
});
export type ScanInput = typeof scanInput.infer;

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

};
}

export function handleBarcodeScan(input: ScanInput) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good logic but nothing is calling handleBarcodeScan, so the kiosk has no way to use it. Step 1 of the task is to expose it as a tRPC procedure called visits.scan. That's what lets the frontend call it over the network.

Please create packages/backend/src/routers/visits.ts:

export const visitsRouter = router({
scan: protectedProcedure
.input(scanInput)
.mutation(({ ctx, input }) => handleBarcodeScan(ctx.db, input)),
});

and mount it as visits: visitsRouter in routers/index.ts. Use .mutation rather than .query, since it writes data, and use protectedProcedure so only a signed-in kiosk can call it.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

}

export function handleBarcodeScan(input: ScanInput) {
const db = getFirestore();

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Take db: Firestore as a parameter instead of calling getFirestore() here and on lines 24 and 64. Pass ctx.db in from the procedure, like the other routers do. That also allows the tests to pass a fake db directly instead of mocking the whole fire-base-admin/firestore module.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done


export function handleBarcodeScan(input: ScanInput) {
const db = getFirestore();
const barcode = input.barcode.trim().toUpperCase(); //ToDo: swap for normalizeBarcode()

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Once #2 merges, please update this branch from main and use normalizeBarcode().

Also write TODOs as //TODO:. So editors and searches can pick them up as this is the usual convention.

) {
const visitRef = getFirestore().collection(COLLECTIONS.visits).doc(); //new visit id

transaction.set(visitRef, {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This visit doesn't match the visit schema in common/src/visit.ts. I checked it on the emulator and it's missing personType, checkInMethod, endReason, flags, updatedAt and updatedBy.

Please add:

personType: person.personType,
checkInMethod: "barcode",
endReason: null,
flags: [],
updatedAt: now,
updatedBy: null,

It would also help to check the object with visit(...) before writing it, so a missing field fails right away.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

const checkedInAt = visitData.get("checkedInAt") as number;
const durationMs = now - checkedInAt;

transaction.update(visitRef, { checkedOutAt: now, durationMs: durationMs });

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please set endReason: "checkout" and updatedAt: now here. This allows reports to tell the difference between a normal checkout and an auto-expired/admin-closed visit.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

transaction,
personRef,
person,
input.visitTypeId ?? null,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

visitTypeId is optional in the input, but the visit schema requires a string, so this can write null. Please default to "member-hours" (the first of DEFAULT_VISIT_TYPES in catalog.ts) when none is given.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@spenfeld
spenfeld requested a review from amanuelabiy November 7, 2026 04:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants