7.6 KiB
7.6 KiB
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, ...
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.