Files
alist-serve-resource/docs/DATABASE_SCHEMA.md
T
hoelee 4693c9d684 feat(W4): daily full reconciliation — user/role drift repair + ReconcileLogs audit
- w4-body.js: ONE-DIRECTIONAL sync (NocoDB status = SOT, never reverse);
  drift matrix: missing user/role (provision w/ username lookup to avoid
  duplicates), dangling refs (adopt/recreate), disabled<->status, canonical
  base_path '/' + permission 16384, scopes vs calculateEffectiveGrants,
  username drift detect+log_only; verify-after-repair on every change;
  password never pushed on repair (方案 C); dry-run via ?dryRun=true
- gen_w4.js: daily 03:00 cron + webhook alist-w4-reconcile; API-import-safe
  (UUID node ids, no pinData, webhookId)
- ReconcileLogs table mktsb7le6fqr2u1 (add_reconcilelogs_table.py, idempotent,
  v2 API); FK column nc_jitu___Customers_id for bt-link writes (v2 ignores
  link column itself)
- test_w4_reconcile.js: 34 assertions / 12 mock worlds, ALL PASSED
- live-verified against production: dry-run (3 drifts + 1 error found),
  real repair (3 repaired, verify all passed, 4 log rows), idempotent rerun
- NocoDB 2026.08.x pitfalls documented (v1 col endpoints gone, row delete
  via body [{Id}]); n8n API import/activation pitfalls (activeVersionId)
- docs: W4-DESIGN.md new; DATABASE_SCHEMA 8 tables; N8N_WORKFLOWS, SETUP,
  PROJECT_STATE updated
2026-08-23 09:34:11 +08:00

7.9 KiB
Raw Blame History

NocoDB 数据结构(Phase 2b — 重建,8 表最终模型)

Source of Truth = NocoDB。AList 只做 enforcement,不存业务授权数据。 本 schema 按《Hermes 调整指导》最终业务模型重建(2026-08-22)。 通过 NocoDB API 自动建表,无需手动点 UI。ReconcileLogs 于 2026-08-23 W4 新增。

  • Base: AlistAccess(id p3lzkresswyowqg),独立新 base,与旧 accessDB 隔离。
  • MySQL source: mysql-server 上的 alistaccess schema(由 NocoDB 自动管理)。
  • API token: workspace token(nc_api_tokens 表内 n8n token),xc-token header。

表 model_id(n8n v2 API 硬编码用)

表 model_id
Customers maqb9zgvza2te3k
Products molyb3pxv81l75g
Resources m6cm7tkxzd8m18c
CustomerProducts mvyqbv8ao7u6bct
AccessGrants mxdx3yhfcyej3ao
AccessLogs ml12zcyzlehgi21
Purchases mwp12z9lcohhsuk
ReconcileLogs mktsb7le6fqr2u1(FK 列 nc_jitu___Customers_id = coa6ynwcdlune6p)

⚠ ID 是本次重建生成的。若再次删库重建,ID 会变,需同步更新 n8n 节点 + 本文档。

关系(LinkToAnotherRecord)

子表 字段 方向 指向 说明
CustomerProducts customer bt Customers
CustomerProducts product bt Products
Products Resources mm Resources M2M link,列 id c4ko4x8kwi16swg
Resources Products mm (reverse) Products 列 id cfxi44n9ixkimqc
AccessGrants customer bt Customers
AccessGrants resource bt Resources
AccessLogs customer bt Customers
Purchases customer bt Customers
Purchases product bt Products
ReconcileLogs customer bt Customers ⚠ 写入时用 FK 列 nc_jitu___Customers_id(v2 忽略 link 列本身)

M2M 读写方式(已实测):GET/POST /api/v2/tables/{products}/links/c4ko4x8kwi16swg/records/{productId}, POST body {"Id": <resourceId>}。反向用 Resources 的 cfxi44n9ixkimqc。

表结构

1. Customers

字段 类型 说明
Id number (PK)
username SingleLineText AList 登录名(唯一)
password SingleLineText plaintext(规格 §2 已确认,勿 hash)
display_name SingleLineText
email Email
notes LongText
alist_user_id Number AList 用户 ID(n8n 回填)
alist_role_id Number AList role ID(n8n 回填)
status SingleSelect pending/active/suspended/expired/deleted(account-level 整户开关,见下)
sync_status SingleSelect pending/syncing/synced/error/unknown
sync_required Checkbox 系统维护,管理员勿手改
last_sync DateTime
last_sync_error LongText

Customers.status 语义(account-level 整户开关,不替代 CustomerProduct 到期):

