Архитектура¶
Платформа следует Clean Architecture: handler → usecase → repository →
domain. Бизнес-ядро никогда не импортирует веб-фреймворк.
Компоненты¶
Internet ──► nginx (TLS)
│
├─ /oauth2/*, /.well-known/*, /userinfo ─► Go API — встроенный OIDC issuer
├─ /rp/sign/* ─► ретранслятор подписи eID (бэкенд)
├─ /rp/eid/* ─► прокси сервисов eID — личный (бэкенд)
├─ /rp/eid-org/* ─► прокси сервисов eID — организации (бэкенд)
└─ всё остальное ─► Next.js BFF (web) ──► API бэкенда (:8080)
│
внутренняя сеть: db (PostgreSQL) · redis
Слои¶
| Слой | Технология | Примечания |
|---|---|---|
| Бэкенд | Go · chi (net/http) · pgx (без ORM) | Clean Architecture, RLS, рукописный SQL |
| Фронтенд | Next.js 16 (BFF) + @gerege/ui-core |
Браузер общается только со своим origin; токены не попадают в клиентский JS |
| Провайдер OIDC | Встроенный (Go, usecases/oidc) | платформа сама ведёт вход/согласие/выход |
| Идентификация | eID Mongolia RP | проверка электронного удостоверения |
| Кэш/очередь | Redis | список отозванных сессий, временное состояние |
| AI | Gemini (REST без SDK) | чат, голос, перевод |
Безопасность¶
- Row-Level Security (RLS) — каждый пользователь видит только свои строки; проверка применимости при старте (в продакшене требуется роль без прав суперпользователя).
- Модель BFF — токены живут в httpOnly-куках и никогда не попадают в JS браузера.
- Двойная защита от CSRF — собственный заголовок + проверка origin.
- Заголовки безопасности — CSP, HSTS, COOP/COEP/CORP; ограничение запросов по IP.
- Аудит — журнал с хеш-цепочкой, только на добавление.
Структура бэкенда — она приходит из ядра¶
Ни одна из перечисленных возможностей (аутентификация, RBAC, шлюз, аудит,
OIDC-провайдер, eID/SSO, ИИ) не написана в этом репозитории — всё приходит
из модуля Go open-gerege-core через go.mod. Поэтому в backend/ лежит
ровно один файл Go:
backend/
├── cmd/api/main.go # ~30 строк: запустить ядро и добавить свои маршруты
├── deploy/ # Dockerfile, инициализация БД
└── .env.example # шаблон конфигурации
func main() {
server.ServiceName = "gerege-template"
app, err := server.NewApp() // ← все возможности из ядра
// Собственные маршруты приложения добавляются здесь:
// app.Router().Route("/api/xxx", xxx.Routes(app.Pool()))
app.Run()
}
Ядро двухслойное: open-gerege-core (открытая основа, её напрямую
используют платформы государственной линии) и наследующий её через go.mod
private-gerege-core (закрытый, для линии Gerege).
Структура фронтенда — @gerege/ui-core¶
Большая часть фронтенда живёт в общем пакете. Приложению принадлежит только то, что специфично для него: брендинг, тексты landing и особые страницы.
frontend/
├── src/brand.config.ts # единственный источник брендинга (имя, домен, docsUrl…)
├── src/components/landing/ # собственные тексты landing
├── src/app/api/**/route.ts # ОДНОСТРОЧНЫЕ обёртки BFF-маршрутов (158 шт.)
└── node_modules/@gerege/ui-core
├── src/api/** # сама логика BFF-маршрутов
└── src/components/** # AppShell, UserMenu, экраны admin/gov/gateway
- Пакет закреплён по тегу в
package.json(…/ui-core/archive/refs/tags/v0.4.0.tar.gz) — обновление всегда явное. - Каждый маршрут — обёртка:
export { GET, POST } from '@gerege/ui-core/api/<путь>'. Next.js регистрирует маршруты по файловой системе, поэтому обёртка обязательна;npm run check:routesнаходит маршруты пакета без обёртки в приложении. - Пакет никогда не импортирует
brand.config.tsприложения — значения приходят через<UiCoreProvider>(brandName,docsUrl,docsLangs). Имя бренда, вписанное в любой другой файл, отклоняетnpm run check:brand.
Обе проверки входят в npm run build, поэтому их обеспечивает CI.