# PDC 业务层主契约

## 项目结构

```
pdc/
├── config/          站点配置（common.php / admin.php / database.php）
├── model/           Model 子类，一表一文件
├── lang/            语言包（zh-CN.php / en.php）
└── admin/
    ├── index.php    入口（Mvc::init + dispatch）
    ├── action/      控制器，文件名 = 模块名（小写）
    └── view/        视图，{模块名}/index.view.php
```

框架层在 `mvc/v2/`，不属于本层，见 `mvc/v2/.claude/CLAUDE.md`。

## 会话使用规则

- 本层会话只改 `pdc/` 目录内的文件
- 需要改框架（Mvc/Action/Model/GridActions）时，切换到框架层会话
- 每次会话开始先读 `.claude/status/modules.md` 了解当前进度
- 每次会话结束更新 `.claude/status/modules.md`

## 子契约索引

| 契约 | 内容 | 何时读 |
|------|------|--------|
| [DB.md](contracts/DB.md) | 表名、字段、FK 命名规则 | 新建/修改 Model 时 |
| [Naming.md](contracts/Naming.md) | PHP 类、方法、文件命名规范 | 新建任何文件时 |
| [UI.md](contracts/UI.md) | 色值、字号、布局尺寸、DevExtreme 配置 | 改 CSS / 视图 / JS 时 |
| [i18n.md](contracts/i18n.md) | lg() 用法、语言包维护流程 | 写任何中文文案时 |
| [Auth.md](contracts/Auth.md) | 认证机制、权限快照、密码规范、权限码格式 | 改认证 / 权限 / 登录相关时 |
| [API.md](contracts/API.md) | 响应格式、错误码、Grid协议、Filter表达式 | 写或改任何接口时 |
| [local.md](contracts/local.md) | 本机访问地址、PHP 路径、可用命令 | 需要本地验证 / 跑命令时 |

> `local.md` 是**每人一份的本机环境说明**，内容因机器而异，不提交到 SVN。
> 其它契约里不要写死本机路径和端口，本机相关的东西一律放 `local.md`。

## 响应格式（所有 Action 统一）

```json
{"code": 0, "data": {...}, "msg": ""}
```

- `code=0` 成功，非 0 为错误码
- 成功用 `$this->success($data)`，失败用 `$this->error(401, '消息')`
- 禁止在 Action 里直接 `echo` 或 `header()`

## Grid 接口三端点

| 端点 | 对应 trait 方法 | 说明 |
|------|---------------|------|
| `/{module}/grid` | `grid()` | 查询列表，DevExtreme CustomStore load |
| `/{module}/save` | `save()` | 新增（无 key）或更新（有 key） |
| `/{module}/remove` | `remove()` | 删除，body `{"key": 主键值}` |

使用 `GridActions` trait 的 Action 只需实现 `gridModel(): Model`，三个端点自动可用。

## 多语言规则

- 中文文案必须用 `lg('原文')` 包裹，才能被语言包扫描工具收录
- `lg()` 内只放可翻译文字，符号/箭头/标点放括号外
  - 正确：`lg('请先选择') . ' →'`
  - 错误：`lg('请先选择 →')`
- 新增文案后跑 `lang/scan.php` 同步语言包条目

## 禁止事项

- Action 里不写 SQL，所有查询走 Model 方法
- Model 里不读 `$_GET` / `$_POST` / `$_SESSION`
- 不在视图文件里做业务判断（超过5行 PHP 逻辑应移入 Action/Model）
- 不注释掉代码后留在文件里，直接删除
