project-overview

Stack AI: карта проєкту

Цей документ ділить stack-ai на основні частини і пояснює, навіщо кожна з них існує. Детальні документи по сервісах лежать у index, по процесах - у index, по базі й інфраструктурі - у index.

Що таке stack-ai

stack-ai - backend-сервіс для AI-задач BeSocial/Stack. У поточному вигляді в ньому є два великі домени:

  1. Legend - генерація Lady Legend для TU: canon, timeline, facts, narrative blocks, full text, translations і QA.
  2. Tips / Memory - допомога оператору в діалозі RU>TU: синхронізація даних, векторна пам’ять, retrieval, LLM-аналіз контексту і генерація 3 варіантів відповіді.

Це не основний Stack backend і не Electron-клієнт. stack-ai стоїть поруч: приймає запити від внутрішніх клієнтів, ходить в upstream API партнерських сайтів, читає/пише Supabase і викликає LLM-провайдерів.

Головна бізнес-ідея

Оператор не має відповідати “з повітря”. Хороший AI-помічник повинен знати:

  • хто такий RU;
  • хто така TU;
  • яка в них історія спілкування;
  • які є notes;
  • які дані профілю актуальні;
  • що вже було сказано раніше;
  • який режим відповіді потрібен зараз;
  • які факти не можна порушувати.

Тому в проєкті є два різні механізми пам’яті:

МеханізмДля чого
Legend pipelineСтворює структурований фон TU: біографія, характер, дитинство, плани, блоки легенди
Vector memoryЗберігає історію конкретного діалогу RU>TU: profile, photo, notes, conversation chunks

Legend відповідає на питання “яка легенда у TU?“. Tips/memory відповідає на питання “що зараз написати цьому RU в цьому діалозі?“.

Частини проєкту

