refactor: enforce frontend readability and UI boundaries #43

Merged
ksv741 merged 2 commits from codex/frontend-view-guardrails into develop 2026-09-28 19:40:24 +03:00
Owner

Presentation-компоненты содержали SVG, обработчики в JSX, локальные схемы Zod и сложные условные выражения. PR переносит эти обязанности к явным владельцам и закрепляет требования к читаемости без изменения API-контрактов.

Изменения

  • SVG и анимации перенесены из application src в @wealthledger/icons. Каждая иконка — цельный декларативный SVG; геометрия не собирается в runtime. Реестр использует английские ключи, названия категорий API остаются данными с нормализацией и fallback.
  • Обработчики и состояние форм вынесены в ViewModel, схемы — в отдельные *.schema.ts. VM полей карты композирует hooks даты и платёжной системы. Сохранены validation, idempotency и обработка конфликтов версий.
  • Условные props получили именованные значения, крупные тернарники заменены явными ветками, добавлены интервалы между JSX siblings и смысловыми блоками. Короткий JSX не обрамляется лишними скобками.
  • ESLint контролирует callbacks/тернарники в props, helpers внутри компонентов, размещение SVG и схем, optional trailing parameters, сложные union-типы и длину строк 80 символов. Строки, template/regex literals, URL и комментарии исключены из max-len; generated artifacts исключены из форматирования.
  • unicorn/no-null отключён для сохранения контрактов API, React и Mantine; массовые локальные suppressions удалены. Известные названия банков вынесены в BankName.
  • Семантические требования к именам, владельцам логики, цельным SVG и композиции VM закреплены в guardrails. Storybook допускает UI-only/form-context VM, сохраняя запрет транзитивного доступа к application API/auth/query providers.

Новых зависимостей нет. Значительная часть diff — форматирование существующих исходников, тестов и stories под новые правила.

Проверки

  • npm ci выполнен; полный npm run verify после доработок — успешно: 58 test files, 379 tests, 8 ESLint regression checks; TypeScript, OpenAPI, coverage thresholds, Knip, оба dependency graph и обе сборки пройдены.
  • Chromium на собранном Storybook после доработок: 26 иконок операций, hover-анимации, reduced motion, клавиатурный выбор платёжной системы и viewport 375 px; без runtime exceptions.
  • Первоначальный Chromium smoke также проверил навигацию приложения, tooltip и смену валюты структуры портфеля на синтетических данных.
  • Сравнение runtime AST подтвердило, что очистка suppressions и скобок не меняет исполняемый код. Геометрия и порядок path сохранены для всех 26 SVG.
  • Pre-commit: Gitleaks, ESLint, dependency checks и commitlint; git diff --check.
Presentation-компоненты содержали SVG, обработчики в JSX, локальные схемы Zod и сложные условные выражения. PR переносит эти обязанности к явным владельцам и закрепляет требования к читаемости без изменения API-контрактов. ## Изменения - SVG и анимации перенесены из application `src` в `@wealthledger/icons`. Каждая иконка — цельный декларативный SVG; геометрия не собирается в runtime. Реестр использует английские ключи, названия категорий API остаются данными с нормализацией и fallback. - Обработчики и состояние форм вынесены в ViewModel, схемы — в отдельные `*.schema.ts`. VM полей карты композирует hooks даты и платёжной системы. Сохранены validation, idempotency и обработка конфликтов версий. - Условные props получили именованные значения, крупные тернарники заменены явными ветками, добавлены интервалы между JSX siblings и смысловыми блоками. Короткий JSX не обрамляется лишними скобками. - ESLint контролирует callbacks/тернарники в props, helpers внутри компонентов, размещение SVG и схем, optional trailing parameters, сложные union-типы и длину строк 80 символов. Строки, template/regex literals, URL и комментарии исключены из max-len; generated artifacts исключены из форматирования. - `unicorn/no-null` отключён для сохранения контрактов API, React и Mantine; массовые локальные suppressions удалены. Известные названия банков вынесены в `BankName`. - Семантические требования к именам, владельцам логики, цельным SVG и композиции VM закреплены в guardrails. Storybook допускает UI-only/form-context VM, сохраняя запрет транзитивного доступа к application API/auth/query providers. Новых зависимостей нет. Значительная часть diff — форматирование существующих исходников, тестов и stories под новые правила. ## Проверки - `npm ci` выполнен; полный `npm run verify` после доработок — успешно: 58 test files, 379 tests, 8 ESLint regression checks; TypeScript, OpenAPI, coverage thresholds, Knip, оба dependency graph и обе сборки пройдены. - Chromium на собранном Storybook после доработок: 26 иконок операций, hover-анимации, reduced motion, клавиатурный выбор платёжной системы и viewport 375 px; без runtime exceptions. - Первоначальный Chromium smoke также проверил навигацию приложения, tooltip и смену валюты структуры портфеля на синтетических данных. - Сравнение runtime AST подтвердило, что очистка suppressions и скобок не меняет исполняемый код. Геометрия и порядок path сохранены для всех 26 SVG. - Pre-commit: Gitleaks, ESLint, dependency checks и commitlint; `git diff --check`.
codex-bot added 1 commit 2026-09-28 18:49:20 +03:00
refactor: enforce frontend view model boundaries
Frontend verify / commits (pull_request) Successful in 28s
Frontend verify / security (pull_request) Successful in 10s
Frontend verify / verify (pull_request) Successful in 8m19s
ca0ad4f824
ksv741 approved these changes 2026-09-28 19:03:16 +03:00
@@ -10,3 +10,3 @@
severity: "error",
to: {
path: String.raw`^src/(shared/api|features/auth|app/routes|app/ui)/|^src/(entities|features)/[^/]+/api/|\.vm\.ts$|^src/pages/[^/]+/ui/.*Page\.tsx$|node_modules/(@tanstack/react-query|openapi-fetch|openapi-react-query)/`,
path: String.raw`^src/(shared/api|features/auth|app/routes|app/ui)/|^src/(entities|features)/[^/]+/api/|^src/pages/[^/]+/ui/.*Page\.tsx$|node_modules/(@tanstack/react-query|openapi-fetch|openapi-react-query)/`,
Owner

можно ли упростить ? без использования String.raw ?

можно ли упростить ? без использования String.raw ?
@@ -0,0 +42,4 @@
"M3 7a14 14 0 0 1 18 0 M6 11a9 9 0 0 1 12 0 M9 15a4 4 0 0 1 6 0 M12 19h.01",
wine:
"M7 3h10v5a5 5 0 0 1-10 0V3Z M7 7h10v1a5 5 0 0 1-10 0V7Z M12 13v8 M8 21h8",
} as const;
Owner

