14 KiB
FNA_V3 独立文章 API
状态:2026-10-27本地实施并联调;2026-10-29已随独立test预览提交、推送和部署,10篇教程真实API迁移通过后,test编辑接口已关闭且临时密钥移除。正式站现已切换,正式10篇教程亦通过同一API迁移;生产临时密钥用后删除,编辑接口默认关闭,后续明确写作/发布任务再按绑定环境启用并完成后关闭。test执行和回执沿发布记录,日常本地调用不受影响。用户明确采用本站独立接收 API,不经过 ATOM;不新增 ATOM 依赖。入口为 http://fna-v3.loc/api/editorial/v1,生产地址尚未指定。
职责与数据
AI负责选题、正文、图解、官方资料核对与自然内链;本站负责保存草稿、生成实际模板预览、按冻结版本发布、记录结果和回退。文章目录和关联登记仍以写作索引为准;API不自动改写该Markdown,也不自动创造反向链接。将相关旧文的修改显式放进同一批次,预览后原子发布。
项目正文源保留可编辑稿;editorial_drafts保存收到并渲染后的冻结版本,发布读取该快照,不临时重新读取文件。articles为公开显示数据,草稿不写入它。editorial_documents按稳定content_key绑定本站文章;editorial_versions保留已发布版本和首次接管旧文的基线版本0;editorial_publications保存独立发布回执及后续处理状态。图片元信息在editorial_assets。
新API不调用旧接收器,不发送旧Telegram通知、IndexNow提交或ATOM请求。旧资源接收接口继续沿用原流程,不在本次改造范围;普通编辑API拒绝免费节点与小火箭ID两个自动资源栏目。旧接口/人工直接编辑同一文章会造成草稿基线变化,新API发布时返回409,不能静默覆盖并行修改。
凭据与环境
配置:config/editorial.php。
- 本地默认启用,但必须先有有效凭据。生产默认关闭,需部署时明确设置
EDITORIAL_API_ENABLED、EDITORIAL_BASE_URL和独立搜索索引;本次没有生产凭据或上线操作。 - 本地安装命令
php artisan editorial:setup仅允许本机fna_v3,已存在凭据不覆盖。凭据在storage/app/private/editorial/credential.json(目录700、文件600,Git忽略),结构使用gemdocs.credential.v1及fields.api_key,绑定项目、环境和base_url。程序在内存中读取,禁止打印、复制进正文、提交Git或放到命令参数。 - 认证为
Authorization: Bearer <专用密钥>。应用提供下述CLI代为读取和发送,不需要AI将密钥带入工具输出。 - 所有编辑接口拒绝整页缓存;预览和私有图片使用30分钟签名地址,返回
noindex, nofollow、private, no-store。持有签名链接的人在有效期内可预览,链接不应公开转载;失效后通过查询草稿重新取得链接。 - 发布接口按分钟限流;API错误不输出SQL、凭据或请求头。生产认证、HTTPS与访问路线仍按项目部署约束核实,不能因代码已存在就认为生产已可调用。
调用方式
以下命令调用当前环境绑定的API,path相对于/api/editorial/v1/,输出JSON结构为http_status与data。
php artisan editorial:request GET catalog
php artisan editorial:request GET source-articles/362
php artisan editorial:request POST assets --image=/绝对路径/操作图.png
php artisan editorial:request POST drafts --payload=/绝对路径/draft.json
php artisan editorial:request GET drafts/草稿UUID
php artisan editorial:request POST drafts/草稿UUID/publish --payload=/绝对路径/publish.json
php artisan editorial:request GET publications/发布请求UUID
示例中的中文路径和UUID均需替换。请求正文放文件,不把多行正文或密钥拼接进shell。CLI关闭HTTP代理和重定向,本地模式拒绝非本地目标;外部环境的调用仍需既有访问授权。
1 保存草稿
POST /drafts:
{
"request_id": "29e2f78a-7adc-4bf6-9eef-1c5f4a586b13",
"articles": [
{
"content_key": "verge-windows-start",
"expected_revision": 0,
"adopt_article_id": 362,
"slug": "clash-verge-rev-windows",
"title": "Clash Verge Rev 使用教程:从安装到第一次连接(Windows)",
"summary": "下载安装、导入订阅、选择节点和开启系统代理。",
"category_slug": "windows",
"format": "markdown",
"body": "<h2 id=\"install\">下载与安装</h2>\n\n此处为实际正文。",
"cover": null,
"show_cover": false
}
]
}
这是结构示例,不可拿占位正文覆盖现有教程。完整正文应来自项目源文件或已核对的接收端原文。
request_id为本次保存动作的新UUID;同UUID同正文重试返回同草稿,不递增版本;同UUID改正文返回409。每批最多10篇,单篇正文最多500000字符。content_key为写作索引中的稳定键。首次为0,后续expected_revision必须等于GET /articles/{key}返回的latest_revision,成功后递增。新草稿会使同文章的旧草稿失去发布资格,但不会改变线上已有正文。- 新文章省略
adopt_article_id。接管现有文章必须显式指定准确ID并沿用原slug;不因标题相似自动绑定。首次接管仅建立映射和旧版快照,不改公开正文。不能把已有键转绑另一篇文章,也不能改已绑定文章URL。 category_slug必须为本站已启用的编辑栏目。tag_ids可选,必须是已有标签ID;省略时保留旧文标签,新文默认为空,不自动创建标签。format为markdown(默认)或html。Markdown支持基础HTML图解,但过滤危险链接、脚本等;富文本不接受任意脚本、事件属性或内联样式。段落锚点使用显式id。cover支持已存在的本站/images/...路径,或上传后的asset:SHA256;显式null可清除旧封面,省略时保留。show_cover控制正文头图,省略时保留旧值,新文默认不展示头图。- 站内文章链接为
/a/slug.html#anchor。本站完整域名链接不作为站内链接接受;引用公共官方资料可用外部HTTPS链接。文章目标必须已发布或在同批草稿内,锚点必须存在。分类链接校验真实父子关系,避免宽松路由把错误URL也返回200。
返回draft_id、hash、status及每篇文章的版本、预期路径和preview_url。查询草稿会生成新的短期预览链接;草稿内容不变。预览复用本站文章模板,关闭统计、点赞和热门列表;同批次文章之间的链接改为签名预览,避免跳到不存在的正式页。
新文章点赞设置
2026-10-29起,创建新文时支持可选like_settings,例如:
"like_settings": {"seven_day": 12, "yearly": 50, "one_year": 200}
省略时采用AI写作规范的默认参数,在草稿保存时随机取值并冻结;草稿响应articles[].like_settings返回确认值。旧文改稿、接管及内容回退保留原点赞参数/进度,普通改稿显式传入此对象返回422;0可在新建时关闭对应项。旧冻结草稿不追加新默认值。
发布后鉴权GET source-articles/{id}的like_growth可核对剩余额度、持续年度参数及一次性年度目标、已支付量和开始时间。年度额度按发布时间计时,累计增加该额度后停止,与真实点赞和持续年度随机增长独立。迁移、调度、字段范围与回退见文章自动点赞维护;先执行指定新增迁移,再使用新代码。
2 图片
POST /assets使用multipart的image字段。支持PNG/JPEG/WebP/GIF,最多8MB,并限制宽高和像素数;不接收SVG/HTML上传,不主动抓取远端图片URL。返回SHA256、尺寸和asset:SHA256引用:

