Files
BalanceServer/docs/ARCHITECTURE.md
T
wtandClaude Opus 5.5 10272f3851
CI / Rust (fmt / clippy / test / build) (push) Successful in 1m41s
CI / HTTP/JSON reference + SQLite persistence (push) Successful in 1m16s
CI / Rust (fmt / clippy / test / build) (pull_request) Successful in 47s
CI / HTTP/JSON reference + SQLite persistence (pull_request) Successful in 1m34s
Remove the Go reference server; keep only Rust
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>
2026-10-30 16:27:33 +07:00

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 должен:

  1. проверить method/content type;
  2. аутентифицировать пользователя, если endpoint защищён;
  3. валидировать input;
  4. вызвать domain/storage logic;
  5. вернуть стабильный 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 не менялись;
  • deleted semantics были одинаковыми;
  • cursor/sequence были монотонными;
  • conflict resolution совпадал с клиентской логикой.