Skip to content

Latest commit

 

History

History
929 lines (691 loc) · 53.4 KB

EMBEDDED-SERVICES.md

File metadata and controls

929 lines (691 loc) · 53.4 KB

Embedded Services (Kiswahili)

🌐 Languages: 🇺🇸 English · 🇪🇹 am · 🇸🇦 ar · 🇦🇿 az · 🇧🇬 bg · 🇧🇩 bn · 🇧🇦 bs · 🇨🇿 cs · 🇩🇰 da · 🇩🇪 de · 🇬🇷 el · 🇪🇸 es · 🇪🇪 et · 🇮🇷 fa · 🇫🇮 fi · 🇫🇷 fr · 🇮🇪 ga · 🇮🇳 gu · 🇳🇬 ha · 🇮🇱 he · 🇮🇳 hi · 🇭🇷 hr · 🇭🇺 hu · 🇦🇲 hy · 🇮🇩 id · 🇳🇬 ig · 🇮🇹 it · 🇯🇵 ja · 🇬🇪 ka · 🇰🇭 km · 🇮🇳 kn · 🇰🇷 ko · 🇱🇹 lt · 🇱🇻 lv · 🇮🇳 ml · 🇮🇳 mr · 🇲🇾 ms · 🇲🇹 mt · 🇲🇲 my · 🇳🇵 ne · 🇳🇱 nl · 🇳🇴 no · 🇮🇳 or · 🇮🇳 pa · 🇵🇭 phi · 🇵🇱 pl · 🇵🇹 pt · 🇧🇷 pt-BR · 🇷🇴 ro · 🇷🇺 ru · 🇱🇰 si · 🇸🇰 sk · 🇸🇮 sl · 🇷🇸 sr · 🇸🇪 sv · 🇮🇳 ta · 🇮🇳 te · 🇹🇭 th · 🇹🇷 tr · 🇺🇦 uk-UA · 🇵🇰 ur · 🇺🇿 uz · 🇻🇳 vi · 🇳🇬 yo · 🇨🇳 zh-CN · 🇹🇼 zh-TW


Toleo: v3.8.44 Ilisasishwa mara ya mwisho: 2026-09-09 Walengwa: Wahandisi wanaoongeza, wanaodumisha, au wanaotatua hitilafu za huduma zilizopachikwa (9Router, CLIProxyAPI, Mux, Bifrost, open-wa).

Huduma zilizopachikwa ni zana saidizi za michakato zilizosakinishwa ndani ya mashine ambazo OmniRoute husakinisha, husimamia, na huziwezesha kama malengo kamili ya uelekezaji. Tofauti na watoa huduma wa nje (ambao hufikiwa kupitia intaneti kwa kutumia funguo za API), huduma zilizopachikwa huendeshwa kwenye mashine ileile kama OmniRoute na huwasiliana kupitia loopback.


Yaliyomo

  1. Muhtasari
  2. Usanifu — tabaka 4
  3. Mashine ya hali ya mzunguko wa maisha
  4. Rejeleo la API
  5. Usalama
  6. Kuongeza huduma mpya iliyopachikwa
  7. Utatuzi wa matatizo
  8. Maswali Yanayoulizwa Mara kwa Mara

1. Muhtasari

Kwa nini huduma zilizopachikwa?

Huduma sita zimepachikwa:

Huduma Kifurushi cha npm Porti chaguo-msingi Kusudi
9Router 9router 20130 Kipanga njia cha AI ambacho OmniRoute inaweza kutumia kama mtoa huduma mdogo. Modeli zinafichuliwa kama 9router/{sub}/{model}
CLIProxyAPI Faili tekelezi ya toleo la GitHub (cliproxy) 8317 Adapta ya proksi ya ndani kwa mitiririko ya uthibitishaji ya Anthropic CLI. Hutoa upangaji mbadala wa njia tokeni za OAuth zinapoisha muda wake
Mux mux (mux server isiyo na kiolesura) 8322 Daemon ya ndani ya uratibu wa mawakala (coder/mux). Inadhibitiwa tu katika mzunguko wake wa uhai — si lengo la upangaji wa njia (hakuna uelekezaji wa proksi wa LLM).
Bifrost @maximhq/bifrost 8080 Mfumo wa nyuma wa upelekaji wa lango la AI la Go. Unapofanya kazi, huchaguliwa kiotomatiki na njia ya upelekaji (/v1/relay/)
Dario @askalf/dario 3456 Proksi ya usajili wa Claude — mbadala/hifadhi ya dharura ya CLIProxyAPI kwa trafiki yenye muundo wa Claude Code; ufunguo unaodungwa huwa DARIO_ADMIN_TOKEN inayodhibiti ufikiaji wa sehemu yake ya udhibiti ya OAuth ya /admin/*
open-wa @open-wa/wa-automate 8323 Uendeshaji otomatiki wa WhatsApp Web (Chromium isiyo na kiolesura kupitia Puppeteer). Inadhibitiwa tu katika mzunguko wake wa uhai — si lengo la upangaji wa njia.

Huduma zote sita hufuata modeli sawa ya usimamizi:

  • OmniRoute huzisakinisha chini ya DATA_DIR/services/{name}/ (zikiwa zimetengwa na package.json ya OmniRoute)
  • OmniRoute huzianzisha na kuzifuatilia kama michakato-toto
  • OmniRoute hudunga ufunguo wa API wa muda mfupi katika mazingira ya mchakato-toto na kuuzungusha bila muda wa huduma kutopatikana (panapohusika)
  • Njia zote za usimamizi (/api/services/*) ni LOCAL_ONLY — zinaweza kufikiwa tu kutoka loopback (kanuni thabiti #17)

Maamuzi muhimu (kutoka kwenye mpango wa usanifu)

Uamuzi Thamani
Ufikiaji wa dashibodi kwenye UI asilia ya 9Router Proksi ya kinyume katika /dashboard/providers/services/9router/embed/*
Utaratibu wa usakinishaji npm install {package} kupitia execFile (hakuna uingizaji wa shell)
Hali ya matumizi Mtoa huduma amesajiliwa kama 9router/{sub}/{model} katika injini ya upangaji wa njia
Usimamizi wa ufunguo wa API OmniRoute huzalisha, husimba kwa njia fiche wakati umehifadhiwa (AES-256-GCM), na hudunga kupitia env
Mahali pa dashibodi /dashboard/providers/services (vichupo vitatu)
Uanzishaji otomatiki Kitufe cha kuwasha/kuzima kwa kila huduma, chaguo-msingi KIMEZIMWA

2. Usanifu — tabaka 4

┌────────────────────────────────────────────────────────────────────┐
│  Tabaka la 1 — UI                                                  │
│  /dashboard/providers/services  (vichupo: CLIProxyAPI | 9Router | Mux)│
│  Kumbukumbu mubashara (SSE), Anzisha/Simamisha/Anzisha upya/Sasisha, Mipangilio, Sakinisha│
│                                                                    │
│  src/app/(dashboard)/dashboard/providers/services/                 │
│    ├── page.tsx               Ganda + uelekezaji wa vichupo kwa ?tab=│
│    ├── tabs/                  CliproxyServiceTab, NinerouterServiceTab,│
│    │                          MuxServiceTab                        │
│    └── components/            ServiceStatusCard, ServiceLifecycleButtons,│
│                               ServiceLogsPanel, ApiKeyCard, ...    │
└──────────────────────┬─────────────────────────────────────────────┘
                       │ HTTP (Next.js fetch)
┌──────────────────────▼─────────────────────────────────────────────┐
│  Tabaka la 2 — API (LOCAL_ONLY — loopback pekee)                   │
│                                                                    │
│  /api/services/9router/{install|start|stop|restart|update|         │
│                          rotate-key|status|auto-start|logs}        │
│  /api/services/cliproxy/{install|start|stop|restart|update|        │
│                           status|auto-start|logs}                  │
│  /api/services/mux/{install|start|stop|restart|update|             │
│                      status|auto-start|logs}                       │
│  /dashboard/providers/services/9router/embed/[...path]             │
│    (proksi ya kinyume ya HTTP + WebSocket → seva chanzo ya 9Router)│
│                                                                    │
│  Lango: LOCAL_ONLY_API_PREFIXES inajumuisha "/api/services/" na    │
│         "/dashboard/providers/services/*/embed/"                   │
└──────────────────────┬─────────────────────────────────────────────┘
                       │ miito ya ndani ya mchakato
