Skip to content

feat: Bring the architecture to a clean archeticture. In the structur…#29

Merged
Fl1riX merged 5 commits into
mainfrom
feat/architecture-improvement
May 30, 2026
Merged

feat: Bring the architecture to a clean archeticture. In the structur…#29
Fl1riX merged 5 commits into
mainfrom
feat/architecture-improvement

Conversation

@Fl1riX
Copy link
Copy Markdown
Owner

@Fl1riX Fl1riX commented May 30, 2026

…e, repeat the project structure for easier navigation. Separate the models into different files.

Summary by Sourcery

Выделены доменные модели в отдельный доменный слой и обновлены ссылки во всех сервисах, тестах и инфраструктуре в соответствии с более чистой архитектурой.

Новые возможности:

  • Введены отдельные модули доменных моделей для пользователей, сервисов, записей на прием, magic tokens и блокировок, включая связи и логику валидации.
  • Добавлен скрипт точки входа для деплоя, который применяет миграции базы данных и запускает сервер приложения.

Улучшения:

  • Рефакторинг сервисов и тестов для импорта моделей из нового пакета доменных моделей вместо прежнего модуля инфраструктурных моделей.
  • Реорганизация и перенос тестов, чтобы лучше отразить доменный и презентационный слои и повысить понятность структуры проекта.
  • Добавлен маркер общего пакета для сквозных (cross-cutting) компонентов.

Деплой:

  • Добавлен скрипт точки входа контейнера для запуска миграций Alembic перед стартом сервера API.

Тесты:

  • Адаптированы и перенесены тесты сервисов и обработчиков JWT в соответствии с новой архитектурой и расположением доменных моделей.
Original summary in English

Summary by Sourcery

Extract domain models into a dedicated domain layer and update references across services, tests, and infrastructure to align with a cleaner architecture.

New Features:

  • Introduce separate domain model modules for users, services, appointments, magic tokens, and bans, including relationships and validation logic.
  • Add a deployment entrypoint script that applies database migrations and starts the application server.

Enhancements:

  • Refactor services and tests to import models from the new domain models package instead of the old infrastructure models module.
  • Reorganize and relocate tests to better reflect domain and presentation layers, improving project structure clarity.
  • Add a shared package marker for cross-cutting components.

Deployment:

  • Add a container entrypoint script to run Alembic migrations before starting the API server.

Tests:

  • Adjust and relocate service and JWT handler tests to match the new architecture layout and domain model locations.

…e, repeat the project structure for easier navigation. Separate the models into different files.
@sourcery-ai
Copy link
Copy Markdown
Contributor

sourcery-ai Bot commented May 30, 2026

Руководство для рецензента

Рефакторинг проекта в сторону «чистой архитектуры»: ORM‑модели перенесены в выделенный пакет доменных моделей, сервисы и тесты обновлены для использования этого пакета, добавлены более богатые доменные модели (users, bans, services, appointments, magic tokens), скрипт входной точки для деплоя и небольшие доработки тестов.

Диаграмма взаимоотношений сущностей для новых доменных моделей

