Gerege Nexus App Store
Апп сторын бүтээгдэхүүн: registry (каталог нийтлэх, гарын үсэг зурах),
publisher studio (гуравдагч тал апп илгээх), review (хянаж нийтлэх).
Дээрээс нь стор өөрөө тээж яваа нэг апп: SSO клиентүүд.
Энэ бол Gerege Nexus
платформын дээр баригдсан distribution — экосистемийн git стратегийн
Түвшин 2.
Энд юу байгаа, юу байхгүй вэ
Энд платформын код нэг ч мөр байхгүй. Нэвтрэлт, тенант, өгөгдлийн сан ба
түүний тусгаарлалт, аппын gate, цэс, HTTP сервер бүгд цөмийнх бөгөөд
go.mod-ын нэг мөрөөр tag-аар авагдана:
require github.com/gerege-systems/open-gerege-nexus/backend v1.14.0
Энэ repo нэмдэг зүйл нь дөрвөн модуль ба тэднийг бүртгэх мөр:
main.go платформыг асааж, дөрвөн модулиа бүртгэнэ
modules/registry каталог, гарын үсэг, нийтлэлийн сувгууд
modules/publisher нийтлэгчийн профайл, апп бүртгэл, хувилбар илгээх
modules/review хянан батлах дараалал
modules/ssoclients OAuth2 клиентийн бүртгэл — сторын биш, стор тээж яваа апп
domain/ssoclients бүртгэл ямар байх ёстойг шийддэг дүрмүүд
catalog/ энэ бүтээгдэхүүний апп багц + manifest
Стор тээж яваа апп — SSO клиентүүд
modules/ssoclients нь энэ бүтээгдэхүүний хэсэг биш. Тэр нь тухайн
суулгацын өөрийнх нь OAuth2 сервер дээр клиент бүртгэдэг апп бөгөөд
2026-08-25 хүртэл цөмийн internal/apps/sso_clients байсан — цөмийн
сүүлчийн апп.
Энд байгаа шалтгаан нь тараалт: репод байгаа апп бол сторт байгаа апп.
Дурын distribution түүнийг гурван мөрөөр авна —
require github.com/gerege-systems/appstore-gerege-nexus v0.1.0 // go.mod
import "github.com/gerege-systems/appstore-gerege-nexus/modules/ssoclients"
ssoclients.New(p) // main()
— каталогийн бичлэг нь энэ registry-ээс гарын үсэгтэй ирнэ, суулгах нь
сторын ердийн товч. Эхний хэрэглэгч нь
sso-gerege-nexus.
Платформоос хэрэгтэй зүйл нь nexus.SSOClientRegistry ганцхан —
цөмийн v1.14.0-д нэмэгдсэн гэрээ. Түүнээс өмнө энэ апп цөмийн
internal/tenant/ssoprovider-ийн хорин экспортолсон нэр рүү шууд хүрдэг
байсан бөгөөд тэр нь өөр репод баригдах боломжгүй байсан цорын ганц шалтгаан.
OAuth2 сервер өөрөө цөмд үлдсэн — код олгох, токен солих, id_token гарын
үсэглэх, redirect шалгах.
Аппын дэлгэцүүд цөмийн web shell-д хэвээр (/sso-clients,
/module/sso-clients/*) — distribution бүр тэр image-ийг ажиллуулдаг тул
энд frontend хуулбарлах шаардлагагүй. Модульгүй суулгац дээр тэдгээр дэлгэц
амьгүй; провайдергүй суулгац дээр API нь 503 гэж үнэн хариулна.
Ажиллуулах
go build ./...
go test ./...
Локал орчинд цөмтэй зэрэг ажиллах бол go.work (commit хийхгүй):
go work init . ../open-gerege-nexus/backend
Нээлттэй ба хаалттай апп
Апп бүр visibility-тэй: public — бүх платформд санал болгоно;
private — зөвхөн энэ registry нэрлэсэн платформуудад. Хоосон бол public.
Хаалттай аппыг платформоос нуух цорын ганц зөв арга нь тухайн платформын
каталогт түүнийг оруулахгүй байх нь мөн. Бүх платформд ижил баримт өгөөд "чи
өөрөө нуу" гэвэл хаалттай аппуудын нэрс баримт барьсан бүх хүнд алдагдана, мөн
харах сонирхолтой тал нь өөрөө шийдэгч болно.
Тиймээс каталогийн endpoint нэрээ хэлсэн хүсэлтэд өөр хариу өгдөг болов:
GET /api/v1/registry/catalog?platform=1.4.0&channel=stable
Authorization: Bearer <тухайн платформын токен>
Токенгүй хүсэлт нэрээ хэлээгүй хүсэлт бөгөөд түүнд нийтийн каталог буцна —
өмнөх бүх зан төлөв яг хэвээр. Танигдаагүй эсвэл эрх нь хураагдсан токен бол
401 биш, мөн л нийтийн каталог: эрх хураах гэдэг нь өгсөн зүйлээ буцааж авах
гэсэн үг, сторыг нь бүхэлд нь салгах гэсэн үг биш.
Операторын endpoint-ууд (/api/v1/appstore/registry, гарц ардаа):
| Метод |
Зам |
Юу хийх |
GET |
/platforms |
Бүртгэгдсэн платформууд, тус бүр юу харж болох нь |
POST |
/platforms |
Платформ бүртгэж, нэг удаа токен буцаана |
PUT |
/platforms/{id}/access |
Токеныг хүчингүй болгох / сэргээх |
PUT |
/platforms/{id}/apps/{appID} |
Хаалттай аппыг тэр платформд нээх |
DELETE |
/platforms/{id}/apps/{appID} |
Буцааж хаах |
Токен нь SHA-256 хураангуйгаар хадгалагдана — үүсгэх агшинд нэг удаа
харагдаад дахиж хэзээ ч харагдахгүй. Алдвал шинийг үүсгэнэ; зуун платформын
ажиллаж байгаа нууцыг буцааж уншиж чаддаг registry бол зөвхөн түүний төлөө
хулгайлах үнэтэй өгөгдлийн сан.
Grant, revoke, хүчингүй болгох гурвуулаа тухайн платформын кэшлэгдсэн
каталогийг устгана. Кэш нь registry-ийн revision тоолуураар түлхүүрлэгддэг ба
эрх олгох нь юу ч нийтлэхгүй — үгүй бол шийдвэр нь дараагийн нийтлэл хүртэл,
өөрөөр хэлбэл огт хамаагүй өдөр хүчин төгөлдөр болох байв.
Схем
00001 бол App Store-ийн өөрийн эзэмшдэг эхний схем. Түүнээс өмнөх бүх
хүснэгт (store_apps, store_app_versions, …) цөмийн 00038 миграцаар үүссэн
бөгөөд энэ бүтээгдэхүүн гарахад тэндээ үлдсэн — талбарт ажиллачихсан миграцыг
устгах нь цэвэрхэн хавтас өгөөд, үнэн биш болсон түүх авчирна. Шинэ схем өөр:
зөвхөн App Store-т хэрэгтэй хүснэгт нь платформын суулгац бүр ажиллуулдаг
миграцад байх ёсгүй.
00002-т (2026-08-25) тэдгээрийн долоо нь эцэст нь энд ирэв. Цөм 2026-08-23-нд
00075-аар store_apps, store_publishers, store_app_texts,
store_external_registrations, store_review_events,
store_catalog_snapshots, store_registry_state долоог устгасан —
"аппын схем платформ дотор байх ёсгүй". Тэр өдөр business-gerege-nexus
өөрийнхөө хүснэгтийг аль хэдийн зарласан байсан, энэ репо зарлаагүй байв.
Тиймээс go.mod цөмийг v1.11.0+ болгосон агшинд шинэ суулгац
store_apps байхгүйгээс унадаг байсан. store_app_versions цөмд үлдсэн —
суулгацын дэлгүүрийн дэлгэцүүд түүнийг уншдаг.
⚠️ appstore.gerege.mn нь цөмийн v1.6.0 дээр байгаа. Түүнийг v1.11.0-аас
дээш гаргах нь өгөгдөл хадгалах алхамгүйгээр бүртгэлийг устгана: цөмийн
00075 энэ файлаас өмнө ажиллаж мөрүүдийг аваад явчихна. Дараалал нь
00002-ын толгойд бичигдсэн — долоон хүснэгтийг _keep хуулбар болгож
аваад, rollout хийж, FK дарааллаар нь буцааж хийнэ.
Тиймээс db/migrations/ энэ repo-гийнх, MIGRATIONS_DIR + өөрийн
MIGRATIONS_TABLE-аар ажиллана (deploy/docker-compose.yml-ийн
migrate-appstore-ыг үз). Нэг өгөгдлийн санд хоёр түүх байх тул
MIGRATIONS_TABLE нь сонголт биш: goose нэг хүснэгтэд нэг мөр бичдэг учир
хоёулангийнх нь 00001 нэг мөр болно.
DB-тэй тестүүд:
APPSTORE_TEST_DATABASE_URL=postgres://... go test ./modules/registry
Каталог ба цөмийн хувилбар
catalog/ дотор энэ бүтээгдэхүүний гурван модуль, тэдгээрийн хажууд суудаг
цөмийн хоёр апп (organisation, egov) байна. Сүүлийн хоёр нь хуулбар —
кодыг нь цөм эзэмшдэг, энд зөвхөн каталогийн бичлэг байна.
Платформ өөрийнхөө компилдсэн модулиудтай зөрчилдсөн каталог дээр асахаа
болино — каталогийн бүрэн бүтэн байдал бол анхааруулга биш, асалтын алдаа.
Тэгэхээр цөмийн шинэ tag тэдгээр аппын нэр, хувилбарыг өөрчилвөл энэ хуулбар
хоцорч, образ баригдаад, deploy болоод, дараа нь асахаа болино.
Бодит жишээ: backend/v1.5.0 дээр io.gerege.nexus.organisation нь
"Organisation & People" 1.0.0-аас "Directory" 2.0.0 болсон бөгөөд энэ каталог
1.0.0 гэж бичсэн хэвээр байв. Renovate-ийн bump PR дээр анзаарагдсан.
Каталогоо унших нь catalog.LoadFile — цөмийн гэрээний пакетынх. Энэ ажлын
явцад тэр функц internal/-д байсан тул эндээс хүрэхгүй байсныг илрүүлж,
цөмийн v1.6.0 дээр гаргав: upstream-first дүрэм яг ийм үр дүн гаргах ёстой —
дутагдал энд олдож, тэнд засагдана.
catalog_test.go нь энэ репогийн эзэмшдэг талыг барина: гурван модулийн
компилдсэн хувилбар каталогийнхтойгоо тэнцүү эсэх. Хуулбарласан хоёр аппыг
барих боломжгүй — тэдний код цөмийн internal/ дотор тул эндээс импортлогдохгүй
— тиймээс тэднийг цөм өөрөө асахдаа шалгана. Цөмийг bump хийхдээ
catalog/apps.json, catalog/manifests/, catalog/chronicle/ доторх тэр
хоёрыг цөмийнхтэй нь тааруулах нь bump-ийн нэг хэсэг.
Дүрмүүд
Цөмийн CONTRIBUTING-ийн
дүрмүүд энд мөрдөгдөнө. Хамгийн чухал хоёр нь:
- Upstream-first — цөмд засвар хэрэгтэй бол цөм рүү PR илгээнэ. Энд
хуулбарлаж засахыг хориглоно; тэр нь зуун repo-гийн drift-ийн эх үүсвэр.
- Бизнес логик зөвхөн модуль хэлбэрээр —
main.go дотор custom код
бичихгүй.
Хувилбар
Цөмийн шинэ tag гармагц Renovate go.mod-ын мөрийг өсгөх PR нээнэ. CI
ногоон бол merge; улаан бол цөмийн release-д асуудал байна гэсэн дохио тул
цөмийн багт issue очно.
Лиценз
Apache 2.0 — LICENSE-ийг үзнэ үү.