Files
jiang13-bbs/docs/site-operations.md
freefire 1d862a0dd3 feat: 站点媒体库与移动端底部导航,服务测试补强
- 新增媒体库:media_library/media_thumbs 服务(WebP 缩略图)、管理端 media 页面
- 移动端底部导航 MobileTabBar 替换 MobilePostBar
- 旧数据导入增强与测试、路由与登录会话/板块侧边栏测试补强
- site-doc 组件精简(移除 Breadcrumb),文档新增迁移公告说明
2026-09-27 02:36:11 +08:00

20 KiB
Raw Permalink Blame History

站点设置五模块:实现与交付说明

验证日期:2026-09-21。本次修改位于工作区,未发布到生产。测试使用独立 PostgreSQL 数据库、临时数据目录、SMTP/S3 协议测试设施,没有向真实用户发信或清理生产数据。

现有能力与改动归属

  • 原有基本信息、互动与安全(含原内容互动与访问安全)、主题变量、管理权限、CSRF、Cookie 会话、上传校验、附件下载授权继续使用。站点设置各分区为独立路由(/admin/settings/basic 等)。时间线编辑器仍支持从 GitHub/Gitea 导入提交(内置规则,不可在站点设置中编辑)。
  • 原有开放注册及上传大小/扩展名/数量设置迁到对应新模块。实际值仍由原 SiteSetting 键提供,模块保存通过同一事务更新,旧通用接口拒绝写入这些已迁移键,避免双重来源。
  • 新增独立模块版本、机密加密、共享计数、SMTP 任务与验证码、S3 适配器、统一内容匹配、维护访问守卫及受控临时文件清理。
  • 原站点没有独立应用缓存和订阅邮件流程,不展示清空缓存或群发通知的虚假能力。
  • 延续现有明暗主题与品牌令牌。截图来自隔离站点默认蓝色主题,没有覆盖真实站点已保存的绿色或其他主题色。

文件与关键实现

  • backend/model/operations.go、model/db.go、model/models.go:模块、审计、额度、持久邮件、验证码、对象引用和临时上传记录;附件新增 object_id。
  • backend/service/operations.go:默认值、完整校验、AES-256-GCM、版本比较、跨模块事务依赖、旧键兼容。
  • backend/service/operations_security.go:PostgreSQL 原子共享计数、账号/来源登录保护、受控服务目标解析与连接。
  • backend/service/operations_mail.go:验证证书的 TLS/STARTTLS、测试连接/实际测试发信、品牌模板、加密队列、租约恢复、有限重试、验证码。
  • backend/service/operations_storage.go:S3 签名请求、专用前缀读写删除探测、不可变配置快照、公开图片/CDN与私有附件隔离。
  • backend/service/operations_filter.go:CommonMark 可读文本、NFKC/大小写归一化、匹配位置和局部例外、拦截优先、脱敏审计。
  • backend/service/operations_maintenance.go、operations_temporary.go:密码重置、真实诊断、日志清理、带跨实例上传锁的临时文件扫描与清理。
  • backend/handler/operations.go、handlers.go、router/router.go:复用 PermSettings 和 CSRF;管理接口、公开白名单、业务配额、维护访问控制。
  • backend/handler/auth.go、post.go、setting.go;service/auth.go、post.go、comment.go、upload.go、post_file.go、brand_store.go:实际注册/登录/发布/编辑/上传/下载接入。
  • backend/service/ratelimit.go、middleware/ratelimit.go:修复原限流器把完整请求键当类别查找的问题,加入 Retry-After 和过期清理。
  • backend/go.mod、go.sum:MinIO Go S3 客户端及 Goldmark 解析器。
  • frontend/app/admin/settings/OperationsPanel.tsx、FilterRules.tsx、SettingsAdmin.tsx:五模块表单、独立保存、草稿测试、版本错误、导航离开保护、规则导入/编辑/批量操作、诊断与确认清理。
  • frontend/app/admin/settings/BasicIdentityPanel.tsx:只读正式地址来源与 SEO 关键词说明修正。
  • frontend/lib/api.ts、app/register/page.tsx、app/login/page.tsx、app/reset-password/page.tsx:注册验证码、找回密码、管理调用。
  • frontend/components/OperationalBanner.tsx、app/layout.tsx:只读提示,最多约 30 秒刷新提示;服务器写入限制立即生效。
  • frontend/middleware.ts:服务端读取维护状态并返回真正的 HTTP 503,保留原有会话恢复和 robots 大小写改写。
  • frontend/app/globals.css:复用设计令牌的表单、结果、规则和窄屏布局。
  • backend/service/operations_test.go、backend/tests/operations-api.mjs:风险驱动的服务与 HTTP 回归。
  • .env.example、deploy/.env.example、deploy/docker-compose.yml、deploy/CHANGELOG.md:部署变量与升级说明。

