Files
frontend/README.md
T
ksv741 57630102e4 chore: add typed ESLint checks #18
Refs WealthLedger/main#18. Keep Biome; add no Prettier dependencies.
2026-09-28 16:36:40 +03:00

21 KiB
Raw Blame History

WealthLedger frontend

React/Vite-клиент WealthLedger. Клиент получает данные только через typed API backend; прямые вызовы T-Bank из frontend не допускаются.

Быстрый старт

Требуется Node 24 (.nvmrc). Создайте .env из примера и установите зависимости строго из lockfile:

cp .env.example .env
nvm use --silent
npm ci
npm run dev

VITE_API_BASE_URL по умолчанию указывает на http://localhost:3000.

Для commits установите Gitleaks 8.30.1 в PATH (macOS: brew install gitleaks). Pre-commit сначала проверяет staged diff с полной редакцией секретов, затем запускает formatting и FSD checks. Находка или отсутствие Gitleaks блокирует commit. Проверка этого поведения: node --test scripts/test-pre-commit.mjs.

Контейнерный image

Dockerfile имеет targets development (Vite HMR и proxy /api/ во внутренний backend) и production (nginx на 8080, SPA fallback и same-origin API proxy). Node соответствует .nvmrc. Build context ограничен .dockerignore; .env, local DB и host node_modules не попадают в image. Изменение packages/tokens или packages/ui требует rebuild development image, если локальный запуск использует bind-mount только src/public.

docker build --target development -t wealthledger-frontend:development .
docker build --target production -t wealthledger-frontend:production .

Gitea image.yml запускается на защищённом release tag vX.Y.Z, проверяет package/lock version и canonical gates. Runner ubuntu-latest должен иметь Docker/buildx. Образы хранятся в Nexus: nexus.personal.ksv741.ru/docker-hosted/wealthledger/frontend. Пользователь wealthledger-ci задаётся Actions secrets NEXUS_USERNAME/NEXUS_PASSWORD; эта же учётная запись используется сервером для загрузки образов. Docker endpoint и token realm должны использовать HTTPS; в docker-hosted включается запрет redeploy. Прежние Gitea secrets сохраняются на время перехода и не передаются в Nexus. Публикуются semver tags, без latest; существующие release tags не перезаписываются. Production выбирает опубликованный version tag.

Compose topology принадлежит workspace, эксплуатационная последовательность — документация, страница architecture/deployment.md. Проверка публикации требует настроенного registry/runner; локальный build не доказывает package permissions.

Установка как приложение (PWA)

Production-сборка поддерживает установку WealthLedger в отдельное окно через vite-plugin-pwa. Нужен HTTPS или localhost. В Chrome/Edge выберите «Установить WealthLedger» в меню браузера или значок установки в адресной строке; на iPhone и iPad — Safari → «Поделиться» → «На экран Домой». Доступность установки зависит от браузера и ОС.

Service worker кеширует только статическую оболочку, включая страницы SPA. Вход, финансовые данные и сохранение изменений требуют сети: API, токены и ответы API не сохраняются в Cache Storage. Это не автономный финансовый клиент. Новая версия загружается в фоне и применяется после закрытия всех вкладок и окон WealthLedger и повторного открытия; открытые формы автоматически не перезагружаются.

Локальная проверка: nvm use --silent, npm run build, npm run preview. В DevTools → Application проверьте Manifest, Service Workers и Cache Storage. В режиме npm run dev и в Storybook service worker не включается.

Проверка

nvm use --silent
npm ci
npx --no-install playwright install chromium
npm run verify

Команда проверяет, что generated OpenAPI types соответствуют committed snapshot, затем запускает strict TypeScript, Biome, ESLint и проверку его конфигурации, один coverage-backed запуск Vitest, Knip, dependency rules приложения и stories, сборки приложения и Storybook.

npm run lint объединяет lint:biome и lint:eslint. Biome сохраняет форматирование, сортировку импортов, magic numbers и accessibility-проверки. ESLint добавляет typed linting, React Compiler/hooks, Fast Refresh, TanStack Query, выбранные Unicorn-правила и проверки тестов/stories. Prettier не добавлен. npm run test:lint проверяет правила на ошибочных примерах и исключение generated/build artifacts. lint:eslint сначала собирает private packages, чтобы анализ типов использовал их актуальные declarations.

Пересекающиеся hook-диагностики принадлежат официальному react-hooks. Testing Library проверяет async-корректность; DOM structure/geometry tests сохраняют прямой доступ к узлам. Async doubles допускаются без искусственного await; Vitest допускает второй аргумент сообщения и ветвления фиксированных it.each сценариев. React event handlers допускают Promise, но их тела остаются под no-floating-promises. Локальные исключения объясняют сохранение wire ProblemDetails, generated query keys и раннее подключение rejection assertions в race-тестах. Плагин Query не доказывает корректность всех generated/custom обёрток: transport/cache сценарии по-прежнему проверяют MSW-тесты.