┌──────────────────────▼─────────────────────────────────────────────┐
│  Tabaka la 3 — ServiceSupervisor (src/lib/services/)               │
│                                                                    │
│  ServiceSupervisor.ts   Msimamizi wa jumla (child_process.spawn)   │
│    ├── install:    execFile('npm', ['install', pkg, '--prefix'])    │
│    ├── start:      spawn(node, [entrypoint], {env, cwd})           │
│    ├── api_key:    crypto.randomBytes(32) → env NINEROUTER_API_KEY  │
│    ├── port:       20130 kwa 9Router (inaweza kusanidiwa)          │
│    ├── logs:       bafa ya mzunguko ya stdio ya MB 5 → matukio ya SSE│
│    ├── health:     HTTP GET /health kila sekunde 2–5, urejeshaji wa polepole│
│    └── lifecycle:  SIGTERM sekunde 15 → SIGKILL                    │
│                                                                    │
│  registry.ts        getSupervisor(name) / registerSupervisor()     │
│  bootstrap.ts       Huanzisha SERVICES[] zote mchakato unapoanza   │
│  apiKey.ts          getOrCreateApiKey(), generateServiceApiKey()   │
│  modelSync.ts       GET /v1/models ya mara kwa mara → jedwali la service_models│
│  ringBuffer.ts      Bafa ya kumbukumbu ya mzunguko (MB 5 kwa kila huduma)│
│  healthCheck.ts     Uchunguzi wa afya wa HTTP kwa upigaji kura     │
│  installers/        ninerouter.ts, cliproxy.ts, mux.ts, openwa.ts  │
│                      (adapta za usakinishaji)                      │
└──────────────────────┬─────────────────────────────────────────────┘
                       │ HTTP inayooana na OpenAI (loopback)
┌──────────────────────▼─────────────────────────────────────────────┐
│  Tabaka la 4 — Mtoa huduma / Uelekezaji                            │
│                                                                    │
│  open-sse/executors/ninerouter.ts                                  │
│    Hutafuta upya porti na ufunguo wa API kwa kila ombi (hakuna uhifadhi wa muda).│
│    Huondoa kiambishi awali cha "9router/" kwenye kitambulisho cha modeli kabla ya kupeleka kwa proksi.│
│    Hurejesha 503 service_not_running ikiwa msimamizi hayuko katika hali ya "running".│
│                                                                    │
│  src/shared/constants/providers.ts                                 │
│    Ingizo la "9router": isEmbeddedService: true                    │
│                                                                    │
│  open-sse/config/providerRegistry.ts                               │
│    Modeli huhifadhiwa kama "9router/{sub}/{model}" (zenye kiambishi awali).│
│    Husawazishwa kila dakika 5 na modelSync.ts.                     │
│                                                                    │
│  Mux inadhibitiwa mzunguko wa uhai PEKEE (Tabaka la 1-3) — ni daemoni ya│
│  uratibu wa mawakala, si proksi ya LLM, kwa hivyo haina kitekelezaji/│
│  ingizo la mtoa huduma la Tabaka la 4 na kamwe hailengwi na uelekezaji.│
└────────────────────────────────────────────────────────────────────┘

Faili muhimu za chanzo

Faili Jukumu
src/lib/services/ServiceSupervisor.ts Darasa kuu: mzunguko wa maisha, kufunga, afya, bafa ya mzunguko
src/lib/services/bootstrap.ts Usajili wa kiwango cha mchakato na uanzishaji wa kiotomatiki
src/lib/services/registry.ts Ramani ya singleton zana → msimamizi
src/lib/services/apiKey.ts Uundaji wa ufunguo, usimbaji fiche wa AES-256-GCM wakati wa kuhifadhi
src/lib/services/modelSync.ts Usawazishaji wa modeli wa mara kwa mara (dakika 5) + unapohitajika
src/lib/services/ringBuffer.ts Bafa ya kumbukumbu ya mzunguko ya MB 5 yenye usajili wa SSE
src/lib/services/healthCheck.ts Uchunguzi wa afya wa HTTP (muda unaweza kusanidiwa)
src/lib/services/installers/ninerouter.ts Usakinishaji/usasishaji/uondoaji wa 9Router kwa npm
src/lib/services/installers/cliproxy.ts Usakinishaji/usasishaji/uondoaji wa CLIProxyAPI kwa npm
src/lib/services/installers/mux.ts Usakinishaji/usasishaji/uondoaji wa Mux kwa npm
src/lib/services/installers/openwa.ts Usakinishaji/usasishaji/uondoaji wa open-wa kwa npm
src/app/api/services/9router/_lib.ts Kitendaji saidizi cha getOrInitSupervisor()
src/app/api/services/[name]/logs/route.ts Endpoint ya pamoja ya kumbukumbu za SSE
open-sse/executors/ninerouter.ts Kitekelezaji cha mtoa huduma (Tabaka la 4)

