Platform components
A small set of microservices behind a single API gateway, connected by RabbitMQ, sharing one PostgreSQL database, with the fiscal work delegated to government and NFS-e providers and the back-office steps automated in n8n.
Component map
Every client talks HTTPS to one API gateway; the gateway forwards each request over RabbitMQ to the owning service. business-contabeleza (Rails) owns businesses, professionals, contracts, business requests and professional invoices; accounting (Go) owns fiscal entities, credentials, NFS-e, MEI diagnosis, DAS and revenue, and talks to the government and fiscal providers. Both share the Contabeleza PostgreSQL database; workflow automation runs in n8n.
🧭How to use
- Click a box to open its card below the map: technology, responsibilities, how it is organized inside and every connection. Click it again (or ✕ Close) to reset.
- Hover a box to preview its connections; hover an arrow for its label.
- Show filters highlight the components of one flow (request path, fiscal setup, NFS-e, MEI data, business requests, login).
- In the card, click any connection to jump to that component. Arrows point from caller to callee; dashed = asynchronous (RabbitMQ message, webhook or event).
Play the flows step by step in Architecture — information flows.
Principles
🚪One door
Only the gateway is exposed. It owns authentication, tenant resolution, the route registry and response caching.
✉️Messages, not HTTP
Services never expose HTTP: every call (gateway→service and service→service) is a RabbitMQ RPC controller#action with a context.
🧾Fiscal work in one place
Everything that touches the government or an NFS-e provider lives in accounting. The tenant service only checks ownership and forwards.
⏳Async by default
Emission, credential validation, DAS and diagnosis data come from slow external systems: the API answers with a pending state and the final result arrives by callback, webhook or worker.
🤖Humans in the loop via n8n
Business requests, contracts and manual invoices are worked by the Contabeleza team in n8n: status webhooks out, /postbacks/n8n/* back in.
⬡Hexagonal services
Inside each service: inbound adapters (message controllers, postbacks, workers) → use cases (actions) → domain → outbound adapters (persistence, other services, providers).
Two routes to accounting
The fiscal features are reachable two ways. Both end in the same accounting actions; they differ in who checks the tenant.
| Route | Path pattern | Path through the platform | Who uses it |
|---|---|---|---|
| Tenant wrapper | /businesses/{id}/fiscal-entity/*/professionals/{id}/fiscal-entity/*/professional-fiscal-entities… | gateway → business-contabeleza (ownership of the business/professional) → accounting | MEI Pro and other tenant apps |
| Direct | /fiscal-entities/*, /buyer-fiscal-entities/*/accounting/search/*, /accounting/callbacks/*, /accounting/diagnosis/* | gateway → accounting (routes registered by accounting itself) | Admin/accounting tools, n8n, provider webhooks — see Internal endpoints ★ |
Inside a service
Every service follows the same ports-and-adapters layout. The dashed rings are the outside world (adapters); the solid ring is the application core. Dependencies point inwards: adapters call actions, actions call domain services, domain uses models; persistence, other services and providers are reached through outbound adapters.
🧭How to use
- Pick the Rails or Go tab, then click a layer to see its responsibility, rules, where it lives in the code and an example.
Multi-tenancy
Gateway
The ilm-business header must be one of the session businesses; it becomes ctx.business_id plus the acting professional and permissions.
business-contabeleza
Controllers force business_id into filters and writes, and check that the professional or business in the path belongs to the tenant before forwarding fiscal calls.
accounting
Fiscal entities carry their owners (business, professional, account); tenant wrappers pass the resolved fiscal entity id. Direct routes are reserved for admin, accounting and external-app tokens.
Data
Every tenant table has business_id; the gateway cache keys are per business.
Deployment
Environments
api.dev2.contabeleza.com.brapi.qa.contabeleza.com.brapi.staging.contabeleza.com.brapi.contabeleza.com.brKubernetes
ilm-brasil · one Helm chart per service (k8s/chart/values/<group>) · same images as iLoveMe for the shared services (gateway, access), Contabeleza values per environmentgateway
web
notifications
From commit to cluster
Technology catalog
🖥️Frontend
MEI Pro, mobile and admin
- React 19 + ViteMEI Pro web
- React Nativemobile shell
- Refine + MUIadmin panel
- Netlifymarketing site
🚪Gateway
the only public entry point
- Node.js + ExpressHTTP server
- express-jwtHS256 JWT
- ioredissessions · cache · routes
- formidableuploads
💎Rails services
business-contabeleza, access
- Rails 7.2API-only
- rails_commonbase library
- jsonapierJSON:API
- rabbiterRabbitMQ RPC
- AASM · PaperTrailstates · audit
- JSON schemasrequest payloads
🐹Go service
accounting
- Golanguage
- go-messengerRabbitMQ RPC
- go-jsonapiJSON:API
- go-database · go-redispersistence
- go-enotas · go-serpro · go-infosimplesproviders
- gocronworkers
🗄️Data & messaging
shared infrastructure
- PostgreSQLcblz database
- Redissessions · cache
- RabbitMQRPC · callbacks
- S3documents · PDFs
🔗Integrations
external providers
- eNotasNFS-e
- Serprogovernment APIs
- InfoSimplesfiscal lookups
- Revenue APImunicipal revenue
- n8nautomation
- Novuemail
⚙️Ops
build, run, observe
- Kubernetes + Helmruntime
- Oktetodev environments
- GitLab CIpipelines
- Sentryerrors