chore: publish clean community baseline
Deploy / deploy (push) Successful in 5m18s
CI / Rust Checks (push) Successful in 6m13s
CI / UI Checks (push) Successful in 5s
CI / Deployment Manifests (push) Successful in 2s
CI / Frontend E2E (push) Successful in 4m16s

This commit is contained in:
github-ops
2026-06-17 06:15:46 +00:00
commit 0d0cb35665
317 changed files with 73100 additions and 0 deletions
+316
View File
@@ -0,0 +1,316 @@
# Rust Code Rules
## 1. Назначение документа
Этот документ фиксирует Rust-specific правила кода для проекта:
- toolchain;
- linting;
- formatting;
- ошибки;
- async;
- ownership;
- visibility;
- dependency hygiene.
Цель документа - убрать плавающие договоренности по стилю и практике командной Rust-разработки.
## 2. Toolchain
### 2.1. Версия Rust
Для проекта должен быть зафиксирован `rust-toolchain.toml`.
В нем должны быть определены:
- стабильный `channel`;
- `protocol`;
- при необходимости `components`.
Рекомендуемый состав:
- `rustfmt`
- `clippy`
### 2.2. MSRV
Нужно зафиксировать `MSRV` - минимально поддерживаемую версию Rust.
Правило:
- без необходимости не использовать возможности языка новее зафиксированного `MSRV`;
- обновление `MSRV` - это отдельное осознанное решение.
## 3. Formatting и linting
### 3.1. Formatting
Обязательное правило:
- весь код форматируется через `cargo fmt`.
Ручной стиль форматирования не обсуждается и не поддерживается.
### 3.2. Clippy
Обязательное правило:
- `cargo clippy --all-targets --all-features -- -D warnings`
Предупреждения считаются ошибками, если нет явно зафиксированного исключения.
### 3.3. CI quality gates
Минимально в CI должны запускаться:
- `cargo fmt --check`
- `cargo clippy --all-targets --all-features -- -D warnings`
- `cargo test`
Опционально позже:
- `cargo deny`
- `cargo audit`
## 4. `unsafe`
Для проекта принимается правило:
- `unsafe` запрещен по умолчанию.
Если когда-либо потребуется `unsafe`, то:
- это должно быть отдельное осознанное решение;
- причина должна быть технически обоснована;
- блок должен быть минимальным;
- вокруг него должны быть тесты.
Для MVP можно считать:
- `unsafe_code = deny`
## 5. Panic policy
В production code запрещены:
- `unwrap()`
- `expect()`
- `todo!()`
- `unimplemented!()`
- `dbg!()`
- необоснованные `panic!()`
Допускается:
- в тестах;
- в очень раннем bootstrap-коде, если это действительно аварийное завершение и не часть доменной логики.
Базовое правило:
- ошибки возвращаются через `Result`, а не через panic.
## 6. Правила ошибок
### 6.1. Domain и service errors
В домене и сервисах использовать типизированные ошибки.
Рекомендуемо:
- `thiserror`
### 6.2. Application boundary
На верхних слоях приложений допускается агрегирование ошибок, если это упрощает wiring.
При необходимости:
- `anyhow` только на внешних границах приложения, не в доменной модели.
### 6.3. Error context
Ошибка должна сохранять стадию отказа:
- schema
- mapping
- adapter
- persistence
- external service
- internal runtime
## 7. Visibility rules
Правило:
- по умолчанию все приватное;
- `pub(crate)` предпочтительнее `pub`;
- публичный API должен быть минимальным.
Нельзя:
- открывать модуль наружу "на всякий случай";
- делать `pub` просто ради удобства из соседнего файла;
- реэкспортировать целые деревья модулей без причины.
## 8. Ownership и данные
### 8.1. Клонирование
Правило:
- не клонировать данные без необходимости;
- клон должен быть осознанным, а не способом обойти borrow checker без понимания причины.
### 8.2. Shared mutability
Правило:
- не использовать `Arc<Mutex<_>>` как универсальный контейнер состояния;
- shared mutability допускается только там, где она действительно нужна по архитектуре.
### 8.3. ID types
Идентификаторы должны быть отдельными типами, а не просто `String`.
Примеры:
- `OperationId`
- `DescriptorId`
- `AuthProfileId`
## 9. Async rules
### 9.1. Где допускается `async`
`async` используется только там, где есть:
- I/O;
- network;
- storage;
- async boundary приложения.
### 9.2. Где `async` не нужен
Нельзя превращать:
- schema validation;
- mapping;
- чистую доменную логику;
- небольшие derived methods
в `async fn` без причины.
### 9.3. `tokio`
`tokio` должен находиться:
- в приложениях;
- в I/O слоях;
- в адаптерах и runtime orchestration, если там есть реальный async.
Доменный слой не должен зависеть от `tokio`.
## 10. API design rules
### 10.1. Конструкторы
Использовать:
- `new()` для гарантированно валидного и простого создания;
- `try_new()` там, где есть валидация и возможна ошибка.
### 10.2. Builders
Если структура имеет много параметров и прямой конструктор становится нечитаемым, допускается builder.
Но:
- builder не должен маскировать плохую модель данных;
- builder не должен использоваться как замена нормальной декомпозиции.
### 10.3. DTO отдельно от domain
Если HTTP payload начинает расходиться с доменной моделью, нужно вводить отдельный DTO слой.
Нельзя:
- тащить `serde`-ориентированный API payload прямо в домен только ради удобства.
## 11. Dependency rules
### 11.1. Внешние crates
Правило:
- сначала использовать `std`;
- потом существующие внутренние abstractions;
- только потом тянуть новый внешний crate.
Нельзя:
- добавлять зависимость "на всякий случай";
- дублировать crates с пересекающейся функцией без причины.
### 11.2. Макросы
Правило:
- не злоупотреблять макросами там, где обычный Rust-код читается лучше;
- derive-макросы допустимы;
- сложные процедурные макросы без сильной причины не нужны.
## 12. Serialization rules
### 12.1. JSON/YAML
Правило:
- доменная модель одна;
- `JSON` и `YAML` - только два формата сериализации;
- нельзя допускать, чтобы YAML export стал отдельной несовместимой моделью.
### 12.2. Secrets
Никогда не сериализовать:
- реальные токены;
- пароли;
- API keys
в exports, logs и test snapshots.
## 13. Тестовые практики на уровне Rust-кода
Минимально:
- unit tests рядом с модулем или в `tests`;
- integration tests для crate boundaries;
- фикстуры для schema/mapping/proto/yaml roundtrip.
Полезное правило:
- баг сначала воспроизводится тестом, потом фиксится кодом.
## 14. Что часто запрещают в Rust-командах
Практически всегда под запретом:
- `unwrap()` в production code;
- `unsafe` без review;
- giant modules;
- giant enums со всем подряд;
- giant services, где смешаны orchestration и transport;
- абстракции "на будущее" без второго реального кейса.
## 15. Практический итог
Для этого проекта правильный Rust-профиль такой:
- фиксированный toolchain;
- обязательные `fmt` и `clippy`;
- `unsafe` запрещен по умолчанию;
- panics запрещены в production code;
- ошибки типизированы;
- `pub` минимизируется;
- `async` только на реальных async boundaries;
- код читается за счет имен и декомпозиции, а не за счет комментариев.