3. Mashine ya hali ya mzunguko wa maisha

                    install()
  ┌─────────────┐ ──────────► ┌─────────────┐
  │ not_installed│             │   stopped   │◄──────────────────┐
  └─────────────┘             └──────┬──────┘                   │
                                     │ start()                   │
                                     ▼                           │ stop()
                               ┌──────────┐                      │
                               │ starting │                      │
                               └────┬─────┘                     │
            uchunguzi wa afya sawa  │         hitilafu / SIGTERM│
                               ┌────▼─────┐  (hutoka ndani ya s 5)│
                               │ running  │─── hitilafu ─────────►┤
                               └────┬─────┘                   ┌─▼────┐
                             stop() │                          │error │
                                    ▼                          └──────┘
                               ┌──────────┐
                               │ stopping │
                               └──────────┘

Hali huhifadhiwa katika jedwali la DB la version_manager (safu ya status) na huakisiwa katika hali ya ndani ya kumbukumbu ya ServiceSupervisor. Hali ya ndani ya kumbukumbu ndiyo yenye mamlaka kwa mchakato unaoendelea; hali ya DB ndiyo mbadala endelevu wakati wa kuwasha mfumo.

Mabadiliko ya hali

Kutoka Tukio Kwenda
not_installed install() inafanikiwa stopped
stopped start() inaitwa starting
starting uchunguzi wa afya unarudisha 200 running
starting mchakato unatoka kabla ya kuwa salama kiafya error
running stop() inaitwa stopping → stopped
running mchakato unatoka bila kutarajiwa (< s 5) error (hitilafu ya haraka)
running mchakato unatoka bila kutarajiwa (> s 5) error
error start() inaitwa starting
yoyote stop() wakati wa stopping hakuna operesheni

Kufuli ya operesheni

ServiceSupervisor hupanga operesheni za mzunguko wa maisha kwa mfuatano kupitia kufuli ya operesheni isiyosawazishwa (withLock()). Miito ya wakati mmoja ya start() kwenye msimamizi yuleyule husababisha uanzishaji wa mchakato mmoja tu; mwitaji wa pili husubiri na kurudisha hali iliyopo. Hii huzuia hali za mashindano wakati, kwa mfano, uanzishaji otomatiki na kitufe cha UI vinapotumika kwa wakati mmoja.


4. Marejeleo ya API

