- GET /v1/capabilities and the extended sync entity allowlist (§0, §1). - Shared ledgers (§7): ledgers, members and hashed one-time invite codes; X-Balance-Ledger selects the space on /v1/sync and /v1/attachments with its own records, change stream and cursor. Personal space keeps the v1 tables and behaviour; the migration only adds tables. - Attachments (§8): SHA-256, size and media type checks, blob files in BALANCE_ATTACHMENTS_DIR (default: attachments next to the database), garbage collection of unreferenced blobs with a grace period for fresh uploads, and ledger deletion removes its blobs. - Tests for every new endpoint and error code; API, sync, data model, security, deployment and README docs updated. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
5.6 KiB
Модель данных BalanceServer
Ниже описана серверная модель на основании исходного кода проекта. При изменении schema обновляйте этот документ.
Где определена schema
src/database.rs— создание и открытие схемы SQLite;tests/fixtures/go_schema_v1.sql— исходная схема Go-сервера v1.0.0; Rust обязан открывать такие базы без изменений;src/sync.rs— валидация и сериализация синхронизируемых записей;src/auth.rs— пользователи, пароли и refresh-сессии.
Общие сущности
Сервер принимает сущности контракта v2 (docs/CONTRACT_V2.md §1):
transaction category budget account transfer recurring
goal debt rate setting attachment
Payload хранится как непрозрачный JSON; сервер читает из него только sha256
записей attachment для сборки мусора файлов. Ниже — сущности v1.
Transaction
Логически содержит:
- стабильный ID;
- amount;
- date;
- note;
- category presentation data;
- transaction kind;
- balance-adjustment flag;
- update timestamp;
- принадлежность пользователю.
Category
Логически содержит:
- стабильный ID;
- name;
- icon/emoji;
- color;
- operation kind;
- creation/update metadata;
- принадлежность пользователю.
Budget
Логически содержит:
- стабильный ID;
- category information;
- monthly limit;
- month start;
- update timestamp;
- принадлежность пользователю.
Change metadata
Для sync необходима метаинформация:
user
entity
record ID
deleted
updatedAt
sequence
payload
sequence используется как серверный порядок изменений, а updatedAt — как timestamp версии самой записи.
Tombstones
Удаление нельзя реализовывать только физическим DELETE, если клиентам нужно узнать о нём при следующем pull.
Используется логическое изменение:
{
"entity": "transaction",
"id": "…",
"deleted": true,
"updatedAt": "…"
}
После того как tombstone перестанет быть нужен для поддерживаемого sync history window, сервер может применять retention policy. Такая политика должна быть согласована с cursor semantics.
Invariants
- Record ID стабилен между sync.
- Record принадлежит одному пользователю.
- Клиент не может читать/изменять чужую запись.
sequenceне должен уменьшаться.- Повторная доставка одного change не должна повреждать данные.
- Удаление должно быть видимо клиенту через sync.
- Timestamps должны храниться в UTC.
- Enum/string values должны быть совместимы с iOS и Android.
Таблицы контракта v2
Таблицы v1 (users, refresh_tokens, records, changes) не меняются. Миграция
только добавляет таблицы через CREATE TABLE IF NOT EXISTS, поэтому существующая
база (в том числе Go v1) открывается без переписывания строк и sequence.
| Таблица | Ключ | Назначение |
|---|---|---|
ledgers |
id (UUID) |
имя, owner_id, created_at |
ledger_members |
(ledger_id, user_id), индекс user_id |
role = owner/member, joined_at |
ledger_invites |
code_hash (SHA-256 кода), индекс ledger_id |
expires_at, used_at, used_by; код в открытом виде не хранится |
ledger_records |
(ledger_id, entity, record_id) |
текущее состояние записей пространства |
ledger_changes |
sequence AUTOINCREMENT, индекс (ledger_id, sequence) |
поток изменений пространства |
attachment_blobs |
(space, sha256) |
метаданные файлов: content_type, size, uploaded_at, referenced |
space в attachment_blobs — user:<userId> или ledger:<ledgerId>. Все таблицы
ledger ссылаются на ledgers(id) ON DELETE CASCADE; строки attachment_blobs
пространства удаляются в той же транзакции, что и ledger.
Файлы лежат в BALANCE_ATTACHMENTS_DIR (по умолчанию attachments рядом с
файлом БД): users/<userId>/<sha[0:2]>/<sha> и
ledgers/<ledgerId>/<sha[0:2]>/<sha>. Каталоги создаются с правами 0750.
Один и тот же файл в двух пространствах хранится дважды.
Миграции
Schema changes должны быть backward-compatible с активными версиями клиентов либо сопровождаться versioned API/миграцией.
Не переименовывайте JSON field без периода совместимости.