77 lines
4.4 KiB
Markdown
77 lines
4.4 KiB
Markdown
# pbl_domain_ext — PBL 基础域薄扩展(M8)
|
||
|
||
world / scene / entity 三模块的 **PBL 侧薄扩展**:为复用平台的世界/场景/实体叠加
|
||
租户 / 蓝图 / 班级 / 团队关联维度。**不改三张基表结构、不侵入复用模块代码**(Q-OPEN-3 裁决:零改表)。
|
||
|
||
## 核心事实
|
||
|
||
- **自有表 1 张**:`pbl_domain_ref`(`UNIQUE(tenant_id, ref_type, ref_id)`)
|
||
- 权威 DDL:`projects/pbls/docs/01-design/data-model.md` §J1
|
||
- 表总账:`projects/pbls/pbls_spec.json` → `tables_by_module.pbl_domain_ext = 1`、`tables_total = 36`
|
||
- **契约 13 个**:设计 `projects/pbls/docs/01-design/modules/pbl_domain_ext.md` §3.1(5) + §3.2(5) + §3.3(3)
|
||
- **复用基表只读**:world / scene / entity 零 ALTER、零写入
|
||
- **他模块表只读**:`pbl_governance.pbl_team_member`(取团队成员,表缺失时降级空列表)
|
||
|
||
## 目录结构
|
||
|
||
```
|
||
pbl_domain_ext/
|
||
├── pbl_domain_ext/ # Python 包(模块名 = 包目录名,无 app.py)
|
||
│ ├── __init__.py # ② 导出 load_pbl_domain_ext + 13 契约
|
||
│ ├── init.py # ③ load_pbl_domain_ext():注册 env.pbl_* + 设计原名;OWN_TABLES
|
||
│ ├── api.py # ① 13 个契约接口实现(设计 §3)
|
||
│ ├── base.py # 复用基表只读投影层(列名运行时探测、悬挂引用过滤)
|
||
│ ├── db.py # 数据访问适配(SqlorAdapter 生产 / SqliteAdapter 测试)
|
||
│ └── errors.py # PBL_E_* 错误码 + 统一异常(优先复用 pbl_common)
|
||
├── models/pbl_domain_ref.json # 表定义四段式(summary 数组 / fields / indexes / codes)
|
||
├── json/pbl_domain_ref.json # CRUD 浏览定义(tblname + params.browserfields/editable)
|
||
├── sql/pbl_domain_ext.sql # 建表 DDL(对齐 data-model.md §J1)
|
||
├── wwwroot/
|
||
│ ├── index.ui # 模块入口页(三组契约卡片导航)
|
||
│ └── api/*.dspy # 13 个契约端点薄封装(与 api.py 一一对应)
|
||
├── scripts/load_path.py # RBAC 路径显式注册(13 dspy + 1 ui,禁通配符)
|
||
├── tests/ # 离线 sqlite 测试(62 用例,覆盖 13 契约 + 薄扩展铁律)
|
||
├── skill/SKILL.md # Agent 必读规范(铁律 + 陷阱 + 契约映射)
|
||
├── pyproject.toml
|
||
└── README.md
|
||
```
|
||
|
||
## 契约清单(设计 §3 → 实现 → 端点)
|
||
|
||
| # | 接口 | 实现 | dspy 端点 |
|
||
|---|---|---|---|
|
||
| 1 | `bind_ref` | `api.py:bind_ref` | `api/pbl_domain_ref_bind.dspy` |
|
||
| 2 | `unbind_ref` | `api.py:unbind_ref` | `api/pbl_domain_ref_unbind.dspy` |
|
||
| 3 | `get_ref` | `api.py:get_ref` | `api/pbl_domain_ref_get.dspy` |
|
||
| 4 | `list_refs` | `api.py:list_refs` | `api/pbl_domain_ref_list.dspy` |
|
||
| 5 | `update_ref` | `api.py:update_ref` | `api/pbl_domain_ref_update.dspy` |
|
||
| 6 | `list_worlds_by_tenant` | `api.py:list_worlds_by_tenant` | `api/pbl_world_list_by_tenant.dspy` |
|
||
| 7 | `list_scenes_by_world` | `api.py:list_scenes_by_world` | `api/pbl_scene_list_by_world.dspy` |
|
||
| 8 | `list_entities_by_scene` | `api.py:list_entities_by_scene` | `api/pbl_entity_list_by_scene.dspy` |
|
||
| 9 | `get_world_with_pbl_context` | `api.py:get_world_with_pbl_context` | `api/pbl_world_get_context.dspy` |
|
||
| 10 | `check_ref_access` | `api.py:check_ref_access` | `api/pbl_domain_ref_check_access.dspy` |
|
||
| 11 | `list_teams_by_class` | `api.py:list_teams_by_class` | `api/pbl_team_list_by_class.dspy` |
|
||
| 12 | `bind_team_to_world` | `api.py:bind_team_to_world` | `api/pbl_team_bind_world.dspy` |
|
||
| 13 | `get_team_worlds` | `api.py:get_team_worlds` | `api/pbl_team_world_list.dspy` |
|
||
|
||
## 挂载
|
||
|
||
```python
|
||
from pbl_domain_ext import load_pbl_domain_ext
|
||
load_pbl_domain_ext(env) # 注册 13 契约到 ServerEnv
|
||
import sys; sys.path.append('modules/pbl_domain_ext/scripts')
|
||
import load_path; load_path.register(env) # RBAC 路径注册(幂等)
|
||
```
|
||
|
||
模块 host-agnostic:只依赖 sqlor / ahserver ServerEnv / 自有表,不依赖宿主入口与配置。
|
||
|
||
## 验证
|
||
|
||
```bash
|
||
python3 -m py_compile pbl_domain_ext/*.py scripts/load_path.py tests/*.py
|
||
python3 tests/test_domain_ref.py # 62 tests OK
|
||
python3 scripts/load_path.py # 路径注册自检 OK
|
||
```
|
||
|
||
详见 `skill/SKILL.md`(铁律、陷阱、需求追溯)与 `docs/work-log-2026-09-18.md`(本轮 QC 退回逐条整改记录)。
|