erDiagram
  User {
    int id
    string role
  }

  Service {
    int id
    int entrepreneur_id
  }

  Appointment {
    int id
    datetime date
    int service_id
    int entrepreneur_id
    int user_id
  }

  MagicToken {
    int id
    int telegram_id
    int user_id
  }

  Ban {
    int id
    int user_id
    int banned_by
    int revoked_by
  }

  User ||--o{ Service : offers
  User ||--o{ Appointment : makes
  User ||--o{ Appointment : serves_as_entrepreneur
  User ||--o{ MagicToken : owns
  User ||--o{ Ban : is_banned_by
  User ||--o{ Ban : issues_ban
  User ||--o{ Ban : revokes_ban

  Service ||--o{ Appointment : booked_for
Loading

Изменения на уровне файлов

Изменение Подробности Файлы
Введение отдельного набора доменных ORM‑моделей для users, appointments, services, magic tokens и bans и экспорт их через пакет доменных моделей.
  • Создана модель User с связями с appointments, services, bans и magic tokens, включая role и логику валидации для created_at.
  • Создана модель Appointment со связями с User и Service, уникальным ограничением и валидацией, гарантирующей, что дата записи не в прошлом.
  • Создана модель Service со связями с User и Appointment и уникальным ограничением на комбинацию name/address/entrepreneur.
  • Создана модель MagicToken для связки с Telegram с необязательной связью с пользователем и полями временных меток.
  • Создана модель Ban со связями с User, ограничениями и индексами для активных блокировок, логикой валидации временных меток блокировки и свойством активного статуса.
  • Добавлен файл src/domain/models/init.py, который реэкспортирует все доменные модели для удобного импорта.
src/domain/models/user_model.py
src/domain/models/appointment_model.py
src/domain/models/service_model.py
src/domain/models/magic_token_model.py
src/domain/models/ban_model.py
src/domain/models/__init__.py
Переход существующих сервисов, тестов и инициализации БД на использование новых доменных моделей и Base вместо старого модуля infrastructure models, а также корректировка расположения/названий тестов под новую структуру.
  • Обновлены AppointmentService, UserService, TgLinkService, AuthService, ServiceService и задача cleanup_magic_tokens для импорта моделей из src.domain.models вместо src.infrastructure.db.models.
  • Обновлены тесты для импорта MagicToken и User из src.domain.models и перенесены тесты сервисов в tests/domain/services, а тесты JWT‑обработчика — в tests/presentation/api/v1/auth.
  • Файл tests/conftest.py обновлён для импорта Base из src.infrastructure.db.database и импорта моделей из src.domain.models для обнаружения metadata.
  • Удалён устаревший модуль src/infrastructure/db/models.py.
src/domain/services/appointments_service.py
src/domain/services/user_service.py
src/domain/services/tg_link_service.py
src/domain/services/auth_service.py
src/domain/services/service_service.py
src/infrastructure/tasks/cleanup_magic_tokens.py
tests/conftest.py
tests/domain/services/test_tg_link_service.py
tests/domain/services/test_auth_service.py
tests/presentation/api/v1/auth/test_jwt_handler.py
src/infrastructure/db/models.py
Полировка и расширение тестов в соответствии с новой архитектурой и для повышения читаемости.
  • Отформатированы и немного уточнены интеграционные тесты для TgLinkService и AuthService (docstring-и, отступы, форматирование запросов).
  • Обновлены тесты JWT‑обработчика для импорта и тестирования decode_token и перенесены в слой тестов презентации; добавлен заготовочный тест для decode_token с созданием и декодированием токена.
  • Убедились, что импорты соответствуют слоям чистой архитектуры (domain, shared schemas, presentation).
tests/domain/services/test_tg_link_service.py
tests/domain/services/test_auth_service.py
tests/presentation/api/v1/auth/test_jwt_handler.py
Добавлен скрипт входной точки для деплоя и заглушка для пакета shared.
  • Создан deploy/entrypoint.sh для запуска миграций Alembic, а затем старта uvicorn.
  • Добавлен src/shared/init.py как заглушка для кросс-срезовых (cross‑cutting) общих компонентов.
deploy/entrypoint.sh
src/shared/__init__.py

Подсказки и команды

Взаимодействие с Sourcery

  • Запустить новый обзор: оставьте комментарий @sourcery-ai review в pull request.
  • Продолжить обсуждение: отвечайте напрямую на комментарии обзора от Sourcery.
  • Создать задачу GitHub из комментария обзора: попросите Sourcery создать
    issue из комментария обзора, ответив на него. Также можно ответить
    на комментарий обзора @sourcery-ai issue, чтобы создать issue на его основе.
  • Сгенерировать заголовок pull request: добавьте @sourcery-ai в любом месте
    заголовка pull request, чтобы в любой момент сгенерировать заголовок. Также можно
    оставить комментарий @sourcery-ai title в pull request, чтобы (пере)сгенерировать заголовок в любой момент.
  • Сгенерировать краткое описание pull request: добавьте @sourcery-ai summary
    в любом месте тела pull request, чтобы в любой момент сгенерировать
    резюме PR ровно в том месте, где вам нужно. Также можно оставить комментарий
    @sourcery-ai summary в pull request, чтобы (пере)сгенерировать резюме в любой момент.
  • Сгенерировать руководство для рецензента: оставьте комментарий
    @sourcery-ai guide в pull request, чтобы (пере)сгенерировать руководство для рецензента в любой момент.
  • Разрешить все комментарии Sourcery: оставьте комментарий @sourcery-ai resolve
    в pull request, чтобы пометить все комментарии Sourcery как решённые. Полезно,
    если вы уже всё исправили и не хотите больше видеть эти комментарии.
  • Отклонить все обзоры Sourcery: оставьте комментарий @sourcery-ai dismiss
    в pull request, чтобы отклонить все текущие обзоры Sourcery. Особенно полезно,
    если вы хотите начать с нуля новый обзор — не забудьте затем оставить комментарий
    @sourcery-ai review, чтобы запустить новый обзор!

Настройка работы

Зайдите в свою панель управления, чтобы:

  • Включать или отключать функции обзора, такие как автоматически
    генерируемое Sourcery резюме pull request, руководство для рецензента и другие.
  • Изменить язык обзора.
  • Добавлять, удалять или редактировать пользовательские инструкции для обзора.
  • Настроить остальные параметры обзора.

Получение помощи

Original review guide in English

Reviewer's Guide

Refactors the project toward a clean architecture by moving ORM models into a dedicated domain models package, updating services/tests to use it, and adding richer domain models (users, bans, services, appointments, magic tokens) plus a deployment entrypoint script and minor test cleanups.

Entity relationship diagram for new domain models

erDiagram
  User {
    int id
    string role
  }

  Service {
    int id
    int entrepreneur_id
  }

  Appointment {
    int id
    datetime date
    int service_id
    int entrepreneur_id
    int user_id
  }

  MagicToken {
    int id
    int telegram_id
    int user_id
  }

  Ban {
    int id
    int user_id
    int banned_by
    int revoked_by
  }

  User ||--o{ Service : offers
  User ||--o{ Appointment : makes
  User ||--o{ Appointment : serves_as_entrepreneur
  User ||--o{ MagicToken : owns
  User ||--o{ Ban : is_banned_by
  User ||--o{ Ban : issues_ban
  User ||--o{ Ban : revokes_ban

  Service ||--o{ Appointment : booked_for
Loading

File-Level Changes

Change Details Files
Introduce dedicated domain ORM models for users, appointments, services, magic tokens, and bans, and expose them via a domain models package.
  • Create User model with relationships to appointments, services, bans, and magic tokens, including role and validation logic for created_at.
  • Create Appointment model with relationships to User and Service, a uniqueness constraint, and validation ensuring appointment dates are not in the past.
  • Create Service model with relationships to User and Appointment and a uniqueness constraint on name/address/entrepreneur.
  • Create MagicToken model for Telegram linking with optional user relationship and timestamp fields.
  • Create Ban model with relationships to User, constraints and indexes for active bans, validation logic on ban timestamps, and active status property.
  • Add src/domain/models/init.py that re-exports all domain models for convenient imports.
src/domain/models/user_model.py
src/domain/models/appointment_model.py
src/domain/models/service_model.py
src/domain/models/magic_token_model.py
src/domain/models/ban_model.py
src/domain/models/__init__.py
Switch existing services, tests, and DB setup to use the new domain models and Base instead of the old infrastructure models module, and adjust test locations/names for the new structure.
  • Update AppointmentService, UserService, TgLinkService, AuthService, ServiceService, and cleanup_magic_tokens task to import models from src.domain.models instead of src.infrastructure.db.models.
  • Update tests to import MagicToken and User from src.domain.models and move service tests under tests/domain/services plus JWT handler tests under tests/presentation/api/v1/auth.
  • Adjust tests/conftest.py to import Base from src.infrastructure.db.database and import models from src.domain.models for metadata discovery.
  • Remove the obsolete src/infrastructure/db/models.py module.
src/domain/services/appointments_service.py
src/domain/services/user_service.py
src/domain/services/tg_link_service.py
src/domain/services/auth_service.py
src/domain/services/service_service.py
src/infrastructure/tasks/cleanup_magic_tokens.py
tests/conftest.py
tests/domain/services/test_tg_link_service.py
tests/domain/services/test_auth_service.py
tests/presentation/api/v1/auth/test_jwt_handler.py
src/infrastructure/db/models.py
Polish and extend tests to match the new architecture and improve clarity.
  • Reformat and slightly clarify integration tests for TgLinkService and AuthService (docstrings, spacing, query formatting).
  • Update JWT handler tests to import and test decode_token and move them under presentation-layer tests; add a decode_token test skeleton with token creation and decoding.
  • Ensure imports reflect clean architecture layers (domain, shared schemas, presentation).
tests/domain/services/test_tg_link_service.py
tests/domain/services/test_auth_service.py
tests/presentation/api/v1/auth/test_jwt_handler.py
Add deployment entrypoint script and shared package placeholder.
  • Create deploy/entrypoint.sh to run Alembic migrations then start uvicorn.
  • Add src/shared/init.py as a placeholder for cross-cutting shared items.
deploy/entrypoint.sh
src/shared/__init__.py

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link
Copy Markdown
Contributor

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - я нашёл 3 проблемы и оставил несколько общих замечаний:

  • Новые модули доменной модели (user_model, appointment_model, service_model, ban_model, magic_token_model) импортируют друг друга напрямую во время выполнения, что легко может привести к циклическим импортам; по возможности используйте TYPE_CHECKING и строковые типы для relationship вместо взаимных импортов.
  • В User.validate_create_date вы сравниваете created_at с datetime.utcnow(), тогда как значение по умолчанию для столбца задаётся через datetime.now(timezone.utc), то есть смешиваются наивные и привязанные к таймзоне объекты datetime; приведите обе стороны к единому варианту с таймзоной, чтобы избежать ошибок при сравнении во время выполнения.
  • Новый тест test_decode_token в tests/presentation/api/v1/auth/test_jwt_handler.py создаёт и декодирует токен, но никак не проверяет результат декодирования, поэтому фактически не валидирует поведение; добавьте проверки (assert) на декодированную полезную нагрузку или ожидаемые ошибки.
Prompt for AI Agents
Пожалуйста, исправьте замечания из этого code review:

## Общие комментарии
- Новые модули доменной модели (`user_model`, `appointment_model`, `service_model`, `ban_model`, `magic_token_model`) импортируют друг друга напрямую во время выполнения, что легко может привести к циклическим импортам; по возможности используйте `TYPE_CHECKING` и строковые типы для `relationship` вместо взаимных импортов.
- В `User.validate_create_date` вы сравниваете `created_at` с `datetime.utcnow()`, тогда как значение по умолчанию для столбца задаётся через `datetime.now(timezone.utc)`, то есть смешиваются наивные и привязанные к таймзоне объекты `datetime`; приведите обе стороны к единому варианту с таймзоной, чтобы избежать ошибок при сравнении во время выполнения.
- Новый тест `test_decode_token` в `tests/presentation/api/v1/auth/test_jwt_handler.py` создаёт и декодирует токен, но никак не проверяет результат декодирования, поэтому фактически не валидирует поведение; добавьте проверки (assert) на декодированную полезную нагрузку или ожидаемые ошибки.

## Отдельные комментарии

### Комментарий 1
<location path="src/domain/models/user_model.py" line_range="82" />
<code_context>
+        if not isinstance(value, datetime) and value is not None:
+            logger.warning("Некорректная дата")
+            raise TypeError("Некорректная дата")
+        elif value > datetime.utcnow():
+            logger.warning("Дата регистрации не может быть в будущем")
+            raise ValueError("Дата регистрации не может быть в будущем")
</code_context>
<issue_to_address>
**issue (bug_risk):** Избегайте сравнения значения `created_at` с таймзоной и наивного `datetime.utcnow()`.

Так как `created_at` — это `DateTime(timezone=True)` со значением по умолчанию `datetime.now(timezone.utc)`, он будет привязан к таймзоне. Сравнение его с `datetime.utcnow()` (наивным) приведёт к `TypeError`. Используйте `datetime.now(timezone.utc)` для сравнения или иным образом убедитесь, что обе стороны имеют согласованные настройки таймзоны, чтобы избежать падения валидатора.
</issue_to_address>

### Комментарий 2
<location path="src/domain/models/ban_model.py" line_range="96" />
<code_context>
+
+        if self.banned_at is not None:
+            if value < self.banned_at:
+                raise ValueError("banned_at не должно быть позже revoked_at")
+
+        return value
</code_context>
<issue_to_address>
**issue (bug_risk):** Сообщение об ошибке в `validate_revoked_at` не соответствует фактическому условию валидации.

Проверка использует `if value < self.banned_at:`, но сообщение говорит, что `banned_at` не должно быть позже `revoked_at`, что является обратным условием. Это будет вводить в заблуждение при отладке. Пожалуйста, либо измените сравнение (например, на `value <= self.banned_at`), чтобы оно соответствовало сообщению, либо обновите сообщение, указав, что `revoked_at` не должно быть раньше `banned_at`.
</issue_to_address>

### Комментарий 3
<location path="src/domain/models/ban_model.py" line_range="75" />
<code_context>
+    def validate_expires_at(self, key, value):
+        if value is not None:
+            if value <= datetime.now(timezone.utc):
+                raise ValueError("expires_at не должно быть в прошлом или None")
+            if value <= self.banned_at:
+                raise ValueError("expires_at не может быть меньше banned_at")
</code_context>
<issue_to_address>
**nitpick:** Сообщение валидации для `expires_at` противоречит логике, которая допускает `None`.

Условие `if value is not None:` разрешает `expires_at=None`, но текст ошибки говорит `"... не должно быть в прошлом или None"`, что подразумевает, что `None` недопустимо. Пожалуйста, приведите сообщение в соответствие с фактическим поведением (например, просто "expires_at не должно быть в прошлом") или обновите валидацию, если по бизнес-правилам `None` действительно должен быть запрещён.
</issue_to_address>

Sourcery бесплатно для open source — если вам нравятся наши обзоры, пожалуйста, расскажите о нас ✨
Помогите мне стать полезнее! Пожалуйста, нажмите 👍 или 👎 на каждом комментарии — я использую этот фидбек, чтобы улучшать обзоры.
Original comment in English

Hey - I've found 3 issues, and left some high level feedback:

  • The new domain model modules (user_model, appointment_model, service_model, ban_model, magic_token_model) import each other directly at runtime, which can easily create circular import issues; consider relying on TYPE_CHECKING and string-based relationship type hints instead of mutual imports wherever possible.
  • In User.validate_create_date you compare created_at against datetime.utcnow() while the column default uses datetime.now(timezone.utc), mixing naive and timezone-aware datetimes; align both sides to be consistently timezone-aware to avoid runtime comparison errors.
  • The new test_decode_token in tests/presentation/api/v1/auth/test_jwt_handler.py constructs and decodes a token but never asserts anything about the decoded result, so it currently doesn't verify behavior; add assertions on the decoded payload or expected failures.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The new domain model modules (`user_model`, `appointment_model`, `service_model`, `ban_model`, `magic_token_model`) import each other directly at runtime, which can easily create circular import issues; consider relying on `TYPE_CHECKING` and string-based `relationship` type hints instead of mutual imports wherever possible.
- In `User.validate_create_date` you compare `created_at` against `datetime.utcnow()` while the column default uses `datetime.now(timezone.utc)`, mixing naive and timezone-aware datetimes; align both sides to be consistently timezone-aware to avoid runtime comparison errors.
- The new `test_decode_token` in `tests/presentation/api/v1/auth/test_jwt_handler.py` constructs and decodes a token but never asserts anything about the decoded result, so it currently doesn't verify behavior; add assertions on the decoded payload or expected failures.

## Individual Comments

### Comment 1
<location path="src/domain/models/user_model.py" line_range="82" />
<code_context>
+        if not isinstance(value, datetime) and value is not None:
+            logger.warning("Некорректная дата")
+            raise TypeError("Некорректная дата")
+        elif value > datetime.utcnow():
+            logger.warning("Дата регистрации не может быть в будущем")
+            raise ValueError("Дата регистрации не может быть в будущем")
</code_context>
<issue_to_address>
**issue (bug_risk):** Avoid comparing a timezone-aware `created_at` value with a naive `datetime.utcnow()` instance.

Since `created_at` is `DateTime(timezone=True)` with default `datetime.now(timezone.utc)`, it will be timezone-aware. Comparing it to `datetime.utcnow()` (naive) will raise `TypeError`. Use `datetime.now(timezone.utc)` for the comparison, or otherwise ensure both sides have matching timezone awareness to avoid crashing the validator.
</issue_to_address>

### Comment 2
<location path="src/domain/models/ban_model.py" line_range="96" />
<code_context>
+
+        if self.banned_at is not None:
+            if value < self.banned_at:
+                raise ValueError("banned_at не должно быть позже revoked_at")
+
+        return value
</code_context>
<issue_to_address>
**issue (bug_risk):** The error message in `validate_revoked_at` does not match the actual validation condition.

The check uses `if value < self.banned_at:`, but the message says `banned_at` must not be later than `revoked_at`, which is the inverse of the condition. This will mislead debugging. Please either change the comparison (e.g. `value <= self.banned_at`) to match the message, or update the message to state that `revoked_at` must not be earlier than `banned_at`.
</issue_to_address>

### Comment 3
<location path="src/domain/models/ban_model.py" line_range="75" />
<code_context>
+    def validate_expires_at(self, key, value):
+        if value is not None:
+            if value <= datetime.now(timezone.utc):
+                raise ValueError("expires_at не должно быть в прошлом или None")
+            if value <= self.banned_at:
+                raise ValueError("expires_at не может быть меньше banned_at")
</code_context>
<issue_to_address>
**nitpick:** Validation message for `expires_at` conflicts with the logic that allows `None`.

The guard `if value is not None:` allows `expires_at=None`, but the error text says `"... не должно быть в прошлом или None"`, which suggests `None` is invalid. Please align the message with the actual behavior (e.g. just "expires_at не должно быть в прошлом") or update the validation if `None` should be disallowed by business rules.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread src/domain/models/user_model.py Outdated
Comment thread src/domain/models/ban_model.py Outdated
Comment thread src/domain/models/ban_model.py Outdated
@coveralls
Copy link
Copy Markdown

Coverage Report for CI Build 26688250472

Coverage increased (+2.5%) to 30.351%

Details

  • Coverage increased (+2.5%) from the base build.
  • Patch coverage: No coverable lines changed in this PR.
  • No coverage regressions found.

Uncovered Changes

No uncovered changes found.

Coverage Regressions

No coverage regressions found.


Coverage Stats

Coverage Status
Relevant Lines: 1196
Covered Lines: 363
Line Coverage: 30.35%
Coverage Strength: 0.61 hits per line

💛 - Coveralls

@coveralls
Copy link
Copy Markdown

coveralls commented May 30, 2026

Coverage Report for CI Build 26688593824

Coverage increased (+2.5%) to 30.351%

Details

  • Coverage increased (+2.5%) from the base build.
  • Patch coverage: No coverable lines changed in this PR.
  • No coverage regressions found.

Uncovered Changes

No uncovered changes found.

Coverage Regressions

No coverage regressions found.


Coverage Stats

Coverage Status
Relevant Lines: 1196
Covered Lines: 363
Line Coverage: 30.35%
Coverage Strength: 0.61 hits per line

💛 - Coveralls

@Fl1riX Fl1riX merged commit 85b12ea into main May 30, 2026
4 checks passed
@Fl1riX Fl1riX deleted the feat/architecture-improvement branch May 30, 2026 16:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants