How atdayev/submission-triage works
Purpose and entry points
submission-triage is a single-binary Go service that monitors an insurance Gmail inbox, evaluates submission attachments against policy checklists, and sends threaded requests for missing material. The production process starts at cmd/server/main.go; cmd/authorize/main.go supports mailbox authorization. Composition and lifecycle wiring are in internal/app/app.go and internal/app/build.go.
Runtime and operational boundary
The service is a long-running poller, not a request-driven application. It runs on Go 1.25+, uses a local SQLite file with SQL migrations, and can be installed as a systemd service via deploy/systemd/submission-triage.service. A small HTTP health endpoint exposes mailbox reachability through internal/delivery/http/router.go and internal/delivery/http/handler/health.go.
Mail ingestion and control plane
IMAP is the inbound boundary: the poller reads unread messages, tracks ingestion state, and applies mailbox-folder controls such as Hold/status folders. Core implementation is in internal/delivery/imap/poller.go, internal/delivery/imap/client.go, and internal/repository/ingest_control.go. Raw messages are translated into domain email/document structures by internal/delivery/emailingest/translate.go; reusable MIME parsing resides in pkg/emlparse/emlparse.go.
Submission triage pipeline
The submission service deduplicates incoming messages, associates follow-ups with existing submissions, determines policy type, evaluates checklist completion, and decides whether broker contact or human review is needed. Its main orchestration is internal/service/submissions.go, based on domain models in internal/model/submission.go, internal/model/document.go, and internal/model/reply.go. Checklist definitions are YAML files under checklists/, loaded through internal/infrastructure/checklist/store.go.
Document extraction and classification
Attachments cross an extraction/classification boundary before entering checklist evaluation. Extractors support PDF, DOCX, XLSX, and CSV in internal/infrastructure/extractor/pdf.go, internal/infrastructure/extractor/docx.go, and internal/infrastructure/extractor/xlsx.go. Deterministic filename/content matching is supplemented, when configured and within spend limits, by Anthropic Claude through internal/infrastructure/classifier/classifier.go and internal/infrastructure/llm/anthropic.go. Unreadable or uncertain documents become internal review signals rather than broker-facing claims.
Durable state and reliable outbound effects
SQLite persistence owns submissions, audit history, LLM spend, ingestion controls, and a transactional outbox. Database setup is in internal/database/sqlite.go; schema evolution is in migrations/0001_init.sql through migrations/0010_ingest_control.sql. Repository boundaries include internal/repository/submissions.go, internal/repository/outbox.go, and internal/repository/audit.go. The outbox worker in internal/service/outbox_worker.go decouples persisted reply intent from SMTP delivery, enabling restart-safe sending and duplicate prevention.
Outbound communication and scheduled lifecycle
SMTP sends broker replies and internal daily digests using internal/infrastructure/email/smtp.go and internal/infrastructure/email/sender.go. Lifecycle jobs handle quiet-submission escalation, digest generation, and retention in internal/service/escalation.go and internal/service/retention.go. These operations update both persisted state and IMAP organization, while REPLIES_ENABLED separates inbox processing from externally visible broker messaging.
Main entry points: submissions.go Submission triage · poller.go IMAP poller · sqlite.go SQLite state · escalation.go Lifecycle jobs
Components 20
Runtime
- Service process · Long-running poller with health endpoint.
cmd/server/main.go - App composition
internal/app/app.go - systemd unit
deploy/systemd/submission-triage.service - Health endpoint · Reports mailbox reachability.
internal/delivery/http/router.go
Mail ingestion
- IMAP poller · Reads unread Gmail messages and applies folder controls.
internal/delivery/imap/poller.go - Email translation · Converts raw mail into domain email and documents.
internal/delivery/emailingest/translate.go - MIME parser
pkg/emlparse/emlparse.go - Ingestion controls · Tracks ingestion state and mailbox controls.
internal/repository/ingest_control.go
Triage pipeline
- Submission triage · Deduplicates, associates replies, evaluates policy completion, and routes outcomes.
internal/service/submissions.go - Document extraction · Extracts attachment content from PDF, DOCX, XLSX, and CSV.
internal/infrastructure/extractor/pdf.go - Document classification · Uses deterministic matching and optional Claude within spend limits.
internal/infrastructure/classifier/classifier.go - Anthropic Claude
internal/infrastructure/llm/anthropic.go - Checklist store
internal/infrastructure/checklist/store.go
Durable effects
- SQLite state · Stores submissions, audit history, spend, controls, and outbox rows.
internal/database/sqlite.go - Schema migrations
migrations/0001_init.sql - Submission repository
internal/repository/submissions.go - Transactional outbox · Persists reply intent before delivery.
internal/repository/outbox.go
Outbound & lifecycle
- Outbox worker · Restart-safe broker reply delivery with duplicate prevention.
internal/service/outbox_worker.go - SMTP sender · Sends broker replies and internal digests.
internal/infrastructure/email/smtp.go - Lifecycle jobs · Escalates quiet submissions, generates digests, and applies retention.
internal/service/escalation.go
Connections 24
- systemd unit → Service process: runs
- Service process → App composition: initializes
- App composition → IMAP poller: starts polling
- App composition → Health endpoint: serves
- Health endpoint → IMAP poller: checks reachability
- IMAP poller → Email translation: raw messages
- Email translation → MIME parser: parses MIME
- IMAP poller → Ingestion controls: reads and updates
- Email translation → Submission triage: domain email and attachments
- Submission triage → Document extraction: extracts attachments
- Document extraction → Document classification: extracted content
- Document classification → Anthropic Claude: optional classification
- Submission triage → Checklist store: loads policy checklist
- Submission triage → Submission repository: persists triage state
- Submission repository → SQLite state: stores
- Ingestion controls → SQLite state: stores
- Schema migrations → SQLite state: evolves schema
- Submission triage → Transactional outbox: records reply intent
- Transactional outbox → SQLite state: stores
- Outbox worker → Transactional outbox: claims pending sends
- Outbox worker → SMTP sender: delivers replies
- Lifecycle jobs → Submission repository: updates lifecycle state
- Lifecycle jobs → IMAP poller: organizes mailbox
- Lifecycle jobs → SMTP sender: sends internal digests