# План миграции: единый SvelteKit-проект + типизированный eval > Статус: **утверждён для проработки** (запуск реализации — по отдельной команде). > Последнее обновление: 2026-09-04 --- ## 1. Общая цель Убрать избыточное разделение на два проекта и перевести всё в **один SvelteKit-проект** на Vercel, а eval-harness — с JavaScript (`.mjs`) на **TypeScript**, с **общими типами** между eval и сайтом. Итог: один домен, один деплой, один контракт данных для отчётов (он не «ломается», потому что eval и рендер сидят на одних типах). --- ## 2. Целевая архитектура ### 2.1. Общий пакет типов — `packages/types` Workspace-пакет `@duck/types`, используемый и eval, и `apps/web`. ```txt packages/types/ package.json # name: "@duck/types" (через pnpm pkg) tsconfig.json src/index.ts # общий контракт ``` Типы (защищают контракт отчёта): - `Task { id, question, answer }` - `ScenarioName = "control" | "blind" | "mentor"` - `ScenarioSummary { tasks, reviewed, correct, accuracy, pending, duckUsed, toolCalls, avgCalls }` - `PerTaskRow { id, scenario, correct: boolean|null, duckUsed, toolCalls, promptTokens, genTokens, duckTokens, response, expected, question }` - `ModelReport`, `ReportRoot { generatedAt, mcpUrl, prompts, models, aggregate, reviewedAt? }` - `Reviews` (контракт `review.json`) Роль: и `apps/eval` при записи `out/report.json`, и `apps/web` при рендере `/reports` используют эти типы. Рассогласование схемы → ошибка на этапе компиляции, а не падение в проде. ### 2.2. Приложение — `apps/web` (единственный деплой на Vercel) ```txt apps/web/ # SvelteKit + TypeScript + @sveltejs/adapter-vercel src/routes/ +layout.svelte # общий nav-каркас +page.svelte # / — домашняя (заглушка «скоро») /mcp/+page.svelte # /mcp — описание MCP + FAQ/README /reports/+page.svelte # /reports — полные отчёты (рендер из report.json) /api/mcp/+server.ts # /api/mcp — MCP endpoint (mcp-handler) src/lib/ mcp.ts # перенос из apps/mcp/lib/mcp.ts reports.ts # рендер-хелперы на базе @duck/types static/report.json # коммитится — источник для /reports ``` **Домен:** `rubber-duck-mcp.vercel.app` — единственный. Всё на нём: - `/` → домашняя - `/mcp` → описание - `/reports` → отчёты - `/api/mcp` → MCP endpoint ### 2.3. Eval — типизация в TS ```txt apps/eval/ src/*.ts # run, runner, report, review (из .mjs) lib/mcpClient.ts # (из lib/mcpClient.mjs) lib/ollama.ts # (из lib/ollama.mjs) tsconfig.json out/report.json # генерируется (НЕ коммитится) data/tasks.json # (как есть) ``` --- ## 3. Все решённые вопросы (закрытые решения) | Вопрос | Решение | | --------------------- | --------------------------------------------------------------------------------------- | | Домен | единый `rubber-duck-mcp.vercel.app` | | Куда класть SvelteKit | новая папка `apps/web` | | Линковка Vercel | перелинковать существующий project `mcp` на `apps/web` (домен сохр.) | | Frontend-домен | удалить `rubber-duck-frontend.vercel.app` и Vercel-проект `frontend` | | `report.json` в проде | коммитить в `apps/web/static/report.json` | | Страница `/reports` | полный формат (сводные таблицы по моделям + разбивка по задачам) | | MCP-фреймворк | mcp-handler совместим с SvelteKit (web-standard `(Request) => Response`), Next не нужен | | Язык eval | TypeScript + общий пакет типов | --- ## 4. Изменение запуска (было → стало) Сейчас (JS): ```bash node src/run.mjs node src/review.mjs ``` Стало (TS): компиляция не требуется для dev — запуск через `tsx`: ```bash # apps/eval tsx src/run.ts tsx src/review.ts ``` > Локальная генерация статического `report.html` (`report-html`) **убрана**: `/reports` на > сайте рендерит те же данные из `report.json` через Svelte-компоненты на общих типах. Скрипты в `apps/eval/package.json` и корневом `package.json` (`eval:*`) обновляются на `tsx`. Добавляется: - **typecheck**: `tsc --noEmit` для eval и web (контракт не ломается). - dev-зависимости eval: `tsx`, `typescript`, `@types/node`. --- ## 5. Шаги реализации (поэтапно) ### Шаг 1 — `packages/types` - Создать workspace-пакет `@duck/types` (манифест через `pnpm pkg`). - Написать `src/index.ts` с общим контрактом + `tsconfig.json`. - Убедиться, что pnpm-workspace (`packages: apps/*`) знает про `packages/*`. ### Шаг 2 — eval → TypeScript - Переименовать `lib/*.mjs` → `.ts`, `src/*.mjs` → `.ts`. - Подключить `@duck/types`, поправить импорты. - Добавить `tsconfig.json`, зависимости (`tsx`, `typescript`, `@types/node`) через `pnpm pkg`/`pnpm add`. - Обновить скрипты запуска (`eval:*` → `tsx ...`). - Проверка: `tsc --noEmit` + короткий прогон `tsx src/run.ts --limit 1`. ### Шаг 3 — `apps/web` (SvelteKit) - Инициализировать SvelteKit + TypeScript + `@sveltejs/adapter-vercel`. - Подключить `@duck/types`. ### Шаг 4 — Перенос MCP - `apps/mcp/lib/mcp.ts` → `apps/web/src/lib/mcp.ts`. - `apps/mcp/app/api/mcp/route.ts` → `apps/web/src/routes/api/mcp/+server.ts` (mcp-handler принимает `Request` → из SvelteKit передаём `event.request`). - Убедиться, что `runtime = "nodejs"` задан. ### Шаг 5 — Страницы - `+layout.svelte` — навигация; - `/` — заглушка «скоро» (дизайн позже); - `/mcp` — описание + FAQ + README (перенести текст из старой `page.tsx`); - `/reports` — `load` из `static/report.json` через `lib/reports.ts` на общих типах; рендер карточек/таблиц — Svelte-компоненты (визуальный стиль перенесён из прежнего `report-html.mjs`). ### Шаг 6 — Данные - Скопировать `apps/eval/out/report.json` → `apps/web/static/report.json` и закоммитить. - Добавить команду «sync отчёта на сайт» (копирует report.json после прогона eval). ### Шаг 7 — Деплой/конфиг - `apps/web/package.json` + корневой: `dev`, `build`, `deploy` → `apps/web`; `eval:*` → `tsx`; убрать `deploy-mcp`, `deploy-frontend`. - Удалить `apps/frontend` + скрипты + Vercel-проект/домен frontend. - Удалить `apps/mcp` (Next) после переноса. - Перелинковать Vercel-проект `mcp` на `apps/web`; проверить, что домен назначен на проект. ### Шаг 8 — Проверка - `tsc --noEmit` (eval + web). - `pnpm dev` → проверить страницы и `/api/mcp`. - `vercel --prod` → verify на домене: `/`, `/mcp`, `/reports`, `/api/mcp` (quack). --- ## 6. Что НЕ делаем сейчас - Детальный дизайн страниц/домашней (делаем позднее, отдельно). - Автоматическое обновление `report.json` на каждый прогон (только sync-команда). - Расширенное наполнение FAQ/README (только перенос базового текста). --- ## 7. Риски и митигация | Риск | Митигация | | -------------------------------------------- | ------------------------------------------------------------------------- | | `mcp-handler` под Next | фреймворк-агностичен (web-standard Request/Response), проверено по `d.ts` | | Нужна компиляция для запуска eval | dev — `tsx`; при необходимости `tsc build` для prod-скриптов | | Несовместимость схемы отчёта | общие типы `@duck/types` + `tsc --noEmit` в eval и web | | Необратимое удаление Vercel-проектов | frontend/mcp удаляем аккуратно, после успешного переноса | | `report.json` рассинхронизируется с прогоном | явная команда sync + коммит | --- ## 8. Порядок выполнения Поэтапно, с проверкой на каждом шаге: `packages/types` → eval-TS → `apps/web` (скелет) → перенос MCP → страницы → данные → деплой/конфиг → проверка. (Реализацию начинать только по явной команде.)