# MDM 项目根契约

## 项目组成

```
mdm/
├── mvc/v2/     框架层（路由、控制器基类、模型基类、视图、多语言）
├── pdc/        业务层（配置、Model、Action、View、语言包）
└── docs/       项目文档
```

版本控制：**SVN**（`.svn/`），不是 git。提交前用 `svn status` 检查改动范围。

## 契约路由

**开工前先读对应层的契约，不要凭猜测写代码。**

| 改动范围 | 必读契约 |
|---------|---------|
| `mvc/v2/**` 框架核心 | [mvc/v2/.claude/CLAUDE.md](../mvc/v2/.claude/CLAUDE.md) |
| `pdc/**` 业务代码 | [pdc/.claude/CLAUDE.md](../pdc/.claude/CLAUDE.md) |

业务层子契约（在 `pdc/.claude/contracts/` 下）：

| 契约 | 何时读 |
|------|--------|
| `DB.md` | 建表、改表、写 Model、任何 DDL |
| `Naming.md` | 新建任何文件、类、方法 |
| `API.md` | 写或改接口 |
| `Auth.md` | 改登录、权限、密码相关 |
| `UI.md` | 改 CSS、视图、前端 JS |
| `i18n.md` | 写任何中文文案 |

当前进度：[pdc/.claude/status/modules.md](../pdc/.claude/status/modules.md)

## 层边界（最重要的一条）

**框架层不放业务代码，业务层不改框架。**

- 业务需求优先在 `pdc/` 解决
- 只有业务层确实实现不了，才动 `mvc/v2/`
- 改框架方法签名后，必须全量检查 `pdc/` 里的调用点

## PHP 版本约束

**全项目按 PHP 8.1 编写**，生产环境为 PHP 8+。

下限由 composer 依赖锁死，不是可选项：`phpoffice/phpspreadsheet` 要求 `^8.1`、`workerman/workerman` 要求 `>=8.1`，低于 8.1 装不上也跑不起来。

| 可用 | 起始版本 |
|------|---------|
| 类型化属性、箭头函数 `fn()`、`??=` | 7.4 |
| 构造函数属性提升 `__construct(private $x)` | 8.0 |
| 联合类型 `array\|string\|null $x`、`mixed` 类型 | 8.0 |
| `match` 表达式 | 8.0 |
| Nullsafe `?->` | 8.0 |
| Named arguments | 8.0 |
| `str_contains()` / `str_starts_with()` / `str_ends_with()` | 8.0 |
| 枚举 `enum`、`readonly` 属性、`never` 返回类型、数组解包字符串键 | 8.1 |

**8.2 及以上的语法不要用**（`readonly class`、DNF 类型、8.3 的类型化类常量、8.4 的属性钩子等）。生产实际版本可能高于 8.1，但按 8.1 写能在所有 8.x 上跑；确认生产版本后要放宽，改本文件，不要在代码里先斩后奏。

**动态属性必须显式声明**：PHP 8.2 起动态属性已弃用，类里用到的属性一律写在类体里，不能只在构造函数里赋值。

## 会话使用规则

1. 一个会话只做一件事（一个模块 / 一个 bug / 一次重构）
2. 会话开始：读本文件 + 对应层契约 + `status/modules.md`
3. 会话结束：更新 `status/modules.md` 的进度和备注
4. 跨层改动（同时动框架和业务）需要在会话开头明确声明，并说明为什么业务层解决不了

## 第三方代码不可改

**任何时候都不要修改第三方代码**，包括但不限于：

| 位置 | 内容 |
|------|------|
| `pdc/admin/static/js/plugins/**` | DevExtreme、FontAwesome |
| `pdc/admin/static/js/jquery-*.js` | jQuery |
| `mvc/v2/composer/vendor/**` | Composer 依赖（Medoo、PhpSpreadsheet 等） |

第三方的行为不满足需求时，**改我们自己的封装层**，不要动它们的源码：

| 想改的东西 | 应该改哪里 |
|-----------|-----------|
| dxDataGrid 的行为、工具条、列渲染、行高对齐 | `pdc/admin/static/js/lib/dxGrid.js` |
| 后台框架的标签页、菜单 | `pdc/admin/static/js/lib/adminLayout.js` |
| DevExtreme 的样式 | `pdc/admin/static/css/dxCustom.css` |
| HTTP 客户端能力 | `mvc/v2/lib/HttpClient.php` |

理由：第三方文件随时可能整包升级，改在里面的东西升级即丢，且没有任何记录。
遇到第三方的坑，优先找它的公开 API（比如 dxDataGrid 的 `updateDimensions()`）在封装层解决；
确实只能改源码时，先停下来说明原因，由人工决定。

## 全局禁止事项

- 不提交注释掉的代码，直接删
- 不修改第三方代码（见上一节），需要改行为一律在自己的封装层解决
- 不在 Action 里写 SQL，不在 Model 里读 `$_GET/$_POST/$_SESSION`
- 不改 `Action::json()/success()/error()` 的响应格式（业务层全依赖它）
- 不引入新的 CSS/JS 框架（已有 DevExtreme + jQuery）
- 不擅自执行 DDL，SQL 交人工审核后执行
