Back to work
Product & UI Lead · Senior Design Project · Computer Vision · React

Designing trust into a barcode-free checkout

Self Checkout+ is a computer vision grocery checkout system that identifies items without barcodes. I led the product direction and built the entire customer-facing experience, designing an interface that makes shoppers trust a system working invisibly behind the scenes.

Project Self Checkout+
My Role Product & UI Lead
Context Senior Design Capstone
Frontend React · Framer Motion
Backend FastAPI · SQLite
Hardware Raspberry Pi · ATmega328p
UX Design React Computer Vision Product Ownership Framer Motion Hardware + Software
01

The System

Traditional self-checkout fails at the same moment every time: when there's no barcode. Loose produce, bulk goods, specialty items, the customer either guesses a code from a printed menu or waves down an attendant. Self Checkout+ eliminates that failure point entirely.

A camera identifies grocery items visually through a YOLOv8 detection pipeline, matches them against a CLIP-trained embedding database, and adds them to a cart, no scanning required. The computer vision pipeline lives on a Raspberry Pi, connected to a custom ATmega328p MCU that handles hardware signaling.

The core challenge wasn't the computer vision. The CV pipeline was strong. The challenge was designing an interface that makes shoppers trust a system working entirely out of sight.

6 distinct customer screens in the checkout flow
2 user types: customer interface and admin dashboard
0 barcodes scanned in the entire checkout flow
4 person team across hardware, CV, and software
02

My Role

As Product & UI Lead, I owned two things that rarely travel together: every pixel of the customer experience, and every major decision about what the product should actually do.

Product Ownership
Defining what the system is
  • Led product decisions with the team and advisor, from feature scope to architecture tradeoffs
  • Raised and resolved questions like: should we auto-add items or ask first? should we show a live video feed?
  • Contributed to the systems thinking and architecture for the computer vision model, not just the customer's side of it
  • Cut features that added complexity without adding trust or speed
Design & Engineering
Building the experience layer
  • Designed and built the complete customer checkout flow in React, all six screens
  • Built the admin dashboard for store operators: inventory, overrides, session monitoring
  • Integrated the Raspberry Pi cameras myself, wiring the hardware capture into the CV module
  • Owned the SQLite schema and the integration between the React frontend and FastAPI backend
  • Implemented Framer Motion animations and resolved animation-blocking issues during API calls
The stack

Customer UI and admin dashboard in React with Framer Motion. Backend in FastAPI with SQLite. CV pipeline using YOLOv8 + CLIP + FAISS + OCR running on a Raspberry Pi. Hardware signaling over an ATmega328p MCU. My domain was mainly the software layer above the CV model, plus the camera integration and input on the CV architecture.

03

The Customer Experience

Six screens, one goal: make shoppers trust a system working entirely out of sight. Every design decision was about control, giving customers a visible way to verify, correct, and confirm before money changed hands.

04

Key Design Decisions

The most interesting design work wasn't the visual styling, it was the product thinking that shaped the flow. Each decision below was a deliberate tradeoff I raised and resolved during the build.

01
Build in a confirmation step, don't auto-add items
When the CV pipeline identifies an item, the shopper sees "Did we get this right?" before it's added to the cart. That trades a little speed for trust: a system that silently adds items, even accurately, feels like it's deciding for you. The confirmation gives the customer a moment of control and an easy way to fix a wrong call without flagging down an attendant. It costs one extra tap per item, and for a brand-new checkout format where trust isn't a given yet, that was worth it.
UX decision
02
Cut the live video feed entirely
An early version showed a live camera feed in the scanning zone. I cut it. Live video is visually noisy, raises real privacy questions, and doesn't help the customer finish any faster. The task is checkout, not watching the camera process food. Removing the feed simplified the UI and put attention where it belonged, on the item confirmation and the cart. What replaced it was a clean scanning zone with a simple status indicator, enough to show the system is working, nothing more.
Product decision
03
Let the backend own the cart total
Early builds kept the cart total in React and synced it with the backend now and then, which caused subtle mismatches, the UI showing one running total while the backend calculated another. Even a few cents off looked like a bug, and in an interface where every number matters, that quietly eroded trust. I moved the cart entirely to the backend and had React simply render whatever the API returned. One source of truth, no drift, no reconciliation bugs.
Engineering decision
04
Keep animations off the data-fetching thread
Framer Motion transitions would stutter and freeze whenever an API call blocked the main thread. The fix was to separate the animation from the data fetch: the UI plays the transition on its own, and the component updates when the fetch resolves, not when it starts. Every screen transition felt instant even while the backend was still working, and the architecture got cleaner too, since the animation and the data fetching stopped competing for the same thread.
Engineering decision
05

