# 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 вместе с клиентом.