# Как переносится раздел из stroy-bot-* в монорепо Образец — главная страница: `src/webparts/stroyBot/pages/hub/` + `app/project/`. ## Главное правило **Поведение 1:1 со старым web part.** Те же запросы (URL, `$select`, `$filter`, `$expand`, `$top`, `$orderby`), те же поля, те же правила доступа, **те же тексты** (дословно), те же валидации. Известные баги переносятся как есть. Любое сознательное отличие записывается в `docs/MIGRATION-CHECKLIST.md` в блок «Сознательные отличия». Меняется только слой интерфейса: HTML-строки и `innerHTML` → React-компоненты на `@tnsu/ui-kit`. ## Структура раздела ``` pages/<раздел>/ <Раздел>Page.tsx — страница: собирает компоненты, обрабатывает loading / error / empty <Раздел>Page.module.scss texts.ts — ВСЕ пользовательские тексты раздела (дословно из старого кода) <раздел>Types.ts — типы данных <раздел>Repository.ts — запросы: функции-конструкторы URL + функции загрузки/записи <раздел>Repository.test.ts — тесты URL и сценариев на fakeHttpClient <раздел>Rules.ts — чистые функции (права, валидация, дерево, форматирование) <раздел>Rules.test.ts use<Что-то>.ts — хуки состояния (загрузка, сохранение) <Компонент>.tsx — под-компоненты, один компонент — один файл ``` ## Правила кода (стайл-гайд проекта) - TypeScript строго, **без `any`**. Ответы сервера описываются интерфейсами. - Компонент ≤ ~300 строк, функция ≤ ~50 строк. Больше — разбивать. - Логика — в `*Rules.ts` / `*Repository.ts` / хуках, не в JSX. - Имена списков — `LISTS` из `config/lists.ts`; таблицы Dataverse — `DV_TABLES` из `config/dataverse.ts`; адреса — из `useAppServices().settings`. - Внутренние имена полей SharePoint / колонок Dataverse — константами в `*Repository.ts` раздела (схемы в разных старых репо отличаются — не унифицировать без проверки). - Комментарии — «почему», а не «что». Без мёртвого кода. - `null` в своих типах не использовать (линтер) — `undefined`. Внешние ответы с `null` приводить через `?? undefined`. - Стили: SCSS-модули, `@import '../../../../styles/design-tokens';`, токены вместо цветов. Без magic numbers без комментария. - Форматирование — `.prettierrc` (одинарные кавычки, 120 символов, без висячих запятых). ## Данные - Клиенты: `const { sharePoint, dataverse, tnsuApi, settings, page } = useAppServices();` - SharePoint: `shared/sharepoint/spRest.ts` (`listItemsUrl`, `getJson`, `fetchCurrentUserId`). Запись — `sharePoint.fetch(url, { method: 'POST', headers, body })` с **теми же заголовками**, что в старом коде (verbose `__metadata` / `X-HTTP-Method: MERGE` / `IF-MATCH` — как было). - Dataverse: `shared/dataverse/dataverseRest.ts` (`dataverseUrl`, `dataverseGet/Post/Patch/Delete`). - Корпоративный API: `tnsuApi.fetch(`${settings.apiBaseUrl}/...`)`. - Текущий пользователь: `page.userId` (legacyPageContext.userId) или `fetchCurrentUserId` — как в старом коде раздела. - Маршрут: `useRouter()` → `route.projectId`, `route.objectId`, `route.reportId`, `route.copyFromId`; переход — `navigate({ page, projectId, ... })`; ссылка — ``. - Ссылки старых web parts на другие страницы (`SendReport.aspx?...`, `worksPageUrl`) → `navigate` / `RouteLink` на раздел приложения. ## UI - ui-kit: `Button`, `IconButton`, `Dialog`, `confirmModal`, `Alert`, `Badge`, `Spinner`, `TextInput`, `TextArea`, `Select`, `Checkbox`, `Tabs`, `DataTable`, `FormCard`, `FormField`, `FormGrid`, `FormActions`, `FormHeader`, `Icon` (имена — `ICON_NAMES` в ките). - `alert()` / `confirm()` → `Alert` / `confirmModal` (тексты те же). - Чего нет в ките (дерево, тосты, контекстное меню, хлебные крошки) — делать в `pages/<раздел>/` своего раздела. Существующие файлы в `shared/` не менять; `EmptyState` и `useOutsideClose` — переиспользовать. - Всегда явные состояния: загрузка (`Spinner`), ошибка (`Alert variant="err"`), пусто (`EmptyState`). ## Тесты - `shared/testing/fakeHttpClient.ts` — заглушка: проверяем точные URL и тела запросов против старого кода, сценарии успеха и ошибок. - Чистые функции правил — отдельными тестами. - Запуск: `npx heft test --clean`. Должно быть 0 ошибок линтера и все тесты зелёные.