原图先在私有存储,不生成公开地址。签名预览通过临时图片路由读取;正式发布时校验哈希并生成本站/images/editorial/SHA256.ext地址,正文替换为此路径。上传文件无同名覆盖问题;失败批次可能留下已准备但未引用的内容寻址图片,不自动删除可能仍被其他版本使用的素材。
3 发布确认过的版本
POST /drafts/{draft_id}/publish:
{
"request_id": "0cf94c73-bafb-4a6c-9cef-39d72e5bc24e",
"expected_hash": "替换成保存草稿返回的64位hash"
}
发布UUID与草稿UUID分开。确认所看版本后使用它的hash;不要重建另一份正文来发布。发布前再次检查最新版本、现有文章基线、栏目/标签、图片、目标链接及受影响旧文的入向锚点。批次中任一篇冲突或失效,整批文章与版本/回执事务回滚。
成功后按稳定映射创建/更新文章,保留已有URL、创建时间、计数、置顶和身份。批次里的所有正文修改同时提交;冻结发布回执与内容写入在同一数据库事务中。重复提交同一发布UUID返回原回执;同UUID换目标/版本返回409。同一草稿换一个发布UUID重试也只返回已有回执,不重复创建文章。
响应包含:
status: published:本次内容已写入本站公开文章表;这是所调用环境的状态,本地成功不代表生产成功。articles:各文章的content_key、article_id、revision和URL。effects.cache/search/sitemap:各后续处理的独立结果。搜索暂时失败不撤销已提交正文,返回pending,不能重发正文来弥补搜索失败。
后续处理为刷新本站响应缓存与热门数据缓存、同步本站搜索,以及使用数据库驱动的sitemap。缓存未刷新时sitemap也标记pending。不调用搜索引擎主动提交。
4 查询、重试与回退
| 方法与路径 | 作用 |
|---|---|
GET /catalog |
当前可用编辑栏目与文章元信息,含已接管键和版本 |
GET /source-articles/{id} |
接管旧文前读取实际HTML、封面、标签、栏目与管理状态 |
GET /articles/{key} |
最新草稿版本、已发布版本、稳定ID/路径、已发布历史列表 |
GET /articles/{key}/versions/{revision} |
读取某个已发布版本的冻结内容;旧文接管基线为0 |
GET /drafts/{id} |
查询保存结果,刷新预览地址 |
GET /publications/{id} |
查询发布UUID的原回执和当前后续处理状态 |
POST /publications/{id}/synchronize |
只重试未完成的缓存/搜索处理,不重写文章;搜索读取当前公开版本,避免旧重试覆盖新索引 |
POST /articles/{key}/rollback |
从指定历史版本建立新草稿,供预览后另行发布 |
回退请求同样包含新request_id,并给出当前expected_revision和历史target_revision。它不会马上覆盖当前文章;返回新草稿后,沿同一预览/发布步骤恢复,版本继续递增、URL不变。若旧版锚点不能满足现有入向链接,需要将关联文的修正一起组批,不能强制制造断链。
HTTP401认证失败,403签名无效/过期,404对象不存在,409幂等/版本/所有权冲突,422格式或链接不满足条件,503功能关闭或凭据绑定无效。网络结果未知时,先按原UUID查询,不盲目生成新UUID重发。
搜索隔离
Articles::searchableAs()优先使用editorial.search_index。本地为独立fna_v3_articles,已把169篇现有公开文章初始化到新索引,未改原继承的articles索引。正常站内搜索和新API写入使用同一索引。editorial:reindex用于初始化/补全;后续每次发布只更新本批当前文章。
本地仅允许回环Meilisearch和fna_v3_前缀。生产必须明确专属索引及服务地址,不能沿用未知共享索引。集合/数据库搜索直接读取当前文章;未支持或未配置的驱动返回pending。Meilisearch任务等待成功后才报告done。
安装、验收与恢复
追加迁移:database/migrations/2026_10_27_190000_create_editorial_tables.php。执行时只指定此迁移,不使用migrate:fresh或批量重置现有数据库。后续代码部署遵守Git发布流程;本次本地安装不授权生产部署。
php artisan migrate --path=database/migrations/2026_10_27_190000_create_editorial_tables.php --force
php artisan editorial:setup
php artisan editorial:reindex
本地已完成:
- SQLite内存隔离功能测试:认证/环境绑定、缓存隔离、草稿私有、签名到期、幂等、版本冲突、原子发布、显式接管、并行修改保护、入向锚点、图片和代码换行、回退与搜索重试;结果见
output/editorial-api/tests.xml。 - 真实本地HTTP:无认证401、图片上传与草稿预览、两文章互链整批发布、同UUID重试、新版、回退、正式HTTP200、真实站内搜索和sitemap;见
output/editorial-api/http-verification.json。 - 1360/390预览截图:签名图片、同批跳转、无点赞、noindex、无横向溢出;浏览器只允许本地来源,未发线上请求。见
output/editorial-api/browser-verification.json和同目录PNG。 - 临时文章2篇及本次测试版本/回执/图片已清理,原169篇文章完整行哈希一致。安装验收结束时接收表为空,后续正常稿件会保留版本和回执;凭据留在私有存储。
恢复时先关闭EDITORIAL_API_ENABLED,保留5张接收表、版本和回执及图片。已发布正文仍在articles可正常显示;撤销某次文章更新优先走历史版本回退。代码回退不得顺带drop表或清理可能被正式文章引用的图片。若撤回本地搜索切换,应在核对原索引后调整EDITORIAL_SEARCH_INDEX与模型配置,不删除未知共享索引。