The Go implementation is preserved in the v1.0.0 tag. Its observable behaviour stays the API reference: responses recorded from the Go server live in tools/compatibility_expected.txt, and tools/compatibility.py now compares the Rust server against them (--update re-records after an intentional change). The Go SQLite schema is frozen in tests/fixtures/go_schema_v1.sql for the existing-database test. Move the web client from internal/httpapi/web to web/, drop the Go CI job and Go version pin, and update README, AGENTS.md and docs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
4.4 KiB
Архитектура BalanceServer
Роль сервера
BalanceServer — backend для синхронизации личных финансов между устройствами.
Поток данных:
iOS/macOS/watchOS ─┐
├── HTTPS/JSON API ──> BalanceServer ──> Database
Android ───────────┘
Сервер отвечает за:
- регистрацию и авторизацию;
- пользовательские сессии;
- хранение финансовых изменений;
- push/pull synchronization;
- глобальную последовательность изменений;
- удаление через tombstones;
- выдачу изменений начиная с cursor.
Исходный код
Production runtime — один Rust-процесс: src/main.rs, runtime.rs, config.rs, database.rs, auth.rs, sync.rs, server.rs, go_json.rs. SQLite bundled через rusqlite; HTTP обслуживается axum/hyper. runtime.rs сохраняет socket deadlines Go (header 5s, read 15s, write 30s, idle 60s) и ограничивает graceful shutdown десятью секундами. go_json.rs сохраняет особенности encoding/json и исходные payload bytes. Статические файлы из web/ встроены при компиляции.
Исходная Go-реализация удалена после v1.0.0 (исходники остались в теге v1.0.0). Её наблюдаемое поведение зафиксировано в tools/compatibility_expected.txt, а SQLite-схема — в tests/fixtures/go_schema_v1.sql; Rust сверяется с обоими в CI.
Конкретные границы package/handler/service/repository нужно сохранять при рефакторинге: перенос кода между слоями не должен менять внешний API.
HTTP layer
HTTP layer принимает JSON requests от мобильных клиентов.
Каждый handler должен:
- проверить method/content type;
- аутентифицировать пользователя, если endpoint защищён;
- валидировать input;
- вызвать domain/storage logic;
- вернуть стабильный JSON response.
Domain / sync layer
Sync layer является наиболее критичной частью backend.
Он должен разделять:
- изменения, созданные текущим клиентом;
- изменения, которые нужно вернуть клиенту;
- удалённые записи;
- cursor/sequence.
Ключевая модель:
client cursor
│
▼
server change log
│
├── sequence 101
├── sequence 102
├── sequence 103
└── ...
Клиент может запросить изменения после своего cursor и затем сохранить новый cursor.
Persistence
Хранилище должно сохранять как минимум:
- user/account identity;
- credentials/session metadata;
- financial records;
- change metadata;
- deletion/tombstone metadata;
- monotonically increasing sequence, если оно является частью текущего sync protocol.
Конкретные entities и schema документированы в docs/DATA_MODEL.md.
Security boundaries
Internet
│
▼
HTTP server
│
├── authentication
├── authorization
├── input validation
│
▼
domain/sync
│
▼
database
Нельзя позволять клиенту выбирать произвольный user_id для чужих records.
Совместимость клиентов
Apple и Android реализации должны видеть одну и ту же семантику данных.
Особенно важно, чтобы:
- enum values были стабильными;
- даты имели единый формат;
- UUID/string IDs не менялись;
deletedsemantics были одинаковыми;- cursor/sequence были монотонными;
- conflict resolution совпадал с клиентской логикой.