Revised the CLAUDE.md file to enhance clarity and accuracy in the project description. Updated terminology to reflect current functionality, including changes in user roles and media processing. Improved the architecture section by detailing the domain model and dependencies, ensuring a clearer understanding of the system's structure. Added references to documentation for better guidance on subsystem specifications.
129 lines
11 KiB
Markdown
129 lines
11 KiB
Markdown
# CLAUDE.md
|
|
|
|
Инструкции для Claude Code при работе в этом репозитории.
|
|
|
|
## Что это
|
|
|
|
**TeleWave** — сервис онлайн-каналов: зритель смотрит сетку каналов, видео отдаётся из хранилища
|
|
на сервере. Админ ведёт библиотеку, каналы и эфир.
|
|
|
|
Работает: аутентификация, роли, пользователи; библиотека шоу/серий, коллекции, жанры, метаданные
|
|
(TMDb/OMDb), обработка медиа (ffmpeg → HLS), изображения; группы, шаблон сетки, стыки и заставки,
|
|
автосборка по профилям, обмен конфигурацией файлом и запросом к ИИ; генерация ленты, live-раздача,
|
|
публичный просмотр, статистика хранилища. Telegram-бот сознательно не делаем. Конвенции — зеркало
|
|
[`PnvPanel`](../PnvPanel) (тот же автор).
|
|
|
|
**Спеки в `docs/` — источник правды по домену**, читай до правок в подсистеме:
|
|
[`tv-scheduler-architecture.md`](docs/tv-scheduler-architecture.md) (группы, сетка, слоты, стыки,
|
|
заставки, планировщик, автосборка, обмен конфигурацией — главный документ),
|
|
[`media-storage-and-streaming.md`](docs/media-storage-and-streaming.md) и
|
|
[`server-storage-setup.md`](docs/server-storage-setup.md) (медиа и хранилище).
|
|
|
|
## Стек
|
|
|
|
- **Backend**: C# / .NET 10, ASP.NET Core Minimal API, Clean Architecture, CQRS через
|
|
[`LiteCqrs.Net`](https://github.com/mrleo1nid/LiteCqrs.Net) (лёгкая альтернатива MediatR с явным
|
|
разделением Command/Query — см. README). EF Core 10 + Npgsql, Identity + JWT, FluentValidation,
|
|
Serilog, маппинг DTO вручную, OpenAPI + Scalar UI, тесты на xUnit + NSubstitute.
|
|
- **Frontend**: React 19 + Vite + TS, TanStack Query/Router (файловые роуты, `routeTree.gen.ts`
|
|
генерируется сборкой), shadcn поверх Radix + Tailwind v4, Zustand (только auth+тема),
|
|
react-hook-form + zod, i18n (ru/en), pnpm + oxlint + prettier.
|
|
|
|
## Архитектура — жёсткие правила
|
|
|
|
Зависимости строго внутрь: **Api → Infrastructure → Application → Domain**.
|
|
|
|
- **Domain** — без внешних зависимостей: `Auth`, `Library` (шоу, серии, коллекции, жанры), `Media`,
|
|
`Images`, `Programming` (группы, сетка, слоты, стыки + **чистый планировщик** `Planning`),
|
|
`Broadcast` (каналы, заставки, лента, live), `Settings`. Модель rich: приватные сеттеры,
|
|
фабрики `Create`, поведенческие методы.
|
|
- **Application** — CQRS-хендлеры, DTO, валидаторы и **порты** (`Common/Interfaces/I*.cs`:
|
|
`IAppDbContext`, `ICurrentUser`, `IMediaProcessor`, `IMediaStorage`, `IBumperRenderer`,
|
|
`IMetadataProvider`, `IImageStore`, `IStorageInspector`, …). Зависит только от Domain: никаких
|
|
`Npgsql`/`AspNetCore.Identity`, лишь их абстракции.
|
|
- **Infrastructure** — реализации портов: EF Core (`AppDbContext : IdentityDbContext<AppUser,
|
|
AppRole, Guid>`, конфигурации в `Persistence/Configurations`), ffmpeg, хранилище, метаданные,
|
|
идемпотентный `DbInitializer` (роли + админ из env `AdminSeed__*`).
|
|
- **Api** — Minimal API (`Endpoints/*Endpoints.cs`), middleware, DI composition root (`Program.cs`).
|
|
|
|
Обязательно:
|
|
- Команды меняют состояние в транзакции (`UnitOfWorkBehavior`); запросы только читают. Диспетчер —
|
|
`ISender`/`ICommandHandler`/`IQueryHandler`, регистрация в `Application/DependencyInjection.cs`.
|
|
- Управляемые ошибки — через `Result<T>` (`Common/Models/Result.cs`), не исключениями. Валидация —
|
|
FluentValidation через `ValidationBehavior`; хендлер не перепроверяет формат ввода.
|
|
- Всё I/O асинхронно, `CancellationToken` пробрасывается до EF/HTTP; никаких `.Result`/`.Wait()`.
|
|
Nullable включён, `TreatWarningsAsErrors=true` — предупреждения анализаторов не игнорировать.
|
|
- Планировщик (`Domain/Programming/Planning`) — **чистая функция**: вход `PlanningInput`, никаких
|
|
запросов и часов внутри. Данные под него собирает `Application/Programming/Planning`.
|
|
|
|
## Инварианты, которые легко нарушить
|
|
|
|
- **Роли** динамические, у пользователя ровно одна; системные `admin`/`user` (`IsSystem=true`) не
|
|
переименовать и не удалить, последнего админа не разжаловать, себя не заблокировать и не удалить.
|
|
- **Регистрация открытая** (создаётся `user`, токены сразу); понадобится модерация — заводи отдельный
|
|
флаг, не переиспользуй `IsBlocked`. Вход по `UserName`, email и SMTP не используются; JWT access +
|
|
refresh в httpOnly `tw_refresh_token` с обнаружением повторного использования отозванного.
|
|
- **Правка сетки эфир не двигает**: команда поднимает ревизию шаблона, ленту пересобирает применение.
|
|
- **Вещательные сутки** начинаются с `Channel.DayStartTime` (06:00), сетка задаётся во времени
|
|
канала (`UtcOffsetMinutes`), в базе всё в UTC.
|
|
|
|
## Единый контейнер
|
|
|
|
- Один образ: Api раздаёт REST (`/api`) и статику SPA из `wwwroot` (fallback на `index.html`), один
|
|
origin, база API — относительный `/api`. Multi-stage Dockerfile: node → dotnet sdk → aspnet.
|
|
Отдельный nginx для статики не вводить — ломает требование единого контейнера.
|
|
- Работает под непривилегированным `USER $APP_UID` (uid/gid 1654) **статически**, без
|
|
gosu/entrypoint: права на bind-mount выставляет оператор (`docs/server-storage-setup.md` § 5).
|
|
Data Protection не заводим — шифруемых секретов на диске нет. **TLS внешний**: `app` отдаёт HTTP
|
|
и доверяет `X-Forwarded-*`.
|
|
- docker-compose: только `app`. PostgreSQL внешний (`ConnectionStrings__Default` из `.env`), база
|
|
и пользователь создаются заранее вручную; миграции применяются на старте (`ApplyMigrationsAsync`),
|
|
прав `CREATEDB` не нужно.
|
|
|
|
## Соглашения по коду
|
|
|
|
- `<Verb><Noun>Command`/`<Get|List><Noun>Query` + `Handler`/`Validator` (где есть что проверить),
|
|
папки по фичам (`Auth/Login/`, `Programming/Templates/Generate/`, …). Один публичный тип на файл =
|
|
имя файла, кроме `Body` — тела Api-эндпоинтов, не совпадающие с командой 1:1 (`sealed record`
|
|
внизу файла эндпоинта). DTO — суффикс `Dto`.
|
|
- Ошибки — каталоги `XErrors` (`Error.Validation/NotFound/Conflict/…`), наружу единым
|
|
`application/problem+json` (`Api/Common/ResultExtensions.cs`). Секреты не логировать.
|
|
- **Изображения — только через реестр `Image`** (`Domain/Images`, галерея `features/admin/images`):
|
|
картинка хранится как `ImageId` и выбирается контролом `ImageGallery`/`GalleryBrowser`, своих
|
|
файловых полей не заводить. Файлы — `images/{id}{ext}`, отдаются по `/api/images/{id}`.
|
|
- Фронт: фича = папка в `src/features/admin/<фича>`; тексты только через i18n, ключи в `ru.ts` и `en.ts`.
|
|
- Комментарии объясняют **почему**, а не что; по-русски, как в существующем коде.
|
|
|
|
## Команды
|
|
|
|
Backend (из `backend/`):
|
|
```bash
|
|
dotnet build
|
|
dotnet csharpier format . # только через dotnet (версия из .config/); в CI — csharpier check
|
|
dotnet test tests/TeleWave.Domain.Tests # по одному проекту: MSBuild не берёт несколько
|
|
dotnet test tests/TeleWave.Application.Tests
|
|
dotnet test tests/TeleWave.Integration.Tests # Testcontainers; без Docker пропускаются
|
|
dotnet run --project src/TeleWave.Api
|
|
dotnet ef migrations add <Name> --project src/TeleWave.Infrastructure --startup-project src/TeleWave.Api
|
|
```
|
|
|
|
Frontend (из `frontend/`):
|
|
```bash
|
|
pnpm install && pnpm dev
|
|
pnpm lint && pnpm typecheck && pnpm build
|
|
pnpm format && pnpm format:check # CI падает на неотформатированном — прогоняй после правок
|
|
```
|
|
|
|
Инфраструктура: `docker compose up -d --build` (только api; postgres внешний). Окружение — Windows,
|
|
оболочка **PowerShell**; для POSIX-скриптов есть Bash-инструмент.
|
|
|
|
## Рабочие принципы
|
|
|
|
- Базовый срез реализован — правь его по месту. Новые крупные направления с непринятыми решениями
|
|
(многоэкземплярность, транскод-профили, новые подсистемы) — только после сверки с пользователем.
|
|
При неоднозначности — вопрос, а не предположение.
|
|
- Меняешь поведение подсистемы — обнови её спеку в `docs/` тем же заходом.
|
|
- Соблюдай границы слоёв — главный инвариант проекта.
|
|
- Не коммить и не пуши без явной просьбы.
|
|
- Отвечай пользователю на русском.
|