Sender validation works (registered email accepted, unregistered rejected)
Attachments filtered by type and size
Queue status tracked through processing lifecycle
Retry logic works (max 3 attempts)
Error emails sent for failures
Relates to #149
## Scope
Create the core processing service that orchestrates the email-to-record pipeline.
### EmailIngestionService
Main orchestration service in `domain/email-ingestion.service.ts`:
1. **Sender validation**: Look up user by sender email via `UserProfileRepository.getByEmail()` (case-insensitive). Reject unregistered senders.
2. **Attachment extraction**: Filter attachments by supported types (PDF, PNG, JPG, JPEG, HEIC). Validate sizes (<10MB per file).
3. **Processing coordination**: For each valid attachment, delegate to receipt classifier + OCR pipeline.
4. **Status tracking**: Update `email_ingestion_queue` status through lifecycle (pending -> processing -> completed/failed).
5. **Error handling**: On failure, increment retry_count. If retry_count < 3, re-process. Otherwise mark as failed.
6. **Reply emails**: Send confirmation or error email back to sender.
### EmailIngestionRepository
Database access layer in `data/email-ingestion.repository.ts`:
- `insertQueueEntry()`, `updateQueueStatus()`, `getQueueEntry()`
- `insertPendingAssociation()`, `getPendingAssociations()`, `resolvePendingAssociation()`
- `findByEmailId()` for deduplication
- Standard `mapRow()` pattern for snake_case -> camelCase
### Files
- `backend/src/features/email-ingestion/domain/email-ingestion.service.ts`
- `backend/src/features/email-ingestion/data/email-ingestion.repository.ts`
## Acceptance Criteria
- [ ] Sender validation works (registered email accepted, unregistered rejected)
- [ ] Attachments filtered by type and size
- [ ] Queue status tracked through processing lifecycle
- [ ] Retry logic works (max 3 attempts)
- [ ] Error emails sent for failures
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 #149
Scope
Create the core processing service that orchestrates the email-to-record pipeline.
EmailIngestionService
Main orchestration service in
domain/email-ingestion.service.ts:UserProfileRepository.getByEmail()(case-insensitive). Reject unregistered senders.email_ingestion_queuestatus through lifecycle (pending -> processing -> completed/failed).EmailIngestionRepository
Database access layer in
data/email-ingestion.repository.ts:insertQueueEntry(),updateQueueStatus(),getQueueEntry()insertPendingAssociation(),getPendingAssociations(),resolvePendingAssociation()findByEmailId()for deduplicationmapRow()pattern for snake_case -> camelCaseFiles
backend/src/features/email-ingestion/domain/email-ingestion.service.tsbackend/src/features/email-ingestion/data/email-ingestion.repository.tsAcceptance Criteria
Milestone: Email Ingestion Processing Service
Phase: Execution | Agent: Feature Agent | Status: PASS
Completed
data/email-ingestion.repository.ts): Queue CRUD operations (insertQueueEntry, updateQueueStatus, getQueueEntry, findByEmailId, getRetryableEntries), pending vehicle association management (insert, get, resolve), standard mapRow() patterndomain/email-ingestion.service.ts): Full processing pipeline:Quality
e7f3728(refs #156)Verdict: PASS | Next: Quality review