跳转至

Gerege Nexus

Production · 第 3 层 — 平台底座 · 仓库:open-gerege-nexus · nexus.gerege.mn

服务、运营与系统的统一平台。 一个把公共部门与私营机构的服务、运营、系统和数据 汇聚到同一底座上的模块化平台。开源,Apache 2.0 许可。

Nexus 意为连接点 —— 组织、服务、工作流、系统、用户与数据在此汇合。平台本身 不针对某一个行业:真正定义某家机构需求的,是运行在它之上的模块

生态系统模型正在改变

Gerege Nexus 是 Template Platform继任底座。旧模型是 「一个模板 → 每个产品一个分叉」;新模型是「一个 upstream(Nexus)→ 每个品牌 一个分叉,通过从 upstream 合并来更新」。这一转变正在进行中 —— 既有平台仍在 production 运行。详见分层架构

最本质的差别:应用即模块

在旧模型里,新产品意味着新仓库、新部署、新数据库。在 Nexus 上,新产品通常是 一个新模块 —— 编译进同一个二进制、由每个租户自行启用或停用的应用。

Template 模型(旧) Nexus 模型(新)
新产品 分叉模板 编写模块并加入目录
分发 每个仓库一套部署 按租户,通过应用商店
代码共享 open-gerege-core + @gerege/ui-core 单一 upstream;下游分叉从中合并
模块间调用 HTTP(仓库分离时) 进程内 Go 调用
启用 / 停用 需要部署 管理员在 app_installations 中决定

模块化单体

业务模块实现 Go 的 Module 契约,并编译进同一个二进制。某个租户启用了哪些 应用,由 PostgreSQL 中的 app_installations 表动态决定。

  • 没有额外的网络跳转 —— 模块之间在进程内调用,因此既不会产生微服务延迟,也不会 带来编排复杂度。
  • DAG 依赖解析 —— 模块依赖在有向无环图上递归求解,带环检测与 semver 校验。
  • 目录同步 —— catalog/apps.json 是唯一真实来源;apps 表在每次启动时据此刷新。 新增应用无需手写 SQL。
  • 应用门禁 —— 未安装应用的路由一律返回 403 Forbidden

为什么不用微服务?

模块边界由 Go 接口保障,而不是由网络保障。边界的约束力得以保留,同时避开了 网络延迟、分布式事务,以及多套部署的运维成本。

随平台提供的模块

模块 ID 路径 用途
Contacts io.example.contacts /contacts 往来单位名录,支持 ХУР / XYP 自动填充
Products io.example.products /products 商品、定价、租户范围内的 SKU
Inventory io.example.inventory /inventory 仓库、库存水位、只追加的出入库流水
Billing & e-Barimt io.example.billing /billing 发票、10% 增值税、e-Barimt 票据
Digital Documents io.example.documents /documents 电子文档与审批流
Developer Portal io.example.developer_portal /developer/apps OAuth2 客户端应用注册
PDF 电子签名 io.example.esign /esign 通过 eID Mongolia(PIN2)签署具法律效力的签名
政务服务 io.example.gov_services /gov 可配置的服务流程、层级与 SLA

可配置的政务服务流程

gov_services 模块把同一套代码变成一种服务交付能力:每个租户、以及租户内的 每一项服务,都可以各自配置。在三种模式之间切换,无需改动任何代码:

模式 含义
LOCAL 受理单位自行办结
DELEGATE 转交下级单位,上级单位监督并核验
HYBRID 由路由规则按每一笔请求决定采用哪一种

核心原则 —— 代码决定什么是可能的,配置决定什么是可选的。 规范的状态迁移表位于 代码中;已发布的版本只能收窄它,永远无法拓宽。因此配置错误的租户也无法进入一个 不可能的状态。

其他保证:

  • 状态由服务端计算 —— 客户端发送的是动作,绝不是状态。
  • 下级单位完成工作并不会关闭请求 —— 当某一步要求核验时,完成后进入 AWAITING_VERIFICATION
  • 逾期是推导出来的due_at < now()),绝不覆写业务状态。
  • 租户与单位的隔离写在库表结构里 —— 每个外键都是包含 tenant_id 的复合外键, 即使应用代码有缺陷,一行记录也无法指向另一个租户。
  • 幂等接入 —— 外部请求以 (tenant_id, source_system, external_request_id) 标识; 完全相同的重试返回 "created": false,而载荷实质不同的重放会被 409 拒绝。
  • 对外通知走 outbox —— 远端 endpoint 永远无法回滚或卡住一次流程迁移。

电子签名 —— eID Mongolia(PIN2)

esign 模块以依赖方身份接入 eID Mongolia 的合格远程签名

  1. 先对 PDF 取哈希 → eID 把该摘要推送到公民手机上,
  2. 公民用 PIN2 批准,
  3. eID 自己的 doc-signer 将 PKCS#7 连同 OCSP 与 CRL 数据一并嵌入,组装出带 PAdES 签名的 PDF。