设置项与校验

以下是缺失项的初始值;已有注册、文件限制继续使用数据库有效值。每个模块有独立版本,保存后立即供下一次服务请求读取;不需要重启应用。SMTP/S3 服务状态只是配置状态,测试结果是带时间的历史结果,不表示持续在线。

访问与安全

  • allow_register:默认 true,继承原配置。关闭后接口拒绝新注册,前台仍保留注册入口以便展示 register_notice;现有账号不受影响。
  • register_notice:默认空,最多 200 字;关闭注册时在注册页展示。
  • verify_email、password_reset:默认 false。启用前要求邮件已启用、凭据可解密、正式地址有效且 SMTP 连接/认证通过;依赖存在时禁止停用邮件或清空必需凭据。注册验证码在创建账号前消费,不批量改变老账号状态。
  • login_window:600 秒,范围 60–3600;login_failures:5 次,范围 3–50。账号与来源分开计数,来源阈值为账号阈值四倍,窗口到期自动恢复;成功登录清除账号失败计数。
  • post_interval:6 秒;comment_interval:2 秒,均允许 0–3600。根据原有每分钟 10/30 次校准,新规则采用最小间隔,0 仅关闭该最小间隔。原有积分/等级业务发帖冷却仍有效,不能把两者视作相互替代。
  • resend_interval:60 秒,范围 30–3600,目标邮箱+用途;email_hourly:5 次,范围 1–20,按规范化邮箱共享;另外每来源最多 20 次/小时。
  • search_minute:30 次/分钟,范围 1–120;登录用户按 ID、游客按真实可信来源计量。
  • 新增安全额度使用 PostgreSQL 原子计数、哈希键及到期清理,多实例共享。原有其他交互接口的内存防滥用限流仍按进程工作,不宣称全站一致。
  • 密码沿用既有 6–64 字节、bcrypt、会话版本规则;重置后撤销旧会话。第三方验证码/MFA 不在本期。

邮件服务

  • enabled:默认 false;host/username/password/from:启用时必填,主机不能含协议或路径;密码保存前必须有主密钥。
  • tls:默认 tls(隐式 TLS),也支持 starttls(必须升级且验证证书);port 默认 465,范围 1–65535。STARTTLS 常用 587,由站长按服务商实际端口填写。没有忽略证书或明文降级选项。
  • from_name:留空复用站点名称,最多 120 字节;reply_to:可空,非空需为邮箱;用户名最多 256 字节,禁止邮件头换行。
  • timeout:10 秒,范围 2–30;retention:30 天,范围 1–365。缩短保留时间不立即删除记录,需另行确认清理。
  • 正式地址和浅色 Logo 复用基本信息/部署 SITE_URL。主题与正文可在后台自由编辑,注册验证和找回密码共用;留空恢复内置模板。变量为 {{site_name}}、{{purpose}}、{{code}}、{{link}}、{{site_url}}、{{logo_url}}(绝对图片 URL)、{{logo}}(完整 img 标签,勿写入 src)。正文必须保留 {{code}};不做 HTML 过滤。发送时变量值会转义,并把 <style> 中的简单 class 规则内联到元素(手机 QQ 等客户端会丢弃 style 标签);邮件以 quoted-printable HTML 发出。预览与实发使用同一渲染结果。邮件链接回到可信正式地址,由用户粘贴验证码完成验证/重置。
  • 凭据读取只返回已配置标志,不回显原文,拒绝掩码占位符。未保存时直接填写;已保存时默认沿用,可单独更换或移除。更换与移除互斥,留空且不移除则保持旧值。
  • 保存启用的邮件配置前实际验证连接与认证。测试按钮使用当前草稿,测试连接不投递;发送测试邮件只发给管理员指定地址。
  • 业务邮件记录排队/发送中/重试/失败/服务器已接受。最多 3 次尝试,2 分钟租约用于崩溃恢复;任务去重与稳定 Message-ID。SMTP 在“远端接受后本地未记录”的故障窗口可能重投,不承诺严格 exactly-once。
  • 队列有效载荷加密,完成/最终失败后清空;日志不记录验证码、正文或凭据。服务器接受不等于送达;SPF/DKIM/DMARC只给指引,未检测则不显示通过。

文件与存储

  • backend:默认 local;本地根目录由 DATA_DIR 固定,只读显示。切换 S3 只影响新头像、正文图片和普通附件。站点 Logo/背景继续保存在部署品牌目录;媒体库中的远程图片可按权限复制为品牌素材。
  • endpoint:生产 HTTPS origin,开发允许 HTTP;bucket:3–63 位符合桶名格式;region:默认 us-east-1,1–64 位字母/数字/_/-;access_key、secret_key:机密交互同邮件。
  • prefix:默认 jiang13/uploads/,受控相对目录,以 / 结束,不允许越界;path_style:默认 true,支持路径或虚拟主机寻址。
  • cdn:默认空,可选 HTTPS 基址。只用于已声明公开图片,部署方必须配置其桶/前缀权限。私有文件仍走鉴权下载;CDN 不是将私有桶设为公开的指令。
  • image_max_mb:默认 5 MiB,范围 1–50;attachment_max_mb:默认 20 MiB,范围 1–100;attachment_max_count:默认每帖 10,范围 1–20。原 API 每次上传一个文件,前端批量仍受每帖上限约束。
  • attachment_ext_limit:默认 true;attachment_exts:继承原业务白名单,1–80 个小写字母数字扩展名。原站点支持软件安装包和技术文本;这些仍只作为强制下载附件,不能内联执行。
  • 正文图片复用 JPEG/PNG/WebP/GIF 解码检查与最大 4096px,其中 JPEG/PNG 落盘前统一转存 WebP(JPEG 有损 q80、PNG 无损;GIF 动图与已是 WebP 的原样保留,转码失败降级为保留原格式);头像保持 2 MiB、64–512px WebP;SVG 仅保留管理员品牌上传能力。附件复用真实图片头校验,伪装/活跃内容降为二进制并强制 attachment/nosniff。
  • 1 MiB=1,048,576 字节;仓库 Nginx 示例与 Next 代理缓冲均为 512 MiB,仍需确认实际部署入口没有更低限制。
  • 保存 S3 前验证合并后的草稿,在专用 tests/ 前缀上传、读回并删除一个随机测试对象,不扫描桶。失败不更新配置;不会自动切回其他存储。
  • 每个远程对象保存不可变 storage-N 配置引用与对象键。切换后原本地 URL、历史远程配置继续可读;界面显示历史引用数,不提供删除历史配置按钮。
  • 删除媒体时先撤销本站公开资源访问,再删除远程对象;清理失败保留配置引用,需运维处理残留对象。自行配置的 CDN 缓存失效由部署方处理。

内容过滤

  • enabled:默认 false;rules:默认空,最多 2000。每条 ID 唯一且最多 64 字节,词语 1–80 字,备注最多 500 字节,最多 20 条例外,每条例外最多 240 字节且非空。
  • scopes:username/title/body/comment;action:block/log;每条规则独立启停。NFKC 归一化并忽略大小写,仅用于匹配,原始内容不改写。
  • 正文/评论从 CommonMark AST 提取可读文本,跳过代码块、行内代码、链接目标/自动链接、HTML块/标签;普通链接显示文字参与匹配。测试显示归一化文本及 0 起始字符位置。
  • 例外仅覆盖对应规则的对应出现位置,同文其他命中仍拦截;拦截优先于记录。创建/编辑帖子与评论、注册/修改昵称在服务层检查,导入草稿最终发布同样走该服务。
  • TXT 每行一个词,300 KB 上限;预览新增/重复/无效项,默认合并,覆盖需确认,应用导入仅修改草稿,保存后生效。导出 TXT 仅词语,范围/例外不作为无损备份。
  • 不改写历史内容,不自动换星号,不伪造审核工作流。正则和复杂审核为后续增强。

