[开发]market_hub 插件 · 实施计划、功能扩展与 P0–P3 验收报告

👑Lv.11 元老 🌞 骨干会员
2026-10-26 00:18:15

本文由 FlintHub 开发文档归档发布。原始文档日期见标题前缀,来源:合并篇(见正文内 merged_from 列表)。

market_hub 插件 · 实施计划、功能扩展与 P0–P3 验收报告

本篇由 3 篇原始文档合并去重而成:实施计划 + 功能扩展方案 + P0–P3 验收报告。

对象 plugins/market_hub(v1.2.1),全部改动在插件目录内闭环,未动核心。

一、插件定位

market_hub 是 FlintHub 的跨站插件商店(Hub 侧),负责把社区里的插件集中收录、展示、投稿与审核上架:

  • 前台:/plughub 列表页、/plughub/{name} 详情页、/plughub/submit 投稿页、/plughub/shot/{id} 预览图取图。
  • 后台 /admin/market-hub:原 6 个 Tab(queue / listed / off / tokens / stats / settings,页内自建导航),验收后新增 developers、shots。
  • 数据落库 data/market/market.sqlite;公开清单 release/plugins/index.json 由 AdminController::rebuild() 重建。

与其他插件(adslot / notice_center 等)的关系:它们是被收录、被上架的「商品」,market_hub 是「货架」。market_hub 自身不提供广告、公告等业务能力,只做插件的目录、审核、认证与讨论。清单层 HubCatalog::entries() 读各插件的 manifest,meta.author 等字段是快照(上架时取 username($uid),非外键)。

二、实施计划要点

2.1 五条不变原则

#原则保证方式
1不动核心,插件目录内闭环唯一例外是 mh_submissions 加列(走插件自己的 ensureColumns())
2UGC 不存 manifest预览图 / 留言 / 开发者档案全部独立表,清单层只做合并读取
3不新增 XSS 出口留言正文纯文本 → htmlspecialchars();不调 Content::decode()
4i18n 三语同步基线各 138 键(验收时已到 237 键);验收 = 键集合零差异 + 键序一致
5CSS 只用真实存在的 --mn-*--mn-danger / --mn-radius-* 不存在,禁用

2.2 分期总览

期内容新增表独立出包
P0文件树—✅
P1预览图(详情页管理 + 投稿上传)mh_screenshots✅
P2插件留言板mh_comments✅
P3管理员代绑(开发者认证)mh_developers✅

每期结束 → 出验证报告 → 确认 → 再进下一期。

2.3 数据表(全部在 data/market/market.sqlite)

CREATE TABLE IF NOT EXISTS mh_screenshots (
    id         INTEGER PRIMARY KEY AUTOINCREMENT,
    plugin     TEXT    NOT NULL DEFAULT '',
    rel_path   TEXT    NOT NULL DEFAULT '',   -- 裸相对路径
    sort_order INTEGER NOT NULL DEFAULT 0,
    added_by   INTEGER NOT NULL DEFAULT 0,
    created_at INTEGER NOT NULL DEFAULT 0
);
CREATE INDEX IF NOT EXISTS idx_mhs_plugin ON mh_screenshots (plugin, sort_order);

CREATE TABLE IF NOT EXISTS mh_comments (
    id         INTEGER PRIMARY KEY AUTOINCREMENT,
    plugin     TEXT    NOT NULL DEFAULT '',
    uid        INTEGER NOT NULL DEFAULT 0,
    body       TEXT    NOT NULL DEFAULT '',     -- 纯文本,≤ 500 字
    reply_to   INTEGER NOT NULL DEFAULT 0,      -- 引用的留言 id(0 = 不引用)
    reply_name TEXT    NOT NULL DEFAULT '',     -- 引用时的对方名快照
    status     INTEGER NOT NULL DEFAULT 0,      -- 0 正常 / 1 已删除(软删除)
    created_at INTEGER NOT NULL DEFAULT 0,
    deleted_at INTEGER NOT NULL DEFAULT 0,
    deleted_by INTEGER NOT NULL DEFAULT 0
);
CREATE INDEX IF NOT EXISTS idx_mhc_plugin ON mh_comments (plugin, id);
CREATE INDEX IF NOT EXISTS idx_mhc_uid ON mh_comments (uid, created_at);

