Files
alist-serve-resource/docs/DATABASE_SCHEMA.md
T
hoelee 80eb2b71be docs: architecture, permissions, admin guide + refresh schema/workflows
- 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
2026-08-23 07:30:41 +08:00

166 lines
6.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# NocoDB 数据结构(Phase 2b — 重建,7 表最终模型)
> Source of Truth = NocoDB。AList 只做 enforcement,不存业务授权数据。
> 本 schema 按《Hermes 调整指导》最终业务模型重建(2026-08-22)。
> 通过 NocoDB API 自动建表,无需手动点 UI。
- **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` |
> ⚠ 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 | |
> 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. 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}`)。