Add instructions management functionality and update related components
CI / Backend (build + test) (push) Successful in 1m17s
CI / Frontend (lint + typecheck + build) (push) Successful in 32s

- Introduced new endpoints for managing instruction intros and tabs, allowing admins to create, update, and delete instructional content.
- Enhanced the FactoryResetCommandHandler to include the seeding of instruction data during a factory reset.
- Updated the database schema to include InstructionIntro and InstructionTab entities, with corresponding migrations.
- Improved frontend routing and components to support the new instructions section, including a dedicated page for displaying instructions and tabs.
- Enhanced API documentation to reflect the new instruction management features and their expected request/response formats.
- Added localization support for the new instructions functionality in both Russian and English.
This commit is contained in:
Leonid Pershin
2026-07-14 22:20:10 +03:00
parent 8c53fcded2
commit bef3880593
52 changed files with 2303 additions and 24 deletions
+26 -3
View File
@@ -105,6 +105,27 @@ status, createdAt }`. `expiresAt` всегда `null` (лимиты по сро
```
Значение `OsPlatform` в C#/JSON`IOS` (не `iOS`).
## Instructions — страница инструкций
Вводный markdown-текст (singleton) над вкладками + дополнительные вкладки, обе части редактируются
из админки. Встроенная вкладка «Приложения» (каталог `ClientApp`) в этот API не входит — фронт
всегда рисует её первой, сама её достаёт через `GET /api/apps`.
| Метод | Путь | Роль | Тело запроса | Тело ответа |
| ------ | ------------------------------------- | ----- | ----------------------------------- | ------------- |
| GET | `/api/instructions/intro` | user | — | `InstructionIntroDto` |
| GET | `/api/instructions/tabs` | user | — | `InstructionTabDto[]` (сортировка `SortOrder asc`) |
| PUT | `/api/admin/instructions/intro` | admin | `{ body }` | `InstructionIntroDto` |
| POST | `/api/admin/instructions/tabs` | admin | `{ title, body, sortOrder }` | `InstructionTabDto` |
| PUT | `/api/admin/instructions/tabs/{id}` | admin | `{ title, body, sortOrder }` | `InstructionTabDto` |
| DELETE | `/api/admin/instructions/tabs/{id}` | admin | — | `204 No Content` |
`PUT /api/admin/instructions/intro` — get-or-create (строка одна на всю систему; если её ещё нет,
создаётся, иначе обновляется на месте). `GET /api/instructions/intro` никогда не 404-ит — если строка
ещё не создана, отдаёт `{ id: "00000000-0000-0000-0000-000000000000", body: "", updatedAt: <MinValue> }`,
чтобы публичная страница не падала. Вкладки — обычный CRUD без статуса черновик/опубликовано, как
у `NewsPostDto`.
## News — лента новостей
| Метод | Путь | Роль | Тело запроса | Тело ответа |
@@ -200,9 +221,11 @@ Support.CannotRequestAdminRole`), либо все три поля новой р
(«Опасная зона») и требует ввести фразу-подтверждение в диалоге (не просто `confirm()`). Удаляет:
всех пользователей кроме текущего админа, все `VpnConfig`/`TrafficSample` (конфиги сначала best-effort
отзываются на нодах через `IXuiPanelGateway.RemoveClientAsync` — недоступная нода не блокирует сброс),
все `Node`/`Inbound`, тикеты с перепиской/вложениями (+файлы), `NewsPost`, весь `AuditLog`, все
кастомные роли (`AppRole.IsSystem == false`) и `ClientApp` каталог приложений затем пересеивается
через `IClientAppCatalogSeeder` (тот же сервис, что использует `DbInitializer` при первом старте).
все `Node`/`Inbound`, тикеты с перепиской/вложениями (+файлы), `NewsPost`, `InstructionIntro`/
`InstructionTab`, весь `AuditLog`, все кастомные роли (`AppRole.IsSystem == false`) и `ClientApp`
каталог приложений и вводный текст инструкций затем пересеиваются дефолтными значениями через
`IClientAppCatalogSeeder`/`IInstructionIntroSeeder` (те же сервисы, что использует `DbInitializer`
при первом старте); вкладки инструкций дефолтами не пересеиваются, как и новости.
Не атомарно целиком (несколько `SaveChangesAsync` внутри хендлера, как и в `DeleteUserCommandHandler`) —
при сбое посередине возможно частичное состояние, компенсации нет, это осознанный компромисс для
редкой ручной админской операции. Финальная запись `FactoryReset` в аудит добавляется уже после