# 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, IQuery, ICommandHandler<,>, IQueryHandler<,>, IPipelineBehavior<,> Models/ # Result, Error, PagedList 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 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`. - Команды — `Command` (`CreateVpnConfigCommand`), запросы — `Query`. - Хендлеры — `Handler`; валидаторы — `Validator`. - DTO — суффикс `Dto` (`VpnConfigDto`); ответы эндпоинтов — `Response`, тела запросов — `Request`. - Async-методы — суффикс `Async`, всегда принимают `CancellationToken`. - Один публичный тип на файл; имя файла = имя типа. ## Паттерны - **Rich domain model**: инварианты в сущностях (приватные сеттеры, фабричные методы `Node.Create(...)`, поведенческие методы `config.Revoke()`), а не анемичные DTO-сущности. - **CQRS через собственный диспетчер**: хендлеры реализуют `ICommandHandler` / `IQueryHandler<,>`; `ISender` резолвит их из DI и прогоняет через `IPipelineBehavior<,>` (валидация, транзакция, логирование). Без внешних CQRS-библиотек. - **Порты в Application, адаптеры в Infrastructure**: никакого `Npgsql`/`SignalR`/`ThreeXui.Net` в Application/Domain. - **`IAppDbContext`** экспонирует `DbSet<>` и `SaveChangesAsync`; хендлеры пишут LINQ напрямую (репозитории — только для сложной агрегатной логики). - **Result-модель**: команды/запросы возвращают `Result`; эндпоинт маппит в 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` для секций конфига; валидация опций на старте. ## Стиль и качество кода - `.editorconfig` + анализаторы (`Microsoft.CodeAnalysis.NetAnalyzers`), nullable reference types **включены**. - `dotnet format` в CI; предупреждения как ошибки для наших проектов. - Комментарии — по необходимости (почему, а не что); публичные контракты портов документируем XML-doc.