- New ARCHITECTURE.md (3-layer model + data flow + lifecycle matrix) - New PERMISSIONS.md (grant calculation rules + enforcement) - New ADMIN_GUIDE.md (華文极简:Customer/CustomerProduct 授权 + Product/Resource 管理) - Rewrite N8N_WORKFLOWS.md from WF1-6 (obsolete) to actual W1/W2/W3 - Update DATABASE_SCHEMA.md: fix status enum (drop 'disabled'), add 5-status semantics - Update README.md doc index
3.7 KiB
3.7 KiB
架构说明(Architecture)
本文解释系统的分层职责与数据流。更新日期 2026-08-23。
三层职责(核心心智模型)
| 层 | 载体 | 职责 | 谁改它 |
|---|---|---|---|
| Account lifecycle | Customers.status |
账户整体状态开关(active / pending / suspended / expired / deleted) | 管理员手工 |
| Product entitlement | CustomerProducts + Products + Resources |
「这个客户买了哪些产品 → 能访问哪些路径」+ 每个产品的到期时间 | 管理员手工 |
| Effective permission | AList Role permission_scopes |
最终生效的路径授权(由 n8n 从上面两层计算出来,写到 AList) | 仅 n8n,管理员不直接碰 |
Customers.status (account-level:整户开关)
+
CustomerProducts (product entitlement:买了什么、何时到期)
+
Product → Resources (产品包含哪些路径)
+
CustomerProduct.expires_at
↓
calculateEffectiveGrants (n8n 共享算法,单一事实源)
↓
AList Role.permission_scopes (effective/materialized permission)
关键原则
-
Customers.status不进入权限计算。它只决定「整户开关」:active→ 允许计算并应用 grantspending/suspended/expired/deleted→ AList user disabled + scopes 清空(账户级封禁)- 权限的「细粒度」永远来自 CustomerProducts 的到期时间,不由 status 替代。
-
AccessGrants 是预留的物化表,当前不经 n8n 写入。将来(W4)可用于 reconciliation 日志/物化审计,但现在不作为 source-of-truth,也不参与计算。
-
n8n 是同步器,不是 SOT。Source of Truth = NocoDB;AList 只做 enforcement。
数据流
管理员在 NocoDB 改 Customers.status 或 CustomerProducts
│ (NocoDB webhook:after insert / after update)
▼
n8n W1 (Customer webhook) ── 处理整户 status lifecycle
n8n W2 (CustomerProduct webhook) ── 重算该客有效 grants 并应用
n8n W3 (每 5 分钟 schedule) ── 全量对账:重算所有客户,修 drift
│
▼
AList Admin API(role/update 写 permission_scopes;user/update 写 disabled)
- W1 单一 Code 节点:provision + status lifecycle(5 状态)+ 幂等 write-back。
- W2 单一 Code 节点:CustomerProduct 变更 → 重算该客 grants → diff → 应用。
- W3 单一 Code 节点:全量 sweep,逐客调共享算法,diff 后应用;支持 dry-run / auto-disable 开关。
三个 workflow 共用同一个 calculateEffectiveGrants(n8n/shared/effective-grants.js,构建时内联),保证三处算法零复制、零漂移。
Status lifecycle(W1)
| status | AList user | scopes | 说明 |
|---|---|---|---|
pending(无 user) |
—(不建) | — | 纯标签,customer 未正式开通 |
pending/suspended/expired/deleted(有 user) |
disabled | 清空 | 账户级封禁,soft,保留历史 |
active(无 user) |
新建 + enabled | 计算应用 | 首次开通 |
active(有 user) |
re-enable | 重算 + 应用 | 恢复/续期,永不恢复旧值 |
任意 X → active |
enable | 重算(仅当前有效) | resume,忽略已过期产品 |
Loop 防护
- n8n 只写回 bookkeeping 字段(
alist_user_id/alist_role_id/sync_status/sync_required/last_sync/last_sync_error)。 - W1 用 old/new field comparison(NocoDB webhook 的
previous_rowsvsrows)区分「管理员业务变更」vs「自己的 write-back echo」:echo 直接短路,零 PATCH。 writeBack()有值比对守卫:字段值没变就不发 PATCH,从物理上掐断 echo loop。