added AGENTS.md and docs for BalanceServer
This commit is contained in:
1 parent
684ac58b73
commit
2f891c9503
10 files changed
+1022
No files matched your search
@@ -0,0 +1,138 @@
|
||||
# Синхронизация
|
||||
|
||||
## Цель
|
||||
|
||||
Один аккаунт Balance может использоваться на нескольких устройствах:
|
||||
|
||||
```text
|
||||
iPhone
|
||||
│
|
||||
├── transaction A
|
||||
├── category B
|
||||
└── budget C
|
||||
│
|
||||
▼
|
||||
BalanceServer
|
||||
│
|
||||
┌────┴────┐
|
||||
▼ ▼
|
||||
Android Mac
|
||||
```
|
||||
|
||||
## Cursor
|
||||
|
||||
Каждый клиент хранит cursor последнего успешно применённого server change.
|
||||
|
||||
Принцип:
|
||||
|
||||
```text
|
||||
cursor = 100
|
||||
|
||||
server:
|
||||
101 A
|
||||
102 B
|
||||
103 C
|
||||
|
||||
pull(cursor=100)
|
||||
→ A, B, C
|
||||
→ new cursor = 103
|
||||
```
|
||||
|
||||
Клиент должен сохранять cursor только после успешного применения соответствующего batch.
|
||||
|
||||
## Sequence
|
||||
|
||||
Server sequence задаёт глобальный порядок изменений в sync stream.
|
||||
|
||||
Требования:
|
||||
- монотонность;
|
||||
- отсутствие уменьшения;
|
||||
- однозначность порядка;
|
||||
- корректность при concurrent requests.
|
||||
|
||||
## Push
|
||||
|
||||
Push передаёт изменения клиента:
|
||||
|
||||
```text
|
||||
local mutations
|
||||
↓
|
||||
POST /v1/sync
|
||||
↓
|
||||
validation
|
||||
↓
|
||||
ownership check
|
||||
↓
|
||||
persist
|
||||
↓
|
||||
append to change stream
|
||||
```
|
||||
|
||||
Retry не должен создавать две разные логические записи из одного client change.
|
||||
|
||||
## Pull
|
||||
|
||||
Pull получает изменения после cursor.
|
||||
|
||||
Сервер не должен возвращать изменения другого пользователя.
|
||||
|
||||
При pagination клиент должен иметь возможность продолжить с нового cursor.
|
||||
|
||||
## Conflict resolution
|
||||
|
||||
Клиенты Balance используют timestamp-based versioning.
|
||||
|
||||
Типовая проверка:
|
||||
|
||||
```text
|
||||
local.updatedAt < remote.updatedAt
|
||||
```
|
||||
|
||||
Следовательно, server должен сохранять `updatedAt` достаточно точно и не подменять его произвольным временем каждого чтения.
|
||||
|
||||
При конкурентных writes сервер должен иметь однозначное правило победителя.
|
||||
|
||||
## Deletions
|
||||
|
||||
Удаление создаёт tombstone/change:
|
||||
|
||||
```json
|
||||
{
|
||||
"entity": "transaction",
|
||||
"id": "...",
|
||||
"deleted": true,
|
||||
"updatedAt": "..."
|
||||
}
|
||||
```
|
||||
|
||||
Tombstone должен попасть в change stream так же, как обычное изменение.
|
||||
|
||||
## Idempotency
|
||||
|
||||
Push может повториться из-за:
|
||||
- timeout;
|
||||
- network failure;
|
||||
- app restart;
|
||||
- retry after 401/token refresh.
|
||||
|
||||
Поэтому сервер должен обрабатывать повторную отправку безопасно.
|
||||
|
||||
## Batch
|
||||
|
||||
Apple-клиент отправляет batches до 100 изменений и может делить крупные payloads.
|
||||
|
||||
Android должен использовать совместимый protocol.
|
||||
|
||||
Server не должен предполагать, что все изменения приходят одним запросом.
|
||||
|
||||
## Reset/full sync
|
||||
|
||||
Если client потерял cursor или требует reset, сервер должен поддерживать предусмотренный текущим API механизм полного pull либо новый cursor baseline.
|
||||
|
||||
Нельзя молча трактовать неизвестный/просроченный cursor как актуальный.
|
||||
|
||||
## Security
|
||||
|
||||
Sync endpoint всегда ограничен текущим authenticated user.
|
||||
|
||||
`deviceId` — идентификатор устройства, а не механизм авторизации.
|
||||
Reference in new issue
Block a user