ali-ahnaf / ali-ahnaf/pocket_pixel
Offline support: sync endpoint and conflict resolution (Backend)
- 主要語言
- TypeScript
- 星號
- 14
- 分支
- 91
- PR 合併指標
- 30 天內沒有已合併 PR
描述
## 📡 Context / Background
Pocket Pixel is adding offline support so users can create transactions and update data while disconnected. When they come back online, those queued operations need to be replayed against the server. This is the **backend** half — see the linked frontend issue for the service worker and local caching.
> **This is part of an epic.** The frontend issue handles the offline queue and sync trigger; this issue handles the API endpoint(s) that accept and process those queued operations.
---
## 🐛 Problem / Goal
When a user performs write operations offline (creating transactions, updating debts, etc.), those operations are queued on the client. When the network returns, the frontend needs an API endpoint to replay them. The backend currently has no dedicated sync surface — individual operations are fine, but there is no way to submit a batch of pending operations or handle the timestamp/ordering issues that come with offline queuing.
---
## 🛠️ Suggested Approach
The API is in `packages/api/src/` and follows a strict layered pattern: **route → service → repository → entity**.
### 1. Design the sync payload
Define a shared DTO in `packages/shared/src/contracts/` (e.g. `sync.ts`):
```ts
// Each pending operation the client sends
export interface SyncOperation {
type: 'CREATE_TRANSACTION' | 'UPDATE_DEBT' | ...;
payload: unknown; // typed per operation
clientTimestamp: string; // ISO8601 — when the user performed the action
}
export interface SyncRequest {
operations: SyncOperation[];
}
export interface SyncResult {
succeeded: string[]; // operation indices or client-generated IDs
failed: Array<{ index: number; reason: string }>;
}
```
Export from `contracts/index.ts` and rebuild: `npm run build:shared`.
### 2. Add the sync route
Create `packages/api/src/routes/sync/sync.route.ts`:
- Mount on `POST /api/users/:userId/sync`
- Protected by `requireAuth`
- Validates body with Joi schema matching `SyncRequest`
- Wraps handler in `asyncHandler` — **no try/catch**
- Calls a `syncService.processOperations(userId, operations)`
### 3. Add the sync service
`packages/api/src/services/sync.service.ts`:
- Iterate over each operation
- Dispatch to the appropriate existing service (e.g. `transactionService.create(...)`)
- Collect results (succeeded/failed) and return `SyncResult`
- Use `clientTimestamp` to preserve user intent ordering where relevant (e.g. set `createdAt` on new records to the client timestamp rather than server `now()`)
### 4. Handle conflicts gracefully
A simple **last-write-wins** strategy is acceptable for v1:
- If an operation tries to update a record that was already updated server-side after the client's `clientTimestamp`, accept the sync (or return a `failed` entry with a clear reason)
- Do **not** hard-fail the entire batch for one bad operation — process the rest and report per-operation results
### 5. Run migrations if entities change
```bash
npm run migration:generate
npm run migration:run
```
---
## ✅ Acceptance Criteria
- [ ] `POST /api/users/:userId/sync` endpoint exists and requires authentication
- [ ] Accepts a batch of typed operations and processes each one
- [ ] Returns a per-operation result (succeeded / failed with reason)
- [ ] One bad operation does not abort the whole batch
- [ ] `clientTimestamp` is respected where relevant (e.g. transaction `createdAt`)
- [ ] Input validated via Joi schema tied to the shared DTO
- [ ] Unit tests for the sync service are added
- [ ] Existing tests still pass (`npm run test:api`)
貢獻指南
這個儲存庫沒有索引到貢獻指南
研究方向
Start by reading the layered patterns under packages/api/src and the shared contracts in packages/shared/src/contracts/. Add the shared DTO and sync route/service described in the issue, then run npm run build:shared and npm run test:api; done means the authenticated endpoint validates batches, reports each result without aborting, respects clientTimestamp where relevant, and has unit tests.
由索引模型根據 Issue 內容生成。
評估
- 技術堆疊
- nodejs, typescript
- 領域
- api, backend
- Issue 類型
- 功能
- 難度
- 5/5
- 預估耗時
- 一週以上
- 活躍度
- 冷清
- 描述清晰度
- 基本清楚
- 新手友好度
- 35/100