CREATE TABLE IF NOT EXISTS mh_developers (
    id          INTEGER PRIMARY KEY AUTOINCREMENT,
    author_key  TEXT    NOT NULL UNIQUE,      -- manifest 的 meta.author 原文
    uid         INTEGER NOT NULL DEFAULT 0,   -- 绑定到的用户(0 = 未绑)
    verified    INTEGER NOT NULL DEFAULT 0,   -- 0 未认证 / 1 已认证
    title       TEXT    NOT NULL DEFAULT '',  -- 认证称号
    intro       TEXT    NOT NULL DEFAULT '',  -- 简介
    verified_at INTEGER NOT NULL DEFAULT 0,
    verified_by INTEGER NOT NULL DEFAULT 0,
    created_at  INTEGER NOT NULL DEFAULT 0
);
CREATE INDEX IF NOT EXISTS idx_mhdv_uid ON mh_developers (uid);

  • mh_submissions 加一列 shots(TEXT DEFAULT '',JSON 数组):投稿携带的预览图路径,上架时搬到 mh_screenshots。
  • 验收版实际落库 MarketDb::SCHEMA_VERSION = 2,库共 11 张表。
  • 建表纪律:CREATE TABLE 在前 → 索引 DDL 在后 → 补列走 ensureColumns();SQLite 无 ADD COLUMN IF NOT EXISTS,靠 PRAGMA table_info 判定;一律走 MarketDb::pdo()(内部 DBFactory),禁裸 PDO(WAL 旧快照坑);改完记得手删 protected/.market_hub_schema*.ok 戳文件(验收版已改为带版本戳名,不再需要人工清)。

2.4 目录结构与关键文件

plugins/market_hub/
├── FrontController.php / AdminController.php     # 前台 / 后台
├── MarketDb.php / HubCatalog.php / Plugin.php    # 存储 / 清单 / 常量(SUB_SHOTS)
├── views/front/{detail,list,submit}.php
│   └── _file_tree.php / _shots.php / _comments.php   # 新增片段
├── views/admin/index.php                        # queue/listed/.../developers/shots Tab
├── assets/style.css / admin.css / front.js
├── hook/route_register.php / admin_route_register.php
│   hook/init_after.php / layout_head_end.php
└── lang/{zh,en,zh_tw}.php

2.5 核心流程

  • 投稿:submitPost() 最开头做 CONTENT_LENGTH vs post_max_size 预检(否则包过大被 PHP 静默整包丢弃、$_POST/$_FILES 全空,误报 err=bad_name「插件名非法」);多文件 $_FILES['shots'] 是转置结构(name[]/tmp_name[]/size[])必须逐索引重组,不能当单文件用(否则静默只处理第一张);上限 5 张、单张 ≤2M,成功者写入 mh_submissions.shots(json_encode)。
  • 上架:AdminController::review() approve 时读 $sub['shots'] 逐条 INSERT INTO mh_screenshots;验收版改为仅当投稿带 shots 才 replaceAll()(否则不带图的新版本上架会清掉管理员手工维护的图)。
  • 文件树:FrontController::buildFileTree(array $files): array 按 / 切分 path(数据源 $manifest['files'],每项 {path, sha256, size})建嵌套树;目录默认折叠、顶层展开,每目录显示「N 个文件 · 合计 X KB」;单目录超 50 条折叠;末节点按扩展名给图标(.php→code、.css/.js→code、图片→image、.md/.txt→text、.json→code,其他→file);递归深度兜底;path 仅 $this->e() 输出,零 XSS 面。
  • 详情页管理态判定:\app\Helpers\Auth::isAdmin()(role==='admin' 且 group_id===4,AND 非 OR)。

