# 网页版 Markdown 转 PDF 服务设计方案

## 1. 简单说明 (非技术版)

这个方案的目标是做一个**在线转换服务**。
就像你把文件投进一个黑盒子，过一会吐出一个 PDF 一样。

**用户做什么：**
- 上传一段 Markdown 文字。
- (可选) 上传文章里用到的图片。
- (可选) 告诉我们想要什么样式的 PDF（比如字体大小、页眉页脚）。

**服务器做什么：**
- 收下这些东西。
- 找个干净的临时桌子（沙箱目录）把它们摆好。
- 只有我们允许的样式和文件才能上桌。
- 呼叫我们的转换工具（`mark2pdf`）开始工作。
- 做好后，把 PDF 递给用户，然后把桌子擦得干干净净。

---

## 2. 核心流程 (伪代码)

我们不写复杂的代码，只看逻辑是如何流转的。

```text
// 定义一个处理上传的接口
API 接收请求 (markdown内容, 图片列表, 配置选项):

    // 1. 准备工作环境
    创建 唯一临时目录 (temp_dir)
    在 temp_dir 下创建 images 文件夹

    // 2. 安置用户资产
    FOR 每一张图片 IN 图片列表:
        安全检查 (文件名是否合法，只能是 .jpg/.png 等)
        保存图片 TO temp_dir/images/

    // 3. 配置转换器
    准备转换选项 (
        Markdown内容 = markdown内容
        图片查找路径 = temp_dir
        转换配置 = 配置选项 (合并用户配置和系统默认配置)
        模板 = 用户指定的模板 (必须在白名单内)
    )

    // 4. 执行核心任务 (复用现有能力)
    TRY:
        // 调用核心转换函数，它会生成 PDF
        PDF文件流 = 调用 markdown2pdf.convert_from_string(转换选项)
        
        RETURN 成功响应 (
            内容类型: application/pdf,
            数据: PDF文件流
        )
    CATCH 错误:
        记录错误日志
        RETURN 失败响应 (错误信息)
    FINALLY:
        // 5. 扫尾工作 (非常重要)
        // 确保无论成功还是失败，都把临时目录删干净
        强制删除 temp_dir 及其所有内容
```

---

## 3. 详细接口设计

我们要开通一个新的窗口给前端（比如 NextJS 网页）使用。

**接口地址**: `POST /convert-upload`
**数据格式**: `multipart/form-data` (网页上传文件标准格式)

**参数列表**:
| 参数名 | 类型 | 必填 | 说明 |
| :--- | :--- | :--- | :--- |
| `markdown` | Text / File | 是 | Markdown 的具体内容 |
| `images` | File List | 否 | 文章插图，支持多张上传 |
| `config` | JSON | 否 | 一些自定义设置，如 frontmatter |
| `template` | String | 否 | 模板名称，如 `nb`，`gaozhi` |

**前端调用方式**:
前端只需要把用户选的文件和填的文字打包成一个表单 (`FormData`) 发送给这个接口即可。

---

## 4. 安全与资源控制

为了保证服务稳定，必须设立一些“红线”：

1.  **战场清理**:
    *   临时目录必须在响应后立即删除。
    *   如果任务超时，也要有后台任务定期清理残留。

2.  **路径限制**:
    *   用户传的图片文件名不能包含 `../` 或 `/`，只能是纯文件名。
    *   防止用户恶意访问服务器上的其他文件。

3.  **资源限额**:
    *   限制上传图片的总大小（比如 20MB）。
    *   限制 Markdown 的长度。
    *   这是一个计算密集型任务，未来可能需要加任务队列。

---

## 5. 现有能力复用

我们不需要从头造轮子，可以直接使用现有的积木：

- **核心引擎**: `markdown2pdf` (已支持从字符串转换，已支持指定图片目录)。
- **Web 框架**: `web_server.py` (FastAPI) 现有的服务。
- **模板系统**: 现有的模板加载和 Typst 编译流程。

这个方案只是在现有引擎上，加了一个“处理上传文件”的外壳。
