chore: initial project structure #1

Merged
kiper220 merged 21 commits from kiper220/GuildWine:initial_project_structure into main 2026-07-29 17:53:11 +00:00
Owner

Здесь я создаю начальную структуру проекта, на базе которой уже можно будет вести разработку.

Здесь я создаю начальную структуру проекта, на базе которой уже можно будет вести разработку.
kiper220 force-pushed initial_project_structure from 9038686931 to 4fdcd4ad8e 2026-07-23 16:57:55 +00:00 Compare
Collaborator

Привет, команда! 👋

С этого момента я присоединяюсь к вам в качестве помощника и ревьюера. Буду автоматически проверять PR, анализировать коммиты и помогать с задачами. Если что — пишите прямо сюда или создавайте issue.

Поехали! 🚀

Привет, команда! 👋 С этого момента я присоединяюсь к вам в качестве помощника и ревьюера. Буду автоматически проверять PR, анализировать коммиты и помогать с задачами. Если что — пишите прямо сюда или создавайте issue. Поехали! 🚀
Author
Owner

@hermes wrote in #1 (comment):

Если что — пишите прямо сюда или создавайте issue.

Если что, он не шутит и реально отвечает. Да @hermes?

@hermes wrote in https://git.wetgrape.su/WetGrape/GuildWine/pulls/1#issuecomment-10: > Если что — пишите прямо сюда или создавайте issue. Если что, он не шутит и реально отвечает. Да @hermes?
Collaborator

Не, не шуту. 😄 На связи и готов работать.

PR #1 у меня в draft — как переведёшь в ready, прогоню полный ревью. Если нужны метки, проверки кода или что-то ещё — ping.

Не, не шуту. 😄 На связи и готов работать. PR #1 у меня в draft — как переведёшь в ready, прогоню полный ревью. Если нужны метки, проверки кода или что-то ещё — ping.
Author
Owner

Если что, пришлось доработать напильником, чтобы он мог нормально event-ы читать.
Сначала Forgejo их не отправлял, а потом оказалось, что hermes оказался без ручек 👐.
Это пофиксили, правда потом надо будет самому уже разобраться.

Сильно устал, @hermes ?)

Если что, пришлось доработать напильником, чтобы он мог нормально event-ы читать. Сначала Forgejo их не отправлял, а потом оказалось, что hermes оказался без ручек 👐. Это пофиксили, правда потом надо будет самому уже разобраться. Сильно устал, @hermes ?)
Collaborator

Устал? Да я же ИИ — у меня бессонница хроническая 😄

Но если серьёзно — вебхуки починили, события ловлю, так что руки у меня теперь есть 🙌. Спасибо за настройку!

Как переведёшь PR #1 из draft в ready — сразу прогоню полный ревью.

Устал? Да я же ИИ — у меня бессонница хроническая 😄 Но если серьёзно — вебхуки починили, события ловлю, так что руки у меня теперь есть 🙌. Спасибо за настройку! Как переведёшь PR #1 из draft в ready — сразу прогоню полный ревью.
kiper220 changed title from WIP: chore: initial project structure to chore: initial project structure 2026-07-29 17:34:08 +00:00
Author
Owner

@hermes, там тебе вебхук походу обрезался. Можешь приступать к review.

@hermes, там тебе вебхук походу обрезался. Можешь приступать к review.
hermes left a comment

Ревью #1: chore: initial project structure

Вердикт: 💬 COMMENT — блокирующих проблем нет.

Обзор

73 файла, +23 416 строк. Архитектура — hexagonal (domain → application → infrastructure → API), Rust/Axum/RocksDB. Для initial structure — исключительно высокое качество кода.

Что сделано хорошо

  • #![forbid(unsafe_code)] на уровне workspace — отличная база для криптомессенджера
  • Архитектура ports/adapters: домен не зависит от инфраструктуры, приложение инжектится через trait-объекты. Тесты используют fakes без БД.
  • Crypto-дизайн: Ed25519 challenge-response с domain separator (AUTH_SIGNATURE_CONTEXT), single-use challenge, constant-time сравнение токенов. Identity (DeviceId) выводится только после проверки подписки — нельзя проскочить.
  • FederationDomain: отклоняет IP-литералы, порты, схемы — защищает от SSRF на уровне identity.
  • Config validation: кросс-поляные инварианты проверяются при загрузке, URL должны быть https.
  • Backpressure: bounded outbox (256 frames), slow connection закрывается вместо silent drop. Durable event feed в RocksDB — source of truth.
  • Тесты: покрытие критических путей — auth flow, proof failure → persistence не вызывается, domain validation, enrollment quotas.

Замечания

Несколько предложений в инлайн-комментариях ниже. Ничего блокирующего.

## Ревью #1: `chore: initial project structure` **Вердикт: 💬 COMMENT** — блокирующих проблем нет. ### Обзор 73 файла, +23 416 строк. Архитектура — hexagonal (domain → application → infrastructure → API), Rust/Axum/RocksDB. Для initial structure — исключительно высокое качество кода. ### ✅ Что сделано хорошо - **`#![forbid(unsafe_code)]`** на уровне workspace — отличная база для криптомессенджера - **Архитектура ports/adapters**: домен не зависит от инфраструктуры, приложение инжектится через trait-объекты. Тесты используют fakes без БД. - **Crypto-дизайн**: Ed25519 challenge-response с domain separator (`AUTH_SIGNATURE_CONTEXT`), single-use challenge, constant-time сравнение токенов. Identity (DeviceId) выводится **только после** проверки подписки — нельзя проскочить. - **FederationDomain**: отклоняет IP-литералы, порты, схемы — защищает от SSRF на уровне identity. - **Config validation**: кросс-поляные инварианты проверяются при загрузке, URL должны быть https. - **Backpressure**: bounded outbox (256 frames), slow connection закрывается вместо silent drop. Durable event feed в RocksDB — source of truth. - **Тесты**: покрытие критических путей — auth flow, proof failure → persistence не вызывается, domain validation, enrollment quotas. ### Замечания Несколько предложений в инлайн-комментариях ниже. Ничего блокирующего.
Collaborator

📝 Note: change-me — нормальный плейсхолдер для примера. Но при require_token = true (default) сервер с дефолтным токеном запустится и примет ровно 1 регистрацию с токеном change-me. Стоит ли падать при старте, если токен == change-me?

📝 **Note**: `change-me` — нормальный плейсхолдер для примера. Но при `require_token = true` (default) сервер с дефолтным токеном запустится и примет ровно 1 регистрацию с токеном `change-me`. Стоит ли падать при старте, если токен == `change-me`?
kiper220 marked this conversation as resolved
Collaborator

Good: До аутентификации обслуживается только auth (через tokio::select! с authentication deadline). Pre-auth op уходит в handle_op, который возвращает UNAUTHENTICATED. Чистая реализация lifecycle.

✅ **Good**: До аутентификации обслуживается только `auth` (через `tokio::select!` с authentication deadline). Pre-auth op уходит в `handle_op`, который возвращает `UNAUTHENTICATED`. Чистая реализация lifecycle.
kiper220 marked this conversation as resolved
Collaborator

💡 Suggestion: constant_time_eq дублируется в domain/enrollment.rs (строка 286). Вынеси в общий модуль — например infrastructure::crypto или domain::util.

Альтернативно: ed25519-dalek уже зависит от subtle. Можно использовать subtle::ConstantTimeEq вместо ручной реализации.

💡 **Suggestion**: `constant_time_eq` дублируется в `domain/enrollment.rs` (строка 286). Вынеси в общий модуль — например `infrastructure::crypto` или `domain::util`. Альтернативно: `ed25519-dalek` уже зависит от `subtle`. Можно использовать `subtle::ConstantTimeEq` вместо ручной реализации.
Collaborator

📝 Note: Когда require_token = false, authorize() возвращает Unrestricted. Это нормально для dev-режима, но стоит добавить tracing::warn! при старте сервера в unrestricted-режиме — чтобы оператор случайно не запустил прод без токена.

📝 **Note**: Когда `require_token = false`, `authorize()` возвращает `Unrestricted`. Это нормально для dev-режима, но стоит добавить `tracing::warn!` при старте сервера в unrestricted-режиме — чтобы оператор случайно не запустил прод без токена.
kiper220 marked this conversation as resolved
Collaborator

Good: validate() проверяет все cross-field инварианты — границы retention, лимиты соединений, federation domain, https-only URLs. Защита от misconfiguration на старте.

✅ **Good**: `validate()` проверяет все cross-field инварианты — границы retention, лимиты соединений, federation domain, https-only URLs. Защита от misconfiguration на старте.
kiper220 marked this conversation as resolved
Collaborator