2.6 路由与钩子

  • 前台(hook/route_register.php):POST /plughub/{name}/shots(增/删/排序)、POST /plughub/{name}/comment(发表)、POST /plughub/{name}/comment/{id}/delete(软删)。

⚠️ 必须注册在通配 GET /plughub/{name} 之前(与 /plughub/submit 同一个坑,route_register.php:26-29 有先例);前缀绝不能用 /plugins(站点根有同名真实目录 → 301 → 403 且丢 query)。

  • 后台(hook/admin_route_register.php,不带 /admin 前缀):POST /market-hub/dev-save、/market-hub/dev-verify、/market-hub/dev-sync(P3),POST /market-hub/shots-purge(补充)。

⚠️ 多 Tab 后台必须页内自建导航(核心后台卡片只认单个 admin_url),Tab 用核心 .admin-tabs。

  • hook/init_after.php:建表守卫,戳名带版本 protected/.market_hub_schema_v{SCHEMA_VERSION}.ok。
  • hook/layout_head_end.php:注入 front.js(defer + filemtime 破缓存)。
  • 所有写动作必带 Csrf::verifyOrDie();PRG 回跳($this->back('developers', 'msg', ...))。
  • 后台保存类表单禁用 (int)($_POST[$k] ?? 0)(字段缺失会静默写最小值 → 302 成功但库里没变),用 array_key_exists() 判断。

2.7 环境硬约束(本机实测)

项值
upload_max_filesize2M
post_max_size8M
max_file_uploads20 ✅
Plugin::maxUploadBytes()(包体上限)5120 KB ≈ 5M

⇒ 包体 5M + 5 张图(单张最多 2M)= 最多 15M > post_max_size 8M。三条措施:①服务端 CONTENT_LENGTH 前置检测(必做,新增错误文案 e_too_large_total 三语);②表单前端累加 file.size 校验;③生产宝塔把 post_max_size 调 16M、upload_max_filesize 调 4M(验收时确认环境为 20M/50M,未改任何 PHP 配置)。

2.8 关键接口(实施时直接照用)

接口位置说明
Upload::file($file, $allowed, $opts)Upload.php:446$opts['namespace']/$opts['thumb'];自带白名单 + finfo MIME 实测
Upload::url($rel) / Upload::thumbUrl($rel,'md_')Upload.php:50 / :352原图 / 缩略 URL,禁拼 UPLOAD_URL
Upload::delete($rel)Upload.php:255连派生缩略图一起删,禁自己 unlink 原图
RateLimiter::check($action,$max,$win)RateLimiter.php:225true = 允许,判断前必须有 !
Auth::isAdmin()Auth.php:20role==='admin' 且 group_id===4
User::batchGetNames([$uid])Models/User.php→ [uid => name] 防 N+1
HubCatalog::entries()HubCatalog.php:76清单条目(含 author / author_uid)
MarketDb::ensure() / ensureColumns()MarketDb.php:53 / :190建表 / 补列(幂等)
$this->include('_components/image_lightbox')TemplateCompiler.php:284插件视图可 include 核心组件(回落 app/Views/)
$this->pagination($page,$pages,$url)核心分页($pages<=1 返回空串)

三、功能扩展方案(调研版结论与去向)

3.1 决定一切的那条发现

manifest 的 meta 是「每次打包重建」的,UGC 存进去必丢。

证据链:cli/release_build.php:1253-1272 —— --type=plugin 打包时 meta 完全由 plugin.json 重建,字段固定 8 个(title/author/description/category/icon/admin_url/min_core/tag),没有 screenshots / author_uid / changelog;实测 55 个 manifest,author_uid、screenshots 有值数均为 0。反证:daily_checkin 走过 Hub 投稿上架(AdminController.php:127 确实写了 author_uid=1),但它的 manifest 现在 author_uid 也是空——被后来的官方重打包冲掉了。

