@startuml components title TextMachine — компоненты бэкенда (MVP, v2 2026-07-04, после ревью) skinparam componentStyle rectangle skinparam wrapWidth 200 package "Интерфейсы" { [CLI tmctl] as CLI [HTTP API\n(для будущей IDE)] as API } package "Оркестратор" { [Проект книги\n(translation brief, конфиг ядра C1/C2/C3)] as PROJ [Импорт txt/epub\n(сегментация: главы -> чанки)] as IMP [Durable jobs\n(глава x стадия + чанк-чекпоинты, resume)] as JOBS [Пайплайн-раннер\n(циклы/ветвления/эскалация = код,\nсостав стадий/модели/пороги = конфиг)] as RUNNER [Экспорт txt/epub/TMX\n+ отчёт (журнал вклада)] as EXP } package "Агентные роли (промпт-конфиги)" { [Analyst\nbook brief] as ROLE_AN [Terminologist\nглоссарий + style sheet] as ROLE_TERM [Translator(ы)\nчерновик / N кандидатов] as ROLE_TR [Stylist / Editor\nрусский стиль] as ROLE_ED [Line Editor (Фаза 2+)\nчек-лист Галь] as ROLE_LE [Continuity Editor (Фаза 2+)\nseries bible] as ROLE_CE [Judge / Selector\nшкала Комиссарова] as ROLE_JU } package "QA-гейты (без LLM)" { [Морфодетектор канцелярита] as QA_MORPH [Детектор CJK-артефактов] as QA_CJK [Глоссарная консистентность >= 98%] as QA_GLOS [Полнота покрытия предложений\n(анти-omission / вырезания)] as QA_COV } package "pkg/llm (ядро из vojo + новое)" { [Роутер роль -> модель] as LLM_RT [Контент-роутер NSFW\n(каналы A/B, уровень 3 = отказ)] as LLM_NSFW [Failover local -> cloud\n(circuit breaker)] as LLM_FO [Адаптеры: DeepSeek / Qwen / GLM /\nGemini / Anthropic / xAI / llama-server] as LLM_AD [Prompt-cache раскладка префикса\n+ Batch API (Фаза 2, батчуемые стадии)] as LLM_BC } package "Банк памяти книги (SQLite на книгу)" { [Глоссарий\n(род, речь, склонения, спойлер-окна)] as MEM_GLOS [Резюме\nглава -> арка -> книга] as MEM_SUM [Series bible\n(персонажи, матрица ты/вы)] as MEM_SB [TM-кэш переводов] as MEM_TM [Векторный индекс (Фаза 2)\n(BLOB + brute-force KNN, bge-m3;\nбез sqlite-vec — pure-Go драйвер)] as MEM_VEC [Селективная инъекция\n(детерминированный отбор в промпт)] as MEM_INJ } package "Деньги и наблюдаемость" { [Ledger: reserve/settle,\nпотолки $ на книгу/день] as OBS_LG [Премиум-бюджет книги\n(<= 2x объёма дорогими моделями)] as OBS_QB [request_log + trace\n(токены, $, cache-hit, вердикты)] as OBS_TEL } package "Eval (оффлайн)" { [Golden-set реплей\n(паттерн routereval)] as EV_GS [CometKiwi сайдкар (Python)] as EV_CK [Refusal/excision бенчмарк 18+] as EV_RB } cloud "LLM-провайдеры" { [DeepSeek V4] as P_DS [Gemini 3.x] as P_GM [Anthropic\n(только уровни 0-1)] as P_AN [xAI Grok\n(канал B)] as P_XA [OpenRouter / агрегаторы / BYOK] as P_OR [llama-server\n(GPU 8GB: скрининг, abliterated, эмбеддинги)] as P_LL } database "SQLite" as DB CLI --> PROJ API --> PROJ PROJ --> IMP IMP --> JOBS RUNNER --> EXP JOBS --> RUNNER RUNNER --> ROLE_AN RUNNER --> ROLE_TERM RUNNER --> ROLE_TR RUNNER --> ROLE_ED RUNNER --> ROLE_LE RUNNER --> ROLE_CE RUNNER --> ROLE_JU RUNNER --> QA_MORPH RUNNER --> QA_CJK RUNNER --> QA_GLOS RUNNER --> QA_COV ROLE_TR --> LLM_RT ROLE_ED --> LLM_RT ROLE_JU --> LLM_RT ROLE_AN --> LLM_RT ROLE_TERM --> LLM_RT ROLE_LE --> LLM_RT ROLE_CE --> LLM_RT LLM_RT --> LLM_NSFW LLM_NSFW --> LLM_FO LLM_FO --> LLM_AD LLM_BC --> LLM_AD LLM_AD --> P_DS LLM_AD --> P_GM LLM_AD --> P_AN LLM_AD --> P_XA LLM_AD --> P_OR LLM_AD --> P_LL LLM_NSFW ..> P_LL : классификатор 0-3 RUNNER --> MEM_INJ MEM_INJ --> MEM_GLOS MEM_INJ --> MEM_SUM MEM_INJ --> MEM_SB MEM_INJ ..> MEM_VEC : Фаза 2, не в горячем пути RUNNER --> MEM_TM : коммит перевода RUNNER --> MEM_GLOS : новые термины RUNNER --> MEM_SUM : обновление резюме RUNNER --> MEM_SB : род, ты/вы LLM_RT --> OBS_LG OBS_LG --> OBS_QB LLM_AD --> OBS_TEL RUNNER --> OBS_TEL JOBS --> DB MEM_GLOS --> DB MEM_SUM --> DB MEM_SB --> DB MEM_TM --> DB MEM_VEC --> DB OBS_TEL --> DB OBS_LG --> DB EV_GS ..> OBS_TEL : реплей решений EV_CK ..> OBS_TEL : оценка качества EV_RB ..> LLM_NSFW : калибровка роутинга @enduml