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 <noreply@anthropic.com>
This commit is contained in:
@@ -12,7 +12,7 @@
|
||||
| `fuel-logs/` | Fuel consumption tracking | Fuel log CRUD, statistics |
|
||||
| `maintenance/` | Maintenance record management | Service records, reminders |
|
||||
| `notifications/` | Email and push notifications | Alert system, email templates |
|
||||
| `ocr/` | OCR proxy to mvp-ocr service | Image text extraction, async jobs |
|
||||
| `ocr/` | OCR proxy to mvp-ocr service (VIN, receipt, manual extraction) | Image text extraction, receipt scanning, manual PDF extraction, async jobs |
|
||||
| `onboarding/` | User onboarding flow | First-time user setup |
|
||||
| `ownership-costs/` | Ownership cost tracking and reports | Cost aggregation, expense analysis |
|
||||
| `platform/` | Vehicle data and VIN decoding | Make/model lookup, VIN validation |
|
||||
|
||||
@@ -1,16 +1,47 @@
|
||||
# ocr/
|
||||
|
||||
Backend proxy for the Python OCR microservice. Handles authentication, tier gating, file validation, and request forwarding for VIN extraction, fuel receipt scanning, and maintenance manual extraction.
|
||||
|
||||
## Files
|
||||
|
||||
| File | What | When to read |
|
||||
| ---- | ---- | ------------ |
|
||||
| `README.md` | Feature documentation | Understanding OCR proxy |
|
||||
| `README.md` | Feature documentation with architecture diagrams | Understanding OCR proxy, data flows |
|
||||
| `index.ts` | Feature barrel export | Importing OCR services |
|
||||
|
||||
## Subdirectories
|
||||
|
||||
| Directory | What | When to read |
|
||||
| --------- | ---- | ------------ |
|
||||
| `api/` | HTTP endpoints and routes | API changes |
|
||||
| `domain/` | Business logic, types | Core OCR proxy logic |
|
||||
| `external/` | External OCR service client | OCR service integration |
|
||||
| `api/` | HTTP endpoints, routes, request validation | API changes, adding endpoints |
|
||||
| `domain/` | Business logic, TypeScript types | Core OCR proxy logic, type definitions |
|
||||
| `external/` | HTTP client to Python OCR service | OCR service integration, error handling |
|
||||
| `tests/` | Unit tests for receipt and manual extraction | Test changes, adding test coverage |
|
||||
|
||||
## api/
|
||||
|
||||
| File | What | When to read |
|
||||
| ---- | ---- | ------------ |
|
||||
| `ocr.controller.ts` | Request handlers for all OCR endpoints (extract, extractVin, extractReceipt, extractManual, submitJob, getJobStatus) | Adding/modifying endpoint behavior |
|
||||
| `ocr.routes.ts` | Fastify route registration with auth and tier guard preHandlers | Route configuration, middleware changes |
|
||||
| `ocr.validation.ts` | Request/response type definitions for route schemas | Changing request/response shapes |
|
||||
|
||||
## domain/
|
||||
|
||||
| File | What | When to read |
|
||||
| ---- | ---- | ------------ |
|
||||
| `ocr.service.ts` | Business logic layer: file validation, size limits (10MB sync, 200MB async), content type checks, service delegation | Core logic changes, validation rules |
|
||||
| `ocr.types.ts` | TypeScript types: OcrResponse, VinExtractionResponse, ReceiptExtractionResponse, ManualExtractionResult, JobResponse, ManualJobResponse | Type changes, adding new response shapes |
|
||||
|
||||
## external/
|
||||
|
||||
| File | What | When to read |
|
||||
| ---- | ---- | ------------ |
|
||||
| `ocr-client.ts` | HTTP client to mvp-ocr Python service (extract, extractVin, extractReceipt, submitJob, submitManualJob, getJobStatus, isHealthy) | OCR service communication, error handling |
|
||||
|
||||
## tests/
|
||||
|
||||
| File | What | When to read |
|
||||
| ---- | ---- | ------------ |
|
||||
| `unit/ocr-receipt.test.ts` | Receipt extraction tests with mock client | Receipt flow changes |
|
||||
| `unit/ocr-manual.test.ts` | Manual PDF extraction tests | Manual extraction flow changes |
|
||||
|
||||
@@ -1,54 +1,180 @@
|
||||
# OCR Feature
|
||||
|
||||
Backend proxy for OCR service communication. Handles authentication, validation, and file streaming to the OCR container.
|
||||
Backend proxy for the Python OCR microservice. Handles authentication, tier gating, file validation, and request forwarding for three extraction types: VIN decoding, fuel receipt scanning, and maintenance manual extraction.
|
||||
|
||||
## API Endpoints
|
||||
|
||||
| Method | Endpoint | Description |
|
||||
|--------|----------|-------------|
|
||||
| POST | `/api/ocr/extract` | Synchronous OCR extraction (max 10MB) |
|
||||
| POST | `/api/ocr/jobs` | Submit async OCR job (max 200MB) |
|
||||
| GET | `/api/ocr/jobs/:jobId` | Poll async job status |
|
||||
| Method | Endpoint | Description | Auth | Tier | Max Size |
|
||||
|--------|----------|-------------|------|------|----------|
|
||||
| POST | `/api/ocr/extract` | Synchronous general OCR extraction | Required | - | 10MB |
|
||||
| POST | `/api/ocr/extract/vin` | VIN-specific extraction | Required | - | 10MB |
|
||||
| POST | `/api/ocr/extract/receipt` | Fuel receipt extraction | Required | - | 10MB |
|
||||
| POST | `/api/ocr/extract/manual` | Async maintenance manual extraction | Required | Pro | 200MB |
|
||||
| POST | `/api/ocr/jobs` | Submit async OCR job | Required | - | 200MB |
|
||||
| GET | `/api/ocr/jobs/:jobId` | Poll async job status | Required | - | - |
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
api/
|
||||
ocr.controller.ts # Request handlers
|
||||
ocr.routes.ts # Route registration
|
||||
ocr.validation.ts # Request validation types
|
||||
domain/
|
||||
ocr.service.ts # Business logic
|
||||
ocr.types.ts # TypeScript types
|
||||
external/
|
||||
ocr-client.ts # HTTP client to OCR service
|
||||
Frontend
|
||||
|
|
||||
v
|
||||
Backend Proxy (this feature)
|
||||
|
|
||||
+-- ocr.routes.ts --------> Route registration (auth + tier preHandlers)
|
||||
|
|
||||
+-- ocr.controller.ts ----> Request handlers (file validation, size checks)
|
||||
|
|
||||
+-- ocr.service.ts -------> Business logic (content type validation, delegation)
|
||||
|
|
||||
+-- ocr-client.ts --------> HTTP client to mvp-ocr:8000
|
||||
|
|
||||
v
|
||||
Python OCR Service
|
||||
```
|
||||
|
||||
## Receipt OCR Flow
|
||||
|
||||
```
|
||||
Mobile Camera / File Upload
|
||||
|
|
||||
v
|
||||
POST /api/ocr/extract/receipt (multipart/form-data)
|
||||
|
|
||||
v
|
||||
OcrController.extractReceipt()
|
||||
- Validates file size (<= 10MB)
|
||||
- Validates content type (JPEG, PNG, HEIC)
|
||||
|
|
||||
v
|
||||
OcrService.extractReceipt()
|
||||
|
|
||||
v
|
||||
OcrClient.extractReceipt() --> HTTP POST --> Python /extract/receipt
|
||||
| |
|
||||
v v
|
||||
ReceiptExtractionResponse ReceiptExtractor + HybridEngine
|
||||
| (Vision API / PaddleOCR fallback)
|
||||
v
|
||||
Frontend receives extractedFields:
|
||||
merchantName, transactionDate, totalAmount,
|
||||
fuelQuantity, pricePerUnit, fuelGrade
|
||||
```
|
||||
|
||||
After receipt extraction, the frontend calls `POST /api/stations/match` with the `merchantName` to auto-match a gas station via Google Places API. The station match is a separate request handled by the stations feature.
|
||||
|
||||
## Manual Extraction Flow
|
||||
|
||||
```
|
||||
PDF Upload + "Scan for Maintenance Schedule"
|
||||
|
|
||||
v
|
||||
POST /api/ocr/extract/manual (multipart/form-data)
|
||||
- Requires Pro tier (document.scanMaintenanceSchedule)
|
||||
- Validates file size (<= 200MB)
|
||||
- Validates content type (application/pdf)
|
||||
- Validates PDF magic bytes (%PDF header)
|
||||
|
|
||||
v
|
||||
OcrService.submitManualJob()
|
||||
|
|
||||
v
|
||||
OcrClient.submitManualJob() --> HTTP POST --> Python /extract/manual
|
||||
| |
|
||||
v v
|
||||
{ jobId, status: 'pending' } GeminiEngine (Vertex AI)
|
||||
Gemini 2.5 Flash
|
||||
Frontend polls: (structured JSON output)
|
||||
GET /api/ocr/jobs/:jobId |
|
||||
(progress: 10% -> 50% -> 95% -> 100%) v
|
||||
| ManualExtractionResult
|
||||
v { vehicleInfo, maintenanceSchedules[] }
|
||||
ManualJobResponse with result
|
||||
|
|
||||
v
|
||||
Frontend displays MaintenanceScheduleReviewScreen
|
||||
- User selects/edits items
|
||||
- Batch creates maintenance schedules
|
||||
```
|
||||
|
||||
Jobs expire after 2 hours (Redis TTL). Expired job polling returns HTTP 410 Gone.
|
||||
|
||||
## Supported File Types
|
||||
|
||||
### Sync Endpoints (extract, extractVin, extractReceipt)
|
||||
- HEIC (converted server-side)
|
||||
- JPEG
|
||||
- PNG
|
||||
- PDF (first page only)
|
||||
|
||||
## Response Format
|
||||
### Async Endpoints (extractManual)
|
||||
- PDF (validated via magic bytes)
|
||||
|
||||
## Response Types
|
||||
|
||||
### ReceiptExtractionResponse
|
||||
```typescript
|
||||
interface OcrResponse {
|
||||
{
|
||||
success: boolean;
|
||||
documentType: 'vin' | 'receipt' | 'manual' | 'unknown';
|
||||
receiptType: string;
|
||||
extractedFields: {
|
||||
merchantName: { value: string; confidence: number };
|
||||
transactionDate: { value: string; confidence: number };
|
||||
totalAmount: { value: string; confidence: number };
|
||||
fuelQuantity: { value: string; confidence: number };
|
||||
pricePerUnit: { value: string; confidence: number };
|
||||
fuelGrade: { value: string; confidence: number };
|
||||
};
|
||||
rawText: string;
|
||||
confidence: number; // 0.0 - 1.0
|
||||
extractedFields: Record<string, { value: string; confidence: number }>;
|
||||
processingTimeMs: number;
|
||||
}
|
||||
```
|
||||
|
||||
## Async Job Flow
|
||||
### ManualJobResponse
|
||||
```typescript
|
||||
{
|
||||
jobId: string;
|
||||
status: 'pending' | 'processing' | 'completed' | 'failed';
|
||||
progress?: { percent: number; message: string };
|
||||
estimatedSeconds?: number;
|
||||
result?: ManualExtractionResult;
|
||||
error?: string;
|
||||
}
|
||||
```
|
||||
|
||||
1. POST `/api/ocr/jobs` with file
|
||||
2. Receive `{ jobId, status: 'pending' }`
|
||||
3. Poll GET `/api/ocr/jobs/:jobId`
|
||||
4. When `status: 'completed'`, result contains OCR data
|
||||
### ManualExtractionResult
|
||||
```typescript
|
||||
{
|
||||
success: boolean;
|
||||
vehicleInfo?: { make: string; model: string; year: number };
|
||||
maintenanceSchedules: Array<{
|
||||
serviceName: string;
|
||||
intervalMiles: number | null;
|
||||
intervalMonths: number | null;
|
||||
details: string;
|
||||
confidence: number;
|
||||
subtypes: string[];
|
||||
}>;
|
||||
rawTables: any[];
|
||||
processingTimeMs: number;
|
||||
totalPages: number;
|
||||
pagesProcessed: number;
|
||||
}
|
||||
```
|
||||
|
||||
Jobs expire after 1 hour.
|
||||
## Error Handling
|
||||
|
||||
The backend proxy translates Python service error codes:
|
||||
|
||||
| Python Status | Backend Status | Meaning |
|
||||
|---------------|----------------|---------|
|
||||
| 413 | 413 | File too large |
|
||||
| 415 | 415 | Unsupported media type |
|
||||
| 422 | 422 | Extraction failed |
|
||||
| 410 | 410 | Job expired (TTL) |
|
||||
| Other | 500 | Internal server error |
|
||||
|
||||
## Tier Gating
|
||||
|
||||
Manual extraction requires Pro tier. The tier guard middleware (`requireTier` plugin) validates the user's subscription tier before processing. Free-tier users receive HTTP 403 with `TIER_REQUIRED` error code and an upgrade prompt.
|
||||
|
||||
Receipt and VIN extraction are available to all tiers.
|
||||
|
||||
Reference in New Issue
Block a user