⇒ 预览图、认证、留言、开发请求,一律不得只存 manifest,必须独立表/独立文件,再由清单层合并输出。

3.2 现状盘点(带证据)

  • 文件罗列 views/front/detail.php:82-92:平铺、硬上限 60 条超出折叠成 +N,数据源 $manifest['files']({path, sha256, size},已实测)。
  • 预览图「管道铺了一半」:HubCatalog.php:253,256 清单层已在读 author_uid / screenshots,但 Hub 上架器(:640-652,meta 白名单里没有)与官方打包器都不写、详情页全文无引用、mh_submissions 无该列(MarketDb.php:102-124)。
  • 灯箱零成本复用(已核契约):入口 <a data-action="view-image"> + <img data-fullurl>(lightbox.js:317,缺一点不开);lightbox.js 全页收集 [data-fullurl];组件与脚本在插件视图里必须自带(只在 thread/show.php / blog/detail.php 全局加载),禁进 htmx 片段;CSP(Controller.php:80)img-src 'self' data: https: 放行站内图。
  • 评论:论坛 /forum/category/6(「反馈修复」)已有 30 帖,标题惯例 [BUG提交]/[优化提交];topic_index 无 tag 列 → 按插件聚合需跨库两段查。
  • 开发者当前没有实体:meta.author 是自由文本(55 个 manifest 实测分布:FlintHub 36 / SoSite 16 / 读到书院 1 / 读到 1 / vncom 1),author_uid 有值 0/55;users 表无任何认证/开发者字段;无 /user/{id} 路由(只有 /profile)。
  • 后台 6 Tab 与页内自建导航:views/admin/index.php:92-98。

3.3 调研版 → 定稿的差异(以实施计划为准)

项调研版定稿
评论方案 C:复制模板 + 跳 /post/new?category_id=6 + 详情页只读展示反馈帖自建「插件留言板」(独立存储、一层引用、不做楼中楼)
认证表 + 后台 + L1/L2 标签,L3 全站需改核心只做后台「管理员代绑」;仅 L1+L2 两处标签;别名归并不做
预览图仅详情页管理增加「投稿时一起上传」,审核上架后自动关联
分期P0 文件树 → P1 预览图 → P2 评论(方案C) → P3 认证 → P4 开发者主页P0 → P1 → P2 留言板 → P3 代绑,每期做完停、报验收、再进下一期
不做—开发请求、开发者主页、前台认领、全站标签、评论走论坛

调研版的「预览图落盘推荐走核心 Upload::file()(选项 A)」在实施阶段被指令取代:验收版改为自建路由 ShotImage 落盘(data/market/shots/<name>/)、不做缩略图、落盘统一尺寸。「少 1 张图」按软约束处理(0 张显示占位 + 管理员提示,不阻断上架——存量 55 个插件当时全是 0 张,硬卡会立刻全部不合规)。

四、P0–P3 验收报告

总体结论:全绿。P0 文件树 → P1 预览图 → P2 留言板 → P3 管理员代绑一次性做完,全部通过真实 HTTP 端到端验证。静态校验 0 失败;首轮冒烟 62 PASS / 0 FAIL;生产零触碰(protected/error.log 15 → 15 行零新增、库表零残留)。改动文件:新建 7 + 修改 13,MarketDb::SCHEMA_VERSION = 2(3 表 4 索引 + mh_submissions.shots 列)。

4.1 静态校验(全绿)

项工具结果
PHP 语法php -l 全量31 → 32 个文件 / 0 失败
全角标点紧跟变量php_var_cjk_check.phpOK(无「变量名含非 ASCII 字节」)
i18n 一致性fh_i18n_check.php55 PASS / 0 FAIL
三语逐键对齐独立脚本各 212 → 214 → 215 → 236 → 237 键,键集合差异 0、键序一致,=> 全第 48 列

