LoVisual/frontend/ARCHITECTURE.md
loki5512344 72bc4c7148 chore(history): squash 100 commit(s) from 2026-09-24
- fix(backend): case-insensitive unique email, revoke PUBLIC schema access, pin Argon2id params
- test(backend): assert password length cap boundary (256 ok, 257 rejected)
- docs(backend): plan — typed JWT token kinds so refresh/device tokens cannot pass as access tokens
- feat(backend): JWT access/refresh token issue and verify
- feat(backend): accounts repository (create/find_by_email/find_by_id)
- refactor(gui): LoVisualAddonManagerScreen 989→10 файлов addon/ (8.5.2)
- docs(backend): plan — fix sqlx::migrate! path in integration tests
- feat(backend): POST /auth/register and /auth/login
- refactor(settings): SettingsPanelComponent 715→81 + 6 helpers (8.5.2)
- docs(backend): plan — harden device flow (single-use codes, bounded store, 404/429)
- feat(backend): OAuth device authorization grant for mod login
- fix(backend): first confirm wins for device codes
- docs(backend): plan — split Task 8 (refactor) and Task 9 (avatars), harden avatar handling
- refactor(mixins): LocalPlayerMixin 691→111 + 4 handlers (8.5.2)
- refactor(visuals): Trails 687→130 (8.5.2)
- refactor(render): ItemBatchRenderer 677->100 (8.5.2)
- refactor(visuals): ReimaginedVisual 674→118 + 5 helpers (8.5.2)
- refactor(config): ConfigSerializer 668→91 + 4 helpers (8.5.2)
- refactor(hud): DynamicIsland 661→158 + 4 helpers (8.5.2)
- refactor(render): GlStencilFramebufferSupport 666→169 (8.5.2)
- refactor(gui): MenuScreen 669→128 + 4 helpers (8.5.2)
- refactor(render): UiStyle 644→170 + 3 helpers (8.5.2)
- refactor(gui): ModuleComponent 613→98 + 4 helpers (8.5.2)
- refactor(media): MediaSessionService 616→200 + 4 helpers (8.5.2)
- refactor(gui): RelationsComponent 661→59 + 4 helpers (8.5.2)
- chore(license): strip GPL file headers from all Java sources
- refactor(aiming): PointTracker 583→168 + 2 helpers (8.5.2)
- refactor(gui): LoVisualProxyManagerScreen 591→132 + 2 helpers (8.5.2)
- refactor(visuals): KillEffect 588→96 + 4 helpers (8.5.2)
- refactor(render): MeshBuilder +4 helpers (8.5.2)
- refactor(visuals): extract WorldParticlesRender helper (8.5.2)
- refactor(world): ExplosionDamageUtil 551→116 + 2 helpers (8.5.2)
- refactor(visuals): TazikHat 596->179 + Model + Palette in hats/tazik (8.5.2)
- chore(license): strip GPL header from remaining 30 files and make strip script variant-aware
- refactor(gui): ThemeComponent 561->166 + CardRenderer + ScrollState (8.5.2)
- refactor(hud): CustomHotbar 556→178 + Renderer + Selection + SelectionGradient (8.5.2)
- refactor(gui): ThemeCardRenderer perf + readability polish
- refactor(clickgui): CooldownRulesSetting 596->198 + Editor + DetailRenderer (8.5.2)
- refactor(hud): HudNotifier 561->200 + Painter + runtime/HudNotifierRuntime (8.5.2)
- refactor(theme): Themes 555->168 + impl/Transition + impl/Blending + impl/ProfileCodec (8.5.2)
- refactor(theme): EditableClickGuiTheme 205->185 + JavaDoc (8.5.2)
- refactor(theme): ThemeStore 491->128 + store/ThemeStoreJson + store/ThemeStoreIO (8.5.2)
- refactor(clickgui): ClickGuiRenderer 604->200 compacted one-line delegators + JavaDoc (8.5.2)
- refactor(mainmenu): LoVisualMainMenuScreen 551->161 + impl/Painter + impl/Renderer + impl/TextUtil (8.5.2)
- refactor(clickgui): ClickGuiTextEditorState 531->187 + impl/EditorCaret + impl/EditorPainter (8.5.2)
- refactor(tab): TabListModel 525->139 + model/Collector + model/Reader + model/Signature + model/TextSplitter (8.5.2)
- refactor(backend): shared bearer helper and test helpers, build_app takes Config, validate JWT secret strength
- refactor(module): ModuleManager 521->198 + impl/Registrar + impl/Dispatcher (8.5.2)
- feat(backend): avatar upload with decode, square crop, PNG re-encode and S3 storage
- refactor(clip): ClipFunction 512->146 + impl/Geometry + impl/Debug (8.5.2)
- docs(backend): implementation plans for gateway (auth hardening, gRPC, rate limits) and configs-service
- refactor(iris-patch): ShaderPatchEngine 499->146 + impl/Repo (8.5.2)
- chore(frontend): add router, react-query, fonts and vitest; dev proxy to gateway
- refactor(hud): ScriptedListHudPanel 499->158 + panel/Props + panel/Signature (8.5.2)
- refactor(hud): BaseHudElement 499->199 + impl/Registry + impl/Namer + impl/Prewarm (8.5.2)
- refactor(clickgui): Setting 498->170 + impl/Localization + impl/I18n (8.5.2)
- refact(viewmodel): split swing animations into camera/swing package
- refact(kineticlyrics): split module into stage, playback and modes
- rename(holeesp): module HoleESP -> CrystalHoles
- refact(crystalholes): split module into crystal scanner, renderer and safety
- refact(addonmanager): split manager into lifecycle, runtime, descriptors and profiles
- refact(accountconfig): split config into store, session and value helpers
- refactor(render): CustomTextRenderer 229->195, extract glyph-pass into GradientTexts helper
- docs(TODO): mark AddonManager split done; close 9.2 refactor gate
- refactor(media): LinuxMediaSession 441->148, split reader + track/seek state
- refactor(nametags): split NameTags into facade + impl helpers
- refactor(clickgui): split MainSettingsComponent into facade + scroll + model
- refactor(hud): split CustomBar into facade, model and BarSettings
- docs(frontend): implementation plan with design system from the mod theme
- feat(frontend): design tokens from the mod theme, fonts and shared UI kit
- fix(accounts): run migrations on startup, offload Argon2, validate register input, JSON error shape
- docs(gateway): plan note on splitting auth handlers before refresh endpoints
- feat(frontend): API client with silent refresh, error descriptions and test helpers
- style(mod): group compact one-line bulk query methods in ModuleManager
- feat(frontend): session restore, login and registration with client-side validation
- refactor(hud): split CustomHealthBar into facade + painter + script renderer
- docs(mod): record the 2026-09-24 HUD/settings split wave in TODO phase 8.5
- refactor(rhi): split GlStencilShapeClipBackend into facade + native-state + pass-lifecycle helpers
- refactor(rhi): split VulkanRenderStateBridge into facade + MSAA and stencil state helpers
- refactor(backtrack): split BacktrackController into facade + model + impl helpers
- refactor(svg): split SvgPathParser into facade + arc geometry + command/curve helpers
- refactor(mixin): split ClientPacketListenerMixin into hook-only mixin + handlers
- refactor(renderer3d): un-nest batch bindings + culling into sibling impl types
- refactor(renderwarp): extract static factories + geometry into impl helpers
- feat(backend): add common crate with shared JWT, internal gateway contract and accounts proto
- refactor(guimixin): move hook bodies into handlers, keep mixin as hooks + shadows
- feat(accounts): accept only gateway traffic, read identity from gateway header
- refactor(cacheduiscriptruntime): extract engine, hashing and frame stats into impl
- refactor(customskyboxrenderer): extract projection, shader passes and sun into impl
- refactor(betterchatstoremanager): extract persistence, key/path and hover helpers into impl
- feat(accounts): rotating opaque refresh tokens in httpOnly cookie, /auth/refresh and /auth/logout
- refactor(targetesp): extract crystal rendering subsystem into impl/TargetEspCrystalRenderer
- refactor(betterchathovercache): extract disk codec and lookup indexing into impl/ChatHoverCacheCodec
- refactor(microsoftauth): split HTTP transport, device-code and Xbox flows into impl/
- refactor(pvpcooldowns): extract local item-rule engine and defaults into impl/PvpCooldownRules
- refactor(lovisual): extract HUD/world render orchestration into HudRender helper
- refactor(statuseffectheuristics): extract palette/inference into ParticlePalette and color utils into ParticleColors
- refactor(dropesp): extract overlay/label render subsystem into impl/DropEspOverlayRenderer
- refactor(proxy): extract SOCKS handshake message builders into ProxyProtocolMessages
- refactor(eagleutil): promote EdgeRecovery controller and RecoveryMode to top-level class
2026-09-24 23:52:12 +02:00

