ocr.routes.ts: Added requireTier('fuelLog.receiptScan') to POST /api/ocr/extract/receipt route. Free-tier users now receive 403 TIER_REQUIRED before the handler executes.
ocr-client.ts: Updated extractReceipt() error handling to attach statusCode from the Python OCR service HTTP response to thrown errors, enabling controller-level error code forwarding.
ocr.controller.ts: Added 422 error handling in extractReceipt catch block. Python 422 "Failed to extract" errors are now forwarded as 422 to the frontend (matching the pattern from extract()).
ocr-receipt.test.ts: Added 2 new tests:
Python 422 forwarded with statusCode for controller forwarding
Route tier guard configuration verification
Test Results
11/11 tests pass in ocr-receipt.test.ts
Type-check: PASS
Lint: PASS (no new warnings)
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
POST by free-tier user returns 403 TIER_REQUIRED
Response includes merchantName, transactionDate, totalAmount, fuelQuantity, pricePerUnit, fuelGrade fields with confidence scores
Python 422 "Failed to extract" forwarded as 422 to frontend
Verdict: PASS | Next: Complete
## Milestone: Backend OCR Receipt Proxy Endpoint
**Phase**: Execution | **Agent**: Developer | **Status**: PASS
### Changes
1. **`ocr.routes.ts`**: Added `requireTier('fuelLog.receiptScan')` to `POST /api/ocr/extract/receipt` route. Free-tier users now receive 403 TIER_REQUIRED before the handler executes.
2. **`ocr-client.ts`**: Updated `extractReceipt()` error handling to attach `statusCode` from the Python OCR service HTTP response to thrown errors, enabling controller-level error code forwarding.
3. **`ocr.controller.ts`**: Added 422 error handling in `extractReceipt` catch block. Python 422 "Failed to extract" errors are now forwarded as 422 to the frontend (matching the pattern from `extract()`).
4. **`ocr-receipt.test.ts`**: Added 2 new tests:
- Python 422 forwarded with statusCode for controller forwarding
- Route tier guard configuration verification
### Test Results
- 11/11 tests pass in `ocr-receipt.test.ts`
- Type-check: PASS
- Lint: PASS (no new warnings)
### Acceptance Criteria
- [x] POST /api/ocr/extract/receipt with valid image returns ReceiptExtractionResponse with extractedFields
- [x] POST with no file returns 400
- [x] POST with unsupported type returns 415
- [x] POST with file > 10MB returns 413
- [x] POST by free-tier user returns 403 TIER_REQUIRED
- [x] Response includes merchantName, transactionDate, totalAmount, fuelQuantity, pricePerUnit, fuelGrade fields with confidence scores
- [x] Python 422 "Failed to extract" forwarded as 422 to frontend
*Verdict*: PASS | *Next*: Complete
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Relates to #129
Milestone 1: Backend OCR Receipt Proxy Endpoint
Files
backend/src/features/ocr/domain/ocr.types.tsbackend/src/features/ocr/external/ocr-client.tsbackend/src/features/ocr/domain/ocr.service.tsbackend/src/features/ocr/api/ocr.controller.tsbackend/src/features/ocr/api/ocr.routes.tsRequirements
ReceiptExtractionResponsetype withreceiptType,extractedFields,rawText,processingTimeMsOcrClient.extractReceipt()method that POSTs to Python/extract/receiptwith optionalreceipt_type=fuelform fieldocrService.extractReceipt()method with file validation (10MB max, image types only)OcrController.extractReceipt()handler with file upload, validation, error mappingOcrController.extractReceipt()translates Python error codes: 413->413, 415->415, 422->422, else 500 (matches pattern fromOcrController.extract())POST /api/ocr/extract/receiptroute withpreHandler: [requireAuth, requireTier('fuelLog.receiptScan')]Acceptance Criteria
Tests
backend/src/features/ocr/tests/unit/ocr-receipt.test.ts(NEW)Milestone: Backend OCR Receipt Proxy Endpoint
Phase: Execution | Agent: Developer | Status: PASS
Changes
ocr.routes.ts: AddedrequireTier('fuelLog.receiptScan')toPOST /api/ocr/extract/receiptroute. Free-tier users now receive 403 TIER_REQUIRED before the handler executes.ocr-client.ts: UpdatedextractReceipt()error handling to attachstatusCodefrom the Python OCR service HTTP response to thrown errors, enabling controller-level error code forwarding.ocr.controller.ts: Added 422 error handling inextractReceiptcatch block. Python 422 "Failed to extract" errors are now forwarded as 422 to the frontend (matching the pattern fromextract()).ocr-receipt.test.ts: Added 2 new tests:Test Results
ocr-receipt.test.tsAcceptance Criteria
Verdict: PASS | Next: Complete