feat: Backend OCR receipt proxy endpoint (#129) #130

Closed
opened 2026-02-11 03:04:35 +00:00 by egullickson · 1 comment
Owner

Relates to #129

Milestone 1: Backend OCR Receipt Proxy Endpoint

Add backend proxy endpoint for receipt-specific OCR extraction that calls the existing Python /extract/receipt endpoint.

Files

  • backend/src/features/ocr/domain/ocr.types.ts
  • backend/src/features/ocr/external/ocr-client.ts
  • backend/src/features/ocr/domain/ocr.service.ts
  • backend/src/features/ocr/api/ocr.controller.ts
  • backend/src/features/ocr/api/ocr.routes.ts

Requirements

  • Add ReceiptExtractionResponse type with receiptType, extractedFields, rawText, processingTimeMs
  • Add OcrClient.extractReceipt() method that POSTs to Python /extract/receipt with optional receipt_type=fuel form field
  • Add ocrService.extractReceipt() method with file validation (10MB max, image types only)
  • Add OcrController.extractReceipt() handler with file upload, validation, error mapping
  • Add POST /api/ocr/extract/receipt route with auth middleware

Acceptance Criteria

  • POST /api/ocr/extract/receipt with valid image returns ReceiptExtractionResponse with extractedFields
  • POST with no file returns 400
  • POST with unsupported type returns 415
  • POST with file > 10MB returns 413
  • Response includes merchantName, transactionDate, totalAmount, fuelQuantity, pricePerUnit, fuelGrade fields with confidence scores

Tests

  • Test files: backend/src/features/ocr/tests/unit/ocr-receipt.test.ts
  • Test type: unit (mock OcrClient HTTP calls)
  • Scenarios:
    • Normal: Valid image returns receipt extraction response
    • Edge: Missing optional fields (some fields not detected)
    • Error: No file, unsupported type, oversized file
Relates to #129 ## Milestone 1: Backend OCR Receipt Proxy Endpoint Add backend proxy endpoint for receipt-specific OCR extraction that calls the existing Python `/extract/receipt` endpoint. ### Files - `backend/src/features/ocr/domain/ocr.types.ts` - `backend/src/features/ocr/external/ocr-client.ts` - `backend/src/features/ocr/domain/ocr.service.ts` - `backend/src/features/ocr/api/ocr.controller.ts` - `backend/src/features/ocr/api/ocr.routes.ts` ### Requirements - Add `ReceiptExtractionResponse` type with `receiptType`, `extractedFields`, `rawText`, `processingTimeMs` - Add `OcrClient.extractReceipt()` method that POSTs to Python `/extract/receipt` with optional `receipt_type=fuel` form field - Add `ocrService.extractReceipt()` method with file validation (10MB max, image types only) - Add `OcrController.extractReceipt()` handler with file upload, validation, error mapping - Add `POST /api/ocr/extract/receipt` route with auth middleware ### Acceptance Criteria - [ ] POST /api/ocr/extract/receipt with valid image returns ReceiptExtractionResponse with extractedFields - [ ] POST with no file returns 400 - [ ] POST with unsupported type returns 415 - [ ] POST with file > 10MB returns 413 - [ ] Response includes merchantName, transactionDate, totalAmount, fuelQuantity, pricePerUnit, fuelGrade fields with confidence scores ### Tests - **Test files**: `backend/src/features/ocr/tests/unit/ocr-receipt.test.ts` - **Test type**: unit (mock OcrClient HTTP calls) - **Scenarios**: - Normal: Valid image returns receipt extraction response - Edge: Missing optional fields (some fields not detected) - Error: No file, unsupported type, oversized file
egullickson added the
status
backlog
type
feature
labels 2026-02-11 03:12:37 +00:00
egullickson added
status
in-progress
and removed
status
backlog
labels 2026-02-11 15:21:15 +00:00
Author
Owner

Milestone: Backend OCR Receipt Proxy Endpoint

Phase: Execution | Agent: Feature Agent | Status: PASS

Changes Made

Types (ocr.types.ts):

  • Added ReceiptExtractionResponse with receiptType, extractedFields, rawText, processingTimeMs, error
  • Added ReceiptExtractRequest with fileBuffer, contentType, optional receiptType

Client (ocr-client.ts):

  • Added extractReceipt() method that POSTs to Python /extract/receipt
  • Supports optional receipt_type form field for specialized fuel extraction

Service (ocr.service.ts):

  • Added extractReceipt() with file validation: 10MB max, image types only (JPEG, PNG, HEIC, HEIF)
  • PDFs explicitly rejected (415) since Python receipt extractor only supports images
  • Added SUPPORTED_IMAGE_TYPES constant separate from general SUPPORTED_TYPES

Controller (ocr.controller.ts):

  • Added extractReceipt() handler with multipart file upload, content type validation, error mapping
  • Reads optional receipt_type form field from multipart data

Routes (ocr.routes.ts):

  • Added POST /api/ocr/extract/receipt with auth middleware

Barrel (index.ts):

  • Exported ReceiptExtractionResponse type

Tests

9 unit tests in ocr/tests/unit/ocr-receipt.test.ts:

  • Valid image returns receipt extraction response with all fields
  • receipt_type hint passed through to client
  • PNG and HEIC support verified
  • Partial fields (some not detected) handled correctly
  • PDF rejected with 415
  • text/plain rejected with 415
  • 11MB file rejected with 413
  • OCR service errors propagated

Verification

  • All 9 unit tests pass
  • TypeScript type-check clean
  • Lint clean (no new warnings/errors)
  • Commit: e0e578a

Verdict: PASS | Next: Sub-issue complete, ready for parent PR

## Milestone: Backend OCR Receipt Proxy Endpoint **Phase**: Execution | **Agent**: Feature Agent | **Status**: PASS ### Changes Made **Types** (`ocr.types.ts`): - Added `ReceiptExtractionResponse` with `receiptType`, `extractedFields`, `rawText`, `processingTimeMs`, `error` - Added `ReceiptExtractRequest` with `fileBuffer`, `contentType`, optional `receiptType` **Client** (`ocr-client.ts`): - Added `extractReceipt()` method that POSTs to Python `/extract/receipt` - Supports optional `receipt_type` form field for specialized fuel extraction **Service** (`ocr.service.ts`): - Added `extractReceipt()` with file validation: 10MB max, image types only (JPEG, PNG, HEIC, HEIF) - PDFs explicitly rejected (415) since Python receipt extractor only supports images - Added `SUPPORTED_IMAGE_TYPES` constant separate from general `SUPPORTED_TYPES` **Controller** (`ocr.controller.ts`): - Added `extractReceipt()` handler with multipart file upload, content type validation, error mapping - Reads optional `receipt_type` form field from multipart data **Routes** (`ocr.routes.ts`): - Added `POST /api/ocr/extract/receipt` with auth middleware **Barrel** (`index.ts`): - Exported `ReceiptExtractionResponse` type ### Tests 9 unit tests in `ocr/tests/unit/ocr-receipt.test.ts`: - Valid image returns receipt extraction response with all fields - receipt_type hint passed through to client - PNG and HEIC support verified - Partial fields (some not detected) handled correctly - PDF rejected with 415 - text/plain rejected with 415 - 11MB file rejected with 413 - OCR service errors propagated ### Verification - All 9 unit tests pass - TypeScript type-check clean - Lint clean (no new warnings/errors) - Commit: `e0e578a` *Verdict*: PASS | *Next*: Sub-issue complete, ready for parent PR
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: egullickson/motovaultpro#130