# 好运豆部署说明

## 2026-09-24 双站点部署

好运豆现在有两个完全独立的数据站点：

| 站点 | 代码目录 | 数据库 | 用户会话 | 公共入口 |
| --- | --- | --- | --- | --- |
| `.com` | `/www/wwwroot/haoyundou.com` | `haoyundou.com` | `haoyundou_session` | `https://haoyundou.com/` |
| `.cn` | `/www/wwwroot/haoyundou.cn` | `haoyundou.cn` | `haoyundou_cn_session` | `https://haoyundou.cn/` |

两个数据库在结构和初始作品上同步，但注册用户、作品、浏览量、审核事件、后台设置和日志之后分别保存，不能跨库读取。顶部的“切换至 com/cn”按钮只切换站点首页或公共工具页，不转移登录状态、草稿、作品 ID 或数据库记录；作品详情切换后回到对应站点的豆社入口。

两个站点都使用服务端自动图片审核。审核服务基于 GitHub 开源的 [Hugging Face Transformers.js](https://github.com/huggingface/transformers.js)，本机加载 `AdamCodd/vit-base-nsfw-detector` 和 `onnx-community/vit-base-violence-detection-ONNX` 两个 Apache-2.0 模型。发布时服务端强制检查生成的完整拼豆图纸，并检查用户提供的原图和参考图；色情或暴力分数达到阈值时拦截，审核服务不可用或结果无效时拒绝发布并提示重试。正常作品直接公开，不进入人工待审队列。后台用于查看检测结果、拦截记录、作品状态、用户和系统配置，管理员仍可手动下架或恢复公开异常作品。

## 目录

站点根目录为 `/www/wwwroot/haoyundou.com`，由面板管理的 Nginx 直接提供静态文件。

| 路径 | 用途 |
| --- | --- |
| `index.html` | 好运豆首页和入口导航 |
| `community.html` | 豆社独立作品浏览页 |
| `convert.html` | 图转拼豆独立转换页 |
| `import.html` | 图纸导入独立入口页 |
| `editor.html` | 独立拼豆图纸工作台 |
| `work.html` | 单个作品分享与展示页 |
| `assets/editor.js` | `HaoyundouEditor` Web Component 及本地处理逻辑 |
| `assets/editor.css` | 工作台样式和移动端布局 |
| `assets/site.js` / `assets/site.css` | 首页交互和站点共用基础样式 |
| `assets/home.css` | 首页专属样式：四列功能入口、瀑布流、侧栏、响应式和 CSS 动效 |
| `assets/fonts/misans/home-navigation.css` | 首页导航专用 MiSans 字体映射，复用本地 WOFF2 和 Unicode 分片 |
| `assets/home-studio.png` / `scripts/render-home-art.php` | 基于现有公开图纸生成的首屏拼豆位图及 CLI 生成脚本 |
| `admin.html` / `assets/admin-panel.*` | 兼容旧链接并自动跳转到 `admin-port/`；完整权限管理使用独立端口服务 |
| `assets/moderation.js` | 基于开源 NSFWJS 的浏览器端图片初筛适配器 |
| `assets/vendor/` | 本地 TensorFlow.js、NSFWJS 运行时及其许可证 |
| `api/auth.php` | 注册、登录、退出和会话查询 |
| `api/works.php` | 豆社作品检索和提交审核 |
| `api/work-thumbnail.php` | 作品图纸到 PNG 缩略图的通用渲染函数 |
| `api/features.php` | 公开读取管理员配置的前端功能开关 |
| `api/home.php` | 首页分类顺序、展示数量和真实创作者榜单，只公开白名单设置 |
| `api/admin.php` | 管理员统计、用户和作品审核操作 |
| `api/moderation.php` | 保存客户端初筛事件，供服务端复核 |
| `api/moderation-client.php` / `api/session.php` | 服务端自动审核客户端和站点独立会话配置 |
| `database/001_editor_schema.sql` | 编辑器色板和草稿表迁移 |
| `database/002_platform_schema.sql` | 用户、作品、标签、评论、举报和审核事件表迁移 |
| `database/003_workbench_schema.sql` | 工作台设置、200×200 画布和作品设置迁移 |
| `database/004_admin_permissions.sql` | 管理端功能权限表和默认权限项迁移 |
| `database/005_showcase_works.sql` | 精选作品、作品浏览量和首页豆社示例数据迁移 |
| `database/006_admin_console.sql` | 管理端站点设置和系统日志表迁移 |
| `database/007_user_activity.sql` | 按天去重的登录用户活跃记录 |
| `database/008_homepage_settings.sql` | 首页展示数量和分类顺序的幂等配置迁移 |
| `database/009_homepage_visual_settings.sql` | 首页视觉版本和导航配色元数据迁移 |
| `database/010_homepage_navigation_tools.sql` | 导航和四列功能入口布局元数据迁移 |
| `database/011_auto_moderation.sql` | 自动审核模型和阈值设置迁移 |
| `database/012_independent_sites.sql` | 双站点域名、数据隔离和自动发布策略迁移 |
| `admin-port/lists.php` | 作品、用户、日志的服务端筛选、分页和缩略图 |
| `tests/editor-zoom.cjs` / `tests/admin-lists.php` | 滚轮缩放浏览器回归、数据库分页事务回归 |
| `tests/homepage.cjs` | 首页真实数据、布局、搜索筛选、移动导航、动效和失败重试回归 |
| `tests/home-auth.cjs` / `tests/work-thumbnail.php` | 登录异常、账号格式、会话竞争以及缩略图逐像素回归 |
| `tests/moderation.php` / `tests/independent-sites.php` | 强制完整图纸审核、跨站数据库和会话隔离回归 |
| `scripts/review-pending.php` | 自动重试历史待检测作品 |
| `admin-port/` | 独立 8081 管理端页面、权限 API 和启动脚本 |

### 当前首页发布状态

- `index.html` 当前引用 `assets/home.css?v=20260923-25` 及 `assets/fonts/misans/home-navigation.css?v=20260923-25`。导航统一使用本地 MiSans 无衬线中文字体：桌面 Logo 24px/600 字重，主导航 18px/500 字重，搜索与辅助操作 14px；当前页主导航为 600 字重和深绿。移动菜单 16px，600px 以下 Logo 20px。浅米白半透明导航、浅色描边登录按钮和深绿色注册按钮延续现有视觉。
- 四个入口固定为同一排四列等宽卡片：豆社、图转拼豆、图纸导入、作品创作分别保留原有链接。桌面卡片高 72px、圆角 14px，标题 15px；白色表面只在图标处使用浅绿、浅珊瑚、浅紫和浅橙黄辅助色。hover 上浮 3px、加深柔影、箭头右移 3px，过渡均为 0.2 秒。
- 桌面、平板和 320px 以上窄屏都保持四列。700px 以下隐藏入口说明和箭头，540px 以下仅将每个入口内部调整为图标在上、标题在下，标题横排 12px、卡片高 76px。Hero、豆社、页脚和业务功能保持原结构。
- `assets/home.css` 末尾的 `v25` 区块是导航与入口的最终规则，包含完整响应式、键盘焦点和减少动画设置。字体使用独立的 `MiSans Navigation` 别名，仅应用到首页导航。后文记录了早期设计，历史 2+2 错位排布和雾蓝导航已被本版本替代。

## 发布文件

前端为静态页面，不需要构建；账号、作品与管理接口需要 PHP 8.3 和 MySQL。更新文件后，确认 Nginx 配置仍指向上述根目录，然后访问：

```text
https://haoyundou.com/
https://haoyundou.com/editor.html
https://haoyundou.com/community.html
https://haoyundou.com/convert.html
https://haoyundou.com/import.html
https://haoyundou.com/work.html?id=作品ID
http://服务器地址:8081/
https://haoyundou.cn/
https://haoyundou.cn/editor.html
https://haoyundou.cn/community.html
https://haoyundou.cn/admin-port/
```

`.com` 管理端由 `haoyundou-admin.service` 独立监听 `8081` 端口，页面和 API 均在 `admin-port/`；`.cn` 使用自己的 `admin-port/` 页面和数据库，通过 HTTPS 入口访问，不与 `.com` 共用会话或数据看板。安装或迁移 `.com` 管理端后执行：

```bash
systemctl daemon-reload
systemctl enable --now haoyundou-admin.service
```

云服务器安全组或上游防火墙需要放行 TCP `8081`，外部访问地址为 `http://haoyundou.com:8081/`；`.cn` 管理端使用 `https://haoyundou.cn/admin-port/`，不要求新增第二个 8081 服务。

当前管理员账号为 `haoyundou`，密码由站点负责人保管，不写入公开部署文档；本次修复未改动该账号密码。管理端登录后可切换上传、导入、色板、编辑工具、底图、下载、保存、发布、分享和拼豆模式等前端功能开关；设置保存到 `hd_feature_permissions`，主站读取失败时默认全部开启。

页面脚本和样式带有日期版本号。修改它们时同步递增 `editor.html` 或 `index.html` 中的查询参数，避免浏览器继续使用旧缓存。工作台脚本只在首次挂载时初始化 Lucide 图标，避免尺寸调整时替换按钮节点影响鼠标点击。

## 数据库迁移

两个站点分别使用同名数据库和面板账号：`haoyundou.com` 与 `haoyundou.cn`。迁移脚本都使用 `IF NOT EXISTS` 或幂等插入，不会删除现有数据。通过面板数据库终端或具有对应数据库权限的账号，分别在两个站点执行完整迁移：

```bash
mysql -u haoyundou.com -p haoyundou.com < database/001_editor_schema.sql
mysql -u haoyundou.com -p haoyundou.com < database/002_platform_schema.sql
mysql -u haoyundou.com -p haoyundou.com < database/003_workbench_schema.sql
mysql -u haoyundou.com -p haoyundou.com < database/004_admin_permissions.sql
mysql -u haoyundou.com -p haoyundou.com < database/005_showcase_works.sql
mysql -u haoyundou.com -p haoyundou.com < database/006_admin_console.sql
mysql -u haoyundou.com -p haoyundou.com < database/007_user_activity.sql
mysql -u haoyundou.com -p haoyundou.com < database/008_homepage_settings.sql
mysql -u haoyundou.com -p haoyundou.com < database/009_homepage_visual_settings.sql
mysql -u haoyundou.com -p haoyundou.com < database/010_homepage_navigation_tools.sql
mysql -u haoyundou.com -p haoyundou.com < database/011_auto_moderation.sql
mysql -u haoyundou.com -p haoyundou.com < database/012_independent_sites.sql

mysql -u haoyundou.cn -p haoyundou.cn < database/001_editor_schema.sql
mysql -u haoyundou.cn -p haoyundou.cn < database/002_platform_schema.sql
mysql -u haoyundou.cn -p haoyundou.cn < database/003_workbench_schema.sql
mysql -u haoyundou.cn -p haoyundou.cn < database/004_admin_permissions.sql
mysql -u haoyundou.cn -p haoyundou.cn < database/005_showcase_works.sql
mysql -u haoyundou.cn -p haoyundou.cn < database/006_admin_console.sql
mysql -u haoyundou.cn -p haoyundou.cn < database/007_user_activity.sql
mysql -u haoyundou.cn -p haoyundou.cn < database/008_homepage_settings.sql
mysql -u haoyundou.cn -p haoyundou.cn < database/009_homepage_visual_settings.sql
mysql -u haoyundou.cn -p haoyundou.cn < database/010_homepage_navigation_tools.sql
mysql -u haoyundou.cn -p haoyundou.cn < database/011_auto_moderation.sql
mysql -u haoyundou.cn -p haoyundou.cn < database/012_independent_sites.sql
```

`006_admin_console.sql` 会创建 `hd_admin_settings` 和 `hd_admin_logs`，并写入站点名称、备案号、站点开关和历史审核配置。`012_independent_sites.sql` 将两个库的 `manual_review` 固定为 `0`、`moderation_mode` 固定为 `automatic`；重复执行不会清空作品、用户、权限或日志。

`007_user_activity.sql` 已于 2026-09-23 在 `haoyundou.com` 数据库执行，新增 `hd_user_activity(user_id, activity_date)`。主站及管理端成功登录、有效会话访问会写入当天记录，同一账号当天只计一次；概览的活跃数表示登录账号日活，包含管理员。部署前没有采集的历史日期显示 0，不推算历史活跃数。迁移可重复执行，不改动现有作品、用户、权限或密码。

`008_homepage_settings.sql` 已于 2026-09-23 在 `haoyundou.com` 执行。它在现有 `hd_admin_settings` 中新增 `homepage_feed_limit=24` 和 `homepage_category_order`（JSON 分类名称数组），供 `api/home.php` 与首页读取；没有新增作品或修改账号资料。重复执行保留已配置的值。展示数量限定为 1–48，分类最多展示 16 项；公开接口不会返回站点开关、违禁词或其他管理配置。现有后台配置界面尚未提供这两个字段，可通过数据库修改，刷新首页生效。

`009_homepage_visual_settings.sql` 已于 2026-09-23 在 `haoyundou.com` 执行，记录 `homepage_visual_version=20260923-18` 和 `homepage_nav_palette=mist-blue`。这两个设置只用于发布追踪和配色说明，不改变账号、作品、审核状态或首页接口返回数据；重复执行会更新到当前视觉版本。

`010_homepage_navigation_tools.sql` 已于 2026-09-23 在 `haoyundou.com` 执行，当前记录 `homepage_visual_version=20260923-25`、`homepage_nav_palette=warm-neutral` 和 `homepage_tools_layout=four-column`。设置只用于发布追踪，通过 PDO 事务更新，不改变账号、作品、审核状态或公开接口字段。

`011_auto_moderation.sql` 和 `012_independent_sites.sql` 已于 2026-09-24 在两个数据库执行。`.com` 和 `.cn` 都记录 `moderation_provider=transformers-js-vit-v1`、`moderation_mode=automatic`、`manual_review=0`、`data_isolation=independent` 和各自的 `site_domain`。已有 `.com` 的待审作品 #238 已自动检测通过并公开；`.cn` 的克隆记录也已执行同样检测。

### 2026-09-23 首页视觉重构

- 继续使用 HTML、CSS、原生 JavaScript 和本地 Lucide。`assets/home.css` 独立维护首页样式，已从共用 `site.css` 中移出原先叠加的首页覆盖规则。当前首页专属样式版本为 `20260923-25`，首屏素材保持 `20260923-13`，共用脚本保持 `site.js?v=20260923-12`。
- 初版四个入口曾使用 2+2 错位布局，现已替换为单行四列；绿/粉/紫/黄图标底色、悬浮反馈和原有豆社、转换、导入、工作台链接继续保留。
- 豆社使用全宽浅绿像素点阵背景。排序与分类分两层胶囊排列，选中态为深绿底白字。原有推荐、最新、热门收藏、讨论最多、全部分类和搜索均可用；排序/分类/搜索直接请求服务端，避免只在前 24 条推荐数据中排序。列表查询支持作者昵称搜索；时间或热度相同时按 ID 倒序保持稳定。
- 作品流使用原生 CSS columns 和 `break-inside: avoid`。不同宽高的展示框形成错落，Canvas 用 `object-fit: contain` 保留完整图纸比例；标题、作者、喜欢数始终展示，悬浮或键盘聚焦时底部浮现品牌、标签和查看箭头，触屏直接展示此信息。少于 6 件作品时桌面使用两列，较多作品使用三列，窄屏为两列。
- 活跃创作者与热门作品为错位的半透明侧栏，桌面滚动时保持 sticky，900px 以下进入普通文档流。创作者按最近一次公开发布排序，展示真实公开作品数和获赞；没有关联作者时显示邀请创作的空状态，不再显示虚构的固定榜单。当前 4 件公开作品的 `owner_id` 都是 NULL，因此创作者榜为空属于预期。
- 首屏的 `home-studio.png` 来源于已有作品 9 和 7，生成时只读数据库，不增加浏览量。它是完整位图素材，不依赖外部图片服务。需更换作品时调整脚本中的作品 ID 和首屏对应链接，然后执行 `php scripts/render-home-art.php`；脚本仅允许 CLI，需 PHP GD。
- 进场只由 IntersectionObserver 添加状态类，动画全部由 CSS transition/transform 完成；进场容器与卡片悬浮元素分开，避免位移冲突。系统启用减少动画时停用过渡和流畅滚动；未执行 JavaScript 时四个主要入口仍可用。
- 顶部保留登录、注册和搜索，900px 以下提供导航菜单，600px 以下提供独立搜索按钮。登录弹窗支持 Escape 关闭、焦点循环和关闭后焦点返回。右下角像素按钮在滚动超过一屏后出现，隐藏时不会进入键盘焦点顺序。
- 作品列表包含加载、空结果、服务失败和重新加载状态，连续筛选会取消旧请求并忽略过期响应。作品卡片保留原生 `work.html?id=...` 链接，可通过键盘和新标签页访问。

### 2026-09-23 首页暖纸质感与错落层次调整

- 页面底色调整为浅米色纸张，导航、工具入口、作品卡片、榜单和页脚统一使用暖白与低饱和绿的层次，首屏真实拼豆图像降低饱和度并融入纸张背景。
- 四个功能入口继续保留 2+2 错位排布，并增加轻微角度、独立留白、像素豆点和更柔和的悬浮阴影；移动端取消旋转以避免窄屏内容拥挤。
- 豆社区域改为带极淡像素点阵的鼠尾草色纸张背景，作品卡片使用不规则圆角和轻微角度形成瀑布流的手作感；筛选、榜单、滚动进场、回到顶部和所有原有链接与交互不变。
- 本次仅修改首页 HTML 查询版本和 CSS 视觉层，不新增数据库迁移；线上静态资源由 Nginx 的首页缓存策略直接刷新。

### 2026-09-23 核心设计原则细化

- 在 2+2 错位、作品瀑布流和下移榜单的基础上，继续拉开标题、正文、标签和按钮的视觉权重，避免等宽等高的表格节奏。
- 使用浅米色纸张渐变、卡片微渐变、柔影和半透明毛玻璃叠加质感；渐变保持低对比度，真实首屏拼豆图像和像素点阵仍是主要视觉素材。
- 入口、筛选、作品、榜单和回到顶部按钮沿用 0.2 秒过渡、悬浮上移、按压回弹和滚动进场；减少动画偏好会自动停用过渡与进场位移。
- 本次仍只修改首页 CSS 与查询版本，不新增数据库迁移或改变作品、账号数据。

### 2026-09-23 顶部导航栏优化

- 首页导航默认使用透明暖纸张叠层，去除底部边框；滚动超过 18px 后切换为白色半透明背景和柔和底部阴影。滚动态类继续由 `assets/site.js` 管理。
- 导航链接颜色、左起下划线、搜索框聚焦放大和登录/注册按钮悬浮反馈均使用 0.2 秒过渡。注册按钮增加深绿微渐变、底部立体层和 hover 阴影。
- 桌面导航高度收窄至 68px，并增加两侧留白；900px 和 600px 断点同步调整移动菜单、移动搜索面板的顶定位，原有菜单、搜索、登录和注册入口不变。
- 对 `prefers-reduced-motion: reduce` 单独覆盖导航过渡和位移，保证辅助功能偏好不会被新增的 hover 动效覆盖。

### 2026-09-23 首屏 Hero 区优化

- 首屏文案整体上移，右侧真实拼豆素材改为带点阵纹理、双层柔影和 1° 微倾斜的悬浮卡片，并保留 `work.html?id=9` 今日灵感链接。
- 主标题增加像素豆子装饰，副标题降低字重并放大行距；主按钮加入深绿渐变、内阴影、悬浮上移和按压回弹，工作台入口改为细描边透明按钮。
- 新增图片本地处理、12–64 豆宽、多品牌色板三个胶囊优势标签，桌面端错落排列，移动端自动收拢；原有图转拼豆、工作台入口和首屏图片功能不变。
- 900px 以下卡片保持右侧缩放，600px 以下改为文字下方单卡，避免窄屏遮挡；本次仅修改首页 HTML/CSS，不新增数据库迁移。

### 2026-09-23 导航配色调整

- 导航栏从暖米色透明层切换为独立的雾蓝灰玻璃渐变，与页面浅米色底和深绿色创作主题形成区分；滚动后进入更明亮的冷白蓝状态并保留柔影。
- 导航文字、搜索框、移动菜单和图标统一使用蓝灰层级，深绿仅作为品牌和注册按钮强调色；hover 下划线改用低饱和珊瑚色，增强识别度但不抢主标题。
- 首页资源版本更新为 `home.css?v=20260923-18`；新增 `009_homepage_visual_settings.sql` 已执行，数据库只记录视觉版本和导航配色元数据。

### 2026-09-23 导航与功能入口收敛（v24）

- 导航改为浅米白/半透明白通栏悬浮层，底部使用极轻柔影；菜单保持横向排列，当前项和 hover 使用深绿短下划线，搜索框与导航高度对齐并在聚焦时显示浅绿色描边。
- 四个入口覆盖旧版错位规则，统一为一排四列等宽卡片，紧凑高度、统一 14px 圆角和白色/极浅米白表面，仅保留豆社浅绿、图转拼豆浅珊瑚、图纸导入浅紫、作品创作浅橙黄作为图标小面积点缀。
- 四个入口仍分别链接 `community.html`、`convert.html`、`import.html` 和 `editor.html`；hover 上浮、阴影加深、背景提亮和箭头右移保持 0.2 秒过渡。入口区域移除装饰标题与编号，缩短说明并收紧上下留白；移动端同样保持单行四列，每张卡片内使用上下图文以保留清晰的横排标题。
- 首页资源版本更新为 `home.css?v=20260923-24`，数据库迁移 `010_homepage_navigation_tools.sql` 已重新执行以记录最终视觉版本。
- 已通过现有 `tests/homepage.cjs` 和导航/入口专项浏览器核验。专项覆盖 1920、1440、1280、1150、1024、920、901、900、768、701、700、601、600、541、540、480、390、320px：四列同排等宽等高、导航不重叠、标题完整且不小于 12px、无横向溢出。截图位于 `/tmp/haoyundou-nav-v24-宽度.png`，另有移动菜单和搜索展开截图。
- 本次修改前备份为 `/root/site-backups/haoyundou-nav-tools-before-v24-20260923.tgz`。本次替换仅需 `index.html` 和 `assets/home.css`，沿用站点现有字体、Lucide 和 JavaScript。回滚时从该备份恢复这两个文件，视觉元数据可保留或重跑备份中的 `010` 迁移；无需恢复业务数据。

### 2026-09-23 首页导航字体优化（v25）

- 旧版共用样式仅为每个 MiSans 字重引用一个分片，导航中文未命中时会使用系统字体。新增 `assets/fonts/misans/home-navigation.css`，通过 CSSOM 从已有 Regular、Medium、Semibold 字体样式生成，共 300 条 Unicode 分片规则。仅修改 CSS 字体别名，原始 WOFF2 文件、分片范围和许可证不变，浏览器按实际文字加载所需分片。
- 字体别名 `MiSans Navigation` 仅用于首页导航及其 Logo、中英文标识、菜单、搜索、登录注册和账号入口。品牌文字保持 600 字重，当前页通过 `aria-current="page"` 加粗；不引入楷体、书法字体或字体大小随视口缩放的规则。
- 已在浏览器核验实际渲染字体：Logo 和当前页菜单使用 MiSans Semibold，其余菜单与登录注册使用 MiSans Medium，搜索文本使用 MiSans Regular。1920、1440、1280、1151、1150、1024、920、901、900、768、601、600、390、320px 共 14 个宽度通过层级和边界检查；移动菜单、搜索、注册弹窗可用，四入口同排保持不变，无字体加载失败和页面 JavaScript 异常。
- 截图：`/tmp/haoyundou-nav-font-v25-1440.png`、`/tmp/haoyundou-nav-font-v25-1024.png`、`/tmp/haoyundou-nav-font-v25-320.png`。修改前备份：`/root/site-backups/haoyundou-nav-font-before-v25-20260923.tgz`。
- 本版需同步发布 `index.html`、`assets/home.css`、`assets/fonts/misans/home-navigation.css`，并保留该字体目录内的 WOFF2 和 `assets/fonts/MiSans-LICENSE.txt`。数据库继续执行 `010_homepage_navigation_tools.sql` 记录 v25。回滚时从上述备份恢复首页和首页样式，新增字体映射可保留但不再引用。

发布直接使用现有 Nginx/PHP 服务，不需要构建、重启或额外前端开发服务器。静态首页必须与 `assets/home.css`、导航字体映射和 WOFF2、`assets/site.js`、`assets/home-studio.png` 和 `api/home.php` 一起发布；迁移依赖 `006_admin_console.sql` 已创建的设置表。只回滚首页时同时恢复对应版本首页与样式；视觉配置可以保留，不影响旧版本。

本次发布前备份位于站点目录外：

- 文件：`/root/site-backups/haoyundou-home-before-20260923-1212.tgz`
- 数据库：`/root/site-backups/haoyundou-db-before-home-20260923-1212.sql`（权限 0600）

首页浏览器回归运行方式：

```bash
PLAYWRIGHT_MODULE=/tmp/singsu-check/node_modules/playwright \
CHROMIUM_PATH=/root/.cache/ms-playwright/chromium_headless_shell-1243/chrome-headless-shell-linux64/chrome-headless-shell \
node tests/homepage.cjs
```

回归覆盖 1920/1440/1280/1024/900/768/600/390/320px 宽度、横向溢出、图纸 Canvas 非空、错落高度、真实 API 排序、分类、搜索、空状态、入口链接、3px 悬浮位移、登录弹窗、移动导航/搜索、回到顶部、接口失败重试、过期响应保护、减少动画和禁用 JavaScript 时的主要入口。截图输出到 `/tmp/haoyundou-home-宽度-20260923.png`。使用 `SITE_URL` 可切换到其他部署地址；该脚本不创建用户或作品，不提交登录表单。

本次上述浏览器回归已全部通过，页面没有 JavaScript 异常；PHP/JavaScript 语法检查通过，豆社、转换、导入、工作台入口均返回 HTTP 200。迁移的重复执行已在数据库事务中验证，确认不会覆盖自定义设置后回滚测试事务。

### 2026-09-23 缩略图与登录修复

- 修正作品缩略图向右下偏移一格的问题。旧实现对只有一个像素的目标格子增加 inset，并使用包含右/下边界的矩形绘制，导致较大缩略图边缘裁切、较小缩略图向相邻空白格溢色。现在每个采样点只写入对应的一个 PNG 像素；保留最大 64 格、按比例缩小和主色采样逻辑。
- 渲染函数从 `api/works.php` 提取到 `api/work-thumbnail.php`，两者必须一起发布。首页、豆社和热门榜继续读取同一个列表接口，封面 URL 的优先级保持不变。PNG 由数据库 `grid_json` 实时生成，不需要重写作品记录、清空数据或新增数据库迁移。
- 首页登录支持邮箱、昵称和已有用户名，注册仍要求有效邮箱。移除请求失败时生成 `localOnly` 演示账号的行为，并清理遗留浏览器缓存；只有服务端返回有效账号才显示已登录。浏览器禁用本地存储时仍可以通过会话 Cookie 登录。注册成功会直接使用服务端会话，不依赖 localStorage。
- 登录失败保留表单和输入，显示网络、账号或服务响应错误；提交中禁用重复提交及模式切换。退出失败不会宣称退出成功，初始会话查询的迟到响应也不会覆盖已确认的登录/退出结果。
- 当前首页脚本版本：`site.js?v=20260923-12`。修改前的备份：`/root/site-backups/haoyundou-before-bugfix-20260923-1245.tgz`。

- 2026-09-23 追加注册缓存修复：首页、首页样式和首页脚本版本升级为 `20260923-12`。主站 Nginx 对 `/index.html`、`/assets/site.js` 和 `/assets/home.css` 返回 `Cache-Control: no-cache, no-store, must-revalidate`，避免浏览器继续执行包含“本地演示账号”提示的旧脚本。Nginx 备份位于 `/root/site-backups/haoyundou-nginx-before-cache-fix-20260923-1259.conf`，已通过 `nginx -t` 并平滑重载。

专项验证命令：

```bash
php tests/work-thumbnail.php
PLAYWRIGHT_MODULE=/tmp/singsu-check/node_modules/playwright \
CHROMIUM_PATH=/root/.cache/ms-playwright/chromium_headless_shell-1243/chrome-headless-shell-linux64/chrome-headless-shell \
node tests/home-auth.cjs
```

缩略图测试覆盖 8×8、24×24、8×24、24×8、64×64 逐像素对比，以及 200×100 下采样、透明区域、背景色和无效输入。登录测试仅拦截浏览器内的账号接口请求，不创建正式用户或修改账号密码；覆盖真实注册成功、重复邮箱、昵称登录、注册邮箱校验、断网、401、非 JSON/无效成功响应、存储不可用、重复提交、退出失败和迟到会话查询。

本次两个专项测试和 `tests/homepage.cjs` 均已通过，9 个响应式宽度无横向溢出。线上 4 件公开作品的缩略图与数据库原始格子逐像素对比为零差异；原有首页配置和作品数据已核验，无需执行新迁移。

工作台基于原生 HTML、CSS 和 JavaScript，桌面端采用“垂直工具列 + 色板面板 + 自适应画布 + 设置面板”的四区工作台布局；顶部导航栏分为当前色号、模式标签和全局操作三组，左侧工具列提供画笔、填充、取色、形状、选区、平移、缩放和橡皮擦，并提供撤销/重做快捷按钮。色板面板支持“本图色卡/全部色板”切换、A/B/C/D/E/F/G/H/M/P 字母分组和全量色号浏览；色号网格固定每行 4 项，显示颜色方块与编号，面板在侧栏内独立垂直滚动，本图色卡只列出当前画布实际使用的颜色。画布支持 8×8 至 200×200，视口使用浅米色点阵底纹；右侧画布尺寸模块提供 35²、52²、78²、104²、144²、200² 预设、宽高滑块、精确输入和等比例缩放。上传图片会先按原图的自然宽高创建画布，最长边超过 200 格时按比例缩小，极小图片会在 8 格下限内尽量保持比例；图片像素按整幅画布映射，不再居中留白或截取。调整尺寸时优先按参考底图、再按上传原图重新采样，仍保持整幅映射。编辑画布在上边缘显示列号、左边缘显示行号，编号随缩放、平移和尺寸变化同步更新，便于定位格子。右侧底图模块提供“导入底图”入口、透明度和显示控制，说明参考图只垫在格子下方用于描色。鼠标左键绘制、右键擦除、滚轮缩放、空格拖拽平移均在浏览器端完成，右侧缩放输入框与画布状态实时同步。参考底图以可调透明度显示在像素和网格下方，不写入像素数据，预览/熨烫/拼豆视图及 PNG 成品导出会自动隐藏参考层；参考底图和上传原图随本地草稿和 JSON 工作台文件保存，不提交到 `hd_works.grid_json` 或作品接口。发布成功返回单作品链接 `work.html?id=作品ID`，作品页直接渲染像素、尺寸、品牌、标签、作者和审核状态，不展示参考底图。画笔、橡皮擦、填充、取色、形状绘制、选区预览、四种视图和实体拼豆模式均在浏览器端完成；浏览器刷新时从 `localStorage` 自动恢复最近草稿。上传的图片不会发往服务器。发布接口会把像素数据写入 `hd_works.grid_json`，把网格主线、背景、笔刷大小和像素完美等设置写入 `hd_works.settings_json`。

首页导航已经拆成 `community.html`、`convert.html`、`import.html` 和 `editor.html` 四个独立界面。独立转换页和导入页仍使用 `sessionStorage` 将本机素材交给工作台，不上传图片。

首页和工作台可以使用开源 NSFWJS 做本地预检，但它不决定发布结果。真正的发布门禁在服务端 `api/moderation-client.php` 和 loopback `haoyundou-moderation.service`：完整图纸、原图和参考图由 Transformers.js 的 NSFW 与 violence 模型共同检测，任一模型达到阈值就写入 `blocked` 并拦截；服务异常也不会放行。`bead_editor_drafts` 表的 `settings_json` 为后续登录和云端草稿功能保留设置字段。

`api/config.php` 只允许 PHP 读取，权限应保持为 `640` 且属主为 `www:www`。两个站点配置分别连接同名数据库，并使用不同的会话名称和会话目录。第一次部署后可将注册用户的 `role` 更新为 `admin`，再登录对应站点管理端；未登录时显示登录界面。工作台提交作品时支持用户填写标签，API 会根据标题和描述补充风景、植物、动物、美食、游戏、动漫、人物等系统标签，自动检测通过后直接公开。

作品分享页使用 `work.html?id=作品ID` 作为稳定链接。打开链接会直接加载该作品的像素数据、尺寸、用色、作者和浏览量，并提供熨烫融合预览、滚轮缩放、拖拽平移、高清 PNG 图纸下载、配色板下载、喜欢/收藏/关注、待拼清单和本机评论交互。首页和豆社卡片均直接跳转到该单作品页；服务端接口在打开作品时累计 `hd_works.views_count`。

2026-09-22 修复了工作台导入图片后的滚轮缩放：滚轮由整个画布视口统一接收，导入图片、重绘画布或平移状态变化不会再让缩放失效。首页和豆社作品卡片同时保留原生 `work.html?id=作品ID` 链接，即使脚本事件尚未完成初始化也可以直接打开作品详情；首页热门作品排行也使用同一分享链接。该修复只涉及前端事件和链接，不需要新增数据库迁移；现有 `hd_works`、`grid_json` 和 `views_count` 数据继续使用。

工作台滚轮缩放使用画布视口捕获阶段监听，兼容鼠标的 `deltaY`、旧式 `wheelDelta` 以及行/页滚轮单位，不再因为绘制或拼豆放置状态残留而跳过缩放。修改 `assets/editor.js` 后请同步递增 `editor.html` 的脚本版本号。

2026-09-22 工作台滚轮缩放进一步兼容 `wheel`、`mousewheel` 和 `DOMMouseScroll` 三类事件，画布层与视口层均接收滚轮，视口设置 `overscroll-behavior: contain` 防止页面滚动抢走焦点；旧式 `wheelDelta`、`wheelDeltaY` 和 `detail` 字段都会统一换算为缩放增量，并保留旧事件的滚轮方向。

2026-09-23 工作台滚轮缩放监听提升到 `haoyundou-editor` 宿主层，并限定事件目标必须在画布视口内。图片转换、JSON 导入和重绘后无需先点击缩放工具，直接在画布上滚动即可放大/缩小；侧栏色板和参数区域仍保持原生滚动。修改 `assets/editor.js` 后同步递增 `editor.html` 的脚本版本号。

2026-09-23 工作台滚轮入口进一步统一为一个捕获处理器，同时挂在视口、画布和工作台宿主上，并用事件路径判断是否位于画布区域，兼容画布重绘后以及旧式 `mousewheel`/`DOMMouseScroll` 直接落到画布的情况。默认画笔或其他编辑工具下不需要先点击缩放工具，导入图片后悬停画布即可连续滚轮缩放；脚本版本更新为 `editor.js?v=20260923-24`。

2026-09-23 修复豆社作品封面全部显示同一占位图的问题。`api/works.php` 列表接口现在从每件作品的 `grid_json` 生成 64 格以内的轻量 PNG 缩略图，已有 `cover_url` 时优先使用封面；豆社页和首页作品卡片按作品 ID 绑定并绘制真实缩略图，支持不同宽高比例，接口失败或旧数据缺少图纸时仍回退到示例图。此次不需要数据库迁移，原有作品图纸数据不变；相关资源版本更新为 `site.css?v=20260923-8`、`community.js?v=20260923-4`、`site.js?v=20260923-8`。

作品详情页对评论计数和本机评论分别渲染：没有历史评论时显示“还没有评论，来抢沙发~”，已有服务端评论计数但列表接口尚未接入时显示数量提示，避免出现评论数量与空状态相互矛盾。

详情页分享按钮会生成规范的 `work.html?id=作品ID` 链接，并自动去除当前地址中的调试或追踪参数。

作品详情页主体使用约 2:1 的“左侧作品展示 / 右侧信息操作”布局；右栏设置最小宽度保证按钮和规格信息不挤压，视口宽度低于 860px 时自动切换为单列。顶部站点导航保持通栏、浅米色背景和圆角卡片视觉。

详情页顶部导航在桌面端显示品牌、首页、豆社、图转拼豆、图纸导入、创作、搜索、登录和注册；650px 以下显示菜单按钮，点击后展开同一组入口，支持 `Esc` 关闭并带有 `aria-expanded` 状态。

2026-09-22 移动端作品详情页将摘要、操作、规格和评论卡片统一设为内容区全宽并垂直排列，避免 flex 子项按内容收缩造成卡片左右错位；桌面端两栏比例和尺寸保持不变。

独立管理端服务监听 `0.0.0.0:8081`，标准地址为 `http://haoyundou.com:8081/`；`.cn` 的管理端地址为 `https://haoyundou.cn/admin-port/`。管理员账号可管理前端功能权限、作品状态和用户状态。两个管理端使用不同的 `admin_session_name` 和数据库，不依赖主站登录页面，也不会共享登录状态。

当前服务器已启动 `haoyundou-admin.service`，本机 `http://127.0.0.1:8081/`、`https://haoyundou.com/admin-port/` 和 `https://haoyundou.cn/admin-port/` 均可访问。若 `.com:8081` 在外网超时，需要在腾讯云安全组放行入站 TCP `8081`；`.cn` HTTPS 管理入口不依赖该端口。

两个站点的页脚和后台入口都使用当前域名，`.com` 默认打开 `https://haoyundou.com/admin-port/`，`.cn` 默认打开 `https://haoyundou.cn/admin-port/`。两个入口的数据、会话和设置分别隔离。

## 管理端功能

管理端采用“顶部通栏 + 固定侧边栏 + 主内容区”的后台布局，入口为 `https://haoyundou.com/admin-port/` 或 `http://服务器地址:8081/`。登录账号为 `haoyundou`，密码不在公开文档记录。页面包括运行概览、作品审核、作品列表、分类管理、用户列表、权限角色、系统日志和基础配置。

管理端支持状态/分类/起止日期筛选、分页、作品详情和真实像素预览；自动检测记录显示色情/暴力分数和检测结果，管理员可对异常作品手动下架或恢复公开，不需要为正常作品逐件点击通过。分类管理支持新增和重命名，用户列表支持资料编辑、启用/禁用和重置密码，管理员下拉菜单的个人设置支持修改昵称、账号和密码，权限和基础配置写入数据库并记录到 `hd_admin_logs`。所有写操作显示加载条和 Toast 反馈，侧边栏在窄屏自动折叠，表格在移动端可横向滚动。

管理端接口位于 `admin-port/api.php`：`login`、`logout`、`me`、`dashboard`、`work_detail`、`moderate`、`moderate_bulk`、`create_category`、`rename_category`、`update_user`、`update_profile`、`user_status`、`reset_password`、`save_permissions`、`save_settings` 和 `logs`。接口使用独立的 `haoyundou_admin_port` 会话，不依赖主站登录状态。

管理端 CSS 使用系统字体回退，不从 8081 跨端口加载主站字体文件，避免浏览器 CORS 错误；修改管理端页面时同步递增 `admin-port/index.html` 中的 `admin.css` 和 `admin.js` 查询版本。

### 2026-09-23 修复记录

- 工作台滚轮的实际根因是 `setZoom()` 把缩放值取整到 0.1：在 10%/20% 等较低比例下，连续滚轮增量会被丢弃，小幅触控板滚动也会停滞。现在状态保留完整精度，仅百分比显示取整；适应窗口也保留精度。保持原有 5%–800% 范围及鼠标指向位置，无需先切换缩放工具。
- 分类管理显示全部分类，包含无关联作品的新分类。用户编辑允许保留既有用户名形式的登录账号，避免 `haoyundou` 因不是邮箱而无法保存；不存在用户、重复邮箱、自停用操作均返回明确错误。重置密码用可复制的持久弹窗展示结果。
- `GET api.php?action=works|users|logs` 支持 `page`、`page_size`（1–50）、`q`，作品和用户另支持状态、分类或角色及起止日期。默认每页 8 条，返回 `rows/total/page/page_size`；取消旧版前 100 条限制，页码窗口跟随当前页。列表请求带有前端序号，离开页面后的旧响应不会覆盖当前内容。
- 作品列表从真实图纸生成小尺寸 Canvas 缩略图，详情仍加载完整图纸。主站首页及作品链接使用主站 HTTPS 地址，8081 端口下不再误跳到管理目录。通知数量取自实际待审数，点击打开待审核筛选。
- 审核写入作品状态、审核事件及日志时使用事务；批量操作先确认所有作品存在，失败不部分提交。单条及批量驳回均需原因，逐作品记录到日志。审核通过趋势按审核事件时间统计，不再因作品浏览量更新而改变日期。
- 概览显示真实的登录活跃记录和近 10 条日志；零值柱状图不再强制绘制非零高度。分类饼图按标签关联数统计，一件作品可以关联多个标签。
- 分享页手机端为 Lucide 替换后的 SVG 图标补齐统计栅格定位，浏览、喜欢、收藏标签不再被挤成竖排。预览处于适应窗口状态时，窗口或横竖屏变化会自动重新适配；用户主动放大、平移后保留其检视位置，点击适应窗口可恢复自动适配。桌面两栏布局保持原样。
- 本站 Nginx 配置 `/www/server/panel/vhost/nginx/haoyundou.com.conf` 增加 `fastcgi_intercept_errors off;`，保留 PHP API 的 JSON 错误响应。已通过 `nginx -t` 并平滑重载；其他站点配置未改动。
- 代码备份：`/root/site-backups/haoyundou-before-repair-20260923.tgz`；Nginx 备份：`/root/site-backups/haoyundou-nginx-before-repair-20260923.conf`。备份位于站点目录之外。
- 分享页修改前的独立备份：`/root/site-backups/haoyundou-share-before-repair-20260923.tgz`。

本次验证使用隔离测试账号、作品和分类完成实际保存、启停用户、重置密码、审核及批量审核、设置和权限原值保存，完成后清理测试数据并还原相关更新人元数据。正式管理员密码、现有作品内容和审核状态未改动；打开公开作品进行浏览测试会正常累计浏览量。HTTPS 入口和本机 8081 均已验证管理员登录与接口读取；外部 8081 是否能连通仍取决于云安全组。Chromium 已检查工作台、后台 1440/1280 宽度和分享页 1440/320/390/430 宽度的截图、画布非空、分享链接及自动适配行为。

例如将已注册账号设为管理员：

```sql
UPDATE hd_users SET role = 'admin' WHERE email = 'admin@example.com';
```

### 2026-09-24 双站点同步与自动审核

- 以 `.com` 当前发布版本复制完整项目到 `.cn`，保留 `.cn` 的证书验证目录；两个站点代码一致，`api/config.php`、站点域名、备案号、会话名称和管理入口按域名区分。
- 使用面板已有账号将 `.com` 数据完整导入 `haoyundou.cn`，导入前备份位于 `/root/site-backups/haoyundou-cn-before-clone-20260924-022430.sql`；之后两个库独立写入，不建立跨库查询、跨域 Cookie 或共享会话。
- 顶部域名按钮在首页、豆社、图转拼豆、图纸导入、工作台和作品页可用。切换时保留公共工具路径，作品详情回到对应站点豆社，不携带登录 Cookie、localStorage 草稿或作品 ID 到另一库。
- 发布接口强制审核服务端生成的完整图纸，不能通过伪造 `moderation_images` 绕过检测；原图和参考图也会校验 MIME、尺寸、大小和 SHA-256。自动审核通过后作品直接为 `published/approved`，拦截结果写入 `hd_moderation_events`。
- 审核服务使用 Transformers.js 的本地模型和 Apache-2.0 许可证；`systemctl enable --now haoyundou-review@com.timer haoyundou-review@cn.timer` 每 5 分钟自动重试历史待检测记录。审核服务或模型不可用时发布失败，不把异常作品自动公开。
- `tests/independent-sites.php` 已验证两个数据库账号、用户会话、管理会话、作品发布链接和完整图纸检测互相隔离；`tests/moderation.php` 已验证边缘像素、无效图片和强制完整图纸检查。

## 验证

```bash
node --check assets/editor.js
node --check assets/site.js
node --check assets/moderation.js
node --check assets/admin-panel.js
node --check assets/work.js
node --check assets/community.js
php -l admin-port/api.php
php -l admin-port/lists.php
node --check admin-port/admin.js
php tests/admin-lists.php
php tests/moderation.php
php tests/independent-sites.php
curl -I https://haoyundou.com/admin-port/
curl -I https://haoyundou.cn/admin-port/
curl -I https://haoyundou.com/editor.html
curl -I https://haoyundou.com/work.html?id=6
curl -I http://127.0.0.1:8081/
```

在浏览器打开工作台后，至少验证上传图片、画笔/橡皮擦/填充/取色、撤销重做、1–20 格笔刷、滚轮缩放、空格平移、四种视图、PNG 导出和 JSON 导入导出；将画布调整为 200×200 后再检查性能与发布接口。移动端再检查画布缩放和侧栏滚动。

滚轮回归脚本需要 Node 和 Playwright，目标地址可通过 `SITE_URL` 设置；当前服务器运行方式：

```bash
PLAYWRIGHT_MODULE=/tmp/singsu-check/node_modules/playwright \
CHROMIUM_PATH=/root/.cache/ms-playwright/chromium_headless_shell-1243/chrome-headless-shell-linux64/chrome-headless-shell \
node tests/editor-zoom.cjs
```

该脚本在默认画笔工具下导入 200×200 PNG，验证连续放大、小幅触控板滚动、鼠标指向位置、13% 精确输入、边界值、侧栏滚动和移动端溢出。`tests/admin-lists.php` 仅允许 CLI 执行，在事务内构造 110 个用户和作品，检查最后一页、筛选、页码边界和缩略图，结束后回滚；自增编号可能留下正常间隙。
