Commit Graph
100 Commits
Author SHA1 Message Date
Eric GullicksonandClaude Opus 4.6 5877b531f9 fix: allow PDF uploads in backend OCR controller and service (refs #182)
Deploy to Staging / Build Images (pull_request) Successful in 3m41s
Deploy to Staging / Deploy to Staging (pull_request) Successful in 52s
Deploy to Staging / Verify Staging (pull_request) Successful in 9s
Deploy to Staging / Notify Staging Ready (pull_request) Successful in 7s
Deploy to Staging / Notify Staging Failure (pull_request) Has been skipped
The backend SUPPORTED_IMAGE_TYPES set excluded application/pdf, returning
415 before the request ever reached the OCR microservice. Added PDF to
the allowed types in both controller and service validation layers.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-02-13 21:27:40 -06:00
Eric GullicksonandClaude Opus 4.6 653c535165 chore: add PDF support to receipt OCR pipeline (refs #182)
Deploy to Staging / Build Images (pull_request) Successful in 38s
Deploy to Staging / Deploy to Staging (pull_request) Successful in 22s
Deploy to Staging / Verify Staging (pull_request) Successful in 8s
Deploy to Staging / Notify Staging Ready (pull_request) Successful in 7s
Deploy to Staging / Notify Staging Failure (pull_request) Has been skipped
The receipt extractor only accepted image MIME types, rejecting PDFs at
the OCR layer. Added application/pdf to supported types and PDF-to-image
conversion (first page at 300 DPI) before OCR preprocessing.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-02-13 21:22:40 -06:00
Eric GullicksonandClaude Opus 4.6 83bacf0e2f chore: accept PDF files in receipt upload dialog (refs #182)
Deploy to Staging / Build Images (pull_request) Successful in 3m39s
Deploy to Staging / Deploy to Staging (pull_request) Successful in 23s
Deploy to Staging / Verify Staging (pull_request) Successful in 9s
Deploy to Staging / Notify Staging Ready (pull_request) Successful in 8s
Deploy to Staging / Notify Staging Failure (pull_request) Has been skipped
Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-02-13 21:14:22 -06:00
Eric GullicksonandClaude Opus 4.6 812823f2f1 chore: integrate AddReceiptDialog into MaintenanceRecordForm (refs #184)
Deploy to Staging / Build Images (pull_request) Successful in 3m31s
Deploy to Staging / Deploy to Staging (pull_request) Successful in 22s
Deploy to Staging / Verify Staging (pull_request) Successful in 9s
Deploy to Staging / Notify Staging Ready (pull_request) Successful in 8s
Deploy to Staging / Notify Staging Failure (pull_request) Has been skipped
Replace ReceiptCameraButton with "Add Receipt" button that opens
AddReceiptDialog. Upload path feeds handleCaptureImage, camera path
calls startCapture. Tier gating preserved.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-02-13 20:57:37 -06:00
Eric GullicksonandClaude Opus 4.6 6751766b0a chore: create AddReceiptDialog component with upload and camera options (refs #183)
Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-02-13 20:55:21 -06:00
Eric GullicksonandClaude Opus 4.6 bc72f09557 feat: add desktop sidebar collapse to icon-only mode (refs #176)
Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-02-13 20:07:00 -06:00
Eric GullicksonandClaude Opus 4.6 f987e94fed chore: verify notification bell functionality and improve empty state (refs #180)
Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-02-13 20:02:56 -06:00
Eric GullicksonandClaude Opus 4.6 da4cd858fa chore: use display name instead of email in header greeting (refs #177)
Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-02-13 20:01:56 -06:00
Eric GullicksonandClaude Opus 4.6 553877bfc6 chore: add upload date and file type icon to document cards (refs #172)
Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-02-13 20:00:49 -06:00
Eric GullicksonandClaude Opus 4.6 daa0cd072e chore: remove Insurance default bias from Add Document modal (refs #175)
Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-02-13 19:56:34 -06:00
Eric GullicksonandClaude Opus 4.6 afd4583450 chore: show service type in maintenance schedule names for differentiation (refs #174)
Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-02-13 19:55:25 -06:00
Eric GullicksonandClaude Opus 4.6 f03cd420ef chore: add Maintenance page title and remove duplicate vehicle dropdown (refs #169)
Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-02-13 19:53:13 -06:00
Eric GullicksonandClaude Opus 4.6 e4be744643 chore: restructure Fuel Logs to list-first with add dialog (refs #168)
Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-02-13 19:49:46 -06:00
Eric GullicksonandClaude Opus 4.6 f2b20aab1a feat: add recent activity feed to dashboard (refs #166)
Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-02-13 19:48:06 -06:00
Eric GullicksonandClaude Opus 4.6 accb0533c6 feat: add call-to-action links in zero-state dashboard stats cards (refs #179)
Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-02-13 19:45:14 -06:00
Eric GullicksonandClaude Opus 4.6 0dc273d238 chore: remove dashboard auto-refresh footer text (refs #178)
Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-02-13 19:43:57 -06:00
Eric GullicksonandClaude Opus 4.6 56be3ed348 chore: add Year Make Model subtitle to vehicle cards and hide empty VIN (refs #167)
Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-02-13 19:41:23 -06:00
Eric GullicksonandClaude Opus 4.6 bc9c386300 chore: differentiate Stations icon from Fuel Logs in bottom nav (refs #181)
Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-02-13 19:40:09 -06:00
Eric GullicksonandClaude Opus 4.6 7a74c7f81f chore: remove redundant Stations from mobile More menu (refs #173)
Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-02-13 19:39:16 -06:00
Eric GullicksonandClaude Opus 4.6 73976a7356 fix: add Maintenance to mobile More menu (refs #164)
Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-02-13 19:38:21 -06:00
Eric GullicksonandClaude Opus 4.6 0e8c6070ef fix: sync mobile routing with browser URL for direct navigation (refs #163)
URL-to-screen sync on mount and screen-to-URL sync via replaceState
enable direct URL navigation, page refresh, and bookmarks on mobile.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-02-13 19:35:53 -06:00
Eric GullicksonandClaude Opus 4.6 325cf08df0 fix: promote vehicle display utils to core with null safety (refs #165)
Create shared getVehicleLabel/getVehicleSubtitle in core/utils with
VehicleLike interface. Replace all direct year/make/model concatenation
across 17 consumer files to prevent null values in vehicle names.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-02-13 19:32:40 -06:00
Eric Gullickson 75e4660c58 Merge branch 'main' of 172.30.1.72:egullickson/motovaultpro
Deploy to Staging / Build Images (push) Successful in 3m25s
Deploy to Staging / Deploy to Staging (push) Successful in 51s
Deploy to Staging / Verify Staging (push) Successful in 9s
Deploy to Staging / Notify Staging Ready (push) Successful in 8s
Deploy to Staging / Notify Staging Failure (push) Has been skipped
2026-02-13 16:28:52 -06:00
Eric Gullickson ff8b04f146 chore: claude updates 2026-02-13 16:28:49 -06:00
Eric GullicksonandClaude Opus 4.6 1bf550ae9b feat: add pending vehicle association resolution UI (refs #160)
Deploy to Staging / Build Images (pull_request) Successful in 8m40s
Deploy to Staging / Deploy to Staging (pull_request) Successful in 52s
Deploy to Staging / Verify Staging (pull_request) Successful in 8s
Deploy to Staging / Notify Staging Ready (pull_request) Successful in 7s
Deploy to Staging / Notify Staging Failure (pull_request) Has been skipped
Backend: Add authenticated endpoints for pending association CRUD
(GET/POST/DELETE /api/email-ingestion/pending). Service methods for
resolving (creates fuel/maintenance record) and dismissing associations.

Frontend: New email-ingestion feature with types, API client, hooks,
PendingAssociationBanner (dashboard), PendingAssociationList, and
ResolveAssociationDialog. Mobile-first responsive with 44px touch
targets and full-screen dialogs on small screens.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-02-13 09:39:03 -06:00
Eric GullicksonandClaude Opus 4.6 8bcac80818 feat: add email ingestion notification handler with logging (refs #159)
- Extract all notification logic from EmailIngestionService into
  dedicated EmailIngestionNotificationHandler class
- Add notification_logs entries for every email sent (success/failure)
- Add in-app user_notifications for all error scenarios (no vehicles,
  no attachments, OCR failure, processing failure)
- Update email templates with enhanced variables: merchantName,
  totalAmount, date, guidance
- Update pending vehicle notification title to 'Vehicle Selection Required'
- Add sample variables for receipt templates in test email flow

Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-02-13 09:27:37 -06:00
Eric GullicksonandClaude Opus 4.6 fce60759cf feat: add vehicle association and record creation (refs #158)
Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-02-13 08:53:08 -06:00
Eric GullicksonandClaude Opus 4.6 d9a40f7d37 feat: add receipt classifier and OCR integration (refs #157)
- New ReceiptClassifier module with keyword-based classification for
  fuel vs maintenance receipts from email text and OCR raw text
- Classifier-first pipeline: classify from email subject/body keywords
  before falling back to OCR-based classification
- Fuel keywords: gas, fuel, gallons, octane, pump, diesel, unleaded,
  shell, chevron, exxon, bp
- Maintenance keywords: oil change, brake, alignment, tire, rotation,
  inspection, labor, parts, service, repair, transmission, coolant
- Confident classification (>= 2 keyword matches) routes to specific
  OCR endpoint; unclassified falls back to both endpoints + rawText
  classification + field-count heuristic

Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-02-13 08:44:03 -06:00
Eric GullicksonandClaude Opus 4.6 e7f3728771 feat: add email ingestion processing service and repository (refs #156)
- EmailIngestionRepository: queue CRUD (insert, update status, get,
  find by email ID), pending vehicle association management, mapRow
  pattern for snake_case -> camelCase conversion
- EmailIngestionService: full processing pipeline with sender validation,
  attachment filtering (PDF/PNG/JPG/JPEG/HEIC, <10MB), dual OCR
  classification (fuel vs maintenance), vehicle association logic
  (single-vehicle auto-associate, multi-vehicle pending), retry handling
  (max 3 attempts), and templated email replies (confirmation, failure,
  pending vehicle)
- Updated controller to delegate async processing to service
- Added receipt_processed/receipt_failed/receipt_pending_vehicle to
  TemplateKey union type

Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-02-13 08:32:10 -06:00
Eric GullicksonandClaude Opus 4.6 2462fff34d feat: add Resend inbound webhook endpoint and client (refs #155)
- ResendInboundClient: webhook signature verification via Svix, email
  fetch/download/parse with mailparser
- POST /api/webhooks/resend/inbound endpoint with rawBody, signature
  verification, idempotency check, queue insertion, async processing
- Config: resend_webhook_secret (optional) in secrets schema
- Route registration in app.ts following Stripe webhook pattern

Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-02-13 08:22:25 -06:00
Eric GullicksonandClaude Opus 4.6 877f844be6 feat: add email ingestion database schema and types (refs #154)
- Create email_ingestion_queue table with UNIQUE email_id constraint
- Create pending_vehicle_associations table with documents FK
- Seed 3 email templates: receipt_processed, receipt_failed, receipt_pending_vehicle
- Add TypeScript types for queue records, associations, and Resend webhook payloads
- Register email-ingestion in migration runner order

Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-02-12 22:01:17 -06:00
Eric GullicksonandClaude Opus 4.6 06ff8101dc feat: add form integration, tier gating, and receipt display (refs #153)
- Add tier-gated "Scan Receipt" button to MaintenanceRecordForm
- Wire useMaintenanceReceiptOcr hook with CameraCapture and ReviewModal
- Auto-populate form fields from accepted OCR results via setValue
- Upload receipt as document and pass receiptDocumentId on record create
- Show receipt thumbnail + "View Receipt" button in edit dialog
- Add receipt indicator chip on records list rows
- Add receiptDocumentId and receiptDocument to frontend types

Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-02-12 21:40:27 -06:00
Eric GullicksonandClaude Opus 4.6 91166b021c feat: add maintenance receipt OCR hook and review modal (refs #152)
Add useMaintenanceReceiptOcr hook mirroring fuel receipt OCR pattern,
MaintenanceReceiptReviewModal with confidence indicators and inline editing,
and maintenance-receipt.types.ts for extraction field types. Includes
category/subtype suggestion via keyword matching from service descriptions.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-02-12 21:31:48 -06:00
Eric GullicksonandClaude Opus 4.6 88d23d2745 feat: add backend migration and API for maintenance receipt linking (refs #151)
Add receipt_document_id FK on maintenance_records, update types/repo/service
to support receipt linking on create and return document metadata on GET.
Add OCR proxy endpoint POST /api/ocr/extract/maintenance-receipt with
tier gating (maintenance.receiptScan) through full chain: routes -> controller
-> service -> client.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-02-12 21:24:24 -06:00
Eric GullicksonandClaude Opus 4.6 90401dc1ba feat: add maintenance receipt extraction pipeline with Gemini + regex (refs #150)
- New MaintenanceReceiptExtractor: Gemini-primary extraction with regex
  cross-validation for dates, amounts, and odometer readings
- New maintenance_receipt_validation.py: cross-validation patterns for
  structured field confidence adjustment
- New POST /extract/maintenance-receipt endpoint reusing
  ReceiptExtractionResponse model
- Per-field confidence scores (0.0-1.0) with Gemini base 0.85,
  boosted/reduced by regex agreement

Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-02-12 21:14:13 -06:00
Eric GullicksonandClaude Opus 4.6 80ee2faed8 fix: Replace circle toggle with MUI Switch pill style (refs #148)
Deploy to Staging / Build Images (pull_request) Successful in 35s
Deploy to Staging / Deploy to Staging (pull_request) Successful in 52s
Deploy to Staging / Verify Staging (pull_request) Successful in 9s
Deploy to Staging / Notify Staging Ready (pull_request) Successful in 7s
Deploy to Staging / Notify Staging Failure (pull_request) Has been skipped
EmailNotificationToggle used a custom button-based toggle that rendered
as a circle. Replaced with MUI Switch component to match the pill-style
toggles used on the SettingsPage throughout the app.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-02-12 20:14:01 -06:00
Eric GullicksonandClaude Opus 4.6 6bb2c575b4 fix: Wire vehicleId into maintenance page to display schedules (refs #148)
Deploy to Staging / Build Images (pull_request) Successful in 3m28s
Deploy to Staging / Deploy to Staging (pull_request) Successful in 52s
Deploy to Staging / Verify Staging (pull_request) Successful in 9s
Deploy to Staging / Notify Staging Ready (pull_request) Successful in 10s
Deploy to Staging / Notify Staging Failure (pull_request) Has been skipped
Maintenance page called useMaintenanceRecords() without a vehicleId,
causing the schedules query (enabled: !!vehicleId) to never execute.
Added vehicle selector to both desktop and mobile pages, auto-selects
first vehicle, and passes selectedVehicleId to the hook. Also fixed
stale query invalidation keys in delete handlers.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-02-12 20:01:42 -06:00
Eric Gullickson 59e7f4053a fix: Data validation for scheduled maintenance
Deploy to Staging / Build Images (pull_request) Successful in 3m24s
Deploy to Staging / Deploy to Staging (pull_request) Successful in 25s
Deploy to Staging / Verify Staging (pull_request) Successful in 8s
Deploy to Staging / Notify Staging Ready (pull_request) Successful in 7s
Deploy to Staging / Notify Staging Failure (pull_request) Has been skipped
2026-02-11 20:47:46 -06:00
Eric Gullickson 33b489d526 fix: Update auto schedule creation
Deploy to Staging / Build Images (pull_request) Successful in 3m29s
Deploy to Staging / Deploy to Staging (pull_request) Successful in 25s
Deploy to Staging / Verify Staging (pull_request) Successful in 8s
Deploy to Staging / Notify Staging Ready (pull_request) Successful in 7s
Deploy to Staging / Notify Staging Failure (pull_request) Has been skipped
2026-02-11 20:29:33 -06:00
Eric Gullickson 55a7bcc874 fix: Manual polling typo
Deploy to Staging / Build Images (pull_request) Successful in 36s
Deploy to Staging / Deploy to Staging (pull_request) Successful in 51s
Deploy to Staging / Verify Staging (pull_request) Successful in 8s
Deploy to Staging / Notify Staging Ready (pull_request) Successful in 7s
Deploy to Staging / Notify Staging Failure (pull_request) Has been skipped
2026-02-11 20:06:03 -06:00
Eric Gullickson a078962d3f fix: Manual scanning
Deploy to Staging / Build Images (pull_request) Successful in 35s
Deploy to Staging / Deploy to Staging (pull_request) Successful in 51s
Deploy to Staging / Verify Staging (pull_request) Successful in 8s
Deploy to Staging / Notify Staging Ready (pull_request) Successful in 7s
Deploy to Staging / Notify Staging Failure (pull_request) Has been skipped
2026-02-11 19:57:32 -06:00
Eric Gullickson b97d226d44 fix: Variables
Deploy to Staging / Build Images (pull_request) Successful in 34s
Deploy to Staging / Deploy to Staging (pull_request) Successful in 51s
Deploy to Staging / Verify Staging (pull_request) Successful in 9s
Deploy to Staging / Notify Staging Ready (pull_request) Successful in 8s
Deploy to Staging / Notify Staging Failure (pull_request) Has been skipped
2026-02-11 19:42:42 -06:00
Eric GullicksonandClaude Opus 4.6 48993eb311 docs: fix receipt tier gating and add feature tier refs to core docs (refs #146)
Deploy to Staging / Build Images (pull_request) Successful in 15m57s
Deploy to Staging / Deploy to Staging (pull_request) Successful in 53s
Deploy to Staging / Verify Staging (pull_request) Successful in 9s
Deploy to Staging / Notify Staging Ready (pull_request) Successful in 7s
Deploy to Staging / Notify Staging Failure (pull_request) Has been skipped
Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-02-11 15:22:38 -06:00
Eric GullicksonandClaude Opus 4.6 11f52258db feat: add 410 error handling, progress messages, touch targets, and tests (refs #145)
- Handle poll errors including 410 Gone in useManualExtraction hook
- Add specific progress stage messages (Preparing/Processing/Mapping/Complete)
- Enforce 44px minimum touch targets on all interactive elements
- Add tests for inline editing, mobile fullscreen, and desktop modal layouts

Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-02-11 15:12:29 -06:00
Eric GullicksonandClaude Opus 4.6 ca33f8ad9d feat: add PDF magic bytes validation, 410 Gone, and manual extraction tests (refs #144)
Add filename .pdf extension fallback and %PDF magic bytes validation to
extractManual controller. Update getJobStatus to return 410 Gone for
expired jobs. Add 16 unit tests covering all acceptance criteria.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-02-11 14:55:06 -06:00
Eric GullicksonandClaude Opus 4.6 209425a908 feat: rewrite ManualExtractor progress to spec-aligned 10/50/95/100 pattern (refs #143)
Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-02-11 14:40:11 -06:00
Eric GullicksonandClaude Opus 4.6 f9a650a4d7 feat: add traceback logging and spec-aligned error message to GeminiEngine (refs #142)
Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-02-11 14:35:06 -06:00
Eric GullicksonandClaude Opus 4.6 4e5da4782f feat: add 5s timeout and warning log for station name search (refs #141)
Add 5000ms timeout to Places Text Search API call in searchStationByName.
Timeout errors log a warning instead of error and return null gracefully.
Add timeout test case to station-matching unit tests.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-02-11 13:03:35 -06:00
Eric GullicksonandClaude Opus 4.6 c79b610145 feat: enforce 44px minimum touch targets for receipt OCR components (refs #140)
Adds minHeight/minWidth: 44 to ReceiptCameraButton, ReceiptOcrReviewModal
action buttons, and UpgradeRequiredDialog buttons and close icon to meet
mobile accessibility requirements.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-02-11 11:33:57 -06:00
Eric GullicksonandClaude Opus 4.6 88c2d7fbcd feat: add receipt proxy tier guard, 422 forwarding, and tests (refs #139)
Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-02-11 11:20:58 -06:00
Eric GullicksonandClaude Opus 4.6 1a6400a6bc feat: add standalone requireTier middleware (refs #138)
Create reusable preHandler middleware for subscription tier gating.
Composable with requireAuth in route preHandler arrays. Returns 403
TIER_REQUIRED with upgrade prompt for insufficient tier, 500 for
unknown feature keys. Includes 9 unit tests covering all acceptance
criteria.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-02-11 11:13:15 -06:00
Eric GullicksonandClaude Opus 4.6 ab0d8463be docs: update CLAUDE.md indexes and README for OCR expansion (refs #137)
Add/update documentation across backend, Python OCR service, and frontend
for receipt scanning, manual extraction, and Gemini integration. Create
new CLAUDE.md files for engines/, fuel-logs/, documents/, and maintenance/
features.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-02-11 11:04:19 -06:00
Eric GullicksonandClaude Opus 4.6 40df5e5b58 feat: add frontend manual extraction flow with review screen (refs #136)
- Create useManualExtraction hook: submit PDF to OCR, poll job status, track progress
- Create useCreateSchedulesFromExtraction hook: batch create maintenance schedules from extraction
- Create MaintenanceScheduleReviewScreen: dialog with checkboxes, inline editing, batch create
- Update DocumentForm: remove "(Coming soon)", trigger extraction after upload, show progress
- Add 12 unit tests for review screen (rendering, selection, empty state, errors)

Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-02-11 10:48:46 -06:00
Eric GullicksonandClaude Opus 4.6 a281cea9c5 feat: add backend OCR manual proxy endpoint (refs #135)
Add POST /api/ocr/extract/manual endpoint that proxies to the Python
OCR service's manual extraction pipeline. Includes Pro tier gating via
document.scanMaintenanceSchedule, PDF-only validation, 200MB file size
limit, and async 202 job response for polling via existing job status
endpoint.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-02-11 10:37:18 -06:00
Eric GullicksonandClaude Opus 4.6 57ed04d955 feat: rewrite ManualExtractor to use Gemini engine (refs #134)
Replace traditional OCR pipeline (table_detector, table_parser,
maintenance_patterns) with GeminiEngine for semantic PDF extraction.
Map Gemini serviceName values to 27 maintenance subtypes via
ServiceMapper fuzzy matching. Add 8 unit tests covering normal
extraction, unusual names, empty response, and error handling.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-02-11 10:24:11 -06:00
Eric GullicksonandClaude Opus 4.6 3705e63fde feat: add Gemini engine module and configuration (refs #133)
Add standalone GeminiEngine class for maintenance schedule extraction
from PDF owners manuals using Vertex AI Gemini 2.5 Flash with structured
JSON output enforcement, 20MB size limit, and lazy initialization.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-02-11 10:00:47 -06:00
Eric GullicksonandClaude Opus 4.6 d8dec64538 feat: add station matching from receipt merchant name (refs #132)
Add Google Places Text Search to match receipt merchant names (e.g.
"Shell", "COSTCO #123") to real gas stations. Backend exposes
POST /api/stations/match endpoint. Frontend calls it after OCR
extraction and pre-fills locationData with matched station's placeId,
name, and address. Users can clear the match in the review modal.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-02-11 09:45:13 -06:00
Eric GullicksonandClaude Opus 4.6 bc91fbad79 feat: add tier gating for receipt scan in FuelLogForm (refs #131)
Free tier users see locked button with upgrade prompt dialog.
Pro+ users can capture receipts normally. Works on mobile and desktop.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-02-11 09:32:08 -06:00
Eric GullicksonandClaude Opus 4.6 399313eb6d feat: update useReceiptOcr to call /ocr/extract/receipt endpoint (refs #131)
Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-02-11 09:30:02 -06:00
Eric GullicksonandClaude Opus 4.6 dfc3924540 feat: add fuelLog.receiptScan tier gating with pro minTier (refs #131)
Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-02-11 09:29:48 -06:00
Eric GullicksonandClaude Opus 4.6 e0e578a627 feat: add receipt extraction proxy endpoint (refs #130)
Add POST /api/ocr/extract/receipt endpoint that proxies to the Python
OCR service's /extract/receipt for receipt-specific field extraction.

- ReceiptExtractionResponse type with receiptType, extractedFields, rawText
- OcrClient.extractReceipt() with optional receipt_type form field
- OcrService.extractReceipt() with 10MB max, image-only validation
- OcrController.extractReceipt() with file upload and error mapping
- Route with auth middleware
- 9 unit tests covering normal, edge, and error scenarios

Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-02-11 09:26:57 -06:00
Eric GullicksonandClaude Opus 4.6 91dc847f56 fix: use correct Auth0 US region domain in WIF token script (refs #127)
Deploy to Staging / Build Images (pull_request) Successful in 34s
Deploy to Staging / Deploy to Staging (pull_request) Successful in 51s
Deploy to Staging / Verify Staging (pull_request) Successful in 8s
Deploy to Staging / Notify Staging Ready (pull_request) Successful in 7s
Deploy to Staging / Notify Staging Failure (pull_request) Has been skipped
Domain was motovaultpro.auth0.com (404) instead of
motovaultpro.us.auth0.com.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-02-10 18:44:30 -06:00
Eric GullicksonandClaude Opus 4.6 7bba28154d fix: capture Auth0 error response in WIF token script (refs #127)
Deploy to Staging / Build Images (pull_request) Successful in 35s
Deploy to Staging / Deploy to Staging (pull_request) Successful in 51s
Deploy to Staging / Verify Staging (pull_request) Successful in 9s
Deploy to Staging / Notify Staging Ready (pull_request) Successful in 7s
Deploy to Staging / Notify Staging Failure (pull_request) Has been skipped
The set -e + curl --fail-with-body inside $() caused the script to exit
with code 22 and empty stderr, hiding the actual Auth0 error. Switch to
writing the body to a temp file and checking HTTP status manually so the
error response is visible in logs.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-02-10 18:41:34 -06:00
Eric GullicksonandClaude Opus 4.6 a416f76c21 fix: copy WIF config to deploy path in CI/CD workflows (refs #127)
Deploy to Staging / Build Images (pull_request) Successful in 35s
Deploy to Staging / Deploy to Staging (pull_request) Successful in 22s
Deploy to Staging / Verify Staging (pull_request) Successful in 8s
Deploy to Staging / Notify Staging Ready (pull_request) Successful in 8s
Deploy to Staging / Notify Staging Failure (pull_request) Has been skipped
The google-wif-config.json was never synced to the deploy path, so the
Docker bind mount created a directory artifact instead of a file. Vision
client initialization failed on every request, silently falling back to
PaddleOCR.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-02-10 18:34:41 -06:00
Eric GullicksonandClaude Opus 4.6 e6dd7492a1 test: add monthly limit, counter, and cloud-primary engine tests (refs #127)
Deploy to Staging / Build Images (pull_request) Successful in 8m46s
Deploy to Staging / Deploy to Staging (pull_request) Successful in 22s
Deploy to Staging / Verify Staging (pull_request) Successful in 8s
Deploy to Staging / Notify Staging Ready (pull_request) Successful in 8s
Deploy to Staging / Notify Staging Failure (pull_request) Has been skipped
- Update existing hybrid engine tests for new Redis counter behavior
- Add cloud-primary path tests (under/at limit, fallback, errors)
- Add Redis counter increment and TTL verification tests
- Add Redis failure graceful handling test
- Update cloud engine error message assertion for WIF config

Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-02-09 20:56:51 -06:00
Eric GullicksonandClaude Opus 4.6 f4a28d009f feat: update all Docker Compose files for Vision primary with WIF auth (refs #127)
- Switch OCR engine config to google_vision primary / paddleocr fallback
- Mount Auth0 OCR secrets and WIF config into all OCR containers
- Add WIF config to repo (not a secret, contains no credentials)
- Remove obsolete google-vision-key.json.example

Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-02-09 20:53:44 -06:00
Eric GullicksonandClaude Opus 4.6 5e4848c4e2 feat: add Auth0 OCR secrets to injection script and CI/CD workflows (refs #127)
- Add AUTH0_OCR_CLIENT_ID and AUTH0_OCR_CLIENT_SECRET to inject-secrets.sh
- Add new secrets to staging and production workflow env blocks
- Create .example files for new secret documentation

Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-02-09 20:52:29 -06:00
Eric GullicksonandClaude Opus 4.6 9209739e75 feat: add Auth0 WIF token script and update Dockerfile (refs #127)
- Create fetch-auth0-token.sh for Auth0 M2M -> GCP WIF token exchange
- Add jq to Dockerfile system dependencies
- Ensure script is executable in container image

Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-02-09 20:51:30 -06:00
Eric GullicksonandClaude Opus 4.6 4abd7d8d5b feat: add Vision monthly cap, WIF auth, and cloud-primary hybrid engine (refs #127)
- Add VISION_MONTHLY_LIMIT config setting (default 1000)
- Update CloudEngine to use WIF credential config via ADC
- Rewrite HybridEngine to support cloud-primary with Redis counter
- Pass monthly_limit through engine factory

Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-02-09 20:50:02 -06:00
Eric GullicksonandClaude Opus 4.6 4412700e12 fix: use valid Redis log levels and add log level comments to all containers
Deploy to Staging / Build Images (push) Successful in 33s
Deploy to Staging / Deploy to Staging (push) Successful in 22s
Deploy to Staging / Verify Staging (push) Successful in 8s
Deploy to Staging / Notify Staging Ready (push) Successful in 8s
Deploy to Staging / Notify Staging Failure (push) Has been skipped
Redis only supports debug|verbose|notice|warning -- not info or error.
The command was using ${LOG_LEVEL:-info} which resolved to INFO in
production (from workflow env), causing Redis to crash loop. Hardcode
the correct Redis-native levels (debug for dev, warning for prod) and
add available log level comments above every container's log setting.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-02-08 21:27:33 -06:00
Eric Gullickson c6b99ab29a fix: Postgres Fixes for Prod
Deploy to Staging / Build Images (push) Successful in 1m34s
Deploy to Staging / Deploy to Staging (push) Successful in 23s
Deploy to Staging / Verify Staging (push) Successful in 2m36s
Deploy to Staging / Notify Staging Ready (push) Successful in 8s
Deploy to Staging / Notify Staging Failure (push) Has been skipped
2026-02-08 20:57:49 -06:00
Eric GullicksonandClaude Opus 4.6 e9020dbb2f feat: improve VIN confidence reporting and editable review dropdowns (refs #125)
Deploy to Staging / Build Images (pull_request) Successful in 4m37s
Deploy to Staging / Deploy to Staging (pull_request) Successful in 51s
Deploy to Staging / Verify Staging (pull_request) Successful in 9s
Deploy to Staging / Notify Staging Ready (pull_request) Successful in 8s
Deploy to Staging / Notify Staging Failure (pull_request) Has been skipped
VIN OCR confidence now reflects recognition accuracy only (not match quality).
Review modal replaces read-only fields with editable cascade dropdowns
pre-populated from NHTSA decode, with NHTSA reference hints for unmatched fields.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-02-08 19:24:27 -06:00
Eric Gullickson e7471d5c27 fix: Python Image Pinning
Deploy to Staging / Build Images (push) Successful in 8m28s
Deploy to Staging / Deploy to Staging (push) Successful in 22s
Deploy to Staging / Verify Staging (push) Successful in 8s
Deploy to Staging / Notify Staging Ready (push) Successful in 8s
Deploy to Staging / Notify Staging Failure (push) Has been skipped
2026-02-08 19:11:13 -06:00
Eric Gullickson 2c3e432fcf fix: Build errors with python3.13
Deploy to Staging / Build Images (push) Successful in 8m50s
Deploy to Staging / Deploy to Staging (push) Successful in 23s
Deploy to Staging / Verify Staging (push) Successful in 8s
Deploy to Staging / Notify Staging Ready (push) Successful in 7s
Deploy to Staging / Notify Staging Failure (push) Has been skipped
2026-02-08 18:54:49 -06:00
Eric GullicksonandClaude Opus 4.6 1ff1931864 fix: re-request camera stream on retake when tracks are inactive (refs #123)
Deploy to Staging / Build Images (pull_request) Successful in 3m20s
Deploy to Staging / Deploy to Staging (pull_request) Successful in 51s
Deploy to Staging / Verify Staging (pull_request) Successful in 9s
Deploy to Staging / Notify Staging Ready (pull_request) Successful in 7s
Deploy to Staging / Notify Staging Failure (pull_request) Has been skipped
The retake button failed because the stream tracks could become inactive
during the crop phase, but handleRetake never re-acquired the camera.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-02-07 20:26:37 -06:00
Eric GullicksonandClaude Opus 4.6 efc55cd3db feat: improve VIN camera crop overlay-to-crop alignment and touch targets (refs #123)
Deploy to Staging / Build Images (pull_request) Successful in 3m20s
Deploy to Staging / Deploy to Staging (pull_request) Successful in 51s
Deploy to Staging / Verify Staging (pull_request) Successful in 9s
Deploy to Staging / Notify Staging Ready (pull_request) Successful in 7s
Deploy to Staging / Notify Staging Failure (pull_request) Has been skipped
Bridge guidance overlay position to crop tool initial coordinates so the
crop box appears centered matching the viewfinder guide. Increase handle
touch targets to 44px (32px on compact viewports) for mobile usability.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-02-07 20:05:40 -06:00
Eric Gullickson 9a2b12c5dc fix: No matches
Deploy to Staging / Build Images (pull_request) Successful in 37s
Deploy to Staging / Deploy to Staging (pull_request) Successful in 22s
Deploy to Staging / Verify Staging (pull_request) Successful in 8s
Deploy to Staging / Notify Staging Ready (pull_request) Successful in 8s
Deploy to Staging / Notify Staging Failure (pull_request) Has been skipped
2026-02-07 16:35:28 -06:00
Eric Gullickson 3adbb10ff6 fix: OCR Timout still
Deploy to Staging / Build Images (pull_request) Successful in 3m23s
Deploy to Staging / Deploy to Staging (pull_request) Successful in 51s
Deploy to Staging / Verify Staging (pull_request) Successful in 8s
Deploy to Staging / Notify Staging Ready (pull_request) Successful in 7s
Deploy to Staging / Notify Staging Failure (pull_request) Has been skipped
2026-02-07 16:26:10 -06:00
Eric Gullickson fcffb0bb43 fix: PaddleOCR timeout
Deploy to Staging / Build Images (pull_request) Successful in 3m20s
Deploy to Staging / Deploy to Staging (pull_request) Successful in 22s
Deploy to Staging / Verify Staging (pull_request) Successful in 9s
Deploy to Staging / Notify Staging Ready (pull_request) Successful in 8s
Deploy to Staging / Notify Staging Failure (pull_request) Has been skipped
2026-02-07 16:18:14 -06:00
Eric Gullickson 9d2d4e57b7 fix: PaddleOCR error
Deploy to Staging / Build Images (pull_request) Successful in 36s
Deploy to Staging / Deploy to Staging (pull_request) Successful in 52s
Deploy to Staging / Verify Staging (pull_request) Successful in 9s
Deploy to Staging / Notify Staging Ready (pull_request) Successful in 7s
Deploy to Staging / Notify Staging Failure (pull_request) Has been skipped
2026-02-07 16:12:07 -06:00
Eric Gullickson 0499c902a8 fix: Crop box broken
Deploy to Staging / Build Images (pull_request) Successful in 3m22s
Deploy to Staging / Deploy to Staging (pull_request) Successful in 22s
Deploy to Staging / Verify Staging (pull_request) Successful in 8s
Deploy to Staging / Notify Staging Ready (pull_request) Successful in 7s
Deploy to Staging / Notify Staging Failure (pull_request) Has been skipped
2026-02-07 16:00:23 -06:00
Eric Gullickson dab4a3bdf3 fix: PaddleOCR error
Deploy to Staging / Build Images (pull_request) Successful in 3m46s
Deploy to Staging / Deploy to Staging (pull_request) Successful in 51s
Deploy to Staging / Verify Staging (pull_request) Successful in 8s
Deploy to Staging / Notify Staging Ready (pull_request) Successful in 7s
Deploy to Staging / Notify Staging Failure (pull_request) Has been skipped
2026-02-07 15:51:04 -06:00
Eric Gullickson 639ca117f1 fix: Update PaddleOCR API
Deploy to Staging / Build Images (pull_request) Successful in 5m6s
Deploy to Staging / Deploy to Staging (pull_request) Successful in 51s
Deploy to Staging / Verify Staging (pull_request) Successful in 8s
Deploy to Staging / Notify Staging Ready (pull_request) Successful in 8s
Deploy to Staging / Notify Staging Failure (pull_request) Has been skipped
2026-02-07 14:44:06 -06:00
Eric Gullickson b9fe222f12 fix: Build errors and tesseract removal
Deploy to Staging / Build Images (pull_request) Failing after 4m14s
Deploy to Staging / Deploy to Staging (pull_request) Has been skipped
Deploy to Staging / Verify Staging (pull_request) Has been skipped
Deploy to Staging / Notify Staging Ready (pull_request) Has been skipped
Deploy to Staging / Notify Staging Failure (pull_request) Successful in 8s
2026-02-07 12:12:04 -06:00
Eric Gullickson cf114fad3c fix: build errors for OpenCV
Deploy to Staging / Build Images (pull_request) Failing after 3m16s
Deploy to Staging / Deploy to Staging (pull_request) Has been skipped
Deploy to Staging / Verify Staging (pull_request) Has been skipped
Deploy to Staging / Notify Staging Ready (pull_request) Has been skipped
Deploy to Staging / Notify Staging Failure (pull_request) Successful in 8s
2026-02-07 11:58:00 -06:00
Eric GullicksonandClaude Opus 4.6 47c5676498 chore: update OCR tests and documentation (refs #121)
Deploy to Staging / Build Images (pull_request) Failing after 7m4s
Deploy to Staging / Deploy to Staging (pull_request) Has been skipped
Deploy to Staging / Verify Staging (pull_request) Has been skipped
Deploy to Staging / Notify Staging Ready (pull_request) Has been skipped
Deploy to Staging / Notify Staging Failure (pull_request) Successful in 7s
Add engine abstraction tests and update docs to reflect PaddleOCR primary
architecture with optional Google Vision cloud fallback.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-02-07 11:42:51 -06:00
Eric Gullickson 1e96baca6f fix: workflow contract 2026-02-07 11:32:36 -06:00
Eric GullicksonandClaude Opus 4.6 3c1a090ae3 fix: resolve crop tool regression with stale ref and aspect ratio minSize (refs #120)
Three bugs fixed in the draw-first crop tool introduced by PR #114:

1. Stale cropAreaRef: replaced useEffect-based ref sync with direct
   synchronous updates in handleMove and handleDrawStart. The useEffect
   ran after browser paint, so handleDragEnd read stale values (often
   {width:0, height:0}), preventing cropDrawn from being set.

2. Aspect ratio minSize: when aspectRatio=6 (VIN mode), height=width/6
   required width>=60% to pass the height>=10% check. Now only checks
   width>=minSize when aspect ratio constrains height.

3. Bounds clamping: aspect-ratio-forced height could push crop area
   past 100% of container. Now clamps y position to keep within bounds.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-02-07 11:29:16 -06:00
Eric GullicksonandClaude Opus 4.6 9b6417379b chore: update Docker and compose files for PaddleOCR engine (refs #119)
- Replace libtesseract-dev with libgomp1 (OpenMP for PaddlePaddle)
- Pre-download PP-OCRv4 models during Docker build
- Add OCR engine env vars to all compose files (base, staging, prod)
- Add optional Google Vision secret mount (commented, enable on demand)
- Create google-vision-key.json.example placeholder

Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-02-07 11:17:44 -06:00
Eric GullicksonandClaude Opus 4.6 4ef942cb9d feat: add optional Google Vision cloud fallback engine (refs #118)
CloudEngine wraps Google Vision TEXT_DETECTION with lazy init.
HybridEngine runs primary engine, falls back to cloud when confidence
is below threshold. Disabled by default (OCR_FALLBACK_ENGINE=none).

Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-02-07 11:12:08 -06:00
Eric GullicksonandClaude Opus 4.6 013fb0c67a feat: migrate VIN/receipt extractors and OCR service to engine abstraction (refs #117)
Replace direct pytesseract calls with OcrEngine interface in vin_extractor.py,
receipt_extractor.py, and ocr_service.py. PSM mode fallbacks replaced with
engine-agnostic single-line/single-word configs. Dead _process_ocr_data removed.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-02-07 10:56:27 -06:00
Eric GullicksonandClaude Opus 4.6 ebc633fb36 feat: add OCR engine abstraction layer (refs #116)
Introduce pluggable OcrEngine ABC with PaddleOCR PP-OCRv4 as primary
engine and Tesseract wrapper for backward compatibility. Engine factory
reads OCR_PRIMARY_ENGINE config to instantiate the correct engine.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-02-07 10:47:40 -06:00
Eric Gullickson 75ce316aa5 chore: Change crop to remove locked aspect ratio
Deploy to Staging / Build Images (pull_request) Successful in 3m21s
Deploy to Staging / Deploy to Staging (pull_request) Successful in 22s
Deploy to Staging / Verify Staging (pull_request) Successful in 8s
Deploy to Staging / Notify Staging Ready (pull_request) Successful in 7s
Deploy to Staging / Notify Staging Failure (pull_request) Has been skipped
2026-02-06 22:15:39 -06:00
Eric GullicksonandClaude Opus 4.6 e4336ce9da fix: extract VIN from noisy OCR via sliding window + char deletion (refs #113)
Deploy to Staging / Build Images (pull_request) Successful in 37s
Deploy to Staging / Deploy to Staging (pull_request) Successful in 51s
Deploy to Staging / Verify Staging (pull_request) Successful in 8s
Deploy to Staging / Notify Staging Ready (pull_request) Successful in 7s
Deploy to Staging / Notify Staging Failure (pull_request) Has been skipped
When OCR reads extra characters (e.g. sticker border as 'C', spurious
'Z' insertion), the raw text exceeds 17 chars and the old first-17
trim produced wrong VINs. New strategy tries all 17-char sliding
windows and single/double character deletions, validating each via
check digit. For 'CWVGGNPE2Z4NP069500', this finds the correct VIN
'WVGGNPE24NP069500' (valid check digit) instead of 'CWVGGNPE2Z4NP0695'
(invalid).

Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-02-06 22:00:07 -06:00
Eric GullicksonandClaude Opus 4.6 432b3bda36 fix: remove char whitelist incompatible with Tesseract LSTM (refs #113)
Deploy to Staging / Build Images (pull_request) Successful in 36s
Deploy to Staging / Deploy to Staging (pull_request) Successful in 51s
Deploy to Staging / Verify Staging (pull_request) Successful in 8s
Deploy to Staging / Notify Staging Ready (pull_request) Successful in 8s
Deploy to Staging / Notify Staging Failure (pull_request) Has been skipped
tessedit_char_whitelist does not work with OEM 1 (LSTM engine) and
causes empty/erratic output. This was the root cause of Tesseract
returning empty text despite clear, well-preprocessed images.
Character filtering is already handled post-OCR by the VIN validator's
correct_ocr_errors() method (I->1, O->0, Q->0, etc).

Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-02-06 21:52:08 -06:00
Eric GullicksonandClaude Opus 4.6 ae5221c759 fix: invert min-channel so Tesseract gets dark-on-light text (refs #113)
Deploy to Staging / Build Images (pull_request) Successful in 35s
Deploy to Staging / Deploy to Staging (pull_request) Successful in 51s
Deploy to Staging / Verify Staging (pull_request) Successful in 8s
Deploy to Staging / Notify Staging Ready (pull_request) Successful in 7s
Deploy to Staging / Notify Staging Failure (pull_request) Has been skipped
The min-channel correctly extracts contrast (white text=255 vs green
sticker bg=130), but Tesseract expects dark text on light background.
Without inversion, the grayscale-only path returned empty text for
every PSM mode because Tesseract couldn't see bright-on-dark text.
Invert via bitwise_not: text becomes 0 (black), sticker bg becomes
125 (gray). Fixes all three OCR paths (adaptive, grayscale, Otsu).

Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-02-06 21:39:48 -06:00
Eric GullicksonandClaude Opus 4.6 63c027a454 fix: always use min-channel and add grayscale-only OCR path (refs #113)
Deploy to Staging / Build Images (pull_request) Successful in 35s
Deploy to Staging / Deploy to Staging (pull_request) Successful in 50s
Deploy to Staging / Verify Staging (pull_request) Successful in 8s
Deploy to Staging / Notify Staging Ready (pull_request) Successful in 7s
Deploy to Staging / Notify Staging Failure (pull_request) Has been skipped
Two fixes:
1. Always use min-channel for color images instead of gated comparison
   that was falling back to standard grayscale (which has only 23%
   contrast for white-on-green VIN stickers).
2. Add grayscale-only OCR path (CLAHE + denoise, no thresholding)
   between adaptive and Otsu attempts. Tesseract's LSTM engine is
   designed to handle grayscale input directly and often outperforms
   binarized input where thresholding creates artifacts.

Pipeline order: adaptive threshold → grayscale-only → Otsu threshold

Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-02-06 21:32:52 -06:00
Eric GullicksonandClaude Opus 4.6 a07ec324fe fix: use min-channel grayscale and morphological cleanup for VIN OCR (refs #113)
Deploy to Staging / Build Images (pull_request) Successful in 35s
Deploy to Staging / Deploy to Staging (pull_request) Successful in 51s
Deploy to Staging / Verify Staging (pull_request) Successful in 8s
Deploy to Staging / Notify Staging Ready (pull_request) Successful in 8s
Deploy to Staging / Notify Staging Failure (pull_request) Has been skipped
Replace std-based channel selection (which incorrectly picked green for
green-tinted VIN stickers) with per-pixel min(B,G,R). White text stays
255 in all channels while colored backgrounds drop to their weakest
channel value, giving 2x contrast improvement. Add morphological
opening after thresholding to remove noise speckles from car body
surface that were confusing Tesseract's page segmentation.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-02-06 21:23:43 -06:00
Eric GullicksonandClaude Opus 4.6 0de34983bb fix: use best-contrast color channel for VIN preprocessing (refs #113)
Deploy to Staging / Build Images (pull_request) Successful in 36s
Deploy to Staging / Deploy to Staging (pull_request) Successful in 1m7s
Deploy to Staging / Verify Staging (pull_request) Successful in 10s
Deploy to Staging / Notify Staging Ready (pull_request) Successful in 9s
Deploy to Staging / Notify Staging Failure (pull_request) Has been skipped
White text on green VIN stickers has only ~12% contrast in standard
grayscale conversion because the green channel dominates luminance.
The new _best_contrast_channel method evaluates each RGB channel's
standard deviation and selects the one with highest contrast, giving
~2x improvement for green-tinted VIN stickers. Falls back to standard
grayscale for neutral-colored images.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
2026-02-06 21:14:56 -06:00
Eric Gullickson ce2a8d88f9 fix: Mobile image crop fix
Deploy to Staging / Build Images (pull_request) Successful in 3m20s
Deploy to Staging / Deploy to Staging (pull_request) Successful in 51s
Deploy to Staging / Verify Staging (pull_request) Successful in 9s
Deploy to Staging / Notify Staging Ready (pull_request) Successful in 7s
Deploy to Staging / Notify Staging Failure (pull_request) Has been skipped
2026-02-06 20:55:08 -06:00