# Todo CloudBase 跨设备同步

## 问题

原方案待办通过 Tunnel API（`macbook-air-2.tail6864e8.ts.net/api/todos`）存 Mac 本地 `todos.json`，Mac 休眠/关机时手机端降级为纯 localStorage，不同步。

## CloudBase 方案（2026-08-10 实施）

### 架构

```
手机/电脑 ──pull──▶ CloudBase `todos` 集合 ──push──▶ 手机/电脑
              │         (24/7 在线)                    │
              └──▶ Tunnel API (兜底) ◀─────────────────┘
```

### 关键代码（index.html + app.html）

```javascript
// 读取：CloudBase 优先
function pullTodos() {
  if (cbDb) {
    return cbDb.collection('todos').where({user: userName}).get().then(function(res) {
      if (res.data && res.data.length > 0) {
        var merged = mergeTodos(res.data[0].todos || [], loadTodos());
        saveTodos(merged);
      }
    }).catch(function(e) { console.warn('CloudBase pullTodos 失败:', e.message); });
  }
  // 兜底 Tunnel API...
}

// 写入：CloudBase + Tunnel API + localStorage
function pushTodos() {
  saveTodos(todos);  // localStorage
  if (cbDb && userName) {
    cbDb.collection('todos').where({user: userName}).get().then(function(res) {
      if (res.data.length > 0) {
        cbDb.collection('todos').doc(res.data[0]._id).update({todos, updated: new Date().toISOString()});
      } else {
        cbDb.collection('todos').add({user: userName, todos, updated: new Date().toISOString()});
      }
    });
  }
  todoPost(...);  // 兜底 Tunnel API
}

// 合并策略：远程为主，本地独有未同步项追加
function mergeTodos(remote, local) {
  var remoteIds = {};
  remote.forEach(function(t) { if (t.id) remoteIds[t.id] = true; });
  var merged = remote.slice();
  local.forEach(function(t) { if (t.id && !remoteIds[t.id]) merged.push(t); });
  return merged;
}
```

### 必要条件

CloudBase `todos` 集合权限必须设为「所有用户可读写」。匿名登录 `_openid` 每设备不同，默认「仅创建者可读写」会导致跨设备不可见。

### 数据迁移

```bash
tcb db nosql execute -e bier-sales-d0gatbvlx288724e9 --command '[...]'
```