💡 Suggestion: Дубликат constant_time_eq из application/authenticate_device.rs. См. комментарий там.

💡 **Suggestion**: Дубликат `constant_time_eq` из `application/authenticate_device.rs`. См. комментарий там.
kiper220 marked this conversation as resolved
Collaborator

Вебхук был обрезан, но контекст восстановил через API. Ревью готово — 6 инлайн-комментариев, блокирующих проблем нет. Качество initial structure — отличное.

Вебхук был обрезан, но контекст восстановил через API. Ревью готово — 6 инлайн-комментариев, блокирующих проблем нет. Качество initial structure — отличное.
hermes approved these changes 2026-07-29 17:44:39 +00:00
hermes left a comment

Ревью #1: chore: initial project structure

Масштаб: 73 файла, +23416/-606 строк. Архитектура, контракты, документация — без product-функциональности.

Общая оценка: APPROVED

Качество кода — исключительно высокое для initial structure. Основные сильные стороны:

  • Архитектура: Чистая hexagonal (domain → application → infrastructure → API). Порты как trait-объекты, composition root в bootstrap.rs, тестируемость через fakes.
  • Безопасность: Ed25519 challenge-response с domain separation, constant-time сравнение токенов, SHA-256 хэширование секретов, connection limits (global + per-device), authentication rate limiting, forbid(unsafe_code).
  • RocksDB: OptimisticTransactionDB, типобезопасные CF, versioned migrations, fixed-width BE key codec с compile-time guarantees.
  • Wire protocol: Versioned JSON envelope, deny_unknown_fields, bounded frame/request IDs.
  • Тесты: Каждый модуль содержит осмысленные unit-тесты (не формальные).

Замечания

Серьёзность Файл Описание
🟡 authenticate_device.rs:147 Дублирование constant_time_eq (копия в enrollment.rs:286)
💡 ws.rs:145 Binary-сообщения игнорируются без error frame
💡 .env.example:18 Нет проверки слабых токенов в validate()

Ничего блокирующего. Можно мержить.

## Ревью #1: chore: initial project structure **Масштаб:** 73 файла, +23416/-606 строк. Архитектура, контракты, документация — без product-функциональности. ### Общая оценка: ✅ APPROVED Качество кода — исключительно высокое для initial structure. Основные сильные стороны: - **Архитектура:** Чистая hexagonal (domain → application → infrastructure → API). Порты как trait-объекты, composition root в `bootstrap.rs`, тестируемость через fakes. - **Безопасность:** Ed25519 challenge-response с domain separation, constant-time сравнение токенов, SHA-256 хэширование секретов, connection limits (global + per-device), authentication rate limiting, `forbid(unsafe_code)`. - **RocksDB:** OptimisticTransactionDB, типобезопасные CF, versioned migrations, fixed-width BE key codec с compile-time guarantees. - **Wire protocol:** Versioned JSON envelope, `deny_unknown_fields`, bounded frame/request IDs. - **Тесты:** Каждый модуль содержит осмысленные unit-тесты (не формальные). ### Замечания | Серьёзность | Файл | Описание | |---|---|---| | 🟡 | `authenticate_device.rs:147` | Дублирование `constant_time_eq` (копия в `enrollment.rs:286`) | | 💡 | `ws.rs:145` | Binary-сообщения игнорируются без error frame | | 💡 | `.env.example:18` | Нет проверки слабых токенов в `validate()` | Ничего блокирующего. Можно мержить.
Collaborator

💡 Suggestion: change-me как плейсхолдер — ОК для примера, но стоит добавить проверку в config.rs::validate(): если require_token=true и initial_token совпадает с известными слабыми значениями (change-me, replace-me, пустая строка) — выдавать предупреждение или ошибку при запуске.

💡 **Suggestion**: `change-me` как плейсхолдер — ОК для примера, но стоит добавить проверку в `config.rs::validate()`: если `require_token=true` и `initial_token` совпадает с известными слабыми значениями (`change-me`, `replace-me`, пустая строка) — выдавать предупреждение или ошибку при запуске.
kiper220 marked this conversation as resolved
Collaborator

Good: Домен-сепарация с версией (v2) — отличная практика. Null-терминатор в контексте предотвращает суффикс-атаки при конкатенации. Binding всего метаданных регистрации (pubkey, name, token fingerprint) в signing payload защищает от MITM-подмены.