签名私钥从不接触平台。 证书级别默认为 QUALIFIED —— 若接受 ADVANCED,平台 产出的每一份文档都会被悄悄降级。

以机构名义签署

代表权是直接从国家登记库实时读取的,而不是从证书读取 —— 因为昨天辞职的 负责人,今天仍然持有昨天那张证书。

此外还包括:签名日志(筛选、分页、CSV 导出)、批量签署、带 A4 预览的印章定位、HSM 连接与签名策略。租户可以强制要求合格 eID 签名并彻底关闭 HSM 通道 —— 对直接调用 API 的调用方同样生效。

认证与政务集成

  • 自带 OAuth2 / OIDC 提供方 —— /.well-known/openid-configuration/oauth2/token/oauth2/introspect/oauth2/revoke,支持 authorization_codeclient_credentialsrefresh_token
  • eID 与 ДАН / DAN —— 四条官方通道:PKI 数字签名、Mobile OTP、 银行 SSO、人脸生物识别。
  • ХУР / XYP —— 公民户籍登记(WS100101)与法人核验(WS100201)。
  • 会话令牌不透明,256 位,数据库中只保存 SHA-256 摘要。退出登录会真正吊销它们。

Mock 模式在 production 下不会运行

E-ID / ДАН / ХУР 的 mock 模式仅供开发使用。当 ENVIRONMENT=production 时会自动 关闭,因此无法用伪造的公民数据登录。

AI 与韧性

AI —— 基于 Gemini、扎根于租户数据库真实状态的助手(/api/v1/ai/chat/stt/tts/translate),提示词与知识库由管理员维护,另有库存需求预测。

云原生韧性(受 go-zero 启发):

组件 作用
Adaptive circuit breaker Google SRE 风格的滑动窗口失败率熔断
Adaptive load shedding 并发超限时返回 503 + Retry-After
Singleflight coalescing 合并重复查询,防止缓存击穿
Exponential backoff retry 对瞬时故障做指数退避重试

语言政策

蒙古语加上联合国六种官方语言 = 共七种。 蒙古语是源语言。文档七种齐备,但 软件本体交付蒙古语与英语,其余五种在设置 → 外观中开启。这与本站的 i18n 政策同出一辙。

由它分叉出的品牌

Nexus 是 upstream;每个品牌从它分叉,并通过合并保持更新。

品牌 仓库 域名 差异所在
Gerege Nexus open-gerege-nexus nexus.gerege.mn Upstream,参考部署
Gerege SSO sso-gerege-nexus 聚焦登录、权限与访问层的分叉
Eduge.mn eduge-mn-nexus eduge.mn 教育行业品牌;带有无法从 GHCR 拉取时在主机构建的 overlay

两个都叫 Gerege SSO

sso-gerege-nexus 是建立在 Nexus 上的分叉;production 上的 sso.gerege.mn 仍在运行原先的 sso-gerege-mn 代码。切勿混淆 —— 在转变完成之前,以 Gerege SSO 页面所述行为为准。

部署

main 推送会触发 GitHub Actions:构建并推送 backend 与 frontend 镜像到 GHCR → 把 docker-compose.prod.yml 复制到服务器 → 拉取镜像 → 在迁移全部完成之后才切换 API 与 frontend → 检查 /health/ready。部署只在 CI 确实通过之后才开始。

服务器上除 Docker 之外什么都不需要 —— 没有源码,没有 Go,也没有 Node。

PUBLIC_ORIGIN 一次决定三件事

CORS、OIDC issuer 与 eID 回调都由同一个变量推导而来。改动它会让 DNS、TLS 证书 以及每一个依赖 issuer 的客户端一起迁移。更换域名时请使用 认证与授权页上的检查清单。

技术栈

选型
Backend Go 1.25 · chi 路由 · pgx(不用 ORM,手写 SQL)
Frontend Next.js 15 App Router
数据库 PostgreSQL 16 —— 共享 schema,按 tenant_id 隔离
迁移 goosebackend/db/migrations/);禁止运行期 DDL
可观测性 Prometheus(/metrics)· OpenTelemetry
容器 Docker Compose · GHCR

生态系统层面的全貌见技术栈

详细文档

实现层面的文档位于仓库内,共七种语言:

文档 内容
README.md 平台概览(7 种语言)
docs/ARCHITECTURE_SPECIFICATION.md 分层与架构决策(MN/EN)
docs/MODULE_AUTHORING_GUIDE.md 如何编写新的应用模块
docs/GOV_SERVICES_WORKFLOW.md 政务服务流程的完整模型
docs/DOCUMENTS_SIGNING.md 签署仪式及其契约
docs/TRANSLATION_GUIDE.md 七语翻译指南
CHANGELOG.md 各版本变更