117 lines
7.7 KiB
Markdown
117 lines
7.7 KiB
Markdown
# Backend Conventions
|
||
|
||
## Структура решения
|
||
|
||
```
|
||
backend/
|
||
PnvPanel.sln
|
||
src/
|
||
PnvPanel.Domain/
|
||
Common/ # Entity, AggregateRoot, IDomainEvent, ValueObject base
|
||
Nodes/ # Node, NodeCredentials, NodeStatus, события
|
||
Inbounds/ # Inbound, VpnProtocol
|
||
Configs/ # VpnConfig, ConfigStatus, TrafficLimit, события
|
||
Plans/ # Plan
|
||
Exceptions/ # DomainException и наследники
|
||
PnvPanel.Application/
|
||
Common/
|
||
Behaviors/ # Validation, Logging, UnitOfWork, Authorization
|
||
Interfaces/ # IAppDbContext, IXuiPanelGateway, ICurrentUser, IRealtimeNotifier, ...
|
||
Messaging/ # ISender, ICommand<T>, IQuery<T>, ICommandHandler<,>, IQueryHandler<,>, IPipelineBehavior<,>
|
||
Models/ # Result<T>, Error, PagedList<T>
|
||
Mapping/ # Mapster-конфиги
|
||
Auth/ # Register/Login/Refresh (Commands, Handlers, Validators, DTOs)
|
||
Configs/ # CreateVpnConfig, EditVpnConfig, RotateVpnConfig, RevokeVpnConfig, GetMyConfigs, GetConfigLink, GetSubscription, ...
|
||
Nodes/ # RegisterNode, SyncNode, ListNodes, ...
|
||
Inbounds/ # PublishInbound, ListInbounds, ...
|
||
Apps/ # (admin) CRUD каталога ClientApp; GetApps (по ОС) для юзера
|
||
Admin/ # ListUsers, BlockUser/UnblockUser, ChangeUserRole, GetStats, Audit, ...
|
||
PnvPanel.Infrastructure/
|
||
Persistence/
|
||
AppDbContext.cs
|
||
Configurations/ # IEntityTypeConfiguration<T>
|
||
Migrations/
|
||
Identity/ # AppUser, AppRole, JwtTokenService, RefreshToken
|
||
Xui/ # XuiPanelGateway, XuiClientFactory (per-node)
|
||
Realtime/ # SignalRRealtimeNotifier
|
||
BackgroundJobs/ # TrafficSyncService, NodeHealthCheckService
|
||
Security/ # DataProtectionSecretProtector
|
||
DependencyInjection.cs
|
||
PnvPanel.Api/
|
||
Endpoints/ # AuthEndpoints, ConfigEndpoints, NodeEndpoints, AdminEndpoints, SubscriptionEndpoints
|
||
Hubs/ # PanelHub
|
||
Middleware/ # ExceptionHandling, RequestCorrelation
|
||
Extensions/ # AddApiServices, UseApiPipeline
|
||
Program.cs
|
||
appsettings*.json
|
||
tests/
|
||
PnvPanel.Domain.Tests/
|
||
PnvPanel.Application.Tests/
|
||
PnvPanel.Integration.Tests/ # Testcontainers PostgreSQL
|
||
```
|
||
|
||
Организация Application — **по фичам** (feature folders), внутри слоёв Clean Architecture.
|
||
|
||
## Именование
|
||
|
||
- Классы/методы/свойства — `PascalCase`; параметры/локальные — `camelCase`; приватные поля — `_camelCase`.
|
||
- Команды — `<Verb><Noun>Command` (`CreateVpnConfigCommand`), запросы — `<Get/List><Noun>Query`.
|
||
- Хендлеры — `<Command/Query>Handler`; валидаторы — `<Command/Query>Validator`.
|
||
- DTO — суффикс `Dto` (`VpnConfigDto`); ответы эндпоинтов — `Response`, тела запросов — `Request`.
|
||
- Async-методы — суффикс `Async`, всегда принимают `CancellationToken`.
|
||
- Один публичный тип на файл; имя файла = имя типа.
|
||
|
||
## Паттерны
|
||
|
||
- **Rich domain model**: инварианты в сущностях (приватные сеттеры, фабричные методы `Node.Create(...)`,
|
||
поведенческие методы `config.Revoke()`), а не анемичные DTO-сущности.
|
||
- **CQRS через собственный диспетчер**: хендлеры реализуют `ICommandHandler<TCommand,TResult>` /
|
||
`IQueryHandler<,>`; `ISender` резолвит их из DI и прогоняет через `IPipelineBehavior<,>`
|
||
(валидация, транзакция, логирование). Без внешних CQRS-библиотек.
|
||
- **Порты в Application, адаптеры в Infrastructure**: никакого `Npgsql`/`SignalR`/`ThreeXui.Net` в Application/Domain.
|
||
- **`IAppDbContext`** экспонирует `DbSet<>` и `SaveChangesAsync`; хендлеры пишут LINQ напрямую
|
||
(репозитории — только для сложной агрегатной логики).
|
||
- **Result-модель**: команды/запросы возвращают `Result<T>`; эндпоинт маппит в HTTP (`.Match(...)`).
|
||
- **Транзакция на команду**: `UnitOfWorkBehavior` оборачивает выполнение команды в транзакцию.
|
||
- **Валидация**: `ValidationBehavior` до хендлера; хендлер не проверяет формат ввода повторно.
|
||
- **Идемпотентность**: команды к 3x-ui устойчивы к повторам; при частичном сбое — компенсация
|
||
(создали клиента в панели, но упала БД → удалить клиента, вернуть ошибку).
|
||
- **Оптимистичная блокировка**: на изменяемых сущностях (нода, конфиг) — `xmin`/rowversion, чтобы
|
||
параллельные правки не затирали друг друга.
|
||
|
||
## Работа с 3x-ui
|
||
|
||
- Только через порт `IXuiPanelGateway`. Гейтвей принимает `Node`/`NodeId` и разруливает per-node клиента.
|
||
- Пароли нод расшифровываются `ISecretProtector` **внутри** Infrastructure, никогда не покидают слой.
|
||
- Сетевые ошибки/недоступность → `Result.Failure`/статус ноды, не «пробрасываем» наружу как 500.
|
||
|
||
## Async / Cancellation
|
||
|
||
- Всё I/O — асинхронно; пробрасывать `CancellationToken` до EF Core и HTTP-вызовов.
|
||
- Не блокировать (`.Result`/`.Wait()`).
|
||
|
||
## Ошибки и логирование
|
||
|
||
- Единый `ProblemDetails` для ошибок API; коды: 400 (валидация), 401/403 (auth), 404, 409 (конфликт домена), 422, 429 (rate limit), 500.
|
||
- Serilog со структурными полями (`UserId`, `NodeId`, `ConfigId`, `CorrelationId`); секреты не логировать.
|
||
|
||
## Тестирование
|
||
|
||
- **Domain.Tests** — инварианты и поведение сущностей, без моков.
|
||
- **Application.Tests** — хендлеры с подменёнными портами (NSubstitute), проверка веток `Result`.
|
||
- **Integration.Tests** — реальный PostgreSQL (Testcontainers), миграции, сквозные сценарии эндпоинтов;
|
||
3x-ui — мок гейтвея или фейковый HTTP-сервер.
|
||
- Именование тестов: `Method_Scenario_ExpectedResult`.
|
||
|
||
## Конфигурация
|
||
|
||
- `appsettings.json` + `appsettings.{Environment}.json` + env vars (перекрывают).
|
||
- Секреты (JWT-ключ, строка подключения, ключ шифрования) — user-secrets (dev) / env/secret-store (prod).
|
||
- Строго типизированные `IOptions<T>` для секций конфига; валидация опций на старте.
|
||
|
||
## Стиль и качество кода
|
||
|
||
- `.editorconfig` + анализаторы (`Microsoft.CodeAnalysis.NetAnalyzers`), nullable reference types **включены**.
|
||
- `dotnet format` в CI; предупреждения как ошибки для наших проектов.
|
||
- Комментарии — по необходимости (почему, а не что); публичные контракты портов документируем XML-doc.
|