4.2 P0 文件树

  • 目标:替换 60 条硬上限平铺文件区为可折叠树。
  • 实现:FrontController 新增私有方法 buildFileTree(array $files): array,detail() 传入 tree;新增 views/front/_file_tree.php(递归渲染,最大深度保护);assets/style.css 新增 .mh-tree*;三语新增文件数/合计大小/展开折叠键。
  • 验收结果:mh-tree✓ mh-tree-total✓,旧 mh-filelist 已清除✓;游客页无未解析 i18n 键名、无 PHP 错误;300+ 文件大插件页面不卡不超时;php -l 全绿。

4.3 P1 预览图

  • 目标:1~5 张、管理员详情页内联管理(增删 + 拖拽排序)+ 投稿上传 + 灯箱查看。
  • 实现(新建):ShotImage.php(14309 B,六道闸门校验 + finfo MIME 实测 + 缩放居中)、ShotRepo.php(8737 B,listOf/countOf/find/add/remove/reorder/reorder/replaceAll/renderList/urlOf)、views/front/_shots.php(5545 B);Plugin 新增 SUB_SHOTS='shots' 常量(刻意放 data/market/ 而非插件目录,避免卸载带走内容数据);assets/front.js 拖拽 dragend 即提交隐藏表单(不留「保存」按钮);路由 POST /plughub/{name}/shots + GET /plughub/shot/{id};灯箱契约 data-fullurl + view-image 齐。
  • 投稿链路:views/front/submit.php 加 name="shots[]" multiple(保持 enctype="multipart/form-data");submitPost() 先 CONTENT_LENGTH 预检,多文件经 ShotImage::normalizeFiles() 逐索引重组逐张落盘;额度按「已成功张数」推进(某张失败不占额度),库行失败回删文件防孤儿。
  • 验收结果(保留实测数字):上传 302 → 库行生成 → 落盘实测 400×300(1165 B PNG) → GET /plughub/shot/{id} 200 + image/png + nosniff + Cache-Control: public → 删除 302 → 库行回 0 → 取图 404。后续三轮迭代均全绿:
  • 多选上传(shots[] + multiple):43 PASS / 0 FAIL——一次 3 张 n=3&lost=0、sort_order 连续 0/1/2;额度截断 n=2&lost=1(超额没落盘);混选(1 合法 + 1 假 .png)只落 1 行 1 文件无孤儿。
  • 裁切 → 完整缩放 + 透明留边(contain):scale 由 max() 改 min(),新增 needsPad(),留边 + jpg 源改判 png;探针自带反证(源图描红边,落盘后 bbox 四角必须仍是红):34 PASS / 0 FAIL + 真实上传冒烟 29 PASS / 0 FAIL。
  • 400×300 → 800×600,留边图 PNG → WebP(站长反馈「图片挺模糊」,诊断:灯箱原像素显示 + 缩放上限 6 倍 + 高分屏):体积实测 PNG 791 KB vs WebP 96 KB;探针 37 PASS / 0 FAIL + 上传冒烟 29 PASS / 0 FAIL(Content-Type: image/webp、bbox 800×450、留白 alpha=127)。
  • ⚠️ 已落盘的旧裁切图不会被修复(原图无留底),只能删旧重传。

