POST /api/v1/legal-entities/{id}/files (DOCUMENT_EDIT, видимость ЮЛ → 404): тип по расширению
со сверкой сигнатуры (domain/file_types.py), лимит UPLOAD_MAX_BYTES → FILE_TOO_LARGE, дедуп по
sha256 в пределах ЮЛ (кроме SUPERSEDED) с рекомендательной блокировкой (ЮЛ, sha256) до конца
транзакции запроса, s3_object → put_object → stored_file(UPLOADED) → recognition_job(queued) →
current_recognition_job_id, аудит FILE_UPLOAD. Каждый файл — SAVEPOINT: частичный успех
(201/422), отказ S3 на файле — STORAGE_UNAVAILABLE только для него; без S3 — 503.
safe_filename/CONTENT_TYPES/read_limited вынесены в common/filenames.py (импорт справочников
их переиспользует). Схемы UploadResult/FileOut/JobBrief/DocumentBrief, PrimaryFilesService и
зависимость для Task 9–10. tasks.md 2.1.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012vJkmBGKKqMoEMzvsXG3y2
`_today()` в `services/legal_entities.py` берёт московскую дату
(`common/clock.py`: `moscow_date`, `MOSCOW_TZ` = Europe/Moscow; без базы
часовых поясов — фиксированный UTC+3, Москва без перехода на летнее время с
2014 г.). Тесты на границе суток: 23:30 МСК (20:30 UTC) — ещё 4-е, 00:30 МСК
(21:30 UTC того же дня) — уже 5-е, и 4-е становится прошлым. README: даты
перевода/вывода — по Москве.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012vJkmBGKKqMoEMzvsXG3y2
Раздел SESSION, object_type app_user, IP и user-agent запроса
(`services/session_audit.py`):
- LOGIN — выдача dev-токена (в транзакции запроса) и первый успешный
`current_user` пользователя после старта процесса (`SessionAudit.logged_in`,
в памяти процесса; параллельные первые запросы — одно событие);
- LOGIN_FAILED — 401 (токен не принят: user_id пуст, причина без токена) и 403
аутентификации (не зарегистрирован / отключён / неоднозначен: email в
description, user_id — если найден). `AuthenticationFailedError` (подкласс
HTTPException) обрабатывается после отката транзакции запроса, запись — в
отдельной транзакции `session_transaction`, поэтому остаётся в журнале.
Без заголовка Authorization и 403 «недостаточно прав» — не события входа;
ошибка записи аудита входа ответ не меняет.
Тесты: `test_login_audit.py` (в т.ч. фиксация при откате запроса на
`committed_app`); счётчики следов импорта не учитывают события SESSION.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012vJkmBGKKqMoEMzvsXG3y2
Реестр имя ограничения PostgreSQL -> (код, постоянный текст) в common/constraint_conflicts.py;
integrity_error_handler для unique_violation (23505) по известному ограничению отдаёт
{"detail": {"code", "message"}}, иначе прежняя общая строка. Имя берётся из полей драйвера
(asyncpg __cause__.constraint_name, psycopg diag), не из текста ошибки; resolved_code пишется в лог.
Тесты: unit обработчика/реестра (ключи есть в Base.metadata), интеграционные гонки (ГК/ЮЛ crm_id,
ИНН, алиас, email, членство, откат и следующий запрос, FK остаётся общим 409).
T15.3: README шаг 4 импорта; T15.4: test_components_have_no_duplicated_models.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012vJkmBGKKqMoEMzvsXG3y2
- get_async_session: одна транзакция на запрос (commit при успехе, rollback при исключении), R-1;
объявляется только через SessionDep (scope="function") — commit до отправки ответа, одна сессия
на все зависимости запроса; current_user и dev-эмитент переведены на SessionDep.
- DomainError/NotFoundError/ConflictError/DomainValidationError + обработчик
{"detail": {"code", "message", ...}}; ответы HTTPException и ошибок БД не меняются.
- RequestAudit/get_request_audit: AuditService.record с user_id, ip_address, user_agent запроса.
- schemas/common.py: Page[T], PageParams (limit 1..200, по умолчанию 50; offset >= 0), ErrorDetail.
- tests/test_uow_and_errors.py: формат ошибок, пагинация, аудит, scope сессии во всех маршрутах,
настоящий commit/rollback на временной БД, commit до http.response.start, ошибка commit -> 409.
- План: Task 2 отмечена; tasks.md: 1.2 отмечен.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012vJkmBGKKqMoEMzvsXG3y2