Gerege Nexus¶
Production · Layer 3 — Platform foundation ·
Repo: open-gerege-nexus · nexus.gerege.mn
An integrated platform for services, operations and systems. A modular platform that brings the services, operations, systems and data of public and private organisations onto one foundation. Open source, Apache 2.0.
Nexus means the point of connection — where organisations, services, workflows, systems, users and data meet. The platform itself targets no single sector: the modules running on top of it are what define a given organisation's needs.
The ecosystem model is changing
Gerege Nexus is the successor foundation to the Template Platform. The previous model was "one template → a fork per product"; the new one is "one upstream (Nexus) → a fork per brand, refreshed by merging from upstream". The transition is in progress — the existing platforms remain in production. See Layered architecture.
The essential difference: an app is a module¶
In the previous model a new product meant a new repository, a new deployment and a new database. On Nexus a new product is usually a new module — an app compiled into the same binary that each tenant can switch on or off.
| Template model (previous) | Nexus model (new) | |
|---|---|---|
| New product | Fork the template | Write a module, add it to the catalogue |
| Distribution | One deployment per repo | Per tenant, through the app store |
| Code sharing | open-gerege-core + @gerege/ui-core packages |
One upstream; downstream forks merge from it |
| Calls between modules | HTTP (when repos are separate) | In-process Go calls |
| Enable / disable | Requires a deploy | An admin decides in app_installations |
Modular monolith¶
Business modules implement a Go Module contract and compile into one
binary. Which apps are active for a given tenant is decided dynamically by the
app_installations table in PostgreSQL.
- No extra network hops — modules call each other in-process, so neither microservice latency nor orchestration complexity arises.
- DAG dependency resolution — module dependencies are resolved recursively over a directed acyclic graph, with cycle detection and semver validation.
- Catalogue sync —
catalog/apps.jsonis the single source of truth; theappstable is refreshed from it on every boot. Adding an app requires no hand-written SQL. - App gating — a route belonging to an uninstalled app answers
403 Forbidden.
Why not microservices?
Module boundaries are enforced by Go interfaces, not by the network. The boundary guarantee is kept while network latency, distributed transactions and the operational cost of many deployments are all avoided.
The modules that ship with it¶
| Module | ID | Path | Purpose |
|---|---|---|---|
| Contacts | io.example.contacts |
/contacts |
Contact directory with XYP auto-fill |
| Products | io.example.products |
/products |
Products, pricing, tenant-scoped SKUs |
| Inventory | io.example.inventory |
/inventory |
Warehouses, stock levels, append-only movement log |
| Billing & e-Barimt | io.example.billing |
/billing |
Invoices, 10% VAT, e-Barimt receipts |
| Digital Documents | io.example.documents |
/documents |
Digital records and approval flows |
| Developer Portal | io.example.developer_portal |
/developer/apps |
OAuth2 client app registration |
| PDF E-Sign | io.example.esign |
/esign |
Legally valid signatures via eID Mongolia (PIN2) |
| Government services | io.example.gov_services |
/gov |
Configurable service workflow, hierarchy, SLA |
Configurable government service workflow¶
The gov_services module turns one codebase into a service-delivery
capability that every tenant — and every service inside a tenant — configures for
itself. No code changes are involved in choosing between three modes:
| Mode | Meaning |
|---|---|
LOCAL |
The receiving unit fulfils the request itself |
DELEGATE |
Forwarded to a lower unit while the upper unit monitors and verifies |
HYBRID |
A routing rule decides per request which of the two applies |
The governing principle — code decides what is possible, configuration decides what is offered. The canonical transition table lives in code; a published version may narrow it but can never widen it. A misconfigured tenant therefore cannot reach an impossible state.
Other guarantees:
- The status is computed server-side — a client sends an action, never a status.
- A lower unit finishing work never closes the request — when a step requires
verification, completion lands in
AWAITING_VERIFICATION. - Overdue is derived (
due_at < now()), never written over the business status. - Tenant and unit isolation live in the schema — every foreign key is
composite, including
tenant_id, so a row cannot point across tenants even if application code has a bug. - Idempotent ingestion — an inbound request is identified by
(tenant_id, source_system, external_request_id); an identical retry returns"created": false, and a replay with a materially different payload is refused with409. - Status delivery goes through an outbox — a remote endpoint can never roll back or stall a workflow transition.
Electronic signature — eID Mongolia (PIN2)¶
The esign module connects to eID Mongolia's qualified remote signature as a
relying party:
- the PDF is hashed → eID pushes that digest to the citizen's phone,
- the citizen approves with PIN2,
- eID's own doc-signer embeds the PKCS#7 together with OCSP and CRL data and assembles a PAdES-signed PDF.
The signing private key never reaches the platform. The certificate level
defaults to QUALIFIED — accepting ADVANCED would silently downgrade every
document the platform produces.
Signing on behalf of an organisation
Representation rights are read live from the national registry, not from a certificate — because a director who resigned yesterday still holds yesterday's certificate.
Also included: a signature log (filters, pagination, CSV export), batch signing, stamp placement with an A4 preview, HSM connection and signing policy. A tenant can require qualified eID signatures and disable the HSM rail outright, including for callers hitting the API directly.
Authentication and state integration¶
- Its own OAuth2 / OIDC provider —
/.well-known/openid-configuration,/oauth2/token,/oauth2/introspect,/oauth2/revoke, supportingauthorization_code,client_credentialsandrefresh_token. - eID and DAN — the four official channels: PKI digital signature, Mobile OTP, bank SSO and biometric face verification.
- XYP — civil registration (
WS100101) and legal-entity verification (WS100201). - Session tokens are opaque, 256 bits, stored only as a SHA-256 digest. Logout revokes them for real.
Mock mode does not run in production
E-ID / DAN / XYP mock modes exist only for development. Under
ENVIRONMENT=production they switch off automatically, so no one can sign in
with fabricated citizen data.
AI and resilience¶
AI — a Gemini assistant grounded in the tenant's actual database state
(/api/v1/ai/chat, /stt, /tts, /translate), admin-managed prompts and
knowledge base, plus an inventory demand forecaster.
Cloud-native resilience (inspired by go-zero):
| Component | Role |
|---|---|
| Adaptive circuit breaker | Google SRE style sliding-window failure ratio |
| Adaptive load shedding | 503 + Retry-After when concurrency is exceeded |
| Singleflight coalescing | Collapses duplicate queries, preventing cache stampedes |
| Exponential backoff retry | Retries transient failures with backoff |
Language policy¶
Mongolian plus the six official UN languages = seven in total. Mongolian is the source. Documentation exists in all seven, but the software ships in Mongolian and English, with the remaining five enabled under Settings → Appearance. This is the same principle as this site's i18n policy.
Brands forked from it¶
Nexus is the upstream; each brand forks from it and is refreshed by merging from upstream.
| Brand | Repo | Domain | What differs |
|---|---|---|---|
| Gerege Nexus | open-gerege-nexus |
nexus.gerege.mn |
Upstream, reference deployment |
| Gerege SSO | sso-gerege-nexus |
— | A fork centred on the sign-in, rights and access layer |
| Eduge.mn | eduge-mn-nexus |
eduge.mn |
Education-sector brand; carries a host-build overlay for rollouts that cannot pull from GHCR |
Two things called Gerege SSO
sso-gerege-nexus is the new fork built on Nexus; sso.gerege.mn in
production still runs the older sso-gerege-mn code. Do not
conflate them — until the transition completes, the behaviour documented on
the Gerege SSO page is the one in force.
Deployment¶
A push to main runs GitHub Actions: build and push
the backend and frontend images to GHCR → copy docker-compose.prod.yml to
the server → pull the images → swap the API and frontend over only once
migrations have finished → check /health and /ready. Deployment starts only
after CI has actually passed.
The server needs nothing but Docker — no source, no Go, no Node.
PUBLIC_ORIGIN defines three things at once
CORS, the OIDC issuer and the eID callback all derive from one variable. Changing it moves DNS, the TLS certificate and every issuer-dependent client together. Use the checklist on Authentication & authorization when changing a domain.
Stack¶
| Layer | Choice |
|---|---|
| Backend | Go 1.25 · chi router · pgx (no ORM, hand-written SQL) |
| Frontend | Next.js 15 App Router |
| Database | PostgreSQL 16 — shared schema, isolated by tenant_id |
| Migrations | goose (backend/db/migrations/); runtime DDL is forbidden |
| Observability | Prometheus (/metrics) · OpenTelemetry |
| Containers | Docker Compose · GHCR |
See Technology stack for the ecosystem-wide picture.
Detailed documentation¶
Implementation-level documentation lives in the repository, in seven languages:
| Document | Contents |
|---|---|
README.md |
Platform overview (7 languages) |
docs/ARCHITECTURE_SPECIFICATION.md |
Layers and architectural decisions (MN/EN) |
docs/MODULE_AUTHORING_GUIDE.md |
How to write a new app module |
docs/GOV_SERVICES_WORKFLOW.md |
The full government service workflow model |
docs/DOCUMENTS_SIGNING.md |
The signing ceremony and its contract |
docs/TRANSLATION_GUIDE.md |
The seven-language translation guide |
CHANGELOG.md |
Changes per release |