ЧастинаКодДокументаціяРоль
Runtime / Nest shellsrc/main.ts, src/app.module.ts, src/common/*runtimeGlobal prefix, wrapper responses, errors, validation, Swagger
Auth / rolessrc/auth/*, src/common/stack-roles.enum.tsauthJWT parsing, role gates, @ApiRoles
Configsrc/settings.ts, src/modules/tips-memory/tips-memory-config.service.tsconfigEnv, provider keys, Supabase config, defaults
Supabase / DBsrc/database/*, supabase/migrations/*supabasePostgres, pgvector, snapshots, token usage
Legendsrc/modules/legend/*legend-serviceLady Legend pipeline
Tips APIsrc/modules/tips/*tips-serviceАктуальна orchestration-логіка /tips/status і /tips/generate
Experimental tips-memory APIsrc/modules/tips-memory/tips-memory.controller.tstips-memory-controllerDebug/experimental endpoints для memory і assistant workflow
Memorysrc/modules/tips-memory/memory.service.tsmemory-service, memory-chunkIngest/search chunks у Supabase pgvector
Assistantsrc/modules/tips-memory/services/assistant-service.tsassistant-serviceLLM workflow: photo/context/drafts/evaluate/repair
AI providersgemini-provider.service.ts, xai-provider.service.tsai-providersЄдиний transport Gemini/xAI structured JSON
Upstreamsrc/upstream/*, src/modules/tips/services/*upstream-serviceЗабір profiles/messages/notes із зовнішніх систем
Token usagesrc/modules/tips/services/token-usage.service.tstoken-usage-serviceОблік вартості LLM calls

Як читати проєкт

Якщо потрібно зрозуміти весь runtime, читати в такому порядку:

  1. runtime - як Nest-застосунок обгортає відповіді й помилки.
  2. auth - які ролі реально закривають endpoints.
  3. project-overview - ця карта.
  4. tips-service - актуальний користувацький flow генерації відповіді.
  5. generation-pipeline - детальна покрокова механіка generate.
  6. memory-service і supabase - як працює long-term memory.
  7. assistant-service і ai-providers - як викликаються LLM.
  8. legend-service - окремий домен Lady Legend.

Якщо задача тільки про базу, йти одразу в supabase. Якщо задача про Swagger/API, звіряти docs з DTO і controller code.

Межі доменів

Legend

Legend не залежить від vector memory і не пише результат у Supabase. Його стан живе в LegendJobStore in-memory. Він працює як staged async pipeline: один stage на один запит, результат забирається polling-ом.

Це важливо: Legend не можна вважати durable storage. Якщо frontend хоче зберегти підсумкову легенду, він має зберегти її сам або викликати окремий зовнішній сервіс.

Tips

Tips - актуальний шар для Electron-клієнта оператора. Він працює по парі ruId + tuId і family. Його задача:

  1. Перевірити, що вже є в Supabase.
  2. Підтягнути свіжі дані з upstream.
  3. Оновити vector memory.
  4. Вибрати top chunks.
  5. Запустити assistant workflow.
  6. Записати token usage.
  7. Повернути оператору варіанти відповіді.

Зараз є важливий gap: POST /stack-ai/tips/generate уже виконує майже весь workflow, але HTTP response поки повертає hardcoded 3 рядки замість workflow.assistantOutput.drafts. Це окремо описано в generation-pipeline.

tips-memory

tips-memory - експериментальний і debug-friendly API, який залишився поруч із новим tips flow. Він корисний для ручного ingest/search/analyze/workflow, але стратегічно новий користувацький flow має жити навколо TipsController.

Supabase

Supabase - durable шар для:

  • vector memory (client_memory_chunks);
  • daily snapshots (tips_daily_entity_snapshots);
  • token usage (token_usage_log);
  • SQL RPC для retrieval (match_client_memory_chunks).

Legend туди зараз не пише.

TODO: аналіз фото як окремий шар пам’яті

Зараз у tips-flow у базу фактично потрапляє URL фото з профілю, а не стабільний текстовий опис самого зображення. Це слабке місце: LLM під час генерації може отримувати photoUrl, але long-term memory не має нормального опису зовнішності, стилю фото, емоції, одягу, локації чи видимих деталей.

Потрібно додати окремий шар:

  1. Взяти photo URL з профілю TU або RU.
  2. Завантажити фото.
  3. Проаналізувати його через vision model.
  4. Перетворити результат у короткий структурований текст.
  5. Записати цей текст у client_memory_chunks як source='photo'.
  6. Використовувати саме цей текст у retrieval, а не передавати сирий screenshot/image у кожен prompt.

Детальний план: photo-analysis-ingest і photo-analysis.

Простими словами про складні терміни

ТермінПросте пояснення
PipelineПослідовність етапів, де кожен етап бере результат попереднього і додає новий шар
Canon”Залізна” база фактів, якій не можна суперечити далі
AnchorВажлива точка або період життя, на якому будується біографія
Fact bankВеликий список маленьких фактів, з яких потім збирається текст
ChunkМалий шматок пам’яті діалогу, який можна шукати через embedding
EmbeddingЧисловий вектор сенсу тексту; потрібен, щоб шукати не по словах, а по змісту
RetrievalВибір релевантних chunks із пам’яті перед LLM-викликом
Source weightНевеликий boost для важливіших джерел пам’яті, наприклад notes важливіші за звичайну переписку
Daily syncОдин раз на день оновити profile/photo/notes і записати snapshots
SnapshotСирий знімок даних для cache/audit, не обов’язково використовується у vector search
Token usageОблік, скільки токенів витратив кожен LLM call
FallbackЗапасний шлях, якщо основний зовнішній сервіс недоступний

Потік даних у Tips

Electron
  |
  v
POST /stack-ai/tips/generate
  |
  v
DailySyncService -----> upstream profiles/notes
  |                         |
  v                         v
Supabase snapshots    MemoryService ingest
  |                         |
  v                         v
MessagesService -----> upstream messages
  |
  v
fresh messages -> snapshots + vector chunks
  |
  v
MemoryService.search -> selectedChunks
  |
  v
AssistantService -> Gemini/xAI
  |
  v
TokenUsageService -> token_usage_log
  |
  v
HTTP response

Потік даних у Legend

Frontend
  |
  v
POST /stack-ai/legend/generate-profile
  |
  v
LegendJobStore running job
  |
  v
stage_0_canon -> stage_1_anchors -> stage_2_fact_bank -> stage_3_blocks
  |
  v
POST /stack-ai/legend/status
  |
  v
result.pipeline

Що зараз вважається стабільним

  • Supabase memory schema і match_client_memory_chunks описані як core для tips.
  • MemoryService.ingest/search/getDialogStatus - основний шар роботи з vector memory.
  • DailySyncService.syncFirstClick - основний механізм daily refresh.
  • AssistantService.runWorkflow - основний LLM workflow, хоча response /tips/generate ще не підключений до його drafts.
  • Legend staged pipeline - окремий async service, але без durable persistence.

Головні ризики

  • HTTP errors завжди 200: клієнти мають дивитися success, а не HTTP status.
  • RolesGuard пропускає endpoint без @ApiRoles: забутий decorator відкриває route.
  • Legend jobs in-memory: restart backend видаляє status/result.
  • /tips/generate response ще placeholder: workflow уже працює, але drafts не повертаються.
  • Upstream реалізований не для всіх families: зараз багато routes є тільки для golden; інші кидають NotImplementedException.
  • Supabase retrieval залежить від Gemini embeddings: без API key ingest/search падають.
  • Debug tips-memory і новий tips flow співіснують: важливо не плутати endpoints.
  • Photo memory ще неповна: потрібно зберігати не тільки URL фото, а й текстовий vision-аналіз.

Пов’язані документи