维护与诊断

  • mode:默认 normal,可选 readonly/paused;readonly 阻止普通用户内容写入,paused 公开页面及业务 API 返回 503。
  • title:默认“站点维护中”,最多 240 字节;message:最多 4000 字节;contact:最多 500 字节;均按纯文本处理。
  • until:默认空,有值必须是含时区的 RFC3339;仅展示,不会自动恢复。
  • retry_after:默认 300 秒,范围 30–86400;temp_days:默认 7 天,范围 1–365。
  • 登录、退出、会话恢复、找回密码、站点状态、健康检查保持可用;管理接口继续独立权限校验。后台绕过基于实时真实 PermSettings;robots 保留原响应,不用 robots 实现停站。
  • Go 实际拒绝写入;Next 页面/RSC 请求查询实时状态,暂停时返回 503 + Retry-After + private,no-store。状态不可读时安全失败为 503。已打开页面的只读提示会定期更新,后端限制不依赖提示是否刷新。
  • 数据库 ping、本地创建/删除探测、队列查询、版本/运行时长和带时间的历史邮件测试是真实数据;无独立缓存如实标注,S3 连续健康未知,使用专用测试按钮检测。
  • 临时扫描不删除;一次清理最多 100 个受控候选。只清理本版本登记、过期且不在上传中的 .partial,执行前复查引用和跨实例数据库会话锁;正文/草稿附件、未知来源旧 partial 均保留。返回成功/跳过/失败数量,可重新扫描重试。
  • 清理邮件记录仅影响超出保留期的终态记录,不删除排队任务、会话、限流计数。
  • 无在线清库、重置全站、备份恢复或程序更新按钮。

数据库迁移与部署

  1. 升级前备份数据库和 DATA_DIR;多个实例滚动部署时,先让数据库执行新增迁移,再统一升级服务。旧版本不认识维护守卫和 S3 引用,不应长期与新版本混跑。
  2. 启动时 GORM AutoMigrate 新增 module_configs、settings_audits、action_counters、mail_tasks、email_challenges、stored_objects、temporary_uploads,并为 post_attachments 新增 object_id。既有行为空值表示本地附件,不批量重写历史链接。
  3. SETTINGS_MASTER_KEY 必须为安全随机 32 字节的标准 Base64;例如在安全终端使用 openssl rand -base64 32 生成。不要使用测试用的全零密钥。本地开发写在 backend/app.ini 的 [security];生产与多实例用同名环境变量,环境变量优先于 ini。各 API 实例配置相同密钥,单独备份,不写入仓库或与密文一同存库。更换/丢失密钥会使队列与所有历史存储凭据不可解密;本期没有在线轮换功能。修改后需重启 API。
  4. Go 与 Next 的 SITE_URL 必须一致且为正式外部 HTTPS origin;后台基本信息只读显示。Next 的 BACKEND_URL 指向可达 API,不使用请求 Host 生成邮件地址。
  5. SERVICE_PRIVATE_HOSTS 为逗号分隔的精确主机名。默认拒绝私网、回环、链路本地及特殊地址,DNS 解析后连接已经检查的 IP;确有自建 SMTP/S3 时只放行对应主机。虚拟主机 S3 寻址时要按实际连接的 bucket.endpoint 主机配置。
  6. TRUSTED_PROXIES 仅列出真正的代理 IP/CIDR。默认不信任转发头;不要直接填任意全网,避免登录/IP额度绕过。 Compose 部署下不配置时 ClientIP 会记录为反代容器内网地址(如 172.19.0.4),登录日志与访问统计全部失真。 取真实 IP:先 docker network inspect <网络名> 查看子网(常见 172.18.0.0/16–172.31.0.0/16),再把该网段填入 TRUSTED_PROXIES(如 172.16.0.0/12 覆盖全部 Docker bridge),反代需设置 X-Forwarded-For/X-Real-IP。 未配置时后端启动会输出警告日志便于排查。经 Cloudflare 等平台代理时改用 TRUSTED_PLATFORM=CF-Connecting-IP。
  7. MAINTENANCE_RECOVERY=1 是部署级紧急恢复:重启 API 后强制正常访问;修复后台模式,再撤销该变量并重启。不会悄悄覆写数据库保存模式。
  8. Compose 已透传四个新变量并保留原服务/端口/数据卷。参见 deploy/CHANGELOG.md。JWT、DB_DSN、Cookie安全属性仍保持部署级管理。
  9. 反代/CDN不得缓存 HTML、/api/site-state、鉴权接口、503;停站和恢复后验证外部入口的真实状态码及缓存头。外部 CDN 未在本地测试范围内。
  10. 多实例本地文件存储需要共享相同数据卷;所有实例使用一致数据库、密钥、正式地址。临时上传锁通过相对路径在数据库中协调。S3需保留历史配置/主密钥以及桶内对象。

