Phase 1-3: AList stock deployment, NocoDB 7-table schema, W1/W2 n8n workflows + docs

This commit is contained in:
2026-08-22 19:26:06 +08:00
commit 71acb88078
21 changed files with 2127 additions and 0 deletions
+30
View File
@@ -0,0 +1,30 @@
# W2 — CustomerProduct 变更 → 同步 AList Role Scopes
事件驱动:NocoDB CustomerProducts 表 webhook → n8n webhook → 重取记录 → 全量重算该 customer 的 effective grants → diff AList role scopes → apply → 物化 AccessGrants + 回写 sync_status。
## 核心逻辑(desired-state,规格 §19/§37)
1. webhook 只带 record Id,n8n `GET /api/v2/tables/{CustomerProducts}/records/{Id}` 重取完整记录。
2. 从记录解析 `customer` link(NocoDB link 字段返回关联行 Id + display value);
若返回对象数组,取第一个的 `Id`。
3. 拉取该 customer 所有 **status=active 且未过期** 的 CustomerProducts。
4. 每个 CP → `product` link → Product;再走 Products 的 M2M link 列
`c4ko4x8kwi16swg`(`GET /api/v2/tables/{Products}/links/c4ko4x8kwi16swg/records/{pid}`)
取该 Product 的全部 Resources(含 `alist_path`)。
5. 汇总:`alist_path -> MAX(expires_at)`(多 Product 重叠取最晚;规格 §18「取最大值」)。
8. 取 customer 的 `alist_role_id` → `GET /api/admin/role/get?id=` 读当前 scopes。
9. diff:desired paths vs 当前 scopes → 要加 / 要删。
10. `POST /api/admin/role/update` 整体重写 `permission_scopes`(幂等)。
11. 物化 AccessGrants:删掉该 customer 的 product 源 grants,重插 desired(manual 源保留不动)。
12. 回写 CustomerProducts 各记录 `sync_status=synced` + `last_sync`。
## 关键 fact(已验证)
- NocoDB link 字段在 v2 records GET 返回形如 `{"customer": {"Id": 5, "username": "..."}}` 或 `[{"Id":5}]`;
Code 节点需兼容两种。
- AList role create/update 返回 `data:null`;role/get 可回读 scopes。
- `permission=0`(read-only bitmask);role scope 用 `{path, permission:0}`。
- M2M link col id: Products.Resources = `c4ko4x8kwi16swg`。
## 首期不做
- expiry 定时扫描/移除(W1/W2 验证后再加)
- 密码 change-detection 的 password_updated_at 触发逻辑(W1 已留字段)