Дополнительные no-unnecessary-condition и no-deprecated пока не включены: первому нужна отдельная оценка индексного доступа и защитных runtime guards, второму — отдельная миграция API зависимостей. Пакеты второй волны и jsx-a11y без заявленной поддержки ESLint 10 отложены в workspace issue #18.

Vitest включает JSDOM-тесты и проверку геометрии секций позиций в headless Chromium при ширинах 375 и 1280 px. Browser project не использует JSDOM setup и его заглушки layout API. Только браузерная проверка: npm run test:run -- --project='browser-*'. После обновления Playwright повторите установку Chromium; CI устанавливает его с --with-deps для Linux. Единый .gitea/workflows/verify.yml запускает commits → security → verify последовательно на PR; на push в develop/main — security → verify. Рабочие ветки проверяются после открытия PR, без дублирующего push-запуска. Изменение заголовка PR тоже повторяет проверки Conventional Commits. Новый запуск отменяет устаревший для того же PR/ветки и типа события (требуется Gitea 1.26+). Ежедневно в 05:17 UTC выполняется только security. Job security проверяет полную доступную историю Gitleaks 8.30.1 и выполняет npm audit --include=dev --audit-level=low. Любой advisory блокирует security job; исключений frontend нет. Локально можно выполнить те же команды: gitleaks git --log-opts=--all --redact=100 --no-banner и npm audit --include=dev --audit-level=low. Audit требует доступа к npm registry; проверка секретов выполняется локально и не выводит их значения.

Имена jobs commits, security, verify сохранены, но Gitea включает имя workflow в статус. При внедрении администратор должен заменить required checks для защищённых веток на Frontend verify / commits (pull_request), Frontend verify / security (pull_request) и Frontend verify / verify (pull_request), удалив старые имена и push-статусы, если они требовались. Все три PR-проверки должны оставаться обязательными. Публикация образов по тегам остаётся в image.yml. Последовательность jobs ограничивает один запуск; для ограничения нагрузки всего сервера настройте runner.capacity: 1 у общего runner и учтите остальные зарегистрированные runners. Конфигурация runner управляется вне этого репозитория.

TypeScript остаётся на 5.9.3: openapi-typescript@7.13.0 требует peer ^5.x. Обновление до TypeScript 7 из Renovate dashboard откладывается до совместимого релиза генератора; --force/--legacy-peer-deps для обхода этого ограничения не используются. Если backend-контракт изменился, обновите src/shared/api/spec/openapi.json копированием backend OpenAPI document и затем выполните npm run openapi:generate.

SonarQube

Проект wealthledger-frontend использует настройки из sonar-project.properties. Анализируются исходники src; тесты учитываются отдельно, а Storybook fixtures, test helpers, generated API types и OpenAPI snapshot исключены. npm run test:coverage (также входит в npm run verify) создаёт coverage/lcov.info для импорта покрытия.

Для первого анализа установите SonarScanner CLI, совместимый с версией сервера, и выполните из корня frontend:

nvm use --silent
npm ci
npm run test:coverage
# SONAR_TOKEN передайте через окружение; не сохраняйте токен в репозитории.
sonar-scanner

В Gitea откройте frontend → Settings → Actions → Secrets и добавьте SONAR_TOKEN с токеном анализа проекта. Переименовывать основную ветку в SonarQube не требуется; sonar.branch.name не задаётся. Используется Community Edition 9.9.8: CI отправляет только push в develop, после успешного verify, и ожидает результат Quality Gate. PR и остальные ветки проходят обычные проверки без отправки в SonarQube. Отрицательный Quality Gate или ошибка scanner завершает verify с ошибкой.

Runner должен поддерживать Docker actions и иметь HTTPS-доступ к https://sonarqube.personal.ksv741.ru, GitHub и Docker Hub. Docker action SonarSource закреплён на commit версии 2.3.0; scanner запускается отдельно от Node 24, используемого для сборки. tsconfig.sonar.json содержит совместимые со старым анализатором TS настройки; приложение проверяется штатным TypeScript 5.9 через npm run verify. После обновления сервера пересмотрите scanner и возможность использовать основной tsconfig. Успешный локальный verify не доказывает доступность сервера и успешность анализа в CI.

UI-каталог Storybook

После nvm use --silent выполните npm run dev:catalog; статическая сборка — npm run build:catalog. Каталог использует общую тему приложения, вымышленные данные и локальные действия без application API. Примеры не доказывают восстановление реального запроса. Визуальные роли описаны в UI convention.

