# MoonLDIF 离线工作台

用同一个 MoonBit 核心完成文件预检、变更审阅和写回。React 负责交互，Vite 负责打包；分析在独立 Web Worker 中运行。所有样例都是合成数据。

从项目根目录执行：

```text
npm --prefix web ci
npm --prefix web run build
npm --prefix web run preview
```

浏览器打开 `http://127.0.0.1:4178/`。端口已被占用时启动失败，不会静默换端口。开发时 `npm --prefix web run dev` 提供开发服务；严格 CSP 禁止网络连接，因此主验收使用生产构建的 preview，不依赖热更新。

## 使用

1. 选择内置场景、拖入 LDIF，或点击“打开 LDIF”。默认拦截整条删除。
2. 在诊断或变更审阅中点击“定位原文”，查看选中的原始物理行。
3. 编辑或更改选项后，旧报告立即失效，导出禁用。点击“重新检查”。
4. 支持范围内检查完成且策略未拦截时，可以“导出新文件”；导出仍会重新运行核心检查和写回核对。文件名追加 `-normalized.ldif`，原编辑内容不自动替换。

“导出”只生成文件，不导入目录、不连接 LDAP。实际保存位置由浏览器决定，页面只报告已生成文件，不把此动作称作服务器验证。

## 数据与资源边界

- 不上传、不写本地存储、不使用第三方字体或分析服务。静态资产从本机服务加载，生产 CSP 的 connect-src 为 none；Worker 的解析、审阅和写出逻辑均来自编译后的 MoonBit。
- 每个文件上限 1 MiB、10,000 行，比 CLI 限制更低。解析仍有核心内部限制，超限不是通过。
- 仅接受有效 UTF-8，不用替代字符改写坏字节；BOM 保留给核心诊断，不静默移除。
- 文件读取、分析与导出有请求版本隔离；旧结果不能覆盖新编辑。Worker 在结果完成、取消或出错后终止，20 秒超时失败。
- 检查只显示限定的前 200 项审阅；有截断提示时应分段查看。输入不完整时保留已识别内容，可下载带不完整标记的审阅报告，不允许导出 LDIF。
- 输入只在当前页面内存中。刷新、关闭页面或选择另一示例会丢弃当前编辑；请先自行保存需要的内容。
- 0.2.0 使用 Chromium、Firefox 桌面以及 390 × 844 手机视口验证，不是真机测试。CLI 是独立入口。详见 docs/BROWSER_QA.md。

设计与验证资料位于 `docs/design/` 和项目验证快照。构建目录、依赖目录及工具链不提交。

## 报告与公开部署

勾选“拦截属性清空”或“拦截改名与移动”后重新检查；仅“拦截整条删除”默认开启。完成结果可选择 Markdown / JSON 并下载审阅报告，报告包含 DN 和源内容指纹，不包含原始属性值。更改选项和编辑立即清空旧结果。

公开入口 https://weir-h.github.io/moonldif/ 仅提供静态资产；构建环境设置 PAGES_BASE=/moonldif/。正式 vX.Y.Z 标签的双平台及浏览器 CI 成功后才部署 web/dist。connect-src 仍为 none，无上传、统计或外部字体。

## 0.4.0 迁移前后核对

顶部切换工作模式，载入合成示例或两份内容导出，开始核对后查看缺失条目/属性和值变化，定位两侧源行并下载报告。每份最多 1 MiB / 10,000 行；独立 Worker、20 秒超时，过期结果禁止下载。指纹为当前实际分析字节，编辑后需复检；DN 按原字符串匹配，不推断重命名。完整边界见 [快照说明](../docs/SNAPSHOTS.md)。