96 lines
5.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Frontend Architecture (продумано заранее, реализация — следующий план)
> Статус: структура согласована до написания implementation-плана фронтенда,
> чтобы план сразу проектировался под правильные границы, а не переписывался
> после первого клубка спагетти. Стек: React + Vite + TypeScript + Tailwind
> (см. `TODO.md`, Фаза 10). Правила платформы (≤250 строк/файл и т.д.) — там же.
## Принцип: структура по фичам, не по типу файла
Раскладывать `src/` на `/components`, `/hooks`, `/services`, `/types` вперемешку —
самая частая ошибка в React-проектах: одна фича размазывается по всему дереву
папок, и её нельзя удалить или вынести, не задев остальное. Вместо этого —
каждая фича владеет всем, что ей нужно, в одной папке.
```
frontend/src/
features/
auth/ # регистрация/логин, device-link экран
components/
hooks/
api.ts # вызовы к accounts-service через gateway
types.ts
configs/ # 4 слота, share-коды, витрина
components/
hooks/
api.ts
types.ts
avatars/
admin/ # /admin, видим только role=admin
shared/ # только то, что реально используют 2+ фичи
components/ # кнопки, инпуты, модалки — дизайн-система
hooks/ # useAuth (общий контекст сессии), useDebounce и т.п.
api/
client.ts # общий fetch-wrapper: base URL gateway, JWT в заголовке,
# обработка 401 (refresh) и 429 (rate-limit) в одном месте
types.ts # общие DTO, если совпадают на нескольких фичах
pages/ # роуты верхнего уровня, тонкие — просто собирают
# фичи в layout, никакой бизнес-логики
App.tsx
main.tsx
```
Правило раздела shared/feature: если код используется ровно в одной фиче —
он живёт в этой фиче, а не в `shared/`. Переносить в `shared/` только когда
появился второй потребитель — не заранее "на всякий случай" (YAGNI).
**Лимиты из правил платформы (`TODO.md`) действуют и тут**: ≤250 строк на
файл, ≤4 файла на папку (подпапки не считаются) — если в `components/`
внутри фичи появляется 5-й файл, выносим смысловую подпапку, а не копим.
## Антипаттерны, которых сознательно избегаем
- **Barrel-файлы `index.ts` на каждую папку** — удобны на вид, но ломают
tree-shaking и IDE go-to-definition на больших проектах; экспортируем
напрямую из файла, где определено
- **Prop drilling через 4+ уровня** — если проп передаётся через компоненты,
которым он сам не нужен (просто транзитом) — это сигнал на React Context
(для auth-сессии) или на подъём компонента ниже по дереву, а не терпеть
drilling
- **Бизнес-логика в `pages/`** — страницы только компонуют фичи и layout;
если в файле страницы появляется `fetch`/сложная derived-логика — она
переезжает в соответствующую фичу
- **Один гигантский `api.ts` на весь проект** — обращения к API живут в
папке своей фичи (`features/configs/api.ts` и т.д.), общий только
low-level `shared/api/client.ts` (fetch-wrapper)
- **any вместо нормальных типов** — DTO с бэкенда типизируются по контрактам
из `backend/PLAN.md` (Task 6: `RegisterResponse`, `LoginResponse` и т.д.),
не `any`/`unknown` без сужения
## Тестирование
Тесты живут в подпапке `tests/` внутри фичи (или `shared/*`), которую они
проверяют — не рядом с файлом (`Component.test.tsx`) и не в отдельном дереве
на верхнем уровне. Это всё ещё удаляется вместе с фичей при её удалении/
переносе, но не съедает бюджет "≤4 файла на папку" — колокация `X.test.tsx`
рядом с `X.tsx` вдвое сокращала бы вместимость каждой папки под этим правилом.
```
frontend/src/
features/
auth/
components/
hooks/
api.ts
types.ts
tests/
api.test.ts
components.test.tsx
shared/
ui/
Button.tsx
TextField.tsx
tests/
ui.test.tsx
```
Источники: [Robin Wieruch — React Folder Structure Best Practices 2026](https://www.robinwieruch.de/react-folder-structure/), [Mastering Modern React + Vite Folder Structure, Medium](https://sandeshrathnayake.medium.com/mastering-modern-react-vite-folder-structure-a-production-ready-guide-for-scalable-applications-9ad8e233f8b9).