Документация

Checkout frontend содержит все входы сборки и проверок. Публичная схема API поступает как отдельный artifact; команды frontend используют только её локальную копию и не обращаются к исходникам или CI сервера. Доставка новой схемы — явное обновление snapshot с review и npm run openapi:generate. Runtime URL API задаётся окружением, а не расположением другого репозитория. Разработка идёт напрямую по задаче пользователя; OpenSpec/SDD — по явному запросу.

Knip исключает conventional-changelog-conventionalcommits: release-it загружает preset по имени из .release-it.json. Версия preset закреплена напрямую.

Релизы

Репозиторий выпускается независимо. develop — интеграция, main — принятые релизы. Работа: codex/<task> от актуального develop, PR в develop. Обычные PR допускают squash; release и обратная синхронизация сохраняют историю. Commits и PR titles — Conventional Commits, включая spec:. Версии вручную не повышай.

  1. Получи main, develop и теги: git fetch origin --tags. Убедись, что develop содержит последний релиз. Создай release/<name> от проверенного develop; nvm use --silent, npm ci. Hotfix начинается от main в release/hotfix-<name> и проходит тот же процесс.
  2. На чистой ветке выполни npm run release:preview, просмотри версию/changelog, затем npm run release:prepare. Команда создаёт chore(release): X.Y.Z, обновляет manifest/lockfile/CHANGELOG; тег и push не выполняет. Не обходи guards ветки, чистого дерева, отсутствующих тегов или уже подготовленной версии.
  3. Проверь diff и штатные gates этого репозитория. Отправь только release-ветку, открой PR в main с заголовком chore(release): X.Y.Z. После зелёных verify, security, commits выполни fast-forward-only merge. Если main изменился, согласуй историю и повтори проверки кандидата.
  4. Получи удалённый main, сравни его HEAD с проверенным release SHA и версией manifest/lockfile. Создай аннотированный vX.Y.Z именно на этом SHA: git tag -a vX.Y.Z <release-sha> -m "Release X.Y.Z", затем отправь только git push origin refs/tags/vX.Y.Z. Не запускай release-it повторно на main.
  5. Верни release-коммит через PR main → develop без squash/rebase; проверь, что develop содержит тег. Опубликованные теги не перемещай. При сбое после merge создай отсутствующий тег без нового bump; до merge исправь и проверь существующий кандидат без повторного повышения версии.

feat: повышает minor, fix:/perf: и прочие разрешённые типы — patch; !/BREAKING CHANGE: — major, включая версии до 1.0. chore(release): исключён из рекомендации и changelog. Конфигурация — .release-it.json. В Gitea для main/develop должны быть запрещены прямой/force push и обход администратором, обязательны verify, security, commits; теги v* защищены. Workflow сам не включает эти настройки. Отдельное review approval для одного владельца не требуется. Npm publishing, deploy и Gitea Releases не включены.

Локальные пакеты

packages/tokens — private npm workspace с единственным export @wealthledger/tokens/tokens.json. packages/ui экспортирует собранные @wealthledger/ui/theme (JS + declarations) и @wealthledger/ui/styles.css. Корневой export @wealthledger/ui содержит EntryCard, StateView и LoadingSkeleton; Потребители импортируют компоненты напрямую из @wealthledger/ui. CSS явно подключается после Mantine; providers остаются в приложении/Storybook. Тема доступна через @wealthledger/ui/theme; compatibility re-exports удалены.

JSON не требует сборки. npm ci связывает workspaces, а существующие команды разработки, проверок и сборки сначала выполняют npm run build:packages. Library build использует отдельный Vite config без app plugins и TypeScript для declarations. После изменения package sources перезапустите npm run dev или npm run dev:catalog; отдельный watch-процесс пока не нужен. Начальная версия manifest взята из приложения; отдельный release-процесс и публикация не настроены.

Private @wealthledger/icons экспортирует AddIcon, EditIcon, DeleteIcon и type IconProps. Единственный source рисунка — TSX в packages/icons/src/svg; поставка содержит ESM/declarations, без raw SVG, CSS, Mantine и motion. React — peer/external. Размер size по умолчанию 24, strokeWidth — 1.5; цвет наследуется через currentColor, SVG props можно передать явно. В action используйте декоративный <AddIcon size={20} strokeWidth={2} />, доступное имя задавайте кнопке. Standalone пример: <EditIcon aria-hidden={false} role="img" aria-label="Редактирование" />. Поддерживается также стандартный aria-labelledby; подпись выбирает caller. Card/Cards используют пакетные Add/Edit/Delete с прежними размерами/strokeWidth. Restore/category SVG и предметный BankOperationIcon остаются в приложении.