Njia zote zilizo chini ya /api/services/ ni LOCAL_ONLY (loopback pekee, kanuni thabiti #17). Maombi yasiyo ya loopback hupokea 403 LOCAL_ONLY bila kujali tokeni ya uthibitishaji.

4.1 Endpointi za 9Router (njia 11)

POST /api/services/9router/install

Sakinisha 9Router kutoka npm. Huunda DATA_DIR/services/9router/ yenye package.json na node_modules/ zake yenyewe. Haikinzani na vitegemezi vya OmniRoute.

Mwili wa ombi (vyote si lazima):

{ "version": "latest" }
Sehemu Aina Chaguo-msingi Maelezo
version string "latest" Lebo ya toleo la npm au semver ya kusakinisha

Majibu:

Hali Maelezo
200 { ok: true, installedVersion: "x.y.z", path: "..." }
400 Mwili batili wa ombi (uthibitishaji wa Zod umeshindwa)
409 Usakinishaji tayari unaendelea (kufuli limeshikiliwa)
500 Usakinishaji wa npm umeshindwa — tazama message kwa hitilafu inayoeleweka

Vidokezo: Hutumia execFile('npm', [...]) — hakuna shell, hakuna uchopekaji (kanuni thabiti #13). Hitilafu za EACCES huwasilishwa kama ujumbe unaoeleweka.


POST /api/services/9router/start

Anzisha 9Router. Husajili msimamizi ikiwa bado hajasajiliwa, kisha huita supervisor.start(). Ni idempotenti ikiwa tayari inaendelea.

Mwili wa ombi: hakuna

Majibu:

Hali Maelezo
200 Kitu cha ServiceStatus (tazama schema hapa chini)
409 9Router haijasakinishwa (status: "not_installed")
503 Uanzishaji umeshindwa (hitilafu ya mchakato — tazama lastError)

Schema ya ServiceStatus:

{
  "tool": "9router",
  "state": "running",
  "pid": 12345,
  "port": 20130,
  "health": "healthy",
  "startedAt": "2026-05-25T10:00:00.000Z",
  "lastError": null
}

POST /api/services/9router/stop

Simamisha 9Router kwa utaratibu salama. Hutuma SIGTERM, husubiri sekunde 15, kisha SIGKILL ikiwa bado inaendelea. Ni idempotenti ikiwa tayari imesimama.

Mwili wa ombi: hakuna

Majibu:

Hali Maelezo
200 ServiceStatus (state: "stopped")
503 Usimamishaji umeshindwa bila kutarajiwa

POST /api/services/9router/restart

Ni sawa na stop() ikifuatwa na start() chini ya kufuli la operesheni.

Mwili wa ombi: hakuna

Majibu: sawa na start (hurejesha ServiceStatus ya mwisho).


POST /api/services/9router/update

Husasisha 9Router hadi toleo jipya zaidi la npm. Ikiwa huduma inaendelea, husimamishwa kwanza, usakinishaji wa npm huendeshwa (ikisakinisha toleo jipya mahali palepale), kisha huduma huanzishwa upya.

Mwili wa ombi (vyote si lazima):

{ "version": "latest" }

Majibu:

Hali Maelezo
200 { ok: true, previousVersion: "...", installedVersion: "..." }
400 Mwili batili
500 Usasishaji wa npm umeshindwa

POST /api/services/9router/rotate-key

Hutengeneza ufunguo mpya wa API kwa ajili ya 9Router, huusimba ukiwa umehifadhiwa, na huanzisha upya huduma (ikiwa inaendelea) ili ichukue ufunguo mpya kutoka kwenye mazingira yake. Ufunguo wa zamani hubatilishwa mara moja.

Mwili wa ombi: hakuna

Majibu:

Hali Maelezo
200 { keyRotated: true, restarted: boolean }
500 Ubadilishaji wa ufunguo umeshindwa

Usalama: Ufunguo mpya haurudishwi kamwe kwenye jibu (hakuna uvujaji wa kitambulisho). Huhifadhiwa ukiwa umesimbwa (AES-256-GCM) katika jedwali la version_manager.


GET /api/services/9router/status

Hurejesha hali iliyounganishwa ya moja kwa moja + DB, ikijumuisha metadata ya toleo na onyesho la awali la ufunguo wa API.

Majibu:

Hali Maelezo
200 Tazama schema hapa chini
500 Usomaji wa hali umeshindwa

Schema ya jibu:

{
  "tool": "9router",
  "state": "running",
  "pid": 12345,
  "port": 20130,
  "health": "healthy",
  "startedAt": "2026-05-25T10:00:00.000Z",
  "lastError": null,
  "installedVersion": "1.2.3",
  "latestVersion": "1.2.4",
  "updateAvailable": true,
  "apiKeyMasked": "nr_****abcd",
  "autoStart": false,
  "providerExpose": false
}

POST /api/services/9router/auto-start

Badilisha hali ya alama ya kuanzisha kiotomatiki. Wakati enabled: true, huduma huanza kiotomatiki OmniRoute itakapowashwa wakati ujao (ikiwa huduma imesakinishwa).

Mwili wa ombi:

{ "enabled": true }

Majibu:

Hali Maelezo
200 { autoStart: true }
400 Mwili batili

GET /api/services/9router/logs

Mtiririko wa SSE wa kumbukumbu za moja kwa moja kutoka kwenye bafa ya mzunguko ya stdout/stderr ya 9Router.

Vigezo vya hoja:

Kigezo Aina Chaguo-msingi Maelezo
tail integer 200 Idadi ya mistari ya kihistoria ya kutuma kwanza (kiwango cha juu 1000)
filter string hakuna Kichujio cha kifungu kidogo kisichojali herufi kubwa au ndogo (hakuna regex — salama dhidi ya ReDoS)

Matukio ya SSE:

Tukio Data Maelezo
snapshot LogLine[] Sehemu ya mwisho ya historia ya awali
log LogLine Mstari wa kumbukumbu wa moja kwa moja
heartbeat {} Kudumisha muunganisho kila sekunde 15

Schema ya LogLine:

{
  "ts": 1716633600000,
  "stream": "stdout",
  "line": "[9router] Listening on :20130"
}

Majibu:

Hali Maelezo
200 text/event-stream
400 Kigezo cha filter ni kirefu mno (> herufi 200)
404 Huduma haijapatikana (msimamizi hajasajiliwa)

4.2 Vituo vya mwisho vya CLIProxyAPI (njia 10)

CLIProxyAPI ina muundo sawa wa vituo vya mwisho na 9Router isipokuwa rotate-key, pamoja na accounts, provider-expose na auto-restart-adopted. Sasa inapokea ufunguo maalumu wa API wa safu ya data unaowekwa wakati wa kuanzishwa (needsApiKey: true katika bootstrap.ts, unaotumika kusawazisha modeli); status inajumuisha sehemu chache zaidi.

Mbinu Njia Maelezo
POST /api/services/cliproxy/install Sakinisha CLIProxyAPI kutoka npm
POST /api/services/cliproxy/start Anzisha CLIProxyAPI
POST /api/services/cliproxy/stop Simamisha CLIProxyAPI
POST /api/services/cliproxy/restart Anzisha upya CLIProxyAPI
POST /api/services/cliproxy/update Sasisha hadi toleo jipya zaidi
GET /api/services/cliproxy/status Hali ya moja kwa moja + DB (bila apiKeyMasked)
POST /api/services/cliproxy/auto-start Washa au zima uanzishaji otomatiki

Kituo cha mwisho kinachoshirikiwa cha GET /api/services/{name}/logs (tazama §4.1) hufanya kazi kwa huduma zote nne kwa kutumia sehemu badilifu ya [name].


4.3 Vituo vya mwisho vya Mux (njia 8)

Mux ina muundo sawa wa vituo vya mwisho na CLIProxyAPI — hakuna njia ya rotate-key katika kiolesura cha API (tokeni ya bearer huzalishwa kwa njia sawa na ya 9Router kupitia getOrCreateApiKey("mux") na kuwekwa kupitia kigezo cha mazingira cha MUX_SERVER_AUTH_TOKEN, lakini bado hakuna kituo maalumu cha mwisho cha kuizungusha). Mux inadhibitiwa tu katika mzunguko wake wa maisha: tofauti na 9Router, haina kitekelezaji cha Safu ya 4 na kamwe haisajiliwi kama mtoa huduma wa uelekezaji.

Mbinu Njia Maelezo
POST /api/services/mux/install Sakinisha Mux kutoka npm (npm i mux)
POST /api/services/mux/start Anzisha Mux (mux server)
POST /api/services/mux/stop Simamisha Mux
POST /api/services/mux/restart Anzisha upya Mux
POST /api/services/mux/update Sasisha hadi toleo jipya zaidi la npm
GET /api/services/mux/status Hali ya moja kwa moja + DB
POST /api/services/mux/auto-start Washa au zima uanzishaji otomatiki

4.4 Vituo vya mwisho vya Bifrost (njia 8)

Bifrost ni mfumo wa nyuma wa relay wa lango la AI ulioandikwa kwa Go (@maximhq/bifrost). Hutumia muundo sawa wa vituo vya mwisho na CLIProxyAPI (hakuna rotate-key — Bifrost hudhibiti funguo zake za watoa huduma katika config.json chini ya -app-dir yake).

Mbinu Njia Maelezo
POST /api/services/bifrost/install Sakinisha Bifrost kutoka npm (@maximhq/bifrost)
POST /api/services/bifrost/start Anzisha Bifrost kwenye porti 8080 (chaguo-msingi)
POST /api/services/bifrost/stop Simamisha Bifrost
POST /api/services/bifrost/restart Anzisha upya Bifrost
POST /api/services/bifrost/update Sasisha hadi toleo jipya zaidi
GET /api/services/bifrost/status Hali ya moja kwa moja + DB
POST /api/services/bifrost/auto-start Washa au zima uanzishaji otomatiki
GET /api/services/bifrost/logs Mwisho wa kumbukumbu wa SSE (kupitia njia badilifu inayoshirikiwa ya [name]/logs)

Muunganisho wa uelekezaji: Wakati BIFROST_BASE_URL haijawekwa na nakala ya Bifrost inayosimamiwa inaendeshwa, getBifrostRoutingConfig() (katika routingBackend.ts) hutumia kiotomatiki http://127.0.0.1:{port} kama URL msingi ya relay. Kigezo cha mazingira cha BIFROST_BASE_URL kilichowekwa wazi hupewa kipaumbele kila wakati.


4.5 Vituo vya mwisho vya Dario (njia 12)

Muundo wa mzunguko wa maisha ni sawa na wa huduma nyingine (install, start, stop, restart, update, status, auto-start, auto-restart-adopted) pamoja na safu ya udhibiti ya OAuth inayolindwa kwa tokeni chini ya admin/: admin/accounts, admin/import-from-omniroute, admin/login-start, admin/login-complete (zote zikiwa nyuma ya DARIO_ADMIN_TOKEN).

4.6 Vituo vya mwisho vya open-wa (njia 7)

open-wa (@open-wa/wa-automate) huendesha nakala ya Chromium isiyo na kiolesura cha picha (kupitia Puppeteer) ili kuendesha WhatsApp Web kiotomatiki. Hutumia muundo sawa wa vituo vya mwisho na Mux (bado hakuna njia ya rotate-key). Inadhibitiwa tu katika mzunguko wake wa maisha — si lengwa la uelekezaji, haina ingizo la kitekelezaji/mtoa huduma wa Safu ya 4.

Mbinu Njia Maelezo
POST /api/services/openwa/install Sakinisha open-wa kutoka npm (@open-wa/wa-automate)
POST /api/services/openwa/start Anzisha open-wa kwenye porti 8323 (chaguo-msingi)
POST /api/services/openwa/stop Simamisha open-wa
POST /api/services/openwa/restart Anzisha upya open-wa
POST /api/services/openwa/update Sasisha hadi toleo jipya zaidi
GET /api/services/openwa/status Hali ya moja kwa moja + DB
POST /api/services/openwa/auto-start Washa au zima uanzishaji wa kiotomatiki
GET /api/services/openwa/logs Mwisho wa kumbukumbu wa SSE (kupitia njia badilifu ya pamoja ya [name]/logs)

Ufunguo wa API: huingizwa kama WA_KEY — ubatilishaji wa jumla wa mazingira wa open-wa wenye kiambishi awali cha WA_* huuweka kwenye chaguo la CLI la --key/-k (dist/cli/setup.js::envArgs(), imethibitishwa dhidi ya package iliyosakinishwa ya 4.76.0). Huongezewa kiambishi awali cha ow_ unapozalishwa na generateServiceApiKey(). open-wa husoma tena ufunguo kutoka kwenye kichwa cha HTTP cha key/api_key (si Authorization: Bearer); /api-docs* imeondolewa waziwazi kwenye ukaguzi (setupAuthenticationLayer katika dist/cli/server.js), kwa hivyo uchunguzi wa afya hauhitaji kichwa cha uthibitishaji.

Uoanishaji: open-wa si rasmi na haina uhusiano na WhatsApp — namba iliyounganishwa ina hatari ya kupigwa marufuku kutokana na utambuzi wa WhatsApp wenyewe wa otomatiki. Inapoanzishwa kwa mara ya kwanza, msimbo wa QR wa uoanishaji huchapishwa kwenye stdout na kuonyeshwa kupitia paneli iliyopo ya Kumbukumbu/mfululizo wa SSE — bado hakuna endpoint maalum ya picha ya QR katika muunganisho huu.


4.7 Proksi ya kinyume (upachikaji wa dashibodi ya 9Router)

Dashibodi hupachika UI ya wavuti ya 9Router ndani ya iframe kupitia proksi ya ndani ya kinyume kwenye:

GET|POST|... /dashboard/providers/services/9router/embed/[...path]

Proksi hii:

  • Husambaza ombi kwenda http://127.0.0.1:{port}/{path} (loopback pekee)
  • Huondoa vichwa vinavyoingia vya cookie na authorization (hakuna kuvuja kwa kipindi cha OmniRoute)
  • Huingiza Authorization: Bearer {apiKey} kwa ajili ya uthibitishaji wa 9Router
  • Huondoa set-cookie, content-security-policy, x-frame-options, cross-origin-* kutoka kwenye jibu
  • Huandika upya majibu ya HTML ili kuingiza <base href> na kusawazisha njia kamili (/foo → /dashboard/.../embed/foo)

Masasisho ya WebSocket kwa dashibodi iliyopachikwa hushughulikiwa na seva saidizi kwenye porti maalum (tazama src/lib/services/embedWsProxy.ts).

Usalama: Njia za proksi ya upachikaji zimeainishwa chini ya LOCAL_ONLY_API_PREFIXES na zinaweza kufikiwa kutoka loopback pekee. Mshambulizi anayepata JWT kupitia handaki la Cloudflare/Ngrok hawezi kuingia kwenye huduma zilizopachikwa kupitia proksi.


5. Usalama

Utekelezaji wa LOCAL_ONLY (kanuni thabiti #17)

Njia zote zilizo chini ya /api/services/ na /dashboard/providers/services/*/embed/ zinaainishwa kama LOCAL_ONLY katika src/server/authz/routeGuard.ts. Ukaguzi wa loopback huendeshwa bila masharti kabla ya tawi lolote la uthibitishaji:

ombi linawasili
  → isLocalOnlyPath(path)?
      → si loopback → 403 LOCAL_ONLY (daima, kabla ya ukaguzi wa uthibitishaji)
      → loopback    → endelea hadi uthibitishaji wa kawaida

Hii huzuia JWT iliyovuja (kwa mfano, kupitia tunnel) kuanzisha npm install au kuanzisha michakato. Tazama docs/security/ROUTE_GUARD_TIERS.md kwa matriki kamili ya viwango.

Uingizaji wa ufunguo wa API

9Router na Mux zinahitaji ufunguo wa API/tokeni ya bearer kwa endpoint zao za HTTP. OmniRoute:

  1. Hutengeneza ufunguo kupitia crypto.randomBytes(32).toString("base64url") wenye kiambishi awali mahususi kwa huduma (nr_ kwa 9Router, mx_ kwa Mux).
  2. Huusimba kwa njia fiche ukiwa umehifadhiwa kwa kutumia AES-256-GCM (algoriti ileile ya usimbaji inayotumika kwa vitambulisho vya watoa huduma).
  3. Huusimbua na kuuingiza kama kigezo cha mazingira wakati wa kuanzisha mchakato — NINEROUTER_API_KEY kwa 9Router, MUX_SERVER_AUTH_TOKEN kwa Mux (kamwe si chaguo la CLI, hivyo tokeni haionekani kamwe katika ps/orodha za michakato).
  4. Hairudishi kamwe ufunguo wa maandishi wazi katika jibu lolote la HTTP.

CLIProxyAPI hupokea ufunguo maalumu wa data-plane unaoingizwa wakati wa kuanzisha mchakato (needsApiKey: true — hutumika kwa ulandanishaji wa modeli dhidi ya adapter).

Ulinzi dhidi ya SSRF

Proksi ya HTTP ya kinyume (/dashboard/.../embed/[...path]) imewekwa moja kwa moja kuelekeza tu kwa http://127.0.0.1:{port}. Haifuati kamwe uelekezaji upya kwenda kwenye maeneo yasiyo ya loopback. Maktaba ya ssrf-req-filter hutumika kukataa URL yoyote ya upstream ambayo hutatuliwa nje ya masafa ya loopback.

Usalama wa shell (kanuni thabiti #13)

npm install huitwa kupitia execFile('npm', ['install', pkg, '--prefix', dir]) — hakuna template literals, hakuna shell, wala uingizaji wa njia za nje katika mfuatano wa amri. Thamani za wakati wa utekelezaji (porti, funguo za API) hupitishwa kupitia kitu cha env cha mchakato mtoto.

Usafishaji wa hitilafu (kanuni thabiti #12)

Majibu yote ya hitilafu kutoka /api/services/* hupitia buildErrorBody() au sanitizeErrorMessage(). err.stack na err.message ghafi hazirudishwi kamwe kama zilivyo kwa mwombaji.


6. Kuongeza huduma mpya iliyopachikwa

Fuata hatua hizi 8. Soma utekelezaji uliopo katika src/lib/services/installers/ na src/app/api/services/ kama marejeleo rasmi.

Hatua ya 1 — Unda kisakinishaji

Unda src/lib/services/installers/{name}.ts kwa kufuata muundo wa ninerouter.ts:

export const NAME_PACKAGE = "your-npm-package";
export const NAME_DEFAULT_PORT = 20132; // chagua porti iliyo wazi

export async function install(version = "latest"): Promise<InstallResult> { ... }
export async function update(version = "latest"): Promise<InstallResult> { ... }
export async function uninstall(): Promise<void> { ... }
export function resolveSpawnArgs(apiKey: string, port: number): SpawnArgs { ... }
export async function getInstalledVersion(): Promise<string | null> { ... }
export async function getLatestVersion(): Promise<string | null> { ... }

Tumia runNpm(['install', NAME_PACKAGE, '--prefix', dir]) kutoka installers/utils.ts — kamwe usitumie execSync au uingizaji wa thamani kupitia shell.

Hatua ya 2 — Sajili katika bootstrap

Ongeza ServiceEntry kwenye safu ya SERVICES katika src/lib/services/bootstrap.ts:

{
  tool: "myservice",
  port: NAME_DEFAULT_PORT,
  healthPath: "/health",
  healthIntervalMs: 5_000,
  stopTimeoutMs: 15_000,
  logsBufferBytes: 5_242_880,
  needsApiKey: true, // false ikiwa ufunguo wa API hauhitajiki
}

Panua buildSpawnArgsFactory() ili kushughulikia cfg.tool === "myservice".

Mkataba wa provider-plugin unaoweza kuchomekwa (Awamu ya 1, #7333)

src/lib/services/providerPlugins/ inaanzisha mkataba wa ServiceProviderPlugin ambao huunganisha sehemu za ServiceEntry za bootstrap.ts ya backend na sehemu za kiolezo cha manifest za serviceBackends.ts kuwa kitu kimoja, badala ya muundo wa backend ileile kuwakilishwa kando katika faili mbili zisizohusiana. Kufikia wakati huu wa uandishi ni 9router pekee iliyohamishwa — bootstrap.ts huzalisha ingizo lake la SERVICES[] kutoka getServiceProviderPlugin("9router") (src/lib/services/providerPlugins/registry.ts), na kutoa hitilafu ya uanzishaji ikiwa plugin hiyo itakosekana. cliproxy, mux, na bifrost zinasalia bila kubadilishwa kwenye literal za SERVICES[] za ndani zilizokuwepo awali.

open-sse/config/providerPluginManifest.ts pia imepata kitendaji saidizi cha nyongeza cha createServiceBackendManifestEntry(pluginId, template) ambacho huunda ProviderPluginManifestEntry yenye muundo sahihi kutoka kwenye ingizo la SERVICE_BACKEND_MANIFEST_TEMPLATE — bado hakijaunganishwa kwenye njia yoyote hai ya maombi (si generateProviderPluginManifestFromRegistry() wala /v1/providers/[provider]/models); hilo litasubiri kazi ya ufuatiliaji baada ya mkataba kuthibitishwa kwa backend ya pili.

Yaliyoahirishwa hadi PR za ufuatiliaji, yanayofuatiliwa chini ya suala #7333: kuhamisha cliproxyapi kupitia registry ileile, kufanya mux/bifrost kuwa za jumla ndani ya muungano wa ServiceBackendPluginId, kuunganisha hali maalumu za uelekezaji wa executor (open-sse/executors/index.ts, open-sse/handlers/chatCore/executorProxy.ts) ndani ya mkataba wa plugin, na kuunganisha createServiceBackendManifestEntry() kwenye njia hai ya msimbo ya manifest/modeli.

Hatua ya 3 — Ongeza uhamishaji na data ya awali ya DB

Hakikisha huduma ina safu katika version_manager kupitia uhamishaji katika src/lib/db/migrations/. Safu hiyo inapaswa kuwa na:

INSERT OR IGNORE INTO version_manager (tool, status, auto_start, provider_expose)
VALUES ('myservice', 'not_installed', 0, 0);

Hatua ya 4 — Unda endpoint 7 za API

Chini ya src/app/api/services/{name}/:

_lib.ts            kitendaji saidizi cha getOrInitSupervisor()
install/route.ts   POST — huita installer.install()
start/route.ts     POST — huita supervisor.start()
stop/route.ts      POST — huita supervisor.stop()
restart/route.ts   POST — huita supervisor.restart()
update/route.ts    POST — huita installer.update()
status/route.ts    GET  — huunganisha hali ya moja kwa moja + hali ya DB
auto-start/route.ts POST — hubadilisha hali ya alama ya auto_start

Njia ya pamoja ya GET /api/services/[name]/logs tayari imeunganishwa — hakuna mabadiliko yanayohitajika hapo.

Kabidhi majibu yote ya hitilafu kupitia createErrorResponse() / buildErrorBody().

Hatua ya 5 — Ongeza kwenye LOCAL_ONLY_API_PREFIXES

Katika src/server/authz/routeGuard.ts, hakikisha kwamba /api/services/ tayari imeorodheshwa. Ukiweka kiambishi awali kipya (kwa mfano, /api/tools/), kiongeze kwenye LOCAL_ONLY_API_PREFIXES na, ikiwa kinaanzisha michakato, kwenye SPAWN_CAPABLE_PREFIXES. Ongeza jaribio katika tests/unit/authz/routeGuard.test.ts.

Hatua ya 6 — Ongeza kichupo cha UI

Unda src/app/(dashboard)/dashboard/providers/services/tabs/{Name}ServiceTab.tsx. Tumia tena vijenzi vya pamoja:

  • ServiceStatusCard — hali ya moja kwa moja + beji ya afya
  • ServiceLifecycleButtons — Anzisha / Simamisha / Anzisha upya / Sasisha
  • ServiceLogsPanel — mwendelezo wa kumbukumbu za SSE (huunganisha kwenye /api/services/{name}/logs)
  • ApiKeyCard — onyesha ufunguo + badilisha (ikiwa needsApiKey: true)

Sajili kichupo katika ServicesPageShell.tsx.

Hatua ya 7 — Ongeza ingizo la mtoa huduma (ikiwa huduma ni lengwa la uelekezaji)

Ikiwa huduma iliyopachikwa inafichua endpoint ya /v1/chat/completions inayooana na OpenAI:

  1. Ongeza ingizo la mtoa huduma katika src/shared/constants/providers.ts lenye isEmbeddedService: true.
  2. Unda open-sse/executors/{name}.ts inayopanua BaseExecutor. Tafuta upya porti na ufunguo wa API kwa kila ombi (usivihifadhi kamwe kwenye constructor). Rudisha jibu la 503 service_not_running wakati hali ya msimamizi si "running".
  3. Sajili modeli katika open-sse/config/providerRegistry.ts ukitumia kiambishi awali cha huduma (kwa mfano, myservice/sub/model). modelSync.ts itazisasisha.

Hatua ya 8 — Andika nyaraka na ufanye majaribio

  1. Sasisha docs/frameworks/EMBEDDED-SERVICES.md (faili hii) — ongeza huduma kwenye jedwali katika §1 na endpoint zozote mpya kwenye §4.
  2. Ongeza majaribio ya kitengo katika tests/unit/services/ (mzunguko wa maisha, kisakinishaji, muundo wa API).
  3. Ongeza jaribio la ujumuishaji katika tests/integration/services/ (nyuma ya RUN_SERVICES_INT=1).
  4. Sasisha docs/openapi.yaml kwa endpoint mpya.

7. Utatuzi wa matatizo

Huduma haianzi

Dalili: Kitufe cha kuanzisha kinarejesha 503, hali inabaki "error" au "starting".

Orodha ya ukaguzi:

  1. Angalia GET /api/services/{name}/logs (au paneli ya Kumbukumbu kwenye dashibodi). Tafuta mistari kama Error: ENOENT, address already in use, au Cannot find module.
  2. Thibitisha kuwa npm iko katika PATH: tumia which npm kutoka kwenye akaunti ileile ya mtumiaji inayoendesha OmniRoute.
  3. Thibitisha kuwa huduma imesakinishwa: angalia GET /api/services/{name}/status kwa installedVersion. Ikiwa ni null, endesha usakinishaji kwanza.
  4. Angalia kuwa DATA_DIR/services/{name}/node_modules/ ipo na si tupu.
  5. Angalia uga wa lastError katika jibu la hali ili kuona sababu ya kusitishwa iliyosafishwa.

Uanzishaji wa kwanza ni wa polepole (> sekunde 10 kufikia running)

Dalili: Hali inabaki "starting" kwa muda mrefu kabla ya kubadilika kuwa "running" au "error".

Maelezo: Uanzishaji wa kwanza wa 9Router unajumuisha kuleta miti mikubwa ya vitegemezi (DNS, tunnel, moduli za MITM). Kipindi chaguo-msingi cha ukaguzi wa afya ni sekunde 2, huku majaribio 3 yakifanywa kabla msimamizi hajatangaza kuisha kwa muda (lakini anaendelea kufanya ukaguzi).

Suluhisho: healthIntervalMs na muda wa kuisha wa waitForHealthy (healthIntervalMs * 3) zinaweza kusanidiwa katika bootstrap.ts. Kwa huduma zenye muda mrefu zaidi wa kuanza, ongeza healthIntervalMs hadi 5000 na stopTimeoutMs hadi 30 000.


Mgongano wa mlango (EADDRINUSE)

Dalili: Kumbukumbu zinaonyesha address already in use :::20130.

Sababu:

  • Mchakato mwingine tayari unatumia mlango 20130.
  • Mchakato wa awali wa 9Router haukusimamishwa kikamilifu (PID mfu).

Suluhisho:

  1. Badilisha mlango chaguo-msingi kupitia kigezo cha mazingira cha NINEROUTER_PORT katika .env.
  2. Tafuta na usitishe mchakato unaogongana: lsof -ti :20130 | xargs kill -9.
  3. Mlango unaweza kusanidiwa kwa kila huduma katika bootstrap.ts kupitia uga wa port.

Kumbuka: 9Router hutumia mlango 20130 kwa chaguo-msingi mahsusi ili kuepuka kugongana na mlango chaguo-msingi wa OmniRoute wa 20128.


Ruhusa imekataliwa (EACCES) wakati wa usakinishaji

Dalili: Usakinishaji unarejesha 500, kumbukumbu zinaonyesha EACCES au permission denied.

Sababu:

  • DATA_DIR au saraka kuu yake haiwezi kuandikwa na mchakato wa OmniRoute.
  • Inaendeshwa ndani ya Docker rootless bila ruhusa ya kuandika kwenye volume iliyounganishwa.

Suluhisho:

  1. Angalia DATA_DIR (chaguo-msingi: ~/.omniroute/): ls -la ~/.omniroute/
  2. Hakikisha mtumiaji wa mchakato wa OmniRoute anamiliki saraka: chown -R $USER ~/.omniroute/
  3. Katika Docker, hakikisha volume mount ina ruhusa sahihi kwa mtumiaji wa container.

Usasishaji unashindwa (kuisha kwa muda wa npm install au hitilafu ya mtandao)

Dalili: Usasishaji unarejesha 500 ikiwa na InstallError, kumbukumbu zinaonyesha kuisha kwa muda wa mtandao.

Orodha ya ukaguzi:

  1. Thibitisha kuwa sajili ya npm inaweza kufikiwa: npm ping.
  2. Angalia kama kuna proksi ya shirika: npm config get proxy, npm config get https-proxy.
  3. Jaribu usakinishaji mwenyewe: npm install {package}@latest --prefix ~/.omniroute/services/{name}/.
  4. Ikiwa uko nyuma ya air-gap, pakua tarball mapema na utumie npm install /path/to/tarball.tgz.

Huduma inaonyesha hali ya "error" mara tu baada ya kuanzishwa (kuvurugika kwa haraka)

Dalili: Hali inabadilika kutoka "starting" hadi "error" ndani ya chini ya sekunde 5. lastError inaonyesha "Fast crash (exited with code 1)".

Orodha ya ukaguzi:

  1. Soma sehemu kamili ya mwisho ya kumbukumbu: GET /api/services/{name}/logs?tail=500.
  2. Sababu ya kawaida: kukosekana kwa vigezo vya mazingira vinavyotarajiwa na huduma.
  3. Kwa 9Router: thibitisha kuwa NINEROUTER_DISABLE_MITM=true na NINEROUTER_DISABLE_TUNNEL=true zimo katika env inayopitishwa wakati wa spawn (angalia installers/ninerouter.ts resolveSpawnArgs).

8. Maswali Yanayoulizwa Mara kwa Mara

Swali: Je, ninaweza kufichua endpoint za huduma zilizopachikwa kwa wateja wasio wa loopback?

Hapana. Ngazi ya LOCAL_ONLY imekusudiwa hivyo (sheria ngumu #17). Routes zinazoweza kutekeleza npm install au kuanzisha michakato ya node lazima zisifikiwe na trafiki isiyo ya loopback, kwa sababu JWT iliyovuja kupitia tunnel (Cloudflare, Ngrok, Tailscale) ingeweza kuruhusu kuanzishwa kwa michakato kiholela. Hakuna msamaha wa hiari kwa /api/services/ — tofauti na /api/mcp/, haijumuishwi kwenye orodha ya kupita ukaguzi wa manage-scope. Angalia docs/security/ROUTE_GUARD_TIERS.md.


Swali: Je, 9Router na CLIProxyAPI zitapatikana katika upelekaji wa uzalishaji/cloud?

Ndiyo. Huduma zote mbili zinafuata muundo uleule unaotanguliza mazingira ya ndani kama OmniRoute yenyewe. Huendeshwa kwenye mashine hiyo hiyo na kuwasiliana kupitia loopback. "Uzalishaji" hapa unamaanisha VPS au seva ya ndani ambako OmniRoute imepelekwa, si mtoa huduma wa cloud wa mbali.


Swali: Ninawezaje kutatua hitilafu za supervisor?

  1. Fuatilia mtiririko wa logi wa SSE: curl -N http://localhost:20128/api/services/9router/logs.
  2. Kagua logi zilizoundwa kwa muundo katika matokeo ya pino ya OmniRoute, yaliyochujwa kwa namespace ya service:supervisor.
  3. Kagua safu ya DB: sqlite3 ~/.omniroute/omniroute.db "SELECT * FROM version_manager WHERE tool='9router'".
  4. Tumia GET /api/services/9router/status kuona hali ya sasa ya moja kwa moja, PID, afya, na lastError kwa ombi moja.

Swali: Supervisor inaonyesha health: "degraded" au health: "unknown" lakini hali ni "running". Je, hilo ni tatizo?

"degraded" inamaanisha uchunguzi wa afya ulirudisha jibu lisilo la 200. "unknown" inamaanisha hakuna uchunguzi ambao umekamilika bado (mkanganyiko wa muda na upigaji kura wa kwanza). Hali zote mbili ni za muda wakati wa kuanza. Ikiwa afya itaendelea kuwa "degraded" kwa zaidi ya ms healthIntervalMs * 3 baada ya "running", huduma iliyopachikwa inaendeshwa lakini HTTP API yake haijibu. Kagua ikiwa port ni sahihi katika jibu la hali na ikiwa huduma kwa hakika inasikiliza kwenye port hiyo.


Swali: Je, ninaweza kubadilisha ufunguo wa API wa 9Router bila kuanzisha upya kikamilifu?

Hapana. Ufunguo wa API hupitishwa kwa 9Router kupitia environment variable wakati wa kuanzisha mchakato. Environment variables haziwezi kubadilishwa katika mchakato unaoendelea. POST .../rotate-key husimamisha na kuanzisha upya huduma kiotomatiki ili kutumia ufunguo mpya. Mzunguko wa ufunguo unaanza kutumika ndani ya stopTimeoutMs ya huduma (chaguo-msingi sekunde 15) pamoja na muda wake wa kuanza.


Swali: Kikomo cha ring buffer ni kipi na nini hutokea inapojaa?

Kila huduma ina ring buffer yake maalumu ya MB 5. Buffer inapojaa, mistari ya zamani zaidi ya logi huondolewa ili kutoa nafasi kwa mipya. Tukio la SSE snapshot hurudisha mistari ya hivi karibuni zaidi ndani ya kikomo cha tail. Logi hazihifadhiwi kwenye diski isipokuwa logsBufferPath iwe imewekwa katika safu ya DB.


Angalia pia

  • docs/security/ROUTE_GUARD_TIERS.md — maelezo ya ngazi ya LOCAL_ONLY
  • docs/architecture/CODEBASE_DOCUMENTATION.md — §3.2 ulinganishaji wa moduli ya Huduma Zilizopachikwa
  • docs/architecture/ARCHITECTURE.md — muktadha wa kiwango cha mfumo
  • docs/openapi.yaml — ufafanuzi wa endpoint unaosomeka na mashine
  • CLAUDE.md §"Adding a New Embedded Service" — orodha ya ukaguzi ya marejeleo ya haraka