The Integration Challenge

The hardest problems weren't in any single layer. They were at the seams between layers. The CV pipeline produced detection events. The FastAPI backend processed them into cart items. The React frontend rendered the cart. When all three systems were moving at once, things broke in ways no single component's tests could catch.

As the person responsible for the integration layer, I owned the SQLite schema that made the CV pipeline's output usable by the frontend. I also designed the API contract between FastAPI and React: which fields the frontend could trust, which had to be calculated server-side, and how errors from the CV layer should surface to the customer.

The key insight

The hardest integration problems weren't really about code. They came down to being clear about which layer owned what. Once each layer had one job, most of the bugs had nowhere to hide.

CV pipeline → SQLite → FastAPI → React
Each layer had a defined contract. The CV pipeline wrote detection events, SQLite stored item metadata, FastAPI computed totals, and React rendered state. Keeping those responsibilities separate is what made the system easy to debug.
06

The Admin Interface

The customer-facing flow was one half of the product. The other half was the operator dashboard, the interface that lets store staff manage inventory, approve manual overrides, and monitor active sessions. I designed and built this separately from the customer UI, giving it a simpler, more utilitarian look that reads as an internal tool rather than a customer product.

Mockup: the admin inventory dashboard — a sidebar with store operations, a product database table showing item, category, price, CV detection confidence, and status, with summary stats for total items, active items, average confidence, and pending reviews.

Mockup: the override queue — three pending items the CV model could not identify, each with the lane, session, reason code, price, and Approve/Reject actions for store staff.

The override queue was one of the most important features I designed, not because it gets used often, but because it's the plan for when things go wrong. When the CV pipeline can't identify an item, store staff need a fast way to add it manually without interrupting the customer's checkout. Every override is logged with a reason code, which also gave us data on exactly where the CV model needed to improve.

"The system could identify a banana with 99% confidence. My job was designing the 1%, the moment it doesn't, and what happens next."

07

The Results

We wrote seven testable specs before building anything, and validated every one. The numbers I cared about most were the ones a shopper actually feels, that the total always matched, that the screen never froze, and that an uncertain item still resolved inside the same six-second window.

100% Top-1 accuracy on the 16-SKU test set, no misclassifications (target was 99 in 100)
<6s Full checkout, from item placement to emailed receipt, across 50 trials, none over 8s
12 hrs Continuous operation with zero crashes or disconnections
<200ms Admin operations, with no freezes during a live customer checkout

Two of those tie straight back to the layer I owned. The cart total matched the backend on all 50 transactions, because I'd made the backend the one place the total lived instead of syncing two running counts. And the interface stayed responsive mid-scan because the animation and the data-fetching ran on separate paths. Speed and accuracy were the baseline. What I really wanted to prove was that the trust held up under real conditions, including the moments the model wasn't sure.

08

What I Learned

01
Accuracy wasn't enough to earn trust
The CV model was genuinely accurate. But accuracy doesn't equal trust. Trust comes from the interface: the confirmation step, the item preview, the clear error path, the ability to delete something. People trust a system when it gives them visible control and an easy way to fix it.
02
Product decisions live in architecture meetings
Some of the biggest product choices happened in technical discussions: whether to cache detection events or query live, how the backend should handle concurrent sessions, what the API contract between FastAPI and React should look like. Being in those conversations, and asking "what does this mean for the customer?", mattered more than any later feature decision.
03
Less on screen made the process smoother for the customer
Removing the live video feed wasn't about making the UI simpler. It was about making the customer's task clearer. Every element on screen should earn its place by helping the user finish. The camera feed was technically impressive but distracting, and impressive doesn't help someone check out faster.
04
Integration is a design problem
The hardest bugs weren't in any single component. They were at the seams: the animation and API call competing, the cart UI and backend total diverging. Designing clear ownership boundaries between layers would have caught those problems before they became debugging sessions. I'd now treat the API contract as something to design carefully up front, not patch in later.

"Anyone can build a system that works when everything goes right. I spent my time on the moments it doesn't, because that's where a shopper decides whether to trust it."

Back to all work