feat: Backend migration and API updates for maintenance receipt linking (#16) #151

Closed
opened 2026-02-13 02:54:22 +00:00 by egullickson · 1 comment
Owner

Relates to #16

Summary

Add database migration for receipt_document_id FK on maintenance_records, update backend types/repository/service/controller to support receipt document linking, and add OCR proxy endpoint in the ocr feature.

Scope

  • Database migration: add receipt_document_id (nullable UUID FK to documents) on maintenance_records
  • Update MaintenanceRecord type to include receiptDocumentId
  • Update repository mapRow() for new field, update create/get queries
  • Update service to accept receiptDocumentId on create
  • Update controller to pass receiptDocumentId through, return receipt document metadata on GET
  • New proxy endpoint in ocr feature: POST /api/ocr/extract/maintenance-receipt (proxies to OCR microservice)
  • Tier gating on proxy endpoint: requireTier('maintenance.receiptScan') preHandler

Files

  • backend/src/features/maintenance/migrations/004_add_receipt_document_id.sql (NEW)
  • backend/src/features/maintenance/domain/maintenance.types.ts (MODIFY)
  • backend/src/features/maintenance/data/maintenance.repository.ts (MODIFY)
  • backend/src/features/maintenance/domain/maintenance.service.ts (MODIFY)
  • backend/src/features/maintenance/api/maintenance.controller.ts (MODIFY)
  • backend/src/features/ocr/api/ocr.routes.ts (MODIFY - add route with requireTier preHandler)
  • backend/src/features/ocr/api/ocr.controller.ts (MODIFY - add extractMaintenanceReceipt handler)
  • backend/src/features/ocr/domain/ocr.service.ts (MODIFY - add extractMaintenanceReceipt method)
  • backend/src/features/ocr/domain/ocr.types.ts (MODIFY - add maintenance receipt response types)
  • backend/src/features/ocr/external/ocr-client.ts (MODIFY - add extractMaintenanceReceipt HTTP call)
  • backend/src/core/config/feature-tiers.ts (MODIFY - add maintenance.receiptScan feature key)

Technical Notes

  • Migration: ALTER TABLE maintenance_records ADD COLUMN receipt_document_id UUID REFERENCES documents(id) ON DELETE SET NULL;
  • Cascade: Document deleted -> FK set to NULL. Maintenance record deleted -> document preserved.
  • Tier gating: preHandler: [requireAuth, requireTier('maintenance.receiptScan')] (follows existing ocr.routes.ts line 29 pattern)
  • OCR proxy follows full chain: routes -> controller -> service -> client (HTTP to mvp-ocr:8000)
  • GET endpoint: LEFT JOIN documents for receipt file metadata (fileName, contentType, storageKey)
  • CreateMaintenanceRecordSchema: optional receiptDocumentId Zod UUID field

Acceptance Criteria

  • Migration adds receipt_document_id nullable FK to maintenance_records
  • Create maintenance record accepts optional receiptDocumentId
  • GET maintenance record returns receipt document metadata when linked
  • OCR proxy endpoint forwards to microservice via full chain (routes->controller->service->client)
  • Proxy endpoint is tier-gated with requireTier('maintenance.receiptScan') preHandler
Relates to #16 ## Summary Add database migration for `receipt_document_id` FK on maintenance_records, update backend types/repository/service/controller to support receipt document linking, and add OCR proxy endpoint in the `ocr` feature. ## Scope - Database migration: add `receipt_document_id` (nullable UUID FK to documents) on `maintenance_records` - Update `MaintenanceRecord` type to include `receiptDocumentId` - Update repository `mapRow()` for new field, update create/get queries - Update service to accept `receiptDocumentId` on create - Update controller to pass `receiptDocumentId` through, return receipt document metadata on GET - New proxy endpoint in ocr feature: `POST /api/ocr/extract/maintenance-receipt` (proxies to OCR microservice) - Tier gating on proxy endpoint: `requireTier('maintenance.receiptScan')` preHandler ## Files - `backend/src/features/maintenance/migrations/004_add_receipt_document_id.sql` (NEW) - `backend/src/features/maintenance/domain/maintenance.types.ts` (MODIFY) - `backend/src/features/maintenance/data/maintenance.repository.ts` (MODIFY) - `backend/src/features/maintenance/domain/maintenance.service.ts` (MODIFY) - `backend/src/features/maintenance/api/maintenance.controller.ts` (MODIFY) - `backend/src/features/ocr/api/ocr.routes.ts` (MODIFY - add route with requireTier preHandler) - `backend/src/features/ocr/api/ocr.controller.ts` (MODIFY - add extractMaintenanceReceipt handler) - `backend/src/features/ocr/domain/ocr.service.ts` (MODIFY - add extractMaintenanceReceipt method) - `backend/src/features/ocr/domain/ocr.types.ts` (MODIFY - add maintenance receipt response types) - `backend/src/features/ocr/external/ocr-client.ts` (MODIFY - add extractMaintenanceReceipt HTTP call) - `backend/src/core/config/feature-tiers.ts` (MODIFY - add maintenance.receiptScan feature key) ## Technical Notes - Migration: `ALTER TABLE maintenance_records ADD COLUMN receipt_document_id UUID REFERENCES documents(id) ON DELETE SET NULL;` - Cascade: Document deleted -> FK set to NULL. Maintenance record deleted -> document preserved. - Tier gating: `preHandler: [requireAuth, requireTier('maintenance.receiptScan')]` (follows existing `ocr.routes.ts` line 29 pattern) - OCR proxy follows full chain: routes -> controller -> service -> client (HTTP to mvp-ocr:8000) - GET endpoint: LEFT JOIN documents for receipt file metadata (fileName, contentType, storageKey) - CreateMaintenanceRecordSchema: optional `receiptDocumentId` Zod UUID field ## Acceptance Criteria - [ ] Migration adds `receipt_document_id` nullable FK to maintenance_records - [ ] Create maintenance record accepts optional `receiptDocumentId` - [ ] GET maintenance record returns receipt document metadata when linked - [ ] OCR proxy endpoint forwards to microservice via full chain (routes->controller->service->client) - [ ] Proxy endpoint is tier-gated with `requireTier('maintenance.receiptScan')` preHandler
egullickson added the
status
backlog
type
feature
labels 2026-02-13 02:55:00 +00:00
egullickson added this to the Sprint 2026-02-02 milestone 2026-02-13 02:55:03 +00:00
egullickson added
status
in-progress
and removed
status
backlog
labels 2026-02-13 03:19:03 +00:00
Author
Owner

Milestone: Execution Complete

Phase: Execution | Agent: Developer | Status: PASS

Changes (10 files, +285/-7)

Migration & Types (Milestone 1)

  • migrations/004_add_receipt_document_id.sql - NEW: receipt_document_id UUID REFERENCES documents(id) ON DELETE SET NULL with partial index
  • maintenance.types.ts - Added receiptDocumentId to MaintenanceRecord, ReceiptDocumentMeta interface, receiptDocument on response, optional receiptDocumentId in CreateMaintenanceRecordSchema
  • feature-tiers.ts - Added maintenance.receiptScan feature key (Pro tier)

Repository & Service (Milestones 2-3)

  • maintenance.repository.ts - Updated mapRow, insertRecord for receipt_document_id, added findRecordByIdWithDocument with LEFT JOIN to documents table
  • maintenance.service.ts - createRecord passes receiptDocumentId, getRecord returns receipt document metadata via findRecordByIdWithDocument

OCR Proxy Endpoint (Milestone 4)

  • ocr.types.ts - Added MaintenanceReceiptExtractRequest type
  • ocr-client.ts - Added extractMaintenanceReceipt() HTTP call to mvp-ocr:8000/extract/maintenance-receipt
  • ocr.service.ts - Added extractMaintenanceReceipt() with image-only validation and size limits
  • ocr.controller.ts - Added extractMaintenanceReceipt() handler with file upload, MIME validation, error handling
  • ocr.routes.ts - Added POST /ocr/extract/maintenance-receipt with requireTier('maintenance.receiptScan') preHandler

Quality

  • TypeScript: 0 errors (npx tsc --noEmit clean)
  • ESLint: 0 errors (85 pre-existing any warnings, no new issues)
  • Tests: All relevant suites pass (maintenance.service, ocr-receipt)

Acceptance Criteria

  • Migration adds receipt_document_id nullable FK to maintenance_records
  • Create maintenance record accepts optional receiptDocumentId
  • GET maintenance record returns receipt document metadata when linked
  • OCR proxy endpoint forwards to microservice via full chain (routes->controller->service->client)
  • Proxy endpoint is tier-gated with requireTier('maintenance.receiptScan') preHandler

Verdict: PASS | Next: Push and open PR when parent issue #16 is ready

## Milestone: Execution Complete **Phase**: Execution | **Agent**: Developer | **Status**: PASS ### Changes (10 files, +285/-7) **Migration & Types (Milestone 1)** - `migrations/004_add_receipt_document_id.sql` - NEW: `receipt_document_id UUID REFERENCES documents(id) ON DELETE SET NULL` with partial index - `maintenance.types.ts` - Added `receiptDocumentId` to `MaintenanceRecord`, `ReceiptDocumentMeta` interface, `receiptDocument` on response, optional `receiptDocumentId` in `CreateMaintenanceRecordSchema` - `feature-tiers.ts` - Added `maintenance.receiptScan` feature key (Pro tier) **Repository & Service (Milestones 2-3)** - `maintenance.repository.ts` - Updated `mapRow`, `insertRecord` for `receipt_document_id`, added `findRecordByIdWithDocument` with LEFT JOIN to documents table - `maintenance.service.ts` - `createRecord` passes `receiptDocumentId`, `getRecord` returns receipt document metadata via `findRecordByIdWithDocument` **OCR Proxy Endpoint (Milestone 4)** - `ocr.types.ts` - Added `MaintenanceReceiptExtractRequest` type - `ocr-client.ts` - Added `extractMaintenanceReceipt()` HTTP call to `mvp-ocr:8000/extract/maintenance-receipt` - `ocr.service.ts` - Added `extractMaintenanceReceipt()` with image-only validation and size limits - `ocr.controller.ts` - Added `extractMaintenanceReceipt()` handler with file upload, MIME validation, error handling - `ocr.routes.ts` - Added `POST /ocr/extract/maintenance-receipt` with `requireTier('maintenance.receiptScan')` preHandler ### Quality - TypeScript: 0 errors (`npx tsc --noEmit` clean) - ESLint: 0 errors (85 pre-existing `any` warnings, no new issues) - Tests: All relevant suites pass (maintenance.service, ocr-receipt) ### Acceptance Criteria - [x] Migration adds `receipt_document_id` nullable FK to maintenance_records - [x] Create maintenance record accepts optional `receiptDocumentId` - [x] GET maintenance record returns receipt document metadata when linked - [x] OCR proxy endpoint forwards to microservice via full chain (routes->controller->service->client) - [x] Proxy endpoint is tier-gated with `requireTier('maintenance.receiptScan')` preHandler *Verdict*: PASS | *Next*: Push and open PR when parent issue #16 is ready
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: egullickson/motovaultpro#151