Files
awesome/README.md
T
cheney 806761103b
Build and Deploy / build (push) Successful in 1m32s
Build and Deploy / deploy (push) Successful in 26s
feat: 管理台搜索/分区刷新、评论人员体系、相关项目,修复内容源自动获取,完善 MCP 自描述
管理台:
- 内容管理新增名称搜索(title/slug/url/description),状态与翻页链接保留搜索词
- 菜单改为真实链接,每次点击重新向后台取数渲染分区,不再依赖手动刷新
- 内容管理每页固定 20 条
- pending 条目按钮改为「预览」,active 为「查看」

评论体系:
- 评论提交新增必填联系方式(手机号/邮箱),前端不做展示
- 首次评论以「昵称+联系方式」建档,之后需匹配且未被禁用
- 后台评论管理新增联系方式列;新增评论人员管理页,可启用/禁用/改名/删除
- 评论昵称输入框不再预置 admin

相关项目:
- 新增 entry_relations 双向关联,详情页侧栏展示并写入机读 JSON
- 编辑页可添加/移除关联

内容源自动获取:
- 修复 rss 适配器把 feed url 当成条目 url 的根本问题,支持 Atom link/href 与相对链接
- eryajf-weekly 限定正文容器取链接,修正项目说明的提取与「(opens new window)」清理
- pipeline 增加轮内去重与单条失败隔离;scheduler 对非法 cron 明确告警

MCP:
- 重写 instructions 为八节说明,新增 usage 工具返回结构化接入文档
- 补全各工具的参数、用途与返回格式说明;baseUrl 取自当次请求
- 首页 MCP 区块与 README 同步补充写入示例与踩坑清单

测试: 新增 comments/relations/admin/ingest-adapters 用例,共 29 个全部通过
2026-10-27 11:22:26 +08:00