值 含义 AList user scopes
pending 已建但未正式开通 若无则不建;有则 disabled empty
active 正常使用 enabled 按当前有效 CP 重算
suspended 管理员暂时封禁 disabled empty
expired 整户生命周期结束 disabled empty
deleted 软删除(保留账号+历史) disabled empty
  • 任意 X → active 恢复时,重算当前有效 grants(忽略已过期产品),不恢复旧 scopes。
  • status 变化不自动改 CustomerProducts(不批量改 status/expires_at、不删除)。

2. Products

字段 类型 说明
Id number (PK)
name SingleLineText 如 "Python Basic"
description LongText
default_duration_days Number 默认有效期天数
status SingleSelect active/inactive
Resources link (mm) 该产品包含的 Resources

3. Resources

字段 类型 说明
Id number (PK)
name SingleLineText 如 "Python 01"
alist_path SingleLineText 真实 AList path,如 "/Class/Python/01"
description LongText
status SingleSelect active/inactive
Products link (mm, reverse)

4. CustomerProducts(核心新表)

字段 类型 说明
Id number (PK)
customer link bt → Customers
product link bt → Products
start_at Date
expires_at Date 实际到期(可 override default_duration)
status SingleSelect scheduled/active/expired/revoked/suspended
sync_status SingleSelect pending/syncing/synced/error/unknown
sync_required Checkbox
last_sync DateTime
last_sync_error LongText

5. AccessGrants(最终实际权限,n8n 计算维护)

字段 类型 说明
Id number (PK)
customer link bt → Customers
resource link bt → Resources
permission SingleSelect read/readwrite
start_at Date
expires_at Date effective expiry(多来源取 max)
status SingleSelect pending/active/revoked/expired
source SingleSelect product/manual
sync_status SingleSelect pending/syncing/synced/error/unknown
sync_required Checkbox
last_sync DateTime
last_sync_error LongText
revoked_at DateTime
revoke_reason LongText

6. AccessLogs(审计)

字段 类型
Id number (PK)
customer link bt → Customers
username SingleLineText
resource_path SingleLineText
file_path SingleLineText
action SingleSelect (login/view/download/preview/logout)
ip_address SingleLineText
user_agent LongText
result SingleSelect (success/denied)
bytes Number
timestamp DateTime

7. ReconcileLogs(W4 对账审计,n8n W4 写入)

字段 类型 说明
Id number (PK)
run_id SingleLineText 本次对账 run(recon-<ISO>)
customer link bt → Customers FK 列 nc_jitu___Customers_id(v2 写链接必须写 FK 列)
drift_type SingleSelect user_missing / role_missing / dangling_user_ref / dangling_role_ref / user_disabled_drift / scopes_drift / base_path_drift / permission_drift / role_binding_drift / username_drift / verify_failed / reconcile_error
details LongText 前后值 JSON
action SingleLineText 做了什么(provisioned / adopted / fixed / rewritten / disabled / log_only / verify …)
result SingleSelect repaired / log_only / failed / skipped
timestamp DateTime

只记 drift / repair / error 行,健康客户不产生行。W4 每日全量或 webhook 触发时写入。

8. Purchases(纯记录,不参与权限)

字段 类型
Id number (PK)
customer link bt → Customers
product link bt → Products
purchase_date Date
amount Decimal
payment_method SingleLineText
order_id SingleLineText
notes LongText

建表 API recipe(实测 2026-08-22,复用见 nocodb-selfhosted skill)

  • 建 base:POST /api/v2/meta/bases/ {"title"}
  • 建表(内联非 select 列):POST /api/v2/meta/bases/{baseId}/tables {"title","table_name","type":"table","columns":[{"title","uidt"}]}
    • 可用 uidt:SingleLineText,LongText,Number,Decimal,Date,DateTime,Email,Checkbox
  • SingleSelect 两段式:
    1. 建空列 POST /api/v1/db/meta/tables/{tid}/columns {"title","uidt":"SingleSelect"}
    2. 设选项 必须同时传 dtxp(逗号枚举串): PATCH /api/v1/db/meta/columns/{colid} {"colOptions":{"options":[{"title","order","color":null}]},"dtxp":"'opt1','opt2'"} ⚠ 只传 colOptions 不传 dtxp 会静默失败(options 空)。
  • Link:POST /api/v1/db/meta/tables/{childTid}/columns {"title","uidt":"LinkToAnotherRecord","parentId","childId","type":"bt"}
  • M2M:type":"mm",然后走 /api/v2/tables/{t}/links/{colId}/records/{rowId} 读写。
  • 删记录:DELETE /api/v2/tables/{tid}/records body [{"Id":N},...](不是 /records/{id})。