Architecture overview

Bounded contexts
Matcher has six modules. Each owns its data and exposes clean interfaces to the others.
- Configuration: What you’re reconciling (contexts, sources, field maps, rules)
- Ingestion: Getting data in (parsing, validation, normalization)
- Matching: The engine (rule execution, confidence scoring)
- Exception: Handling unmatched items (workflow, routing, resolution)
- Governance: Audit trails (immutable logs for compliance)
- Reporting: Visibility (reports, exports, dashboards)
Configuration
Defines what you’re reconciling and how. Handles:- Contexts (what’s being reconciled)
- Sources (where data comes from)
- Field maps (translating external fields)
- Rules (how to match)
ReconciliationContext: The reconciliation scopeReconciliationSource: Source configurationFieldMap: Field translation rulesMatchRule: Matching logic
Ingestion
The Ingestion bounded context handles data intake and normalization. Responsibilities:- Parse uploaded files (CSV, JSON, XML)
- Validate incoming data against configured schemas
- Normalize external data into a canonical representation
- Detect and handle duplicate records
- Emit domain events when ingestion completes
IngestionJob: Tracks ingestion lifecycle and statusRawImport: Original uploaded payloadCanonicalTransaction: Normalized transaction record
IngestionCompleted: Indicates data readiness for matching
Matching
The Matching bounded context contains the reconciliation engine. Responsibilities:- Load applicable rules for a reconciliation context
- Execute matching strategies (exact, tolerance, date-based)
- Calculate confidence scores
- Create match groups and allocate transactions
- Identify unmatched transactions
MatchRun: Execution of a matching jobMatchGroup: Group of reconciled transactionsMatchItem: Individual transaction allocation
MatchConfirmed: A match group has been finalizedTransactionUnmatched: A transaction could not be reconciled
Exception management
The Exception bounded context manages unresolved transactions. Responsibilities:- Classify exceptions by severity
- Route exceptions to internal teams or external systems
- Support manual overrides and adjustments
- Track resolution status and SLAs
- Integrate with external workflow tools
Exception: An unresolved transactionResolution: Outcome of exception handlingRoutingRule: Routing and escalation logic
- JIRA for issue tracking
- ServiceNow for critical incidents
- Webhooks for custom workflows
Governance
The Governance bounded context preserves reconciliation traceability. Responsibilities:- Record all system actions in immutable audit logs
- Provide queryable audit history
- Support regulatory and compliance reporting
AuditLog: Append-only record of system activity
Reporting
The Reporting bounded context provides operational visibility. Responsibilities:- Generate reconciliation reports
- Expose dashboard metrics
- Export reconciliation data in multiple formats
Report: Reconciliation summaryDashboard: Aggregated operational metricsExportJob: Asynchronous export execution
Data flow
Reconciliation follows a deterministic pipeline across bounded contexts:
Configuration
Reconciliation contexts, sources, field mappings, and rules are defined through the API.
Ingestion
External data is uploaded or fetched. Files are parsed, validated, normalized, and deduplicated. An
IngestionCompleted event is emitted.Matching
Matching rules are applied to eligible transactions, producing match groups with confidence scores. High-confidence matches are approved automatically. Unmatched items become exceptions.
Exception handling
Exceptions are classified, routed, and resolved either manually or via external systems. Resolution updates are propagated back to Matcher.
Infrastructure components
Matcher relies on the following infrastructure services:
| Component | Purpose | Usage |
|---|---|---|
| PostgreSQL | Primary data store | Domain data with schema-per-tenant isolation |
| Redis | Cache and coordination | Deduplication, locks, idempotency keys |
| RabbitMQ | Message broker | Asynchronous communication between contexts |
Database architecture
- Schema-per-tenant isolation for strong data separation
- Strong consistency for matching and exception state
- Eventual consistency for reporting views
Multi-tenancy
Matcher enforces strict tenant isolation:- Tenant identity is extracted exclusively from JWT claims
- Tenant identifiers are never accepted via request parameters
- Database access is scoped through schema resolution
- All queries are automatically constrained to the active tenant
This model prevents cross-tenant data access and supports regulatory and audit requirements.
Design patterns
Hexagonal architecture
Each bounded context follows the ports-and-adapters pattern:Cqrs-light
Write and read paths are separated at the service level:*_command.gofor state mutations*_query.gofor read operations
Outbox pattern
Event publication follows the outbox pattern:- Domain state and outbox records are persisted atomically
- Background workers publish events to RabbitMQ
- Events are marked as processed after successful delivery