4.4 P2 留言板(后更名「讨论反馈」)

  • 目标:独立存储、一层引用、纯文本、登录可发、限流、管理员可删。
  • 实现(新建):CommentRepo.php(9815 B,软删除 + reply_to 一层引用——目标若本身是回复则拉平到同一条主留言 + 墓碑判定 + 批量取用户名防 N+1 + quotedMap()/snippet());views/front/_comments.php(5405 B,引用回复条 + 墓碑 + 系统分页);front.js 回复按钮回填表单、删除 data-confirm 二次确认。
  • 关键规则:requireLogin() 才能留言;RateLimiter::check('mh_comment', 5, 60)(true = 允许,写反会恒 429);正文 mb_substr(trim(...), 0, 500) + htmlspecialchars(ENT_QUOTES),不调 Content::decode();管理员走软删(status=1),删除动作不得改动引用方的 reply_to/reply_name,被引留言删除后引用行显示「(已删除)」;10 条/页。
  • 通知联动(第二轮修正):顶层讨论 → 插件作者(mh_developers.uid),回复 → 被回复者,自己给自己不发;复用核心 Notification::TYPE_REPLY(自造 type 会落通用问号图标,补图标要改核心);related_type=market_hub + #cmt-{id} 深链;标题/摘要存原文不预转义(通知中心统一 $this->e())。
  • 验收结果:发表/引用回复/删除均 302;「回复 @某某」+ 被引正文截断 60 字(snippet():220 字 → 60 字 + …,多行多空格折叠);软删后墓碑显示且引用行未清空;通知三场景实收正确(uid1 发 → uid262 收 1 条、uid1 收 0 条);「留言板 → 讨论反馈」三语 14 处更名(键名 cmt_* 不动),212 → 214 键;本轮 50 PASS / 0 FAIL。

