Введены доменные исключения Deal.SharedKernel.Errors: DealException (код ошибки + текст из ресурсов), NotFoundException, ValidationException, ConflictException, ServiceUnavailableException.
Тексты ошибок вынесены в ресурсы Deal.SharedKernel/Resources/ErrorMessages.resx (нейтральная культура = ru); доступ через ErrorResources/ErrorResourceKeys. Добавление языка — отдельный .resx-спутник без правок кода.
HTTP-граница: DealExceptionHandler (IExceptionHandler) — доменный код → 404/400/409/503, непредвиденное → 500 с обобщённым русским текстом; лог с контекстом (метод, путь, tenantId, traceId), стектрейс только в лог.
gRPC-граница: RpcCallLoggingInterceptor маппит DealException.ErrorCode → статус gRPC (NotFound/InvalidArgument/FailedPrecondition/Unavailable), прочие сбои → Unknown с текстом из ресурсов.
Ожидаемые ветки аутентификации (ResolveSessionAsync, LogoutAsync без impersonation).
Вынесено в отдельную задачу
CardResultDto-потоки (AddLink/RemoveLink/MoveStage и др.), MlReviewService, pipeline-воркеры, DiscoveryCandidatesService — требуют решения Result-паттерн vs исключения.
Ссылка на задачу: https://gitea.khomegeneric.keenetic.pro/rust/Deal/issues/16
## Что сделано
- Введены доменные исключения `Deal.SharedKernel.Errors`: `DealException` (код ошибки + текст из ресурсов), `NotFoundException`, `ValidationException`, `ConflictException`, `ServiceUnavailableException`.
- Тексты ошибок вынесены в ресурсы `Deal.SharedKernel/Resources/ErrorMessages.resx` (нейтральная культура = ru); доступ через `ErrorResources`/`ErrorResourceKeys`. Добавление языка — отдельный `.resx`-спутник без правок кода.
- HTTP-граница: `DealExceptionHandler` (`IExceptionHandler`) — доменный код → 404/400/409/503, непредвиденное → 500 с обобщённым русским текстом; лог с контекстом (метод, путь, tenantId, traceId), стектрейс только в лог.
- gRPC-граница: `RpcCallLoggingInterceptor` маппит `DealException.ErrorCode` → статус gRPC (NotFound/InvalidArgument/FailedPrecondition/Unavailable), прочие сбои → Unknown с текстом из ресурсов.
- Конверсия «не найдено»: `ContainersService`, `CardsService` (карточка/файлы), `DiscoveryTasksService` бросают `NotFoundException`; эндпоинты убрали null-проверки.
- Правила закреплены в `docs/spec/Код-стайл-Дейл.md` §10.
- Тесты: ресурсы, HTTP-обработчик, обновлены затронутые тесты сервисов.
## Проверки
- Сборка 5 решений: 0 предупреждений / 0 ошибок.
- Тесты: core 1348, telegram 130, ai 52, ml 38, storage 9 — зелёные.
## Согласованные исключения (null допустим)
- Выборки-запросы репозиториев/сторов (`Get*` возвращает null — «нет строки»).
- Парсеры/извлечение полей (JsonExtractor, AmountParser, ContactsQualifier, LocalFieldsParser, BudgetNormalizer и т.п.) — «нет значения».
- Ожидаемые ветки аутентификации (`ResolveSessionAsync`, `LogoutAsync` без impersonation).
## Вынесено в отдельную задачу
- `CardResultDto`-потоки (`AddLink`/`RemoveLink`/`MoveStage` и др.), `MlReviewService`, pipeline-воркеры, `DiscoveryCandidatesService` — требуют решения Result-паттерн vs исключения.
DealException/NotFoundException/Validation/Conflict/ServiceUnavailable с кодом ошибки, тексты в ErrorMessages.resx. Общий HTTP-обработчик (DealExceptionHandler) и маппинг в gRPC-интерцепторе: доменные ошибки → статус, прочие → обобщённый текст без стектрейса. Правила закреплены в код-стайле §10.
CardsService (карточка/файл) и ContainersService бросают NotFoundException вместо возврата null; эндпоинты больше не проверяют null — 404 отдаёт общий обработчик. Тесты обновлены под новое поведение.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Ссылка на задачу: #16
Что сделано
Deal.SharedKernel.Errors:DealException(код ошибки + текст из ресурсов),NotFoundException,ValidationException,ConflictException,ServiceUnavailableException.Deal.SharedKernel/Resources/ErrorMessages.resx(нейтральная культура = ru); доступ черезErrorResources/ErrorResourceKeys. Добавление языка — отдельный.resx-спутник без правок кода.DealExceptionHandler(IExceptionHandler) — доменный код → 404/400/409/503, непредвиденное → 500 с обобщённым русским текстом; лог с контекстом (метод, путь, tenantId, traceId), стектрейс только в лог.RpcCallLoggingInterceptorмаппитDealException.ErrorCode→ статус gRPC (NotFound/InvalidArgument/FailedPrecondition/Unavailable), прочие сбои → Unknown с текстом из ресурсов.ContainersService,CardsService(карточка/файлы),DiscoveryTasksServiceбросаютNotFoundException; эндпоинты убрали null-проверки.docs/spec/Код-стайл-Дейл.md§10.Проверки
Согласованные исключения (null допустим)
Get*возвращает null — «нет строки»).ResolveSessionAsync,LogoutAsyncбез impersonation).Вынесено в отдельную задачу
CardResultDto-потоки (AddLink/RemoveLink/MoveStageи др.),MlReviewService, pipeline-воркеры,DiscoveryCandidatesService— требуют решения Result-паттерн vs исключения.