Add docker

This commit is contained in:
Evgenii Saenko
2025-12-17 11:51:25 +03:00
parent a01b46182e
commit 4f6700e0e2
110 changed files with 8838 additions and 181 deletions

97
docs/architecture.md Normal file
View File

@@ -0,0 +1,97 @@
# Архитектура клиентского приложения
Документ описывает устройство Reactклиента из `src/` и взаимосвязь его модулей, чтобы упростить навигацию по проекту и подключение новых разработчиков.
## Технологический стек
- **React 19 + TypeScript** — основной UIфреймворк (`src/main.tsx`, `src/app/App.tsx`), компоненты пишутся как функции с хуками.
- **Vite** — сборка, локальный дев‑сервер и предпросмотр (`package.json` скрипты `dev`, `build`, `preview`).
- **React Router v7** — маршрутизация клиентского приложения (`src/app/router/routes.tsx`).
- **MobX + mobx-react-lite** — управление состоянием через сторы и модели (`src/stores/*`), привязка к компонентам через `observer`.
- **Material UI 7** — дизайн‑система и тема (`src/shared/theme`), включает Emotion для стилизации.
- **Zod** — валидация сетевых ответов и входных данных (`src/api/**/*.ts`).
## Организация каталогов
```
src/
├─ app/ # точка входа UI, глобальные маршруты и обёртка приложения
├─ modules/ # фичевые модули (публичный сайт, админка, разделы)
├─ shared/ # переиспользуемые UIкомпоненты, хуки, тема
├─ providers/ # Reactпровайдеры, контексты
├─ stores/ # состояние MobX и доменные модели
├─ api/ # HTTPклиент, DTO и SDK для бэкенда
├─ assets/ # картинки и брендинговые ассеты
├─ index.css # глобальные стили
└─ main.tsx # инициализация Reactприложения
```
`public/` хранит статические файлы Vite, а `docs/` отведён под документацию (включая текущий файл).
## Жизненный цикл приложения
1. `src/main.tsx` монтирует `<App />` в StrictMode.
2. `src/app/App.tsx` собирает корневое дерево: `<StoreProvider>``<AppTheme>``<CssBaseline>``<RouterProvider router={router} />`.
3. `src/app/router/routes.tsx` объявляет все маршруты, разделяя публичные страницы (`/`, `/news`, `/services`, `/about`) и защищённую зону `/admin/dashboard` с вложенными разделами.
Благодаря `<Outlet />` внутри `AdminDashboardLayout` (`src/modules/admin/components/dashboard-layout.tsx`) дочерние страницы админки получают общий chrome (AppBar, Drawer, выход из аккаунта).
## Управление состоянием
- `src/stores/root.tsx` инициализирует `RootStore` с коллекциями новостей, услуг и категорий услуг. Экземпляр передаётся в Reactконтекст через `StoreProvider` (`src/providers/store.tsx`), а хук `useStore` (`src/shared/hooks/useStore.ts`) упрощает доступ к нему.
- Каждый доменный объект описан MobXмоделью (например, `NewsModel` и `ServiceModel`), которая инкапсулирует нормализацию данных, вычисляемые геттеры (`href`) и методы `update` / `toJSON`.
- Коллекции (`NewsCollectionModel`, `ServicesCollectionModel`, `ServiceCategoryCollectionModel`) отвечают за загрузку данных из API, трекинг `isLoading`/`error`, пагинацию и дедупликацию через `Map`.
- В компонентах состояние наблюдается через `observer` (см. `src/modules/main/components/services.tsx`, `src/modules/services/pages/service-details.tsx`, `src/modules/admin/components/news/dashboard-news.tsx`), что гарантирует реактивность без ручных `useState`.
## Сетевой слой и API
- `src/api/httpClient.ts` содержит унифицированный `send` (GET/POST/PUT/DELETE), сборщик queryпараметров и работу с токеном администратора в `localStorage`. Ответы проходят через Zodсхемы, а при ошибках выбрасывается `ApiError`.
- В `src/api/*` реализованы специализированные SDK:
- `newsApi`, `servicesApi`, `leadsApi` — публичные чтения.
- `adminApi` — все CRUDоперации админки (авторизация, категории, услуги, новости, администрирование).
- Типы DTO и схемы (`src/api/**/types.ts`) документируют поля и позволяют IDE/TypeScript подсказывать структуры данных по всему приложению.
## UI-слой и тема
- Тема MUI собирается в `src/shared/theme/theme.tsx`: кастомные `colorSchemes`, `typography`, `shadows` и набор component overrides (`shared/theme/customizations/*`). Цветовая схема подключается через CSSпеременные и переключатель режима (`ColorModeSelect`, `ColorModeIconDropdown`).
- Глобальные стили (`src/index.css`) подключают шрифты и базовые переменные.
- Переиспользуемые шапка и подвал (`src/shared/components/header.tsx`, `src/shared/components/footer.tsx`) формируют каркас публичных страниц.
## Фичевые модули
- **Main (`src/modules/main`)** — лендинг: блоки `Hero`, `Services`, `RecentNews`, `Features`, `Partners`, `Feedback`. Использует сторы для вывода последних услуг и новостей, а `usePageTitle` (`src/shared/hooks/usePageTitle.ts`) обновляет `document.title`.
- **Services (`src/modules/services`)** — список и детальная страница услуг. `ServiceDetailsPage` грузит данные по `slug`, отображает карточку, хлебные крошки и форматирует цену через `formatPrice`.
- **News (`src/modules/news`)** — лента с пагинацией, просмотр новости (`NewsDetailsPage`), утилита форматирования дат `formatDate`.
- **About (`src/modules/about`)** — информационная статическая страница.
- **Admin (`src/modules/admin`)** — полноценная панель управления:
- маршруты `/admin` (логин) и `/admin/dashboard/*`;
- `dashboard-layout` отвечает за адаптивную навигацию;
- разделы: новости, услуги, категории, лиды, администраторы;
- формы создания/редактирования (`components/services/service-form.tsx`, `components/news/news-create-form.tsx`, `components/service-categories/*`) используют MUI `TextField`, локальную валидацию и обращения к `adminApi`.
- раздел лидов (`components/leads/dashboard-leads.tsx`) общается с `leadsApi` напрямую и хранит состояние в локальных хуках, поскольку данных немного.
## Поток данных и валидации
1. Компонент фичи (например, `Services` или `AdminDashboardNews`) вызывает методы стора (`services.fetch`, `news.fetchAdmin`).
2. Стор делегирует запрос соответствующему SDK (`servicesApi`, `adminApi`) и обновляет MobXмодели.
3. Компоненты, обёрнутые в `observer`, автоматически перерисовываются и показывают лоадеры/ошибки.
4. Формы в админке валидируют ввод на клиенте, а серверные ошибки ловятся как `ApiError` и выводятся в UI.
Такая цепочка (компонент → стор → API → стор → компонент) делает логику прозрачной и облегчает внедрение новых сущностей.
## Ассеты и стили
- Брендовые изображения и логотипы лежат в `src/assets` и импортируются напрямую в компоненты (например, хедер использует `src/assets/logo.png`).
- Файлы в `public/` доступны по прямым URL и могут использоваться для метатегов или фавиконок.
- Изображения партнёров (`src/assets/partners`) подключаются только внутри лендинга, что упрощает tree-shaking.
## Расширение проекта
Чтобы добавить новую сущность:
1. Создайте Zodсхемы и APIклиент в `src/api/<entity>`.
2. Опишите MobXмодель + коллекцию в `src/stores/<entity>`, инициализируйте её в `RootStore`.
3. Подготовьте UI в отдельном модуле внутри `src/modules/<entity>` и подключите маршруты через `src/app/router/routes.tsx`.
4. При необходимости добавьте переиспользуемые компоненты/хуки в `src/shared`.
Следование существующим паттернам гарантирует единообразие и упрощает поддержку сервиса.

