← Back to featured work

Evidence-based implementation walkthrough

PSA Card Scanner and Batch Processor — Technical Case Study

This public project connects browser image preparation and selected barcode detection to a FastAPI processing boundary and persisted result states. The walkthrough is based on inspectable source code, not performance benchmarks, production telemetry, or client outcome claims.

PSA Card Scanner and Batch Processor architecture cover

Project at a glance

Frontend

React 19 and Vite browser interface

Image boundary

Canvas resize, compression, crop, rotation, and filters

Detection

Native BarcodeDetector with ZXing fallback

Backend

Python, FastAPI, Uvicorn, and HTTPX

State

SQLAlchemy process records backed by PostgreSQL

Evidence

Public source repository and recorded demo

The scanning workflow

The implemented path begins with multiple image selection or live camera input. Image files are prepared in the browser, decoded values enter a local queue, and each value crosses the FastAPI boundary. A background task updates a PostgreSQL-backed process record while the frontend polls for a complete, partial, or error result.

Implemented PSA scanning flow and separately labeled future hardening

Client-side image processing

Uploaded images are read into Canvas-backed data, resized and compressed before they enter the queue. The scanner normalizes large images and generates transformed regions across selected rotations, scales, contrast levels, brightness adjustments, and binary thresholds. A manual ReactCrop editor also lets a user isolate and rotate a region for another scan attempt. These are implemented transformations; they are not evidence of measured detection quality.

Barcode detection boundary

Uploaded images

Code 128 and Code 39 format hints.

Camera mode

Code 128, Code 39, EAN-13, and UPC-A format hints.

The image path tries the browser's native BarcodeDetector where available and then uses ZXing as a fallback. README material describes QR support, but the implemented format hints inspected for these paths do not establish it. This case study therefore does not present QR as an implemented capability.

Browser queue and status model

Queue items and the selected scan mode are stored in localStorage. Pending image and camera items carry explicit UI states, and auto-processing selects up to two eligible items at a time before marking them as scanning or backend processing. This is a browser-local workflow queue, not a durable server-side job queue.

FastAPI and backend state

The POST /process endpoint checks for a cached complete or partial record, creates a new process record when needed, and schedules a FastAPI background task. SQLAlchemy persists the barcode, result JSON, error message, timestamp, and state. The frontend polls GET /status/{process_id} until it receives a terminal result.

Structured output and enrichment

Evidence-supported output includes the decoded barcode, a structured result object, PSA and PriceCharting-related fields when available, generated eBay search links, persisted JSON text, and copy controls in the result UI. No CSV creation or export path appears in the inspected implementation, so CSV output is not claimed here.

Evidence-supported code excerpts

These deliberately small excerpts show safe architectural boundaries from the public repository. They contain no environment values, API keys, card identifiers, or local filesystem paths.

Multiple-image ingestion

frontend/src/components/ImageUpload.jsx

const files = Array.from(e.target.files);
const processedFiles = [];

for (const file of files) {
  processedFiles.push(await compressImage(file));
}

if (onImagesQueued) onImagesQueued(processedFiles);

Uploaded-image format hints

frontend/src/utils/scannerUtils.js

const hints = new Map();
hints.set(DecodeHintType.POSSIBLE_FORMATS, [
  BarcodeFormat.CODE_128,
  BarcodeFormat.CODE_39,
]);
hints.set(DecodeHintType.TRY_HARDER, true);

Persisted process states

backend/models.py

class CardProcess(Base):
    __tablename__ = "card_processes"
    id = Column(Integer, primary_key=True, index=True)
    barcode = Column(String, index=True)
    status = Column(String, default="pending")
    result_json = Column(Text, nullable=True)
    error_message = Column(String, nullable=True)

Process and status boundaries

backend/main.py

@app.post("/process")
def process_barcode(req: ProcessRequest, background_tasks: BackgroundTasks,
                    db: Session = Depends(get_db)):
    new_process = CardProcess(barcode=req.barcode)
    db.add(new_process)
    db.commit()
    db.refresh(new_process)
    background_tasks.add_task(run_pipeline, req.barcode, new_process.id)

@app.get("/status/{process_id}")
def get_status(process_id: int, db: Session = Depends(get_db)):

Error handling

Current implementation evidenced by source

  • Image read failures reject the client-side preparation operation.
  • An undecoded image becomes a barcode-not-found error state.
  • Network and API failures become visible queue-item errors.
  • The backend exposes not-found, server, and database-unavailable responses.
  • Persisted states distinguish pending, processing, complete, partial, and error.
  • Database startup retries and lookup failure can produce a partial result.

What the public evidence proves

EvidenceDemonstratesDoes not prove
React/Vite interfaceBrowser-based input and workflow UIProduction adoption or usability outcomes
BarcodeDetector + ZXingSelected barcode formats are implementedUniversal detection or measured quality
Canvas preprocessingResize, crop, rotation, and filter pathsA validated computer-vision model
FastAPI backendA process/status API and background-task boundaryThroughput or service-level guarantees
PostgreSQL statePersisted process and result statusBackup, recovery, or durability guarantees
Public demoA recorded interface and workflowMeasured performance or privacy clearance
Public repositoryInspectable implementation evidenceCommercial success or client outcomes

What the evidence does not establish

The inspected implementation does not establish QR support, OCR, CSV export, folder-based processing, measured detection quality, throughput, production scale, time savings, client or business outcomes, or a service-level guarantee. The README also lists OpenCV, Pyzbar, NumPy, and Pillow, but those libraries do not describe the current scanner path evidenced by the frontend package and source.

What I would harden next

Future recommendations — not current claims

  • Add deterministic scan fixtures and API, state-transition, and integration tests.
  • Bound status polling with timeouts, cancellation, and explicit terminal contracts.
  • Define structured retry policies for each external integration boundary.
  • Add input limits, format validation, privacy review, and safe media-retention rules.
  • Introduce structured logs, traces, health signals, and operator-visible failure context.
  • Clean environment files, local paths, generated dependencies, and caches from public history.
  • Run lint, tests, secret scanning, and repository-hygiene checks in CI.
  • Build an evaluation harness before publishing any detection or performance statement.

Repository and demo hygiene

Before using a public repository as portfolio evidence, generated dependencies, environment files, local paths, logs, and potential secrets should be reviewed and cleaned. This observation identifies a review requirement; it does not claim that an active secret was verified or exposed.

The embedded demo remains a visual demonstration of the workflow; individual frames should be reviewed for portfolio privacy before broader reuse. No card identifiers are transcribed or reproduced in this case study.

What this project demonstrates

The public implementation demonstrates frontend/backend integration, browser image preparation, selected barcode formats, local queue state, an asynchronous API boundary, persisted process states, structured results, and visible failure states. Its strongest portfolio value is the inspectable separation of those boundaries.

Review the implementation

Read the public source for implementation evidence, watch the recorded workflow, or return to the portfolio for other projects.