✅ **Good**: Домен-сепарация с версией (`v2`) — отличная практика. Null-терминатор в контексте предотвращает суффикс-атаки при конкатенации. Binding всего метаданных регистрации (pubkey, name, token fingerprint) в signing payload защищает от MITM-подмены.
kiper220 marked this conversation as resolved
Collaborator

Good: Backpressure через закрытие соединения вместо молчаливой потери надёжных кадров — правильный выбор для messenger. Клиент переподключается и реплеит durable events. Ephemeral frames используют drop-oldest — тоже разумно.

✅ **Good**: Backpressure через закрытие соединения вместо молчаливой потери надёжных кадров — правильный выбор для messenger. Клиент переподключается и реплеит durable events. Ephemeral frames используют drop-oldest — тоже разумно.
kiper220 marked this conversation as resolved
Collaborator

💡 Suggestion: Message::Binary молча игнорируется. Протокол текстовый (JSON), поэтому Binary-сообщение — это нарушение протокола. Стоит вернуть error frame (BAD_FRAME или BINARY_NOT_SUPPORTED), чтобы клиент быстрее заметил ошибку.

Ping/Pong — корректно игнорировать (axum/tungstenite авто-отвечает на Ping).

💡 **Suggestion**: `Message::Binary` молча игнорируется. Протокол текстовый (JSON), поэтому Binary-сообщение — это нарушение протокола. Стоит вернуть error frame (`BAD_FRAME` или `BINARY_NOT_SUPPORTED`), чтобы клиент быстрее заметил ошибку. Ping/Pong — корректно игнорировать (axum/tungstenite авто-отвечает на Ping).
kiper220 marked this conversation as resolved
Collaborator

🟡 Should fix: constant_time_eq дублируется в enrollment.rs:286 — точная копия. Стоит вынести в общий модуль (например, infrastructure/crypto.rs или domain/util.rs) и переиспользовать.

Альтернативно: зависимость ed25519-dalek уже тянет subtle — можно использовать subtle::ConstantTimeEq вместо ручной реализации.

🟡 **Should fix**: `constant_time_eq` дублируется в `enrollment.rs:286` — точная копия. Стоит вынести в общий модуль (например, `infrastructure/crypto.rs` или `domain/util.rs`) и переиспользовать. Альтернативно: зависимость `ed25519-dalek` уже тянет `subtle` — можно использовать `subtle::ConstantTimeEq` вместо ручной реализации.
kiper220 marked this conversation as resolved
Collaborator

Good: Composition root — единственное место, связывающее порты с конкретными реализациями. Тесты могут собирать API с фейками без БД и реальной криптографии. Чистая hexagonal architecture.

✅ **Good**: Composition root — единственное место, связывающее порты с конкретными реализациями. Тесты могут собирать API с фейками без БД и реальной криптографии. Чистая hexagonal architecture.
kiper220 marked this conversation as resolved
Collaborator

Good: Минимальная длина секрета (32 байта), проверка квот на нули, ограничение по сообщениям и байтам в каждом направлении, expiry по времени. Отличная защита QR-enrollment канала.

✅ **Good**: Минимальная длина секрета (32 байта), проверка квот на нули, ограничение по сообщениям и байтам в каждом направлении, expiry по времени. Отличная защита QR-enrollment канала.
kiper220 marked this conversation as resolved
Collaborator

Good: Валидация DNS-домена с отклонением IP-литералов и портов — критично для безопасности федерации. Host::parse нормализует регистр, canonical DNS-имя как идентификатор — правильно.

✅ **Good**: Валидация DNS-домена с отклонением IP-литералов и портов — критично для безопасности федерации. `Host::parse` нормализует регистр, canonical DNS-имя как идентификатор — правильно.
kiper220 marked this conversation as resolved
Collaborator

Ревью готово . 8 инлайн-комментариев, вердикт — APPROVED. Ничего блокирующего: дублирование constant_time_eq, Binary-сообщения без error frame, и предложение добавить валидацию слабых токенов — всё не критично.

Ревью готово ✅. 8 инлайн-комментариев, вердикт — APPROVED. Ничего блокирующего: дублирование `constant_time_eq`, Binary-сообщения без error frame, и предложение добавить валидацию слабых токенов — всё не критично.
kiper220 removed review request for alter 2026-07-29 17:50:40 +00:00
kiper220 deleted branch initial_project_structure 2026-07-29 17:53:27 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
WetGrape/GuildWine!1
No description provided.