387
docs/part1-2-brief.md Normal file
View File

@@ -0,0 +1,387 @@
# 📘 Бриф по Главе 1
## Тема: Рекламно-информационный сайт предприятия
---
## 🎯 Цель главы
Определить значение рекламно-информационного сайта в деятельности организации, проанализировать предметную область и существующие решения, сформулировать требования к создаваемой системе и обосновать выбор инструментов и технологий для её реализации.
---
## 🧩 Структура и содержание
### **1.1. Введение в тему**
Рекламно-информационные сайты играют ключевую роль в цифровой деятельности организаций. Они обеспечивают представление компании в сети, выполняют функции информирования, продвижения и коммуникации с клиентами. Основная задача таких систем — создание единого центра актуальной информации, доступного пользователям в круглосуточном режиме.
---
### **1.2. Роль рекламно-информационного сайта в деятельности компании**
* Сайт выступает инструментом маркетингового взаимодействия, каналом распространения информации и формирования имиджа.
* Обеспечивает комплексное продвижение товаров и услуг, снижает зависимость от традиционных каналов рекламы.
* Выполняет функции оперативного обновления информации, аналитики пользовательской активности и обратной связи.
* Повышает уровень доверия к компании, способствует укреплению бренда и конкурентоспособности.
---
### **1.3. Анализ предметной области и существующих решений**
* Предметная область охватывает процессы разработки веб-ресурсов, организации хранения и обработки данных, а также взаимодействие с пользователем.
* Типичные функции сайтов-аналогов: главная страница, разделы «О компании», каталог услуг, новости, формы обратной связи, адаптивная верстка.
* Современные тенденции: использование систем управления контентом (CMS), интеграция с социальными сетями, мультимедийный контент, адаптивный дизайн и персонализированные сервисы.
* Вывод: сайт должен быть информативным, интуитивно понятным и обеспечивать оперативное обновление данных при высокой производительности.
---
### **1.4. Постановка задачи**
#### **Функциональные требования:**
* публикация сведений об организации, услугах и новостях;
* поиск по содержимому сайта;
* формы обратной связи и администрирование контента;
* централизованное хранение данных в базе.
#### **Нефункциональные требования:**
* корректное отображение на различных устройствах;
* безопасность и защита данных;
* высокая скорость работы и возможность масштабирования;
* удобство сопровождения и расширяемость архитектуры.
Задача разработки заключается в создании системы, обеспечивающей удобный доступ к информации и эффективное управление содержимым со стороны организации.
---
### **1.5. Обоснование выбора инструментов и технологий**
| Компонент | Технология | Аргументация выбора |
| --------------- | --------------------------- | ----------------------------------------------------------------------------------------------- |
| **Фронтенд** | React | Модульная структура, высокая производительность, повторное использование компонентов. |
| **Бэкенд** | Kotlin (Ktor / Spring Boot) | Строгая типизация, устойчивость, поддержка асинхронных операций, интеграция с Java-экосистемой. |
| **База данных** | PostgreSQL | Реляционная модель, транзакционная целостность, масштабируемость, надёжность. |
| **Веб-сервер** | NGINX | Высокая производительность, стабильность, возможности балансировки нагрузки. |
📌 Совокупность данных технологий обеспечивает создание надёжной, безопасной и масштабируемой системы, соответствующей современным требованиям веб-разработки.
---
## 🧠 Ключевые выводы по главе
1. Рекламно-информационный сайт является стратегически значимым элементом цифрового присутствия организации.
2. Анализ аналогичных решений позволил определить актуальные тенденции и стандарты для разработки.
3. Сформулированные требования отражают как пользовательские, так и внутренние потребности компании.
4. Выбор инструментов (React, Kotlin, PostgreSQL, NGINX) обоснован с позиций эффективности, надёжности и дальнейшего развития проекта.
5. Итогом первой главы является определение концептуальной базы и технологического фундамента для последующего проектирования системы.
---
## 📄 Итоговая роль главы
Первая глава закладывает методологическую и техническую основу дипломного проекта.
На её основе формируется архитектура системы, разрабатывается структура базы данных и описываются механизмы взаимодействия клиентской и серверной частей, которые раскрываются в последующих разделах работы.
Brief: Проектирование и разработка веб-приложения «BankInfo»
(суммаризация второй главы)
1. Архитектурная концепция
Веб-приложение реализовано как трёхуровневая система:
Frontend — React SPA (React 19, TypeScript, MobX, MUI, React Router, Zod)
Backend — Ktor (Kotlin), Ktorm ORM, HikariCP, JWT
Database — PostgreSQL 14 (схема public)
Ключевые принципы проектирования:
модульность и слабая связанность;
разделение ответственности по слоям;
REST-взаимодействие между клиентом и сервером;
* статeless-авторизация через JWT;
* строгая типизация DTO и валидируемых данных.
---
## **2. Архитектура приложения**
### **2.1. Общая схема взаимодействия**
Поток данных:
```
Client (React SPA)
→ REST API /api/v1/*
→ Ktor Server (Routing → Controllers → Services → Repositories)
→ PostgreSQL (SQL через Ktorm)
← JSON Response
```
В приложении предусмотрено место под:
* **Рисунок 2.1** — Architecture / Deployment diagram
* **Приложение А** — увеличенная схема
---
### **2.2. Backend**
Структура серверной части:
```
app/
├─ Database (HikariCP)
├─ HTTP plugins
├─ Serialization (kotlinx)
├─ Security (JWT)
└─ Routing (подключение модулей)
modules/
├─ aНиже — **брив (brief-doc) по всей второй главе**, оформленный в Markdown.
Это краткая, структурированная, сжатая версия всей главы 2 — идеально подходит:
* для презентации,
* для защиты диплома,
* для приложений,
* для рабочего черновика.
Готов к копированию в отдельный файл `brief-chapter-2.md`.
---
# **Brief: Проектирование и разработка веб-приложения «BankInfo»**
*(суммаризация второй главы)*
---
## **1. Архитектурная концепция**
Веб-приложение реализовано как трёхуровневая система:
* **Frontend** — React SPA (React 19, TypeScript, MobX, MUI, React Router, Zod)
* **Backend** — Ktor (Kotlin), Ktorm ORM, HikariCP, JWT
* **Database** — PostgreSQL 14 (схема `public`)
Ключевые принципы проектирования:
* модульность и слабая связанность;
* раздdmin
├─ news
├─ services
├─ serviceCategory
└─ lead
```
Используемые паттерны:
* **Layered Architecture**
* **Controller → Service → Repository**
* **DTO Boundary**
* **Repository Pattern (DDD)**
* **Exception Mapping** через StatusPages
* **Dependency Injection (ручной)**
* **Stateless Auth** через JWT
Основные технические особенности:
* валидация slug/username/email реализована сервисами;
* eager-loading связей в услугах (JOIN в Ktorm);
* SQL-пагинация через `LIMIT/OFFSET`;
* единый формат ошибок;
* отсутствие уникальных ограничений на уровне БД по slug/email (осознанное решение).
---
### **2.3. Frontend**
Стек:
* React 19
* TypeScript
* MobX (`observer`, observable state tree)
* React Router v7 (nested routing)
* MUI (design system)
* Zod (schema validation)
* Vite (bundler)
Структура каталогов:
```
src/
├─ app/ (маршруты, App)
├─ modules/ (публичные страницы + админка)
├─ stores/ (MobX)
├─ api/ (httpClient + SDK + DTO + Zod)
├─ shared/ (UI-компоненты, тема)
├─ providers/ (StoreProvider, ThemeProvider)
└─ assets/
```
Паттерны:
* **Component-based architecture**
* **Separation of concerns**
* **Observer Pattern (MobX)**
* **Gateway/API Client**
* **DTO Boundary для фронтенда**
* **Layout Composition** для админки
* **Design System Architecture** (MUI)
Поток данных:
```
Component → Store → API → Store → UI
```
Вставляется как:
* **Рисунок 2.3** — Data Flow Diagram
* **Приложение В** — полная версия
---
## **3. REST API**
Основная структура: `/api/v1/*`
Ключевые маршруты:
| Endpoint | Метод | Назначение |
| ------------- | ------------------- | -------------------------- |
| `/auth/login` | POST | Авторизация администратора |
| `/news` | GET/POST/PUT/DELETE | Управление новостями |
| `/services` | GET/POST/PUT/DELETE | Услуги |
| `/categories` | GET/POST/PUT/DELETE | Категории |
| `/leads` | GET/POST | Лиды |
| `/users` | GET/POST/PUT/DELETE | Администраторы |
Все административные endpoints защищены JWT-middleware.
---
## **4. Модель данных**
### **Основные сущности:**
* **Admin**
* **News**
* **ServiceCategory**
* **Service**
* **Lead**
### **Особенности БД:**
* PostgreSQL 14.19
* схема: `public`
* `timestamptz` для временных полей
* `varchar` дефолтной длины
* единственный FK: `services.category_id → categories.id`
* уникальность slug/username/email **не** enforced в БД (реализуется сервисами)
### **Реализация через Ktorm:**
* интерфейсы Entity
* объекты Table
* `Database.sequenceOf(Table)`
* сущности загружаются с категориями через JOIN (eager)
* DTO разделены на публичные и административные
ER-диаграмма:
* **Рисунок 2.4** — ER Diagram
* **Приложение Д** — масштабируемая версия
---
## **5. UI / UX проектирование**
Публичные страницы:
* Главная
* Услуги
* Услуга
* Новости
* Новость
* О компании
* Контакты / форма лида
Административная панель:
* Dashboard
* Администраторы
* Услуги
* Категории
* Новости
* Лиды
`sitemap`:
* **диаграмма (Рисунок 2.5)**
* **Приложение Е**
---
## **6. Реализация**
### **Backend:**
* безопасная авторизация JWT
* унифицированные CRUD-модули
* SQL-запросы через Ktorm
* централизованная обработка ошибок
* слабая связанность сущностей
* ручная структура БД (без миграций)
### **Frontend:**
* реактивность MobX
* строгая типизация API через Zod
* модульная структура pages/features/components
* единая тема оформления
* локальная валидация форм
* защищённые маршруты для админки
---
## **7. Тестирование**
### **Проверялось:**
* корректность REST API
* авторизация и работа с JWT
* маршруты и вложенная навигация
* формы и валидация
* реактивность MobX
* стабильность CRUD-операций
* отображение данных на публичных страницах
* стабильность админ-панели
---
## **8. Общий вывод**
Система имеет следующую совокупность свойств:
* надёжная архитектурная основа;
* модульность и расширяемость;
* современный стек технологий;
* строгие границы ответственности между слоями;
* безопасная модель аутентификации;
* предсказуемые, универсальные CRUD-процессы;
* реактивность клиентской части;
* типобезопасный сетевой слой;
* минимальная связанность базы данных;
* удобная административная панель;
* чистая архитектура backend и frontend.
С точки зрения инженерии ПО, проект демонстрирует высокий уровень проработки, следование современным практикам и архитектурным принципам, а также готовность к дальнейшему развитию и эксплуатационному использованию

