# 管理员后台 API

## 接口说明

这组接口服务于 Proof DB 的管理员维护面板，包括：

- 管理员登录与会话读取
- `archives` 表管理
- OpenSearch 状态查看
- 管理员用户管理
- APIDOC 文档查看
- 维护脚本执行

管理员网页入口仍然是：

- `GET /`
- `GET /admin/login`
- `GET /admin`

## 管理员认证

### 管理员登录

```http
POST /api/admin/login
```

`Content-Type: application/json`

| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `username` | string | 是 | 管理员用户名 |
| `password` | string | 是 | 管理员密码 |

### 管理员退出登录

```http
POST /api/admin/logout
```

### 当前管理员会话

```http
GET /api/admin/me
```

未登录时返回：

```json
{
  "code": 401,
  "message": "Admin session not found."
}
```

## archives 表管理

### 获取档案列表

```http
GET /api/admin/archives
```

### 查询参数

| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `query` | string | 否 | 按 `archive_uid`、`title`、`summary`、`author`、`source`、`series` 模糊搜索 |
| `page` | integer | 否 | 页码，默认 `1` |
| `page_size` | integer | 否 | 每页条数，默认 `20`，最大 `100` |

### 请求示例

```bash
curl '<APIdomain>/api/admin/archives?query=iraq&page=1&page_size=20'
```

### 成功响应

```json
{
  "code": 0,
  "message": "Archive list loaded.",
  "data": {
    "items": [
      {
        "archive_uid": "01KQHVREB6XPYF604RVZAP9NNY",
        "title": "1.test",
        "summary": "....",
        "year": 1991,
        "author": "....",
        "source": "....",
        "series": null,
        "tags": ["Iraq", "Kuwait"],
        "chunk_count": 14,
        "created_time": "2026-05-07 12:00:00+00",
        "updated_time": "2026-05-07 12:10:00+00"
      }
    ],
    "total": 1,
    "page": 1,
    "page_size": 20
  }
}
```

### 获取单条档案详情

```http
GET /api/admin/archives/{archive_uid}
```

### 更新单条档案

```http
PATCH /api/admin/archives/{archive_uid}
```

`Content-Type: application/json`

可更新字段：

- `title`
- `summary`
- `year`
- `author`
- `source`
- `series`
- `tags`
- `metadata`

其中：

- `tags` 可以传字符串，也可以传数组；字符串会按逗号或换行拆分
- `metadata` 可以传 JSON 对象，也可以传 JSON 字符串
- `year` 为空时会写回 `null`

### 更新请求示例

```bash
curl -X PATCH <APIdomain>/api/admin/archives/01KQHVREB6XPYF604RVZAP9NNY \
  -H 'Content-Type: application/json' \
  --data '{
    "title": "Updated Title",
    "summary": "Updated summary",
    "year": 1991,
    "tags": ["Iraq", "Kuwait"],
    "metadata": {
      "reviewed_by": "admin"
    }
  }'
```

### 删除单条档案

```http
DELETE /api/admin/archives/{archive_uid}
```

删除后会因外键约束级联删除对应 `chunks` 记录。

## OpenSearch 状态查看

### 获取 OpenSearch 管理状态

```http
GET /api/admin/opensearch/status
```

### 成功响应要点

响应中会同时返回：

- OpenSearch 连接配置摘要
- PostgreSQL 侧 `archives/chunks` 数量
- `embedded_chunks`
- `indexed_chunks`
- 当前索引是否存在
- `docs_count`
- cluster 健康状态
- mapping 字段列表

如果 OpenSearch 当前不可达，仍会返回数据库部分统计，但 `opensearch.error` 会带出错误信息。

### 获取 OpenSearch 索引文档粗览

```http
GET /api/admin/opensearch/documents
```

### 查询参数

| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `query` | string | 否 | 按 `title`、`summary`、`source`、`author`、`text` 等字段做粗略搜索 |
| `size` | integer | 否 | 返回条数，默认 `20`，最大 `50` |

说明：

- 这是索引粗览接口，不返回向量字段本身。
- 返回中会包含 `text_preview`，用于后台快速检查索引内容是否正确进入 OpenSearch。

## 管理员用户管理

### 获取管理员用户列表

```http
GET /api/admin/users
```

### 创建管理员用户

```http
POST /api/admin/users
```

`Content-Type: application/json`

| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `username` | string | 是 | 新管理员用户名 |
| `password` | string | 是 | 新管理员密码 |
| `display_name` | string | 否 | 展示名称 |

### 更新管理员用户

```http
PATCH /api/admin/users/{id}
```

`Content-Type: application/json`

可更新字段：

- `display_name`
- `password`
- `is_active`

说明：

- `password` 为空时表示不修改
- `is_active=false` 后，该账号将不能再登录

## APIDOC 查看

### 获取文档列表

```http
GET /api/admin/docs
```

返回 `/apidoc` 目录下当前可查看的 `.md` 文档列表。

### 获取单份文档内容

```http
GET /api/admin/docs/{name}
```

例如：

```bash
curl <APIdomain>/api/admin/docs/searchapi.md
```

响应中会带：

- `name`
- `title`
- `content`
- `html`

其中：

- `content` 为原始 Markdown 文本
- `html` 为后台面板可直接渲染的 HTML

## 维护脚本伪终端

### 获取白名单脚本列表

```http
GET /api/admin/scripts
```

当前返回的是允许在管理员面板里执行的 `scripts/*.php` 白名单，而不是任意文件系统扫描。

如果对应脚本在 `/scriptdoc` 中存在同名文档，列表接口也会带出：

- `doc_title`
- `doc_html`
- `doc_content`

### 获取单个维护脚本详情

```http
GET /api/admin/scripts/{name}
```

这个接口会返回单个脚本的说明、参数提示，以及可用的脚本文档内容。

### 执行维护脚本

```http
POST /api/admin/scripts/run
```

`Content-Type: application/json`

| 字段 | 类型 | 必填 | 说明 |
| --- | --- | --- | --- |
| `script_name` | string | 是 | 白名单脚本名，如 `reindex_opensearch` |
| `args` | string[] | 否 | 参数数组，仅允许 `--key=value` 风格 |

### 请求示例

```bash
curl -X POST <APIdomain>/api/admin/scripts/run \
  -H 'Content-Type: application/json' \
  --data '{
    "script_name": "reindex_opensearch",
    "args": ["--archive_uid=01KQHVREB6XPYF604RVZAP9NNY"]
  }'
```

### 成功响应

```json
{
  "code": 0,
  "message": "Maintenance script finished.",
  "data": {
    "script_name": "reindex_opensearch",
    "command": [
      "php",
      "scripts/reindex_opensearch.php",
      "--archive_uid=01KQHVREB6XPYF604RVZAP9NNY"
    ],
    "exit_code": 0,
    "stdout": "....",
    "stderr": "",
    "ok": true
  }
}
```

## 权限与错误语义

- 除 `POST /api/admin/login` 外，本文件中的所有接口都要求已有管理员会话。
- 未登录时统一返回 `401`。
- 参数不合法时通常返回 `422`。
- JSON 格式错误时返回 `400`。
- 后端异常时返回 `500`。