не нужно так, svg должны быть целостными, а не разбиты по кускам, чтобы собираться в рантайме

не нужно так, svg должны быть целостными, а не разбиты по кускам, чтобы собираться в рантайме
@@ -98,0 +111,4 @@
)
: (
<DocumentTitle title={t("navigation.accounts")} />
);
Owner

для компонентов, которые помещаются в 1 строку не обязательно добавлять скобки

для компонентов, которые помещаются в 1 строку не обязательно добавлять скобки
@@ -21,3 +21,2 @@
const card: BankCard = (/* eslint-disable unicorn/no-null -- Fixture preserves the production contract’s explicit null values. */
{
/* eslint-disable unicorn/no-null -- Fixture preserves the production contract’s explicit null values. */
Owner

слишком часто отключаем это правило, его нужно или совсем выключить или же правильно писать код, чтобы не дизейблить правило

слишком часто отключаем это правило, его нужно или совсем выключить или же правильно писать код, чтобы не дизейблить правило
@@ -4,2 +8,4 @@
variant: OperationIconProps["variant"];
};
const categoryIcons: Record<string, OperationIcon> = {
Owner

эту логику нужно переработать, потому что svg должны быть целостными, а не собираться в рантайме
также ключи в виде русских слов это порнография

эту логику нужно переработать, потому что svg должны быть целостными, а не собираться в рантайме также ключи в виде русских слов это порнография
@@ -42,0 +38,4 @@
"Сбербанк",
"Т-Банк",
"Альфа-Банк",
"ВТБ",
Owner

названия банков должны быть вынесены в отдельный enum

названия банков должны быть вынесены в отдельный enum
@@ -0,0 +7,4 @@
import { bankDateInputValue } from "../../model/form-validation";
import { type BankCardValues, bankDateSchema } from "../../model/form.schema";
function useBankCardFieldsVm() {
Owner

возможно лучше использовать внутри дополнительные хуки, в которых будет инкапсулировано поведение по смыслу, например все on* действия вынести в отдельный хук, который в хуке useBankCardFieldsVm будет просто отдавать наружу детали и т.д

возможно так будет понятнее логика + сделать в виде guardrails

возможно лучше использовать внутри дополнительные хуки, в которых будет инкапсулировано поведение по смыслу, например все on* действия вынести в отдельный хук, который в хуке useBankCardFieldsVm будет просто отдавать наружу детали и т.д возможно так будет понятнее логика + сделать в виде guardrails
ksv741 added 1 commit 2026-09-28 19:21:27 +03:00
refactor: address frontend review feedback
Frontend verify / commits (pull_request) Successful in 29s
Frontend verify / security (pull_request) Successful in 9s
Frontend verify / verify (pull_request) Successful in 8m54s
Frontend verify / commits (push) Skipped
Frontend verify / security (push) Successful in 12s
Frontend verify / verify (push) Successful in 9m59s
a4046dbe87
ksv741 merged commit a4046dbe87 into develop 2026-09-28 19:40:24 +03:00
Sign in to join this conversation.
No Reviewers
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: WealthLedger/frontend#43