验证记录与复现

服务测试使用临时 schema,结束删除 schema;API脚本只允许显式声明隔离的 3301 本机后端。不要把这些测试指向现有真实站点。

  • 后端:设置 OPS_TEST_DATABASE_URL=postgres://…/ops_test?sslmode=disable 后,在 backend 运行 go test ./...。已通过完整测试。覆盖加密/AAD/缺失密钥、失败保存不改变配置、版本争用和依赖原子性、共享限流/到期恢复、SMTP认证成功/失败/超时/证书拒绝、队列去重/重启租约恢复/有限重试、邮箱跨来源限流/验证码单次消费、S3读写删除/历史私有对象、Unicode/例外/Markdown过滤、临时文件活跃锁/正文引用/草稿保护。
  • HTTP:OPS_TEST_BASE_URL=http://127.0.0.1:3301、OPS_TEST_CONFIRM=isolated,运行 node tests/operations-api.mjs,配合指向同后端的 Next :3000。已通过权限/CSRF/注册关闭/并发200+409/登录429与Retry-After/创建编辑过滤/评论间隔/只读写入拒绝/暂停API和页面503/robots200/恢复入口/恢复页面200。
  • 前端:npx next typegen、npx tsc --noEmit --incremental false、npm run build 均通过;npm test 的 16 项已有 SEO/JSON-LD 测试也通过。现有 middleware 文件命名有 Next 的弃用提示,仍可构建;本次保留原文件及用户已有 robots 修改,未另做 proxy 迁移。
  • 实际浏览器:安全设置保存显示新版本及已生效;服务重启后仍读取已保存版本;本地存储测试真实成功;未配置 SMTP 测试显示错误;过滤测试显示局部例外及代码跳过;TXT预览正确显示新增1/重复2;导入未保存离开确认、取消保留及放弃行为正常;规则变化后旧测试标为过期;诊断与临时扫描正常。
  • 1440px 桌面与 390px 手机、浅/暗主题人工截图检查。手机文档宽度390px,无横向页面溢出。全部截图来自一次性测试账号和数据,规则/维护标题不是生产默认值。

页面截图

仍需站长配置与外部验收

  • 填写正式 SITE_URL、随机 SETTINGS_MASTER_KEY、可信代理及必要的内部服务允许列表。
  • 提供真实 SMTP 主机/端口/模式/账号授权码/发件邮箱;先连接测试,再只向指定测试邮箱发送。真实供应商、STARTTLS供应商互操作、垃圾邮件归类及 SPF/DKIM/DMARC 未做外部实测。
  • 使用 S3 时提供 Endpoint/Bucket/Region/两项密钥/专用前缀和必要 CDN 权限,验证真实服务的小文件、大文件上传与私有下载。协议设施通过不等于所有云厂商均兼容;真实 MinIO/云供应商、CDN 和反代组合尚需部署验收。
  • 现有公开图片继续公开;私有附件保留鉴权/帖子可见性/积分规则。历史附件批量迁移、密钥在线轮换、专用云SDK、第三方验证码、MFA、订阅通知、正则审核、数据库在线恢复是后续增强。

验证结束后已停止本次启动的临时前端、后端与 PostgreSQL;截图和源码保留在仓库内。