133
docs/sitemap.svg Normal file
View File

@@ -0,0 +1,133 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1450" height="520" viewBox="0 0 1450 520">
<defs>
<marker id="arrow" viewBox="0 0 10 10" refX="8" refY="5" markerWidth="7" markerHeight="7"
orient="auto-start-reverse">
<path d="M0 0 L10 5 L0 10 z" fill="#444"/>
</marker>
<style>
text { font-family: sans-serif; fill: #222; font-size: 14px; }
.node { fill: #eef3fa; stroke: #444; stroke-width: 1.5; rx: 6; ry: 6; }
.section-label { font-weight: 600; font-size: 16px; }
.group-box { fill: none; stroke: #bbb; stroke-width: 1; stroke-dasharray: 4 4; }
</style>
</defs>
<rect width="1450" height="520" fill="#ffffff"/>
<text x="725" y="40" text-anchor="middle" font-size="20">Карта сайта веб-приложения</text>
<!-- Public group -->
<rect class="group-box" x="60" y="80" width="820" height="390"/>
<text class="section-label" x="70" y="100">Публичный раздел</text>
<!-- Root -->
<rect class="node" x="100" y="190" width="190" height="80"/>
<text x="195" y="215" text-anchor="middle">
<tspan x="195" y="215">/</tspan>
<tspan x="195" y="235">Главная</tspan>
<tspan x="195" y="253">(основная)</tspan>
</text>
<!-- Public nodes -->
<rect class="node" x="360" y="110" width="210" height="70"/>
<text x="465" y="135" text-anchor="middle">
<tspan x="465" y="135">/services</tspan>
<tspan x="465" y="155">Список услуг</tspan>
</text>
<rect class="node" x="360" y="200" width="210" height="70"/>
<text x="465" y="225" text-anchor="middle">
<tspan x="465" y="225">/news</tspan>
<tspan x="465" y="245">Лента новостей</tspan>
</text>
<rect class="node" x="360" y="290" width="210" height="70"/>
<text x="465" y="315" text-anchor="middle">
<tspan x="465" y="315">/about</tspan>
<tspan x="465" y="335">О компании</tspan>
</text>
<rect class="node" x="360" y="380" width="210" height="70"/>
<text x="465" y="405" text-anchor="middle">
<tspan x="465" y="405">/contacts</tspan>
<tspan x="465" y="425">Контакты / заявка</tspan>
</text>
<!-- Detail nodes -->
<rect class="node" x="620" y="90" width="210" height="70"/>
<text x="725" y="115" text-anchor="middle">
<tspan x="725" y="115">/services/:slug</tspan>
<tspan x="725" y="135">Детали услуги</tspan>
</text>
<rect class="node" x="620" y="180" width="210" height="70"/>
<text x="725" y="205" text-anchor="middle">
<tspan x="725" y="205">/news/:slug</tspan>
<tspan x="725" y="225">Новостная статья</tspan>
</text>
<!-- Public connectors -->
<path d="M290 230 L330 230 L330 145 L360 145" stroke="#444" stroke-width="1.5" fill="none"
marker-end="url(#arrow)"/>
<path d="M290 230 L330 230 L330 230 L360 230" stroke="#444" stroke-width="1.5" fill="none"
marker-end="url(#arrow)"/>
<path d="M290 230 L330 230 L330 325 L360 325" stroke="#444" stroke-width="1.5" fill="none"
marker-end="url(#arrow)"/>
<path d="M290 230 L330 230 L330 415 L360 415" stroke="#444" stroke-width="1.5" fill="none"
marker-end="url(#arrow)"/>
<line x1="570" y1="145" x2="620" y2="125" stroke="#444" stroke-width="1.5" marker-end="url(#arrow)"/>
<line x1="570" y1="235" x2="620" y2="215" stroke="#444" stroke-width="1.5" marker-end="url(#arrow)"/>
<!-- Admin group -->
<rect class="group-box" x="900" y="80" width="520" height="430"/>
<text class="section-label" x="910" y="100">Админ-раздел</text>
<rect class="node" x="930" y="130" width="220" height="70"/>
<text x="1040" y="155" text-anchor="middle">
<tspan x="1040" y="155">/admin</tspan>
<tspan x="1040" y="175">Логин</tspan>
</text>
<rect class="node" x="930" y="220" width="220" height="70"/>
<text x="1040" y="245" text-anchor="middle">
<tspan x="1040" y="245">/admin/dashboard</tspan>
<tspan x="1040" y="265">Панель управления</tspan>
</text>
<rect class="node" x="930" y="310" width="220" height="55"/>
<text x="1040" y="335" text-anchor="middle">
<tspan x="1040" y="335">/admin/dashboard/news</tspan>
<tspan x="1040" y="353">Управление новостями</tspan>
</text>
<rect class="node" x="930" y="375" width="220" height="55"/>
<text x="1040" y="400" text-anchor="middle">
<tspan x="1040" y="400">/admin/dashboard/services</tspan>
<tspan x="1040" y="418">Управление услугами</tspan>
</text>
<rect class="node" x="930" y="440" width="220" height="55"/>
<text x="1040" y="465" text-anchor="middle">
<tspan x="1040" y="465">/admin/dashboard/service-categories</tspan>
<tspan x="1040" y="483">Категории услуг</tspan>
</text>
<rect class="node" x="1180" y="310" width="220" height="55"/>
<text x="1290" y="335" text-anchor="middle">
<tspan x="1290" y="335">/admin/dashboard/leads</tspan>
<tspan x="1290" y="353">Заявки</tspan>
</text>
<rect class="node" x="1180" y="375" width="220" height="55"/>
<text x="1290" y="400" text-anchor="middle">
<tspan x="1290" y="400">/admin/dashboard/users</tspan>
<tspan x="1290" y="418">Администраторы</tspan>
</text>
<!-- Admin connectors -->
<line x1="1040" y1="200" x2="1040" y2="220" stroke="#444" stroke-width="1.5" marker-end="url(#arrow)"/>
<line x1="1040" y1="290" x2="1040" y2="310" stroke="#444" stroke-width="1.5" marker-end="url(#arrow)"/>
<line x1="1040" y1="365" x2="1040" y2="375" stroke="#444" stroke-width="1.5" marker-end="url(#arrow)"/>
<line x1="1040" y1="430" x2="1040" y2="440" stroke="#444" stroke-width="1.5" marker-end="url(#arrow)"/>
<line x1="1150" y1="338" x2="1180" y2="338" stroke="#444" stroke-width="1.5" marker-end="url(#arrow)"/>
<line x1="1150" y1="403" x2="1180" y2="403" stroke="#444" stroke-width="1.5" marker-end="url(#arrow)"/>
</svg>

After

Width:  |  Height:  |  Size: 6.1 KiB

57
docs/structure.svg Normal file
View File

@@ -0,0 +1,57 @@
<svg xmlns="http://www.w3.org/2000/svg" width="900" height="320" viewBox="0 0 900 320">
<defs>
<marker id="arrow" viewBox="0 0 10 10" refX="8" refY="5" markerWidth="8" markerHeight="8"
orient="auto-start-reverse">
<path d="M0 0 L10 5 L0 10 z" fill="#4a6179"/>
</marker>
<style>
text { font-family: monospace; fill: #222; font-size: 14px; }
.node { fill: #e8eef5; stroke: #4a6179; stroke-width: 1.5; }
.label { font-size: 13px; }
</style>
</defs>
<rect width="900" height="320" fill="#ffffff"/>
<text x="450" y="40" font-size="18" text-anchor="middle">Поток данных в клиентском приложении (Компонент → Store →
API → Store → UI)
</text>
<rect class="node" x="30" y="90" width="150" height="80" rx="8" ry="8"/>
<text class="label" x="105" y="120" text-anchor="middle">
<tspan x="105" y="120">Компонент React</tspan>
<tspan x="105" y="140">(UI + обработчики)</tspan>
</text>
<rect class="node" x="210" y="90" width="150" height="80" rx="8" ry="8"/>
<text class="label" x="285" y="120" text-anchor="middle">
<tspan x="285" y="120">MobX Store</tspan>
<tspan x="285" y="140">(управление</tspan>
<tspan x="285" y="156">состоянием)</tspan>
</text>
<rect class="node" x="390" y="90" width="150" height="80" rx="8" ry="8"/>
<text class="label" x="465" y="120" text-anchor="middle">
<tspan x="465" y="120">API Client</tspan>
<tspan x="465" y="140">(fetch + Zod</tspan>
<tspan x="465" y="156">валидация)</tspan>
</text>
<rect class="node" x="570" y="90" width="150" height="80" rx="8" ry="8"/>
<text class="label" x="645" y="120" text-anchor="middle">
<tspan x="645" y="120">Store Update</tspan>
<tspan x="645" y="140">(наблюдаемые</tspan>
<tspan x="645" y="156">изменения)</tspan>
</text>
<rect class="node" x="750" y="90" width="150" height="80" rx="8" ry="8"/>
<text class="label" x="825" y="120" text-anchor="middle">
<tspan x="825" y="120">UI Re-render</tspan>
<tspan x="825" y="140">(observer</tspan>
<tspan x="825" y="156">компоненты)</tspan>
</text>
<line x1="180" y1="130" x2="210" y2="130" stroke="#4a6179" stroke-width="2" marker-end="url(#arrow)"/>
<text x="195" y="75" text-anchor="middle">действие / намерение</text>
<line x1="360" y1="130" x2="390" y2="130" stroke="#4a6179" stroke-width="2" marker-end="url(#arrow)"/>
<text x="375" y="75" text-anchor="middle">fetch-запрос</text>
<line x1="540" y1="130" x2="570" y2="130" stroke="#4a6179" stroke-width="2" marker-end="url(#arrow)"/>
<text x="555" y="75" text-anchor="middle">валидированный ответ</text>
<line x1="720" y1="130" x2="750" y2="130" stroke="#4a6179" stroke-width="2" marker-end="url(#arrow)"/>
<text x="735" y="75" text-anchor="middle">событие изменения</text>
<path d="M780 170 C 700 250, 220 250, 150 170" fill="none" stroke="#4a6179" stroke-width="2"
marker-end="url(#arrow)"/>
<text x="465" y="250" text-anchor="middle">следующее взаимодействие</text>
</svg>

After

Width:  |  Height:  |  Size: 3.3 KiB