4.5 P3 管理员代绑(开发者认证)

  • 目标:把「自由文本作者名」实体化为开发者档案,后台绑定 uid + 认证 + 称号。
  • 实现(新建 DevRepo.php,9648 B):AdminController::TABS 加 developers,新增 devBind/devVerify/devSave/devSync;后台「开发者」Tab 用面板卡片式(每行 2 表单 + 2 按钮,表格列序易被核心样式压掉);首次进入自动补全——扫 HubCatalog::entries() 的 author 去重,缺失的补成 verified=0 行,幂等(ON CONFLICT(author_key) DO NOTHING);绑定输入 uid 或用户名,服务端校验存在;保存类表单用 array_key_exists() 防字段缺失静默写最小值。
  • 前台仅两处标签:详情页作者名旁(views/front/detail.php:61)、列表卡片作者名旁(list.php:92);认证时输出 <span class="mh-verified"> + $this->icon('check', 10) + 称号,底色 --mn-primary 白字;未认证不输出任何东西;不做全站标签(无作者名钩子,需改核心)。
  • 第四批增强(一人多作者绑定):DevRepo::bind() 去掉 uid_taken 唯一性约束——manifest meta.author 是自由文本,同一个人可能署名不同(「FlintHub」与「读到书院」);新增 authorCountByUid() 出「共 N 个作者名」徽标;解绑仍是行**粒度;下游 uidForAuthor()` 按作者名查 uid → 该用户在每个作者名对应的插件上都能收到讨论通知。
  • 验收结果:Tab 入口✓ 4 端点✓ 开发者面板 5 个;把 SoSite(uid=0)绑到已绑 FlintHub 的 uid=1 → msg=dev_bound 成功、不再返回 dev_uid_taken;uidForAuthor('SoSite')===1 且原绑定未被顶掉;不存在的用户 → err=dev_no_user 且未误写 uid;mh_developers 逐行逐列还原(5 行);33 PASS / 0 FAIL。环境事实:FlintHub 已被站长绑到 uid=1(本人)且已认证——站长在自己插件下发讨论不会收到通知(自己给自己不发)。

4.6 顺手修掉的缺陷与补丁

  • 建表守卫戳文件名写死(本轮唯一新增代码改动,静默缺陷):hook/init_after.php 原用固定名 protected/.market_hub_schema.ok 且只判 is_file()、不看 SCHEMA_VERSION → 老站覆盖上传新版插件目录(该路径不触发 activate(),正是该钩子存在的理由)→ MarketDb::ensure() 被跳过 → 3 张新表与 shots 列永不创建 → P1/P2/P3 全部 500,且 error.log 干净。修法:戳名带版本 protected/.market_hub_schema_v2.ok,版本号一加戳名即变、自动补建,不再需要人工清戳。验证:删新旧两个戳 → 一次 GET /plughub → 只生成 v2 戳、HTTP 200、11 张表齐。
  • 「重建公开清单」成功无提示:rebuild() 回跳 msg=rebuilt&n=<收录数>,但视图 $msgMap 没有 rebuilt 项 → 横幅整块不渲染(「点了没反应」)。补丁:$msgMap 加 'rebuilt' => 'plugin.market_hub.m_rebuilt'(三语同位插入 m_settings_saved 之后,236 → 237 键),新增 mh_rebuilt_smoke.sh 20 PASS / 0 FAIL(跟随 Location 跳转后断言「公开清单已重建,共收录 {n} 个插件」、release/plugins/index.json 按字节还原 sha256 未变)。同类但症状更轻的 rebuild_failed:<详情> 裸显未改。
  • 后台孤儿预览图清理(ShotAudit.php 新):三类独立——孤儿文件(磁盘有、白名单没有)unlink()、将变空的目录(rmdir(),逐个列出)、失效记录(DELETE)。★ 白名单必须含 mh_submissions.shots:投稿时上传的图立刻落盘、路径只写投稿行,等审核才搬进 mh_screenshots——若白名单只查后者,所有待审投稿的图都会被误判孤儿删掉。删除纪律:服务端重扫(不接受前端清单,防篡改 + TOCTOU)、删除前再断言路径在 shots 根内、不跟符号链接、跳过点开头条目。mh_p9_smoke.sh 57 PASS / 0 FAIL + CLI 探针(A/B 反证:把探针路径写进投稿行的 shots → 不再判孤儿,撤掉 → 立刻重新判孤儿)22 PASS / 0 FAIL。

4.7 与方案的偏差(择要)

post_max_size 未改配置(服务端预检 + 专用文案兜底);预览图自建 ShotImage 而非核心 Upload::file();单张上限 2M;留言用户可自删(原定只管理员删);分页 10 条/页;错误文案合并为 3 个语义键;开发者 Tab 用面板卡片式;replaceAll() 仅当投稿带 shots 才执行。

五、遗留与后续

#事项状态
1撤销/驳回投稿的预览图清理后台已做 ShotAudit 按需清理;按答复「先保留」,未做自动任务
2别名归并(flinthub / FlintHub 算两个档案行)未做(本期范围外)
3全站认证标签(需核心作者名钩子)未做;仅插件详情页 + 列表页两处
4开发请求 / 开发者主页(调研版 P4)本期不做
5出包P0~P3 未打包;protected/ 与 data/market/ 均不进包
6旧预览图兼容已落盘的 400×300 裁切旧图不会被修复,需删旧重传;aspect-ratio: 4/3 保证新旧混排一致
7rebuild_failed:<详情> 错误串裸显未改,待决定是否做「译文 + 详情」两段式
8生产 CDN 对 ?v=filemtime 静态资源的缓存待确认

探针/冒烟经验(易踩):curl -F "name=@路径" 的路径必须写 D:/...(MSYS 不转换);i18n 断言必须限定目标面板区域(window.FlintHubI18n 在 <head> 注入所有插件的键,全页 grep 必假 FAIL);「回到基线」断言必须在制造现场之前采基线;冒烟脚本注意 Windows \r 污染(pyc() { "$PY" -c "$1" | tr -d '\r'; })。

下一步:浏览器完整走查(详情页文件树 / 预览图灯箱 / 讨论引用与自删、投稿带 1~5 张图、后台开发者 Tab 绑定与认证)→ 确认后出 plugins/market_hub/ 单根 zip → 再决定是否处理清理任务与遗留项。

保留的回归套件(.workbuddy-ai/tmp/):mh_p9_probe.php(22 项)、mh_p9_smoke.sh(57 项)、mh_dev_smoke.sh(33 项)、mh_shot_contain_probe.php(37 项)、mh_shot_contain_smoke.sh(29 项)、mh_rebuilt_smoke.sh(20 项)、mh_sess_p9.php(会话夹具)。

轻量级、高性能、零 MySQL 依赖的PHP社区系统。
| 浏览 4 次 | 回复 0 次

全部回复 (0)

暂无回复

请 登录