Files
iistwin/.superpowers/sdd/di2-embed/task-1-report.md
Ильяс Султанов 254950f151 DI2 внедрение, таск 1: серверная интеграция Data-Insight2 (server/finance-di2)
- Копия DI2-сервера в server/finance-di2/ с правками: schema/db-client/cache/table-config/override-tables/google-auth/audit-agent/routes
- db-client — обёртка над существующим пулом server/finance/db-client (второй пул не создаётся, добавлен экспорт isConnectionError)
- ai-config.ts — чистое IO конфигов из ai-agent.ts без Telegram-поллинга; роуты /api/ai/toggle и /api/ai/status удалены, без compression/startAuditScheduler/autoStartIfEnabled
- Обёртка registerDi2Routes с auth-gate (authenticateToken + finance.manage), регистрация строго перед registerFinanceRoutes
- Статика /di2 из dist/public-di2 перед веткой vite/static (dev и prod)
- Фикс предсуществующего бага DI2: buildGlobalExclusionConditions без cats в /api/profitability
2026-09-06 19:27:43 +03:00

7.4 KiB
Raw Blame History

Task 1 — Серверная интеграция Data-Insight2: отчёт

Статус: DONE

Что сделано

Новая папка server/finance-di2/

  • schema.ts — копия tmp/Data-Insight2/shared/schema.ts (чистые типы/константы, zod).
  • db-client.ts — НЕ копия DI2, а обёртка поверх server/finance/db-client.ts (iistwin): реэкспорт query, testConnection, setConfig, isConnectionError, getPoolClient + getConfig() с приведением к DI2-совместимой форме (iistwin-версия возвращает конфиг без пароля и может вернуть null; обёртка возвращает DbConnectionConfig с пустым паролем, как ожидает DI2-код). Второй пул не создаётся.
  • cache.ts, table-config.ts, override-tables.ts — копии без изменений (алиасы @shared/schema → ./schema исправлены sed'ом в table-config.ts и routes.ts; override-tables/cache и так используют ./db-client).
  • google-auth.ts — копия, getRedirectUri() переделан: process.env.APP_BASE_URL || "https://iistwin.ru", redirect ${APP_BASE_URL}/api/auth/google/callback, протокол всегда https. REPLIT_DOMAINS удалён.
  • ai-config.ts — НОВЫЙ файл: чистое IO из DI2 ai-agent.ts — loadAiConfig/saveAiConfig (data/ai-config.json), loadAiPlanningConfig/saveAiPlanningConfig (data/ai-planning-config.json), getAiLog/saveLogEntry (data/ai-query-log.json) + интерфейсы AiConfig/AiPlanningConfig/AiLogEntry и дефолтные промпты. Без cron, fetch, Telegram.
  • audit-agent.ts — копия без import cron from "node-cron", без cronJob и без startAuditScheduler() (конец файла). Оставлены runIntegrityAudit, getAuditHistory. node-cron в package.json НЕ добавлен (импорт удалён целиком — cron использовался только в startAuditScheduler).
  • routes.ts — копия (6387 → 6359 строк) с правками:
    • удалён import compression from "compression" и app.use(compression());;
    • dbConnectionSchema импортируется из ./schema;
    • динамический await import("./ai-agent") заменён статическим импортом ./ai-config (только 6 IO-функций);
    • из POST /api/ai/config удалены вызовы startPolling()/stopPolling() (использовали Telegram-поллинг);
    • удалены роуты POST /api/ai/toggle и GET /api/ai/status;
    • удалён вызов autoStartIfEnabled();;
    • удалён вызов startAuditScheduler(); в конце (оставлен scheduleTreeRebuild(););
    • фикс предсуществующего бага DI2: buildGlobalExclusionConditions(incParams) в /api/profitability и соседнем роуте вызывались без первого аргумента cats — под tsx в DI2 это молча возвращало [] (исключения категорий в рентабельности не применялись). Добавлен loadCategories() первым аргументом (строки ~2974 и ~3080). Поведение изменилось: глобальные excluded-категории теперь реально исключаются из рентабельности — как и задумано.
  • index.ts — НОВЫЙ файл-обёртка registerDi2Routes(app): express.Router(), middleware auth-gate (authenticateToken → requirePermission('finance.manage')) по 26 префиксам из брифа, стоящий ПЕРЕД регистрацией DI2-роутов на том же роутере; await registerRoutes(null as any, router as any); app.use(router) без mount-префикса.

Изменения вне finance-di2

  • server/finance/db-client.ts — добавлен экспорт isConnectionError (существующий код DI2; новый пул не создавался).
  • server/routes/index.ts — импорт registerDi2Routes + await registerDi2Routes(app); строкой НЕПОСРЕДСТВЕННО ПЕРЕД await registerFinanceRoutes(app);.
  • server/index.ts — блок статики /di2 из dist/public-di2 (path/fs уже импортированы, import.meta.dirname — Node 20.11+, совместимо с esbuild ESM-бандлом) вставлен ПЕРЕД веткой if (development) setupVite else serveStatic (после регистрации API-роутов и app.use('/apps', ...)). В dev и prod /di2/* не уйдёт в main index.html. Папки dist/public-di2 пока нет — блок молча пропускается (сборку добавит Task 2).
  • package.json — НЕ изменён (node-cron не нужен, scripts.build не тронут).

Проверки

  1. grep -rn "ai-agent\|compression\|REPLIT" server/finance-di2/ → пусто (exit 1). grep -rn "node-cron" server/finance-di2/ → пусто.
  2. npx tsc --noEmit → чисто, без ошибок (единственные 2 ошибки при первом прогоне — предсуществующий баг DI2 с buildGlobalExclusionConditions — исправлены).
  3. npm run build → прошёл: vite build + esbuild dist\index.js 2.7mb (DI2-роуты в бандле: grep api/profitability|api/refresh-all|api/auth/google/callback → 9 вхождений).
  4. Дев-сервер не запускался (по брифу достаточно typecheck+build).

Открытые вопросы / опасения

  • Дублирование путей со старым модулем финансов: DI2 регистрируется ПЕРЕД registerFinanceRoutes, поэтому при совпадении путей (/api/income, /api/connection, /api/db/tables, /api/audit/* и др.) побеждают DI2-обработчики. Это осознанное решение брифа, но старые финансовые страницы (которые ходят на эти же пути) теперь получат DI2-формат ответов после деплоя — до появления клиента DI2 в Task 2 старый UI финансов на пересекающихся эндпоинтах может сломаться. Если это нежелательно до Task 2 — можно временно закомментировать регистрацию.
  • /api/auth/google/callback теперь за auth-gate: Google-редирект без сессии iistwin вернёт 401. В DI2 он тоже требовал входа (Replit auth), поведение осознанное.
  • /api/telegram/* в routes.ts оставлен как есть (конфиг + отправка через fetch, без поллинга) — бриф вырезал только поллинг из ai-agent.
  • Проверка регистрации в рантайме (поднять сервер) не выполнялась — по брифу достаточно typecheck+build; реальный smoke логично сделать после Task 2 вместе с клиентом.