{"id":46183382,"url":"https://github.com/lerianstudio/matcher","last_synced_at":"2026-05-16T00:08:39.078Z","repository":{"id":340458373,"uuid":"1162103478","full_name":"LerianStudio/matcher","owner":"LerianStudio","description":"Open-source transaction reconciliation engine. Automates multi-source matching with configurable rules, confidence scoring, fee verification, exception workflows, and immutable audit trails. Multi-tenant, SOX-ready, built in Go.","archived":false,"fork":false,"pushed_at":"2026-04-23T20:53:41.000Z","size":9558,"stargazers_count":14,"open_issues_count":5,"forks_count":3,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-04-23T22:22:00.825Z","etag":null,"topics":["audit-trail","compliance","cqrs","ddd","exception-management","fee-management","financial-operations","finops","fintech","golang","hexagonal-architecture","multi-tenant","open-source","postgresql","reconciliation","reconciliation-engine","transaction-matching"],"latest_commit_sha":null,"homepage":"https://lerian.studio","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/LerianStudio.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-02-19T21:52:09.000Z","updated_at":"2026-04-23T13:51:13.000Z","dependencies_parsed_at":null,"dependency_job_id":"42d75024-bfb5-49c7-9fa2-6d2e68b5c3bc","html_url":"https://github.com/LerianStudio/matcher","commit_stats":null,"previous_names":["lerianstudio/matcher"],"tags_count":58,"template":false,"template_full_name":null,"purl":"pkg:github/LerianStudio/matcher","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LerianStudio%2Fmatcher","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LerianStudio%2Fmatcher/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LerianStudio%2Fmatcher/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LerianStudio%2Fmatcher/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/LerianStudio","download_url":"https://codeload.github.com/LerianStudio/matcher/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LerianStudio%2Fmatcher/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32234730,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-24T13:21:15.438Z","status":"ssl_error","status_checked_at":"2026-04-24T13:21:15.005Z","response_time":64,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["audit-trail","compliance","cqrs","ddd","exception-management","fee-management","financial-operations","finops","fintech","golang","hexagonal-architecture","multi-tenant","open-source","postgresql","reconciliation","reconciliation-engine","transaction-matching"],"created_at":"2026-03-02T21:12:57.617Z","updated_at":"2026-05-16T00:08:39.071Z","avatar_url":"https://github.com/LerianStudio.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"![Lerian Matcher Banner](image/README/matcher-banner.png)\n\n\u003cdiv align=\"center\"\u003e\n\n[![Latest Release](https://img.shields.io/github/v/release/LerianStudio/matcher?include_prereleases)](https://github.com/LerianStudio/matcher/releases)\n[![License](https://img.shields.io/badge/license-Elastic%20License%202.0-4c1.svg)](LICENSE.md)\n[![Go Report](https://goreportcard.com/badge/github.com/lerianstudio/matcher)](https://goreportcard.com/report/github.com/lerianstudio/matcher)\n[![Discord](https://img.shields.io/badge/Discord-Lerian%20Studio-%237289da.svg?logo=discord)](https://discord.gg/DnhqKwkGv3)\n\n\u003c/div\u003e\n\n# Lerian Matcher\n\n**Matcher** is Lerian Studio's reconciliation engine. It automates transaction matching between [Midaz](https://github.com/LerianStudio/midaz) (Lerian's ledger) and external systems — banks, payment processors, ERPs — applying configurable matching rules, managing exceptions through workflow integrations, and maintaining a complete audit trail for compliance.\n\n## Why Matcher?\n\n| | |\n|---|---|\n| **Automated Matching** | Reduce manual reconciliation with deterministic rules, tolerance-based matching, and confidence scoring |\n| **Configurable Rules** | Define exact and tolerance-based rules, date windows, fee verification, and multi-source matches |\n| **Exception Workflows** | Route unresolved items to JIRA, ServiceNow, or webhooks where teams already work |\n| **Audit-First** | Append-only audit logging with hash chains for SOX-ready traceability |\n| **Multi-Tenant** | Schema-per-tenant isolation in PostgreSQL with JWT-based tenant resolution |\n| **Runtime Configurable** | Hot-reloadable settings via systemplane API — no restarts for tuning |\n\n## Reconciliation Pipeline\n\nMatcher implements a complete reconciliation pipeline:\n\n1. **Configure** — Define reconciliation contexts, sources, field maps, match rules, and fee schedules\n2. **Ingest** — Import external data (CSV, JSON, XML, ISO 20022), normalize fields, deduplicate\n3. **Match** — Execute deterministic and tolerance-based matching, produce match groups with confidence scores\n4. **Handle Exceptions** — Classify unmatched items, route to teams, record manual resolutions\n5. **Govern** — Maintain immutable audit log, verify hash chain integrity, archive for compliance\n6. **Report** — Dashboard analytics, variance analysis, export to CSV/PDF\n\n## Architecture\n\nMatcher is a **modular monolith** built with Domain-Driven Design (DDD), hexagonal architecture, and CQRS-light separation.\n\n### Bounded Contexts\n\n| Context | Purpose |\n|---------|---------|\n| **Configuration** | Reconciliation contexts, sources, field maps, match rules, fee schedules/rules, scheduling |\n| **Discovery** | External data source connection management, schema detection, extraction orchestration |\n| **Ingestion** | File parsing (CSV/JSON/XML/ISO 20022), normalization, BOM handling, Redis-based dedup |\n| **Matching** | Rule execution, confidence scoring (0-100), fee verification, manual match/unmatch, adjustments, cross-currency |\n| **Exception** | Exception lifecycle, disputes with evidence tracking, bulk operations, external dispatch |\n| **Governance** | Immutable audit logs, cryptographic hash chain verification, S3 archival |\n| **Reporting** | Dashboard metrics, async export jobs (CSV/PDF), streaming reports, Redis caching |\n| **Outbox** | Reliable event publication via transactional outbox pattern |\n\n### Technical Highlights\n\n- **Hexagonal Architecture** — Ports and adapters per bounded context with strict import boundaries\n- **Schema-Per-Tenant** — PostgreSQL `search_path` isolation with JWT-derived tenant identity\n- **Transactional Outbox** — Reliable event publication for ingestion and matching workflows\n- **Fee Schedule Engine** — Net-to-gross normalization with parallel and cascading fee application\n- **Distributed Locking** — Redis-based locks preventing concurrent match runs\n- **Cross-Currency Matching** — FX rate lookups and base-currency normalization\n- **Idempotency** — Redis-backed idempotency keys for safe client retries\n- **Systemplane** — Runtime configuration authority with hot-reloadable settings, history, and schema API\n- **Chaos Testing** — Toxiproxy-based fault injection for resilience validation\n- **OpenTelemetry** — Distributed tracing and metrics via lib-commons\n\n## Getting Started\n\n### Prerequisites\n\n- [Go 1.26.0+](https://go.dev/dl/)\n- [Docker](https://docs.docker.com/get-docker/) and Docker Compose\n- [golang-migrate](https://github.com/golang-migrate/migrate) (for database migrations)\n\n### 1. Clone and Start Infrastructure\n\n```bash\ngit clone https://github.com/LerianStudio/matcher.git\ncd matcher\nmake up\n```\n\nThis starts PostgreSQL (primary + replica), Valkey (Redis-compatible), RabbitMQ, SeaweedFS (S3), and the app with live reload.\n\n### 2. Apply Migrations\n\n```bash\nmake migrate-up\n```\n\n### 3. Verify\n\n```bash\ncurl http://localhost:4018/health\n# Returns plain text \"healthy\" or HTTP 503\n```\n\nThe API is available at `http://localhost:4018`. Swagger UI is accessible at `http://localhost:4018/swagger/index.html` when running in non-production mode.\n\n### Configuration\n\nNo configuration files needed — all defaults are baked into the binary and match the docker-compose setup.\n\nFor production, override via environment variables. See [`config/.config-map.example`](config/.config-map.example) for bootstrap-only keys (require restart). Runtime hot-reload is limited to systemplane-managed settings (for example: body limit, rate limits, worker intervals, feature flags, timeouts, export settings, and archival intervals) via `/system/matcher/:key` (`GET`/`PUT`) and `/system/matcher` (list with inline schema metadata). The admin API is a management-plane surface and is intentionally excluded from the public OpenAPI specification.\n\n### Deployment Notes\n\n**GOMEMLIMIT (Go memory hint).** The image does not set `GOMEMLIMIT`. Operators must configure it per-deployment at roughly 85% of the container memory limit (for example, `GOMEMLIMIT=425MiB` for a 500 MiB pod). Go 1.26 auto-detects cgroup CPU via `GOMAXPROCS` but does **not** auto-detect cgroup memory; leaving `GOMEMLIMIT` unset risks OOM-kills from an uncapped Go heap. Kubernetes example:\n\n```yaml\nenv:\n  - name: GOMEMLIMIT\n    valueFrom:\n      resourceFieldRef:\n        resource: limits.memory\n        divisor: \"1\"\n```\n\n## Project Structure\n\n```\nmatcher/\n├── cmd/                  # Application entry points\n│   ├── matcher/          # Main service binary\n│   └── health-probe/     # Health check binary for distroless containers\n├── config/               # Environment templates and storage config\n├── docs/                 # Design documents and API specs\n│   ├── swagger/          # Generated OpenAPI spec (JSON + YAML)\n│   ├── multi-tenant-guide.md\n│   └── PROJECT_RULES.md\n├── internal/             # Core application code (bounded contexts)\n│   ├── auth/             # JWT extraction, RBAC, tenant resolution\n│   ├── bootstrap/        # Composition root (config, DI, server, systemplane)\n│   ├── configuration/    # Reconciliation setup and scheduling\n│   ├── discovery/        # External data source discovery\n│   ├── ingestion/        # File parsing and normalization\n│   ├── matching/         # Core matching engine\n│   ├── exception/        # Exception and dispute management\n│   ├── governance/       # Audit logs and archival\n│   ├── reporting/        # Analytics and exports\n│   ├── outbox/           # Transactional outbox\n│   ├── shared/           # Shared kernel (cross-context types and ports)\n│   └── testutil/         # Shared test helpers\n├── migrations/           # PostgreSQL schema migrations (21 migrations)\n├── pkg/                  # Reusable library packages\n│   └── chanutil/         # Safe channel utilities\n├── scripts/              # Dev and CI utility scripts\n├── tests/                # Integration, E2E, chaos, and static analysis tests\n└── tools/                # Custom linters and dev tooling\n```\n\n## Development\n\n### Common Commands\n\n| Command | Purpose |\n|---------|---------|\n| `make dev` | Live reload with [air](https://github.com/air-verse/air) |\n| `make build` | Build binary to `bin/matcher` |\n| `make test` | Run unit tests |\n| `make test-int` | Integration tests (requires Docker) |\n| `make test-e2e` | End-to-end tests (requires full stack) |\n| `make test-chaos` | Fault injection tests (Toxiproxy) |\n| `make lint` | Linting (75+ linters via golangci-lint) |\n| `make lint-custom` | Custom architectural linters |\n| `make sec` | Security scanning (gosec) |\n| `make ci` | Full local CI pipeline |\n\n### Infrastructure\n\n| Service | Image | Port |\n|---------|-------|------|\n| PostgreSQL (primary) | `postgres:17` | 5432 |\n| PostgreSQL (replica) | `postgres:17` | 5433 |\n| Valkey (Redis) | `valkey/valkey:8` | 6379 |\n| RabbitMQ | `rabbitmq:4.1.3-management-alpine` | 5672 (AMQP), 15672 (UI) |\n| SeaweedFS (S3) | `chrislusf/seaweedfs:3.80` | 8333 (S3), 9333 (Master) |\n| Matcher App | `golang:1.26.2-alpine` | 4018 |\n\n### Testing\n\nMatcher uses TDD (Test-Driven Development) with four test tiers:\n\n- **Unit** (`make test`): Pure logic tests with mocks — no external dependencies\n- **Integration** (`make test-int`): Real containers via testcontainers\n- **E2E** (`make test-e2e`): Full-stack journey tests against running services\n- **Chaos** (`make test-chaos`): Fault injection with Toxiproxy (latency, connection loss, partitions)\n\nCoverage threshold: **70%**, enforced in CI.\n\n## API Documentation\n\nThe full OpenAPI specification is available at [`docs/swagger/swagger.json`](docs/swagger/swagger.json).\n\nWhen running in development mode, Swagger UI is accessible at `/swagger/index.html`.\n\nKey API areas:\n- **Reconciliation Contexts** — Create and manage reconciliation configurations\n- **Sources \u0026 Field Maps** — Define data sources and normalization rules\n- **Match Rules \u0026 Fee Schedules** — Configure matching logic and fee verification\n- **Ingestion** — Upload and parse external transaction data\n- **Matching** — Execute match runs, manage match groups, handle adjustments\n- **Exceptions \u0026 Disputes** — Manage exceptions, create disputes, collect evidence\n- **Governance** — Query audit logs, verify hash chains, manage archives\n- **Reporting** — Dashboard metrics, export jobs, variance analysis\n- **System** — Health checks, runtime configuration (systemplane)\n\n## Contributing\n\nWe welcome contributions from the community! Here's how to get started:\n\n1. **Fork** the repository\n2. **Create a branch** from `develop` (e.g., `feat/my-feature`)\n3. **Follow conventions**: Run `make lint \u0026\u0026 make test \u0026\u0026 make check-tests` before pushing\n4. **Submit a PR** to `develop` with a conventional commit title and a description of at least 50 characters\n\n### PR Requirements\n\n- Conventional commit format in PR titles (e.g., `feat: add batch matching endpoint`)\n- Every `.go` file must have a corresponding `_test.go`\n- Test build tags required (`//go:build unit`, etc.)\n- Run `make generate-docs` if you changed any API endpoint\n\n### Code Standards\n\n- Go 1.26 with 75+ linters enforced\n- Hexagonal architecture: adapters, ports, domain, services\n- CQRS separation: `*_commands.go` for writes, `*_queries.go` for reads\n- Multi-tenancy via JWT context — never accept tenant IDs from request parameters\n- Error wrapping with `%w`, UTC timestamps, parameterized SQL queries\n\nFor detailed conventions, see [`docs/PROJECT_RULES.md`](docs/PROJECT_RULES.md).\n\n## Community \u0026 Support\n\n- **Discord**: [Join our community](https://discord.gg/DnhqKwkGv3) for discussions, support, and updates\n- **GitHub Issues**: [Bug reports \u0026 feature requests](https://github.com/LerianStudio/matcher/issues)\n- **GitHub Discussions**: [Community Q\u0026A](https://github.com/LerianStudio/matcher/discussions)\n- **Twitter/X**: [@LerianStudio](https://twitter.com/LerianStudio)\n- **Email**: [contact@lerian.studio](mailto:contact@lerian.studio)\n\n## License\n\nMatcher is licensed under the [Elastic License 2.0](LICENSE.md).\n\n## About Lerian\n\nMatcher is developed by [Lerian](https://lerian.studio), a technology company founded in 2024, led by a team with deep experience in ledger and core banking systems. Matcher is part of the Lerian Studio ecosystem alongside [Midaz](https://github.com/LerianStudio/midaz) (open-source ledger).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flerianstudio%2Fmatcher","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flerianstudio%2Fmatcher","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flerianstudio%2Fmatcher/lists"}