Architecture overview
mcomtask is a multi-tenant SaaS ERP built as a modular monolith with compiler-enforced module boundaries. This page is the short version; the reasoning lives in the architecture design spec.
| Concern | Choice |
|---|---|
| Backend | Go, Gin, sqlc, pgx v5, goose, River (Postgres-backed jobs) |
| Frontend | React 19, Vite, TanStack Query / Router / Table, shadcn on Radix, i18next |
| Database | Postgres 17, shared schema, row-level security per organization |
| Contract | Spec-first OpenAPI via oapi-codegen; REST only, SSE for realtime |
| Money | shopspring/decimal in Go, NUMERIC(19,4) in Postgres, a string on the wire |
| Storage | S3-compatible; presigned uploads, bytes never transit the API |
| Tests | testify + testcontainers-go against real Postgres |
flowchart TD M["modules/ — HTTP surface per business area<br/>expenses, payables, receivables, crm, payroll, …"] P["platform/ — shared capabilities<br/>workflow, posting, numbering, documents, i18n, …"] K["kernel/ — tenancy, money, audit, errors, event bus"] M --> P --> K
Dependencies point downward only. A kernel package importing a platform package is a
bug. Nothing outside a module may import its internal/; cross-module access goes through
contract.go or a published event. The package map lists every package
with its own doc comment.
Request path
Section titled “Request path”Every request runs in one transaction, reads included. The tenant is set with
SET LOCAL inside that transaction, which is what makes row-level security safe under
connection pooling. The organization comes from the authenticated session, never from a
request header.
Money and the ledger
Section titled “Money and the ledger”Modules never write journal lines. They register posting rules with accounting/, which
reacts to semantic tags on workflow states, never to state names — that is what lets a
customer rearrange their workflow safely. The ledger is append-only; corrections are
reversals.
Binaries
Section titled “Binaries”| Binary | Role |
|---|---|
cmd/api |
HTTP server; wires modules |
cmd/worker |
River workers: FX sync, reminders, OCR, exports, retention |
cmd/migrate |
goose runner |
cmd/operator |
The service provider’s private console across organizations |
cmd/orgadmin |
Creates organizations — there is deliberately no public sign-up |
cmd/telegram-webhook |
Points Telegram’s webhook at a deployment |
cmd/myinvois-fake |
Local stand-in for LHDN’s MyInvois API |
Go deeper
Section titled “Go deeper”- Roadmap — what is built, what is next
- Project invariants
- Workflow engine
- Lock order — advisory lock classes and the order they are taken