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:
Eric Gullickson
2026-02-11 11:04:19 -06:00
parent 40df5e5b58
commit ab0d8463be
11 changed files with 385 additions and 45 deletions

View File

@@ -14,7 +14,7 @@
| `config/` | Configuration loading (env, database, redis) | Environment setup, connection pools |
| `logging/` | Winston structured logging | Log configuration, debugging |
| `middleware/` | Fastify middleware | Request processing, user extraction |
| `plugins/` | Fastify plugins (auth, error, logging) | Plugin registration, hooks |
| `plugins/` | Fastify plugins (auth, error, logging, tier guard) | Plugin registration, hooks, tier gating |
| `scheduler/` | Job scheduling infrastructure | Scheduled tasks, cron jobs |
| `storage/` | Storage abstraction and adapters | File storage, S3/filesystem |
| `user-preferences/` | User preferences data and migrations | User settings storage |

View File

@@ -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 |

View File

@@ -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 |

View File

@@ -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.