- Копия 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
10 KiB
10 KiB
Task 1 — Серверная интеграция Data-Insight2
Цель: перенести серверную часть DI2 (C:\1Ai\1iistwin\tmp\Data-Insight2\server) в server/finance-di2/ репозитория C:\1Ai\1iistwin\1Project, обёрнуть в авторизацию iistwin и зарегистрировать роуты ДО старого модуля финансов. Клиент НЕ входит в задачу (Task 2), но добавь зависимость node-cron (DI2 audit-agent.ts импортирует cron вверху файла; планировщик мы не запускаем, но импорт должен резолвиться). НЕ меняй scripts.build в package.json (это Task 2).
Источник (только чтение)
C:\1Ai\1iistwin\tmp\Data-Insight2\server\: routes.ts (6387 строк), cache.ts, table-config.ts, override-tables.ts, google-auth.ts, audit-agent.ts (477 строк), db-client.ts, storage.ts (5 строк).C:\1Ai\1iistwin\tmp\Data-Insight2\shared\schema.ts(366 строк, чистые типы/константы, без drizzle).
Что создать в 1Project
server/finance-di2/— копии файлов DI2 с правками:schema.ts← копияtmp/Data-Insight2/shared/schema.ts(типы и константы).db-client.ts— НЕ копировать DI2-версию. Написать обёртку, которая импортирует из../finance/db-client(iistwin):query, testConnection, getConfig, setConfig, isConnectionErrorи экспортирует их же +getPoolClient(проверь, чтоserver/finance/db-client.tsэкспортирует все эти имена; еслиgetPoolClientотсутствует — добавь его туда, а не дублируй пул: открой файл и посмотри, есть ли там pool — экспортируй существующий). Формат конфига (data/db-config.json) идентичен — это тот же код по происхождению.cache.ts,table-config.ts,override-tables.ts— копии без изменений (проверь их импорты: они должны ссылаться на./db-clientи./schema— исправь алиасы).google-auth.ts— копия с правкойgetRedirectUri(): вместоprocess.env.REPLIT_DOMAINSиспользоватьprocess.env.APP_BASE_URL || "https://iistwin.ru", redirect${APP_BASE_URL}/api/auth/google/callback. Протокол всегда https.ai-config.ts— НОВЫЙ файл: вырезать изtmp/Data-Insight2/server/ai-agent.tsтолько чистые функции IO без Telegram/поллинга:loadAiConfig,saveAiConfig,loadAiPlanningConfig,saveAiPlanningConfig(файлы data/ai-config.json, data/ai-planning-config.json), а такжеgetAiLog,saveLogEntry(посмотри их реализацию в ai-agent.ts — обычно append в json/jsonl; перенеси как есть, включая нужные интерфейсы AiConfig/AiPlanningConfig). Без cron, без fetch, без Telegram.audit-agent.ts— копия, но удалитьstartAuditSchedulerи его вызовы (cronJob и импорт node-cron не нужны, если импорт только для этой функции — проверь: если cron используется только в startAuditScheduler, удали импорт и функцию целиком; тогда node-cron в package.json НЕ нужен — не добавляй). ОставитьrunIntegrityAudit,getAuditHistory.routes.ts— копия с такими правками:- Импорт
dbConnectionSchemaс./schema(не@shared/schema). - Удалить
import compression from "compression"иapp.use(compression());(строка ~1142). - Строку 1371
const {...} = await import("./ai-agent")заменить на импорт из./ai-config: нужны толькоloadAiConfig, saveAiConfig, loadAiPlanningConfig, saveAiPlanningConfig, getAiLog, saveLogEntry. - Удалить роуты
app.post("/api/ai/toggle", ...)иapp.get("/api/ai/status", ...)(используют startPolling/stopPolling/isPolling). - Удалить вызов
autoStartIfEnabled();(~строка 1508). - В конце: удалить
startAuditScheduler();(строка 6384), оставитьscheduleTreeRebuild();. - Проверь, что в routes.ts больше нет ссылок на ai-agent, compression, node-cron (grep).
- Проверь остальные импорты вверху routes.ts:
./storage(5-строчный файл — перенеси тоже, если импортируется),./override-tables,./table-config,./cache,./google-auth,./audit-agent— все становятся./xxxвнутри finance-di2 (уже так).
- Импорт
index.ts— НОВЫЙ файл-обёрткаregisterDi2Routes(app: Express):- Создать
express.Router(). - Middleware на роутере: если
req.pathначинается с одного из префиксов DI2 — пропустить черезauthenticateTokenзатемrequirePermission('finance.manage')(импорт из../middleware/auth.middleware), иначеnext(). - Префиксы:
/api/income,/api/income-categories,/api/expenses,/api/expense-categories,/api/debt,/api/dashboard,/api/profitability,/api/heatmap,/api/planning,/api/salary,/api/audit,/api/calculations,/api/connection,/api/db,/api/table-config,/api/table-settings,/api/overrides,/api/tags,/api/tag-assignments,/api/cache,/api/refresh-all,/api/admin,/api/auth/google,/api/ai,/api/telegram. - Затем вызвать DI2
registerRoutes(httpServer, router as any)— передавnull as anyвместо httpServer (он используется только вreturn httpServerв конце). Функция async — await. Затемapp.use(router)— но НЕ сmount-префиксом, роуты абсолютные. - ВАЖНО порядок middleware:
router.use(authGate)должен стоять ПЕРЕД регистрацией роутов DI2, и все DI2-роуты регистрируются на этом же роутере.
- Создать
server/routes/index.ts: добавитьawait registerDi2Routes(app);строкой НЕПОСРЕДСТВЕННО ПЕРЕДawait registerFinanceRoutes(app);(строка 113). Импорт добавь рядом с импортом registerFinanceRoutes (строка 33).server/index.ts: перед вызовомserveStatic(app)(или где там статика подключается в prod-ветке — найди поserveStatic() добавить:(проверь, какие импорты path/fs уже есть в index.ts; позицию выбери так, чтобы это было ДО catch-all// Data-Insight2 sub-app (финансы v2) const di2Dist = path.resolve(import.meta.dirname, "public-di2"); if (fs.existsSync(di2Dist)) { app.use("/di2", express.static(di2Dist)); app.use("/di2", (_req, res) => res.sendFile(path.resolve(di2Dist, "index.html"))); }serveStatic, но ПОСЛЕ регистрации API-роутов). В dev-режиме (setupVite) тоже должен работать: setupVite вешаетapp.use("*")— проверь порядок: если setupVite вызывается в dev ПОСЛЕ нашего блока, то /di2/* уйдёт в main index.html. Чтобы dev тоже работал, добавь этот блок ПЕРЕД веткойif (process.env.NODE_ENV === "development") setupVite(...) else serveStatic(app)(найди эту ветку и вставь до неё). Проверь наличие fs/path импортов.- package.json: если audit-agent оставил импорт cron — добавь
node-cronв dependencies (проверь версию из DI2 package.json). Если импорт удалён — не добавляй.scripts.buildНЕ трогать.
Проверки (обязательно выполнить и приложить вывод)
grep -rn "ai-agent\|compression\|REPLIT" server/finance-di2/— пусто.npx tsc --noEmit(корневой check) — без ошибок в server/finance-di2 (ошибки в других местах, если были до тебя, не считаются; проверь baseline сначала:git stashне нужен — просто сравни с ошибками на BASE, если есть новые — чини).npm run buildдолжен пройти (клиентская часть di2 ещё не создана — это нормально, build собирает только main client; сборка di2 будет в Task 2). Если build падает из-за твоих изменений — чини.- Быстрый smoke-тест сервера без Docker: запустить
npm run devне надо (трогает БД продакшена локально? нет — локальный dev стучится в локальную БД; НЕ запускай дев-сервер). Достаточно typecheck+build.
Контракт отчёта
Напиши файл C:\1Ai\1iistwin\1Project\.superpowers\sdd\di2-embed\task-1-report.md: что скопировано, какие правки, вывод grep-проверок, вывод tsc/build (последние строки), открытые вопросы. Верни: статус, список коммитов, одну строку по проверкам, опасения.
Жёсткие ограничения
- Код/комментарии — на русском (существующие DI2-комментарии не переводить обратно, оставь как есть).
- Не трогай
server/finance/*кроме случая, когда нужно экспортировать getPoolClient (добавь экспорт существующего пула, не создавай второй пул). - Не коммить изменения в tmp/Data-Insight2.
- Pre-push hook прогоняет check+build — коммить в main.