docs: translate development guide and agent rules to English

development.md and agent-rules.mdc in English; progress.md and roadmap.md stay Russian as internal docs.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
mixeme
2026-08-08 10:58:38 +03:00
parent 1a8603b887
commit d46920bb02
4 changed files with 119 additions and 115 deletions
+16 -16
View File
@@ -1,24 +1,24 @@
--- ---
description: Правила работы агента в репозитории SelfPost (ранее spec §12) description: Agent rules for the SelfPost repository (formerly spec §12)
alwaysApply: true alwaysApply: true
--- ---
# Правила для агентов # Agent rules
1. **Без git-коммитов** без явной инструкции в промпте. 1. **No git commits** without an explicit instruction in the prompt.
2. После правок Go: `go build`, `go vet`; исправить все проблемы. `go test`, 2. After Go changes: `go build`, `go vet`; fix all issues. Run `go test` when
когда тесты есть. tests exist.
3. Перед «готово» для контейнерной задачи: образ собирается, контейнер стартует. 3. Before calling a container task done: the image builds and the container starts.
4. Итерации: минимальный скелет, затем фичи. 4. Iterate: minimal skeleton first, then features.
5. Требования безопасности — `docs/security.md`; внедрять с фичей, не откладывать. 5. Security requirements — `docs/security.md`; implement with the feature, not deferred.
6. Не делать out-of-scope (`docs/product.md`); не менять зафиксированные 6. Do not implement out-of-scope items (`docs/product.md`); do not change fixed
допущения без согласования. assumptions without agreement.
7. Крупные задачи — план до кода, если пользователь не утвердил план ранее. 7. For large tasks: propose a plan before coding unless the user already approved one.
8. Совместимость лицензий новых Go-зависимостей (permissive или GPL-family для 8. Check licence compatibility of new Go dependencies (permissive or GPL-family for
AGPL-3.0). AGPL-3.0).
Маршрутизация моделей — `docs/progress.md` § «Модель по типу работы». Model routing — `docs/progress.md` § «Model by task type». Pre-release security
Предрелизная **ревизия** безопасности (не авторство) — Fable. **review** (not authorship) — Fable.
Протокол коммитов, CHANGELOG и закрытия фазы — `docs/progress.md` § «Коммиты» Commit protocol, CHANGELOG, and phase closure — `docs/progress.md` § «Commits»
и «Протокол закрытия фазы». and «Phase closure protocol».
+2
View File
@@ -42,6 +42,8 @@ Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); version
- `docs/development.md` restructured into stack, dependencies, build, release, - `docs/development.md` restructured into stack, dependencies, build, release,
testing, and CI; agent rules moved to `.cursor/rules/agent-rules.mdc`; testing, and CI; agent rules moved to `.cursor/rules/agent-rules.mdc`;
dev-host-specific workflow and `example.com` references removed from docs. dev-host-specific workflow and `example.com` references removed from docs.
- `docs/development.md` and `.cursor/rules/agent-rules.mdc` translated to
English; `progress.md` and `roadmap.md` remain Russian (internal tracker).
## [0.6.0] - 2026-08-08 ## [0.6.0] - 2026-08-08
+98 -95
View File
@@ -1,198 +1,201 @@
# SelfPost — разработка # SelfPost — development
**Что это.** Как собрать, проверить и выкатить изменения. Текущий спринт — **What this file is.** How to build, test, and ship changes. Current sprint
[progress.md](progress.md) (читать первым после `/clear`). state lives in [progress.md](progress.md) — read that first after `/clear`.
Границы продукта: [product.md](product.md). As-built устройство: Product boundaries: [product.md](product.md). As-built layout:
[architecture.md](architecture.md). [architecture.md](architecture.md).
--- ---
## Технологический стек и инструменты ## Technology stack and tools
| Компонент | Версия / заметки | | Component | Version / notes |
|---|---| |---|---|
| **Go** | 1.26+ (`go.mod`); `CGO_ENABLED=0`чистый Go, статическая линковка | | **Go** | 1.26+ (`go.mod`); `CGO_ENABLED=0`pure Go, static linking |
| **SQLite** | `modernc.org/sqlite` (pure Go, без cgo) | | **SQLite** | `modernc.org/sqlite` (pure Go, no cgo) |
| **Сборка** | [Makefile](../Makefile): `vet`, `test`, `build`, `e2e` | | **Build** | [Makefile](../Makefile): `vet`, `test`, `build`, `e2e` |
| **Контейнер** | Docker + Compose v2 на хосте разработки и в CI | | **Container** | Docker + Compose v2 on the dev host and in CI |
| **Образ (build stage)** | `golang:1.26-bookworm` — [build/Dockerfile](../build/Dockerfile) | | **Image (build stage)** | `golang:1.26-bookworm` — [build/Dockerfile](../build/Dockerfile) |
| **Образ (runtime)** | `debian:bookworm-slim` + Postfix, OpenDKIM, supervisord, SASL, logrotate | | **Image (runtime)** | `debian:bookworm-slim` + Postfix, OpenDKIM, supervisord, SASL, logrotate |
| **CI** | GitHub Actions — [.github/workflows/](../.github/workflows/) | | **CI** | GitHub Actions — [.github/workflows/](../.github/workflows/) |
| **Реестр образов** | `ghcr.io/mixeme/selfpost` | | **Image registry** | `ghcr.io/mixeme/selfpost` |
**Структура репозитория** (кратко; детали процессов — в [architecture.md](architecture.md)): **Repository layout** (brief; process details in [architecture.md](architecture.md)):
- `cmd/panel` — HTTP-панель + journal-milter + log-tailer - `cmd/panel` — HTTP panel + journal-milter + log-tailer
- `cmd/selfpost-backup`CLI бэкапа (`docker exec … selfpost-backup`) - `cmd/selfpost-backup`backup CLI (`docker exec … selfpost-backup`)
- `internal/`доменная логика, store, web, health - `internal/`domain logic, store, web, health
- `build/` — Dockerfile, supervisord, Postfix/OpenDKIM, entrypoint - `build/` — Dockerfile, supervisord, Postfix/OpenDKIM, entrypoint
- `deploy/``docker-compose.yml`, примеры прокси, `.env.example` - `deploy/``docker-compose.yml`, proxy examples, `.env.example`
- `test/e2e/`**отдельный Go-модуль**; контейнерные интеграционные тесты - `test/e2e/`**separate Go module**; container integration tests
--- ---
## Внешние библиотеки ## External libraries
Проект — **AGPL-3.0** ([LICENSE](../LICENSE)). Новые Go-зависимости — только The project is **AGPL-3.0** ([LICENSE](../LICENSE)). New Go dependencies must
permissive или GPL-family (см. [.cursor/rules/agent-rules.mdc](../.cursor/rules/agent-rules.mdc)). be permissive or GPL-family (see
[.cursor/rules/agent-rules.mdc](../.cursor/rules/agent-rules.mdc)).
### Основной модуль (`go.mod`) ### Main module (`go.mod`)
| Пакет | Версия | Репозиторий | Лицензия | | Package | Version | Repository | License |
|---|---|---|---| |---|---|---|---|
| `github.com/emersion/go-milter` | v0.4.1 | <https://github.com/emersion/go-milter> | BSD-2-Clause | | `github.com/emersion/go-milter` | v0.4.1 | <https://github.com/emersion/go-milter> | BSD-2-Clause |
| `golang.org/x/crypto` | v0.54.0 | <https://github.com/golang/crypto> | BSD-3-Clause | | `golang.org/x/crypto` | v0.54.0 | <https://github.com/golang/crypto> | BSD-3-Clause |
| `modernc.org/sqlite` | v1.53.0 | <https://gitlab.com/cznic/sqlite> (зеркало: <https://github.com/modernc-org/sqlite>) | BSD-3-Clause | | `modernc.org/sqlite` | v1.53.0 | <https://gitlab.com/cznic/sqlite> (mirror: <https://github.com/modernc-org/sqlite>) | BSD-3-Clause |
Транзитивные зависимости`go mod graph` / `go.sum`; все indirect в дереве Transitive dependencies`go mod graph` / `go.sum`; all indirect packages in
совместимы с AGPL-3.0. the tree are AGPL-3.0-compatible.
### Модуль e2e (`test/e2e/go.mod`) ### E2e module (`test/e2e/go.mod`)
| Пакет | Версия | Репозиторий | Лицензия | | Package | Version | Repository | License |
|---|---|---|---| |---|---|---|---|
| `github.com/emersion/go-msgauth` | v0.6.8 | <https://github.com/emersion/go-msgauth> | BSD-2-Clause | | `github.com/emersion/go-msgauth` | v0.6.8 | <https://github.com/emersion/go-msgauth> | BSD-2-Clause |
Тестовый модуль не входит в граф основного `go build` и не попадает в образ. The test module is not part of the main `go build` graph and is not shipped in
the image.
### Пакеты Debian в runtime-образе ### Debian packages in the runtime image
Postfix, OpenDKIM, `supervisord`, `sasl2-bin`, `logrotate` и др. — Postfix, OpenDKIM, `supervisord`, `sasl2-bin`, `logrotate`, and others come
из репозиториев Debian bookworm; лицензии — в `copyright` соответствующих from Debian bookworm repositories; licenses are in each package's `copyright`
пакетов на <https://packages.debian.org/bookworm/>. file on <https://packages.debian.org/bookworm/>.
--- ---
## Сборка исполняемого файла и образа ## Building binaries and the image
### Локальные бинарники ### Local binaries
Требуется Go 1.26+ и `CGO_ENABLED=0`. Requires Go 1.26+ and `CGO_ENABLED=0`.
```sh ```sh
make build # bin/panel, bin/selfpost-backup (VERSION=dev по умолчанию) make build # bin/panel, bin/selfpost-backup (VERSION=dev by default)
make build VERSION=1.0.0 make build VERSION=1.0.0
``` ```
Или напрямую: Or directly:
```sh ```sh
go build -trimpath -ldflags "-X github.com/mixeme/selfpost/internal/buildinfo.Version=dev" -o bin/panel ./cmd/panel go build -trimpath -ldflags "-X github.com/mixeme/selfpost/internal/buildinfo.Version=dev" -o bin/panel ./cmd/panel
``` ```
Версия вшивается в оба бинарники через `-ldflags` и **должна совпадать с тегом The version is stamped into both binaries via `-ldflags` and **must match the
Docker-образа** — restore проверяет совместимость версий бэкапа. Docker image tag** — restore checks backup version compatibility.
### Docker-образ ### Docker image
Из корня репозитория: From the repository root:
```sh ```sh
docker build -f build/Dockerfile -t selfpost:dev --build-arg VERSION=dev . docker build -f build/Dockerfile -t selfpost:dev --build-arg VERSION=dev .
``` ```
В Dockerfile: build stage (`go vet`, `go build` с `VERSION`), runtime stage The Dockerfile has a build stage (`go vet`, `go build` with `VERSION`) and a
(Debian + почтовый стек). См. [architecture.md](architecture.md) § Image and runtime stage (Debian + mail stack). See [architecture.md](architecture.md) §
processes. Image and processes.
--- ---
## Сборка релиза ## Release build
Релизный образ публикуется **только по тегу** `vX.Y.Z` (не на каждый push в The release image is published **only on tag** `vX.Y.Z` (not on every push to
`main`). Тег — единственный источник версии: из него берутся тег образа и `main`). The tag is the single source of version: it drives the image tag and
`-ldflags` в бинарниках, чтобы они не расходились. `-ldflags` in the binaries so they cannot drift apart.
**Шаги (по явному запросу):** **Steps (on explicit request):**
1. Закрыть `[Unreleased]` в [CHANGELOG.md](../CHANGELOG.md). 1. Close `[Unreleased]` in [CHANGELOG.md](../CHANGELOG.md).
2. Создать и запушить git-тег `vX.Y.Z`. 2. Create and push git tag `vX.Y.Z`.
3. Workflow [release.yml](../.github/workflows/release.yml) собирает, гейтит 3. Workflow [release.yml](../.github/workflows/release.yml) builds, e2e-gates,
e2e и публикует `ghcr.io/mixeme/selfpost:X.Y.Z`. and publishes `ghcr.io/mixeme/selfpost:X.Y.Z`.
4. Обновить закреплённый тег в [deploy/docker-compose.yml](../deploy/docker-compose.yml) 4. Update the pinned tag in
(см. [roadmap.md](roadmap.md) § «v1.x — хвост документации и деплоя»). [deploy/docker-compose.yml](../deploy/docker-compose.yml) (see
[roadmap.md](roadmap.md) § «v1.x — documentation and deploy tail»).
Обычные коммиты **не** публикуют образ. Ordinary commits **do not** publish an image.
--- ---
## Тестирование ## Testing
### Статический анализ и unit-тесты ### Static analysis and unit tests
Основной модуль (`go test ./...`); e2e — отдельный модуль, см. ниже. Main module (`go test ./...`); e2e is a separate module — see below.
```sh ```sh
make vet # go vet ./... make vet # go vet ./...
make test # go test ./... make test # go test ./...
``` ```
Или напрямую: Or directly:
```sh ```sh
gofmt -l . # в CI — fail при расхождении gofmt -l . # in CI — fails on drift
go vet ./... go vet ./...
go test ./... go test ./...
``` ```
### Регресс документации env ### Env documentation regression
`go test ./cmd/panel -run TestLoadConfig`каждый новый ключ `loadConfig` `go test ./cmd/panel -run TestLoadConfig`every new `loadConfig` key must
должен появиться в списках env в [guide.md](guide.md) appear in the env lists in [guide.md](guide.md)
([cmd/panel/envdoc_test.go](../cmd/panel/envdoc_test.go)). ([cmd/panel/envdoc_test.go](../cmd/panel/envdoc_test.go)).
### End-to-end (контейнерный suite) ### End-to-end (container suite)
Отдельный Go-модуль `test/e2e/`; **не** входит в `go test ./...` основного Separate Go module `test/e2e/`; **not** included in the main module's
модуля. `go test ./...`.
```sh ```sh
make e2e make e2e
# то же: cd test/e2e && go test -v -timeout 20m ./... # same as: cd test/e2e && go test -v -timeout 20m ./...
``` ```
**Стек:** [deploy/docker-compose.yml](../deploy/docker-compose.yml) + **Stack:** [deploy/docker-compose.yml](../deploy/docker-compose.yml) +
[test/e2e/compose.override.yml](../test/e2e/compose.override.yml) — те же [test/e2e/compose.override.yml](../test/e2e/compose.override.yml) — same
`cap_drop`/`cap_add`/`no-new-privileges`, что в production. Override: высокие `cap_drop`/`cap_add`/`no-new-privileges` as production. Override: high ports
порты (`20465`/`20587`/`20080`), тестовый hostname, self-signed TLS, (`20465`/`20587`/`20080`), test hostname, self-signed TLS,
`PANEL_COOKIE_SECURE=false`, изолированный compose-проект. Почта герметична: `PANEL_COOKIE_SECURE=false`, isolated compose project. Mail is hermetic:
CoreDNS (fake zone) + Postfix `smtp-sink` как sink-MX; DKIM TXT скрапится с CoreDNS (fake zone) + Postfix `smtp-sink` as sink-MX; DKIM TXT is scraped from
панели и публикуется в зону — тест проверяет записи, которые оператор реально the panel and published into the zone — the test verifies the records an
использует. operator would actually use.
**Покрытие (сводка):** bootstrap → SMTP AUTH → доставка → DKIM verify → **Coverage (summary):** bootstrap → SMTP AUTH → delivery → DKIM verify →
send-log `queued → sent`; негативы (без AUTH, relay, sender/login mismatch, send-log `queued → sent`; negatives (no AUTH, relay, sender/login mismatch,
L1/L2 лимиты, fail-open milter, неверный `SELFPOST_HOSTNAME`, сессия после L1/L2 limits, milter fail-open, bad `SELFPOST_HOSTNAME`, session survives
`docker restart`). Только polling с таймаутами — без фиксированных `sleep`. `docker restart`). Polling with timeouts only — no fixed `sleep`.
Требует **Docker + Compose v2** на машине, где гоняется suite. Requires **Docker + Compose v2** on the machine running the suite.
--- ---
## CI ## CI
Workflows в [.github/workflows/](../.github/workflows/). Что именно гоняется Workflows in [.github/workflows/](../.github/workflows/). What each job runs
в [§ Тестирование](#тестирование) выше. [§ Testing](#testing) above.
### `test.yml` — каждый push и PR в `main` ### `test.yml` — every push and PR to `main`
`gofmt -l``go vet ./...``go test ./...` (основной модуль, без e2e). `gofmt -l``go vet ./...``go test ./...` (main module, no e2e).
### `release.yml` — push тега `vX.Y.Z` или `workflow_dispatch` ### `release.yml` — push of tag `vX.Y.Z` or `workflow_dispatch`
``` ```
prepare (версия из тега) prepare (version from tag)
→ build [matrix: ubuntu-latest / ubuntu-24.04-arm] → build [matrix: ubuntu-latest / ubuntu-24.04-arm]
→ docker build --load (VERSION из тега) → docker build --load (VERSION from tag)
→ e2e (test/e2e) → e2e (test/e2e)
→ push ghcr.io/...:X.Y.Z-amd64 | X.Y.Z-arm64 → push ghcr.io/...:X.Y.Z-amd64 | X.Y.Z-arm64
→ merge → merge
→ docker buildx imagetools create → единый манифест X.Y.Z → docker buildx imagetools create → unified manifest X.Y.Z
``` ```
Нативная матрица per-arch (без QEMU): полный стек Postfix/OpenDKIM под Native per-arch matrix (no QEMU): running the full Postfix/OpenDKIM stack under
эмуляцией для e2e непрактичен. Сначала e2e, затем push — в registry попадают emulation for e2e is impractical. E2e first, then push — the registry receives
байты, прошедшие гейт. the bytes that passed the gate.
Провал e2e **блокирует** публикацию образа. A failed e2e **blocks** image publication.
+3 -4
View File
@@ -158,10 +158,9 @@ git-тег `vX.Y.Z`; `implementation-plan.md` в `docs/archive/`, ссылок
проекта один разработчик и внешнего потока PR нет, поэтому сейчас проекта один разработчик и внешнего потока PR нет, поэтому сейчас
`CONTRIBUTING.md` был бы документом без аудитории и ещё одним местом, где `CONTRIBUTING.md` был бы документом без аудитории и ещё одним местом, где
расходится правда о dev loop. Уместен вместе с тем, что реально открывает расходится правда о dev loop. Уместен вместе с тем, что реально открывает
проект вовне: английская документация процесса (сейчас процессные документы — проект вовне: английская документация процесса ([development.md](development.md),
`progress.md`, `roadmap.md`, `development.md` — на русском, а README и README, `architecture.md`; `progress.md`, `roadmap.md` — внутренние, на русском)
`architecture.md` на английском; для EN-only контрибьютора это барьер) и и первый внешний интерес после публикации релиза.
первый внешний интерес после публикации релиза.
**Готово, когда:** `CONTRIBUTING.md` в корне описывает dev loop, требования к **Готово, когда:** `CONTRIBUTING.md` в корне описывает dev loop, требования к
проверкам перед PR и протокол коммитов; [development.md](development.md) не проверкам перед PR и протокол коммитов; [development.md](development.md) не