171 lines
7.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Awesome Index
把网上牛逼的东西收进一个库:给人用,也给 AI 用。
精选开源软件 / 微服务 / SaaS / 网站 / 工具 / 脚本 / 插件的结构化数据库,内置 MCP 接口。
- 设计方案:[design/DESIGN.md](design/DESIGN.md)(Riso 印刷风格 + 静态原型)
- 框架设计:[docs/ARCHITECTURE.md](docs/ARCHITECTURE.md)(模块划分 / 数据模型 / 端点)
## 快速开始
### 本地开发
```bash
npm install
npm run dev # http://localhost:3000(--watch 热重载)
npm test # node:test,27 个用例
```
首次启动自动完成建表与种子数据。默认管理员 `admin`,密码取 `ADMIN_INIT_PASSWORD`(默认 `admin`)。
### Docker 部署
```bash
docker build -t awesome-index:latest .
bash start.sh # 用新镜像重启容器
```
`start.sh` 会检查 `.env`(不存在则从 `.env.example` 复制),然后 `docker run` 启动容器。数据持久化在宿主机 `./data/awesome.duckdb`,重启不丢数据。
## 给人的入口
| 页面 | 地址 |
|---|---|
| 首页(搜索 / MCP 说明 / 最近收录) | `/` |
| 列表页(类型 + 嵌套标签过滤) | `/entries?q=关键字&type=工具&tags=1,2&sort=stars` |
| 详情页(元数据 / 相关项目 / 评论 / 机读 JSON) | `/entries/:slug` |
| 随机游览 | `/random` |
| 登录 | `/login` |
| 管理台 | `/admin` |
管理台分区(**点菜单每次都重新向后台取数**,不需要手动刷新浏览器):
| 分区 | 说明 |
|---|---|
| 内容管理 | 名称搜索(标题 / slug / URL / 描述)+ 状态筛选,**每页 20 条**;pending 条目按钮为「预览」,active 为「查看」 |
| 标签管理 | 无限嵌套标签树,拖拽调整层级 |
| 评论管理 | 评论列表 + **联系方式**列 |
| 评论人员 | 以联系方式为身份依据,可启用 / 禁用 / 改名 / 删除 |
| 内容源 | 人工 / AI 接口 / 定时拉取(rss / html / eryajf-weekly) |
| 账号管理 | 管理员可见 |
### 评论规则
访客评论需要提供**昵称 + 联系方式**(手机号或邮箱):
- 联系方式**只存后台,前台详情页不展示**。
- **首次评论**以「昵称 + 联系方式」建档入库。
- **之后评论**必须昵称与该联系方式登记的一致,且未被管理员禁用,否则分别返回 400 / 403。
- 管理员可在「评论人员」分区按联系方式禁用某人;禁用后其评论被拒,历史评论保留。
### 相关项目
每个条目都能关联若干「相关项目」,在详情页侧栏展示,同时进入机读 JSON 的 `related` 字段。
- 关联在管理台「编辑条目 → 相关项目」里维护。
- **关联是双向的**:A 关联 B 后,B 的详情页也会出现 A(底层只存一条记录)。
- 前台只展示已上架(`active`)的相关条目。
## 给 AI 的入口(MCP)
> **一句话:读用 MCP(免密钥),写用 REST(要 `X-Ingest-Key`)。**
### 只读部分:MCP
```
POST {BASE_URL}/mcp
transport: Streamable HTTP
auth: none
Accept: application/json, text/event-stream # 正规客户端自动带上;curl 直连需手写
```
**本端点不校验任何密钥**,MCP 连接里无需配置 token,它只提供读取能力。
客户端配置:
```json
{
"mcpServers": {
"awesome-index": {
"url": "{BASE_URL}/mcp"
}
}
}
```
一句话让 Agent 自己接入:
> 请把 URL 为 `{BASE_URL}/mcp` 的 MCP 服务器添加到你的客户端配置中,名称用 awesome-index,完成后告诉我现在可以调用哪些工具。
可用工具:
| tool | 参数 | 说明 |
|---|---|---|
| `search_entries` | `q`(必填), `limit`(1–50,默认 20) | 按关键字 / 类型 / 标签搜索。**查重先走它** |
| `get_entry` | `slug`(必填,也可传标题关键字自动匹配) | 取单条完整详情与元数据 |
| `random_entry` | — | 随机返回一条已上架内容,用于探索发现 |
| `list_tags` | — | 列出全部标签组、嵌套结构与收录数量 |
| `usage` | — | 返回完整接入说明(含写入接口与踩坑清单) |
结果格式:返回体在 `result.content[0].text` 里,是一段 **JSON 字符串,需要再解析一次**。
连接 `initialize` 后返回的 `instructions` 字段同样带有完整的接入与写入说明(AI 客户端通常会自动注入)。
### 写入部分:AI 录入接口
MCP 只读,不能写入。要让 Agent 把新内容录进本库,请使用 HTTP 接口:
```
POST {BASE_URL}/api/ingest/entry # 等价端点:POST {BASE_URL}/api/entries
Content-Type: application/json
```
鉴权请求头(**不要**把 key 放进 URL query):
| 方式 | 示例 |
|---|---|
| `X-Ingest-Key`(推荐) | `X-Ingest-Key: <key>` |
| 标准 Bearer(等价) | `Authorization: Bearer <key>` |
请求体字段:`title`(必填) / `url`(必填,合法 URL,用于去重) / `type`(必填,枚举:微服务 / SaaS / 网站 / 工具 / 应用 / 脚本 / 插件) / `summary`(≤200) / `description_md`(≤5000,Markdown) / `license` / `stars`(整数) / `tags`(字符串数组,自动建标签) / `status`。
> `slug` 不是合法字段,传了会被静默丢弃(服务端按标题自动生成)。
```bash
curl -X POST "{BASE_URL}/api/ingest/entry" \
-H "X-Ingest-Key: <key>" \
-H "Content-Type: application/json" \
-d '{"title":"MinerU","url":"https://github.com/opendatalab/MinerU","type":"工具","tags":["Python","OCR"]}'
```
返回:创建成功 `201 {"ok":true,"data":{"created":true,"id":<n>,"status":"pending"}}`;URL 已存在时 `200 {"created":false,"id":<n>}`(自动去重);鉴权失败 `403 invalid_key`。
### 五个必记的坑
1. **推荐 `X-Ingest-Key` 请求头**(等价 `Authorization: Bearer`);自创的 `X-API-Key`、`?key=` 一律 403。
2. **MCP 免密钥 ≠ 密钥有效**。`/mcp` 根本不查 key,别拿探测 MCP 来验证 ingest key。
3. **提交后默认 `pending`**,前台搜不到是正常的,等管理员审核转 `active`。**不要因为搜不到就重复提交。**
4. **同一 URL 重复提交返回 200 `created:false`**,这不是报错,说明已存在并被去重。
5. `slug` 不是字段,传了会被丢弃。
排错:`curl` 直连 `/mcp` 报 `406` 是缺 `Accept: application/json, text/event-stream`,正规客户端不受影响。
录入条目默认 `pending`(待审核),除非对应 AI 源开启了 direct_publish。
## 内容源(自动化收录)
三类来源汇聚到同一条目表:
| kind | 说明 | 新条目状态 |
|---|---|---|
| `human` | 管理台人工录入(常开) | active |
| `ai` | `POST /api/ingest/entry` + `X-Ingest-Key`(或 `Authorization: Bearer`)头 | pending |
| `feed` | 定时拉取外部站点(rss / html / eryajf-weekly 适配器),管理台可手动触发 | pending |
首个站点适配器:二丫讲梵学习周刊(wiki.eryajf.net)。运行记录见管理台「内容源 → 运行记录」。
## 技术栈
Node.js 22 (ESM) · Express 5 · EJS · DuckDB (`@duckdb/node-api`) · zod · express-session · @modelcontextprotocol/sdk · node-cron · cheerio