<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>晚风如歌</title><description>晚风的博客</description><link>https://bytefun.site/</link><templateTheme>Firefly</templateTheme><templateThemeVersion>6.16.8</templateThemeVersion><templateThemeUrl>https://github.com/CuteLeaf/Firefly</templateThemeUrl><lastBuildDate>2026年10月6日 21:45:30</lastBuildDate><item><title>上下班打卡APP</title><link>https://bytefun.site/posts/new-42fd0bdb/</link><guid isPermaLink="true">https://bytefun.site/posts/new-42fd0bdb/</guid><description>基于一次迟到开发出来的APP😭</description><pubDate>Tue, 06 Oct 2026 13:20:58 GMT</pubDate><content:encoded>&lt;section&gt;&lt;h1&gt;上下班打卡：开发记录与使用说明&lt;a href=&quot;#上下班打卡开发记录与使用说明&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h1&gt;&lt;p&gt;本文记录「上下班打卡」从首次开发到 1.2 版的实现、问题修复与验证过程，并提供与当前界面一致的操作说明。&lt;/p&gt;

&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;项目&lt;/th&gt;&lt;th&gt;内容&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;文档整理日期&lt;/td&gt;&lt;td&gt;2026 年 10 月 6 日&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;当前应用版本&lt;/td&gt;&lt;td&gt;1.2（构建号 3）&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;运行设备&lt;/td&gt;&lt;td&gt;安装 iOS 27 或更新系统的 iPhone&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;已验证开发环境&lt;/td&gt;&lt;td&gt;Xcode 27.0（27A266a）、iOS 27 SDK、Swift 6&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;已验证真机&lt;/td&gt;&lt;td&gt;iPhone 17，iOS 27.0&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;界面与存储&lt;/td&gt;&lt;td&gt;SwiftUI、SwiftData、本机照片文件&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;使用方式&lt;/td&gt;&lt;td&gt;无需注册、无需后端服务器；记录默认保存在本机&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;本文根据现有源代码、开发对话和留存验证材料整理。下文的编译与测试结果是此前实际执行的记录；本次文档整理没有重新运行测试，也不将未验证项目写成已经通过。&lt;/p&gt;&lt;section&gt;&lt;h2&gt;一、开发过程&lt;a href=&quot;#一开发过程&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;section&gt;&lt;h3&gt;1. 初始需求与产品范围&lt;a href=&quot;#1-初始需求与产品范围&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;最初目标是开发一个可以直接编译、安装和使用的个人上下班打卡工具，而不只是界面演示。首版范围包括：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;每天分别记录一次上班、下班打卡，附带可选照片和备注。&lt;/li&gt;
&lt;li&gt;显示当天状态，提供月历、历史筛选、搜索和记录详情。&lt;/li&gt;
&lt;li&gt;设置上下班本地通知，选择提醒时间及生效星期。&lt;/li&gt;
&lt;li&gt;修改、补录和删除记录前确认，导出 CSV，清除本机数据。&lt;/li&gt;
&lt;li&gt;处理权限拒绝、保存失败、照片不可用及首次启动空状态。&lt;/li&gt;
&lt;li&gt;使用简体中文、原生组件、系统颜色，适配深色模式、Dynamic Type 和 VoiceOver。&lt;/li&gt;
&lt;li&gt;提供单元、持久化和 UI 测试，完成真机安装验证。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;产品定位是个人记录工具。打卡时间来自设备系统时钟，用户可以补录和修改内容，因此不作为企业防篡改考勤认证或历史地点证明。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;2. 工程搭建与架构选择&lt;a href=&quot;#2-工程搭建与架构选择&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;工程采用 SwiftUI + ViewModel + Repository / Service 的分层结构，尽量把界面、业务规则、持久化和系统能力分开。通知、照片存储、数据仓库与定位提供可替换接口，便于测试成功和失败场景。&lt;/p&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;签到打卡/&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;├── WorkPunch.xcodeproj/           Xcode 工程与共享 Scheme&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;├── WorkPunch/&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;│   ├── App/                      App 入口、依赖组装、通知路由&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;│   ├── Core/&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;│   │   ├── Models/               打卡、位置、提醒、节假日模型&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;│   │   ├── Repositories/         仓库接口与 SwiftData 实现&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;8&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;│   │   ├── Services/             打卡事务、照片文件与 CSV&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;9&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;│   │   └── Utilities/            日期、月历、筛选等规则&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;10&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;│   ├── ViewModels/               今日、日历、记录、设置与编辑逻辑&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;11&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;│   ├── Views/                    四个标签页与编辑、详情、隐私页面&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;12&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;│   ├── Services/                 通知、节假日、定位与图片处理&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;13&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;│   ├── Components/               相机、记录行、图片查看与分享面板&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;14&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;│   └── Resources/                权限、隐私清单、图标、节假日资源&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;15&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;├── WorkPunchTests/               单元与 SwiftData 集成测试&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;16&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;├── WorkPunchUITests/             真机交互流程测试&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;17&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;├── Scripts/                      工程生成、检查、编译与测试脚本&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;18&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;├── TestResults/                  编译日志、测试摘要、截图和验证报告&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;19&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;├── Package.swift                 可在 Mac 上测试的共享业务代码&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;20&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;├── README.md                     工程入口说明&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;21&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;└── 开发记录与使用说明.md          本文&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;span&gt;展开&lt;/span&gt;&lt;span&gt;收起&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;主要技术选择及作用如下：&lt;/p&gt;

&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;技术或组件&lt;/th&gt;&lt;th&gt;用途与选择原因&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;SwiftUI、TabView、NavigationStack、List、Form&lt;/td&gt;&lt;td&gt;使用原生导航、列表和表单，保持日常工具的简洁界面&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;SwiftData&lt;/td&gt;&lt;td&gt;保存结构化记录，支持查询、唯一约束及后续模型迁移&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;@Observable&lt;/code&gt;、共享 &lt;code&gt;PunchStore&lt;/code&gt;&lt;/td&gt;&lt;td&gt;数据提交成功后更新快照，让今日、日历、记录和详情同步&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;UserNotifications&lt;/code&gt;&lt;/td&gt;&lt;td&gt;本地通知授权、日程更新、测试通知和通知操作&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;PhotosPicker&lt;/td&gt;&lt;td&gt;用户只需选择要提供的照片，无需开放整个相册&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;UIImagePickerController&lt;/td&gt;&lt;td&gt;封装系统相机并接入 SwiftUI&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Core Location&lt;/td&gt;&lt;td&gt;单次获取打卡位置，不申请后台定位&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;MKReverseGeocodingRequest&lt;/td&gt;&lt;td&gt;使用已安装 SDK 支持的地址查询 API，将坐标转换为可读地址&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;文件沙盒&lt;/td&gt;&lt;td&gt;保存压缩照片，数据库只存相对文件名&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Swift Testing、XCTest&lt;/td&gt;&lt;td&gt;验证业务、数据库、权限配置及实际界面流程&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;Swift 6 并发检查用于约束线程访问。界面、相机和主 ModelContext 的操作在主 Actor 执行，图片解码压缩、导出等耗时工作放到后台任务。工程将编译警告视为错误。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;3. 数据和核心业务实现&lt;a href=&quot;#3-数据和核心业务实现&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;&lt;code&gt;PunchRecord&lt;/code&gt; 除了 UUID、类型、打卡时间、备注、照片路径、创建时间和更新时间，还保存以下信息：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;dayKey&lt;/code&gt;、&lt;code&gt;timeZoneID&lt;/code&gt;：记录打卡时的当地日期和时区，避免切换时区后历史记录换到另一日期。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;uniquenessKey&lt;/code&gt;：日期与打卡类型组成唯一键，配合业务检查防止同一天同类型重复保存。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;isManual&lt;/code&gt;：标记经过确认的补录记录。&lt;/li&gt;
&lt;li&gt;可选位置字段：纬度、经度、水平精度、采集时间和地址。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;图片最长边压缩到 1800 像素，使用 JPEG 质量 0.78；缩略图单独降采样。处理时移除原图的 EXIF 和原始定位等元数据。用户主动附加的打卡位置作为独立记录字段保存。&lt;/p&gt;&lt;p&gt;保存新照片后如果数据库提交失败，会回滚记录并清理新文件。删除记录后同步清理无引用照片；清理异常会显示说明，并在后续加载时重试。提醒设置使用 Codable 编码后保存在 UserDefaults 中。&lt;/p&gt;&lt;p&gt;相关代码：&lt;a href=&quot;WorkPunch/Core/Models/PunchRecord.swift&quot;&gt;数据模型&lt;/a&gt;、&lt;a href=&quot;WorkPunch/Core/Services/PunchStore.swift&quot;&gt;打卡业务&lt;/a&gt;、&lt;a href=&quot;WorkPunch/Core/Services/PhotoStorageService.swift&quot;&gt;照片存储&lt;/a&gt;。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;4. 首次编译和真机安装&lt;a href=&quot;#4-首次编译和真机安装&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;开发开始时，命令行环境未找到可用的完整 Xcode。随后确认 Xcode 已安装，并完成 Apple 许可确认与首次组件安装；编译命令显式选择完整 Xcode 的 Developer 目录。&lt;/p&gt;&lt;p&gt;真机通过数据线连接后，依次完成解锁、信任电脑、签名安装及开发者 App 信任。安装初期系统曾拒绝启动尚未信任的开发者应用，完成信任后继续验证。真机测试期间也遇到设备锁定导致无法启动的情况，解锁后恢复测试。&lt;/p&gt;&lt;p&gt;首版留存的真机测试摘要为 &lt;strong&gt;22 / 22 通过&lt;/strong&gt;，无运行时警告。证据见 &lt;a href=&quot;TestResults/device-test-summary.json&quot;&gt;首版测试摘要&lt;/a&gt;。这只代表该阶段测试覆盖的范围；后续用户实际使用反馈又发现并推动修复了相机和通知问题。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;5. 1.1：修复闪退并完善提醒和节假日&lt;a href=&quot;#5-11修复闪退并完善提醒和节假日&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;用户反馈点击拍照闪退、点击通知进入应用闪退，同时希望提醒持续保留、每小时再提醒，并跟随中国节假日和调休。处理过程如下。&lt;/p&gt;&lt;section&gt;&lt;h4&gt;相机闪退&lt;a href=&quot;#相机闪退&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;读取真机崩溃报告后，确认系统因安装包缺少 &lt;code&gt;NSCameraUsageDescription&lt;/code&gt; 而执行隐私保护终止。&lt;/p&gt;&lt;p&gt;修复措施包括恢复相机和相册用途说明、在工程生成器中固定相关构建设置、打开相机前检查用途说明，以及增加最终安装包权限字符串测试。验证对象覆盖了实际安装包，避免只检查源文件却遗漏打包结果。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h4&gt;点击通知闪退&lt;a href=&quot;#点击通知闪退&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;崩溃记录显示异步通知委托桥接在协作执行器完成，进入 UIKit 快照或状态恢复流程时触发主线程断言。&lt;/p&gt;&lt;p&gt;修复采用系统支持的 completion-handler 委托入口，在 MainActor 上完成页面路由和完成回调，并通过 UIApplicationDelegate 在启动阶段注册、持有通知委托。随后验证了应用在后台以及完全终止后，点击真实本地通知进入打卡页的两种流程。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h4&gt;持续提醒与可操作的测试入口&lt;a href=&quot;#持续提醒与可操作的测试入口&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;设置页新增约 10 秒后的上班、下班测试通知，便于快速验证权限和点击跳转。正式提醒新增每小时追提醒、分类型停止按钮和通知长按操作。&lt;/p&gt;&lt;p&gt;刷新日程不再自动清空通知中心。普通通知点击、打开应用、完成打卡均不会自动停止追提醒；用户需要明确停止本轮或关闭对应提醒。实现同时保留了 iOS 的真实限制：第三方应用无法强制锁定通知中心条目，也不能保证无限期后台提醒。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h4&gt;中国节假日与调休&lt;a href=&quot;#中国节假日与调休&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;加入 2026 年离线安排，以及公开节假日 JSON 的下载、校验和缓存。放假日暂停，调休上班日开启，普通日期按所选星期。自动检查受 12 小时间隔限制，设置页可手动同步；尚未取得某年的安排时按所选星期回退并明确提示。&lt;/p&gt;&lt;p&gt;该阶段完整真机回归 &lt;strong&gt;39 / 39 通过&lt;/strong&gt;，其中 32 项单元／集成测试、7 项 UI 测试；后续通知交付复测 &lt;strong&gt;34 / 34 通过&lt;/strong&gt;。详细根因、日志和限制见 &lt;a href=&quot;TestResults/VALIDATION-1.1.md&quot;&gt;1.1 验证报告&lt;/a&gt;。&lt;/p&gt;&lt;/section&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;6. 1.2：附带当前位置与修复删除布局&lt;a href=&quot;#6-12附带当前位置与修复删除布局&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;第二轮新增需求是打卡时附带当前位置，并修复删除操作位置过高、布局不正常的问题。&lt;/p&gt;&lt;section&gt;&lt;h4&gt;单次定位及数据迁移&lt;a href=&quot;#单次定位及数据迁移&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;新增 &lt;code&gt;LocationService&lt;/code&gt;、&lt;code&gt;PunchLocation&lt;/code&gt; 和 &lt;code&gt;LocationSummary&lt;/code&gt;。实时打卡自动尝试单次定位，允许只使用近似位置；地址查询失败时保留有效坐标。获取位置最多等待约 25 秒，地址查询另有约 5 秒超时。&lt;/p&gt;&lt;p&gt;普通编辑默认保留原位置；补录默认关闭当前位置采集。实时打卡保存前，如果已有位置超过一分钟，会重新获取，以减少长时间停留表单造成的位置陈旧问题。关闭位置开关会取消请求并忽略后续结果。&lt;/p&gt;&lt;p&gt;数据库通过新增可选标量字段支持轻量迁移，使用旧版模型复制件测试升级后保留原记录、备注和照片路径。今日、日历、历史、详情和 CSV 同步支持位置。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h4&gt;删除操作布局&lt;a href=&quot;#删除操作布局&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;&lt;p&gt;真机复现表明，旧 &lt;code&gt;confirmationDialog&lt;/code&gt; 附着在整个详情页面上，会出现靠上方的确认气泡，且没有明确可见的取消按钮。改为居中的原生 &lt;code&gt;alert&lt;/code&gt;，显示“取消”和“删除记录及照片”；记录操作行采用合适的按钮样式。&lt;/p&gt;&lt;p&gt;UI 测试验证了确认按钮高度、弹窗位置、取消保留记录以及确认后删除。见 &lt;a href=&quot;TestResults/LocationScreenshots/DB248194-5E35-4126-8D58-F4F12933DD5A.png&quot;&gt;删除确认截图&lt;/a&gt;。&lt;/p&gt;&lt;/section&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;7. 实际验证结果与边界&lt;a href=&quot;#7-实际验证结果与边界&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;

&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;阶段&lt;/th&gt;&lt;th&gt;记录中的实际结果&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;首版真机测试&lt;/td&gt;&lt;td&gt;22 / 22 通过&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;1.1 完整真机回归&lt;/td&gt;&lt;td&gt;39 / 39 通过，0 失败、0 跳过、0 运行时警告&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;1.1 后续通知交付复测&lt;/td&gt;&lt;td&gt;34 / 34 通过&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;1.2 Mac 核心及 SwiftData 测试&lt;/td&gt;&lt;td&gt;33 / 33 通过&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;1.2 真机完整运行&lt;/td&gt;&lt;td&gt;51 / 52 通过；1 项备注编辑 UI 断言失败&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;1.2 修正断言后定向复测&lt;/td&gt;&lt;td&gt;1 / 1 通过&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;1.2 最终覆盖&lt;/td&gt;&lt;td&gt;41 项单元／集成测试、11 项不同 UI 用例均通过，包含上述复测&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;1.2 构建及交付&lt;/td&gt;&lt;td&gt;编译无警告，测试结果无运行时警告；完成签名安装并以普通模式启动&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;1.2 唯一失败的 UI 断言假定新文字一定追加在备注末尾，而自动化点击后的光标实际位于其他位置。将断言改为核对编辑框的实际输入与保存结果一致后，该用例单独复测通过。这里没有将两次结果写成一次完整的 52 / 52 全绿运行。&lt;/p&gt;&lt;p&gt;测试覆盖打卡保存、重复判断、日历状态、月份与闰年、历史筛选、CSV 转义、通知日程、节假日调休、照片删除、SwiftData 持久化和位置迁移。UI 覆盖无照片打卡、日历、筛选、修改提醒时间、位置保存与保留、关闭定位、删除弹窗、相机打开取消，以及通知后台点击与冷启动。&lt;/p&gt;&lt;p&gt;真机实际取得当前位置的流程已验证，但获取后取消，未保存真实位置或附加真实坐标截图。普通 UI 测试使用独立数据目录和虚构位置，不清除正常使用的记录。相机自动化只验证打开和取消，未拍摄用户环境；每小时间隔由固定时钟单元测试覆盖，没有声称完成长期每小时实际等待测试。&lt;/p&gt;&lt;p&gt;不同屏幕尺寸、横屏、深色模式、全部大字号和 VoiceOver 组合没有逐一完成真机验收。后台刷新执行时间、长期通知送达和专注模式／摘要的各种组合由系统影响，不作保证。&lt;/p&gt;&lt;p&gt;完整证据：&lt;a href=&quot;TestResults/VALIDATION.md&quot;&gt;当前验证报告&lt;/a&gt;、&lt;a href=&quot;TestResults/location-test-summary.json&quot;&gt;1.2 完整运行摘要&lt;/a&gt;、&lt;a href=&quot;TestResults/location-edit-summary.json&quot;&gt;定向复测摘要&lt;/a&gt;、&lt;a href=&quot;TestResults/location-core.log&quot;&gt;Mac 测试日志&lt;/a&gt;。&lt;/p&gt;&lt;/section&gt;&lt;/section&gt;&lt;section&gt;&lt;h2&gt;二、应用使用方法&lt;a href=&quot;#二应用使用方法&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;section&gt;&lt;h3&gt;1. 首次打开与四个页面&lt;a href=&quot;#1-首次打开与四个页面&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;无需登录。底部四个标签的作用如下：&lt;/p&gt;

&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;标签&lt;/th&gt;&lt;th&gt;主要用途&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;今日&lt;/td&gt;&lt;td&gt;查看实时日期和时间，完成上下班打卡，查看今天的记录&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;日历&lt;/td&gt;&lt;td&gt;按月查看完成状态，选择日期查看详情，补录遗漏记录&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;记录&lt;/td&gt;&lt;td&gt;按日期浏览，按月份、类型和备注筛选，进入记录详情&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;设置&lt;/td&gt;&lt;td&gt;配置提醒、节假日、权限，导出或清除数据，查看隐私说明&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;首次没有记录时会显示空状态，这是正常情况。完成第一条打卡后，各页面会同步显示。&lt;/p&gt;&lt;p&gt;默认上班时间为 &lt;strong&gt;08&amp;lt;50&amp;gt;&lt;/strong&gt;，下班时间为 &lt;strong&gt;18&amp;lt;00&amp;gt;&lt;/strong&gt;，普通工作日为周一至周五。上下班提醒初始都关闭；“每小时追提醒”和“同步中国节假日与调休”默认开启，但需要先开启相应的上下班提醒才会安排正式通知。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;2. 完成一次上班或下班打卡&lt;a href=&quot;#2-完成一次上班或下班打卡&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;打开“今日”，点击“上班打卡”或“下班打卡”。&lt;/li&gt;
&lt;li&gt;确认页面会尝试获取当前位置；首次使用时按系统提示允许“使用 App 期间”定位。如果不需要位置，关闭“附带位置”。&lt;/li&gt;
&lt;li&gt;可点击“拍照”调用相机，也可点击“从相册选择”。照片选填，拍照时首次需要相机授权。&lt;/li&gt;
&lt;li&gt;在“备注”中填写说明，也可以留空。&lt;/li&gt;
&lt;li&gt;点击“确认打卡”。实时打卡以保存时的设备时间记录。&lt;/li&gt;
&lt;li&gt;成功后页面关闭，显示“打卡已保存”并给出触觉反馈；今日状态更新。&lt;/li&gt;
&lt;/ol&gt;&lt;p&gt;同一天每种类型最多一条。已经完成的项目会显示记录和“查看或修改记录”，不会再次新增相同类型的打卡。照片处理中、定位中或保存中需要等待；如果开启了附带位置却没有取得位置，可重试，也可主动关闭开关后继续保存。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;3. 使用打卡位置&lt;a href=&quot;#3-使用打卡位置&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;位置记录包括地址（如果查询成功）、经纬度、定位精度和实际采集时间。允许近似位置时，会保存系统提供的近似结果；精度受权限、信号和设备状态影响。&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;保留原位置&lt;/strong&gt;：编辑已有记录时默认保留，修改备注不会自动把位置替换为当前所在地。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;重新采集&lt;/strong&gt;：在编辑页点击“重新获取当前位置”，确认保存后替换原位置。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;不带位置或移除位置&lt;/strong&gt;：关闭“附带位置”。编辑已有记录时，确认保存会移除该记录的位置。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;没有地址&lt;/strong&gt;：只要取得有效坐标，即使地址查询失败，也可以保存坐标。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;授权失败&lt;/strong&gt;：按页面提示打开定位设置，或从“设置 → 权限 → 打开系统设置”调整权限，再返回重试。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;应用不在后台持续定位。补录时取得的是此刻的位置，不代表所补录时刻的历史地点。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;4. 在日历查看和补录&lt;a href=&quot;#4-在日历查看和补录&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;点击“日历”，用左右箭头切换月份；右上角“今天”返回当天。点击某一天，下面显示该日记录和可用操作。&lt;/p&gt;

&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;标识&lt;/th&gt;&lt;th&gt;含义&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;绿色圆点&lt;/td&gt;&lt;td&gt;上班、下班均已完成&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;橙色圆点&lt;/td&gt;&lt;td&gt;只完成一种打卡&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;没有圆点&lt;/td&gt;&lt;td&gt;没有打卡记录&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;“休”&lt;/td&gt;&lt;td&gt;已取得的节假日安排中的休息日&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;“班”&lt;/td&gt;&lt;td&gt;已取得的安排中的调休上班日&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;“休／班”表示已知的节假日安排，实际是否按它安排提醒取决于设置中的节假日开关；普通周末不会因此都标成“休”。&lt;/p&gt;&lt;p&gt;补录步骤：选择今天或过去日期 → 点击缺少的“补录上班打卡”或“补录下班打卡” → 调整时间，填写可选内容 → 保存 → 在二次确认框确认。未来日期不提供补录操作；补录记录会有补录标记，默认不附带当前位置。&lt;/p&gt;&lt;p&gt;点击照片缩略图可全屏查看，支持捏合缩放、双击缩放，点击“完成”关闭。若照片损坏或丢失，会显示“照片不可用”，可去详情替换。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;5. 搜索、筛选、修改和删除&lt;a href=&quot;#5-搜索筛选修改和删除&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;进入“记录”，默认按日期倒序展示全部记录。可选择“月份”，通过“打卡类型”选择“全部、上班、下班、异常”，并在搜索栏输入备注关键字。这些条件可以组合使用。&lt;/p&gt;&lt;p&gt;“异常”指过去日期只完成一次打卡，或者记录本身带有补录标记。整天没有任何打卡时，不会自动生成缺勤记录，也不会出现在异常列表中；今天尚未下班而只有上班记录，不因这一点立即判为异常。&lt;/p&gt;&lt;p&gt;修改记录：&lt;/p&gt;&lt;ol&gt;
&lt;li&gt;点击记录进入“打卡详情”。&lt;/li&gt;
&lt;li&gt;点击“修改备注、照片或位置”。&lt;/li&gt;
&lt;li&gt;修改内容后点击“保存修改”，再确认保存。&lt;/li&gt;
&lt;li&gt;原始打卡时间不变，今日、日历、记录页面同步更新。&lt;/li&gt;
&lt;/ol&gt;&lt;p&gt;删除记录：进入详情 → 点击“删除记录” → 在居中的系统弹窗选择“取消”或“删除记录及照片”。确认后移除本条记录、位置及对应照片，无法在应用内撤销。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;6. 开启和修改每日提醒&lt;a href=&quot;#6-开启和修改每日提醒&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;打开“设置”，分别开启“启用上班提醒”和／或“启用下班提醒”。&lt;/li&gt;
&lt;li&gt;首次启用时，允许系统通知权限。&lt;/li&gt;
&lt;li&gt;点击“上班提醒时间”或“下班提醒时间”，选择小时、分钟并点击“保存”。&lt;/li&gt;
&lt;li&gt;在“提醒生效的星期”勾选需要的日期；星期选择同时用于两类提醒。&lt;/li&gt;
&lt;li&gt;根据需要保留或关闭“同步中国节假日与调休”“每小时追提醒”。&lt;/li&gt;
&lt;li&gt;在“测试与提醒状态”查看“下一次提醒”“已安排至”和待发送数量。&lt;/li&gt;
&lt;/ol&gt;&lt;p&gt;修改时间后，应用取消旧日程并安排新日程，使用稳定标识避免重复通知。首次开启或修改时间时，如果当天时间已经过去，会从下一个有效日期开始，不补发启用前的通知。&lt;/p&gt;&lt;p&gt;通知文案分别是“上班时间快到了，别忘记打卡”和“准备下班了，记得完成下班打卡”。点击通知进入相应打卡页；已有对应记录时进入编辑流程，不会直接新增重复记录，也不会自动保存。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;7. 立即测试通知&lt;a href=&quot;#7-立即测试通知&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;不用等到上班时间，也不用更改手机时间：&lt;/p&gt;&lt;ol&gt;
&lt;li&gt;进入“设置 → 测试与提醒状态”。&lt;/li&gt;
&lt;li&gt;点击“发送上班测试通知（10 秒）”或“发送下班测试通知（10 秒）”。&lt;/li&gt;
&lt;li&gt;如有授权提示，允许通知，然后返回桌面等待。&lt;/li&gt;
&lt;li&gt;收到后点击通知，确认进入对应打卡页面。&lt;/li&gt;
&lt;/ol&gt;&lt;p&gt;测试通知不受所选星期和节假日限制，不会自动保存打卡，也不会替你开启正式的上下班提醒。系统专注模式、通知摘要或其他设置可能延迟它，约 10 秒是安排时间，不是必达承诺。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;8. 每小时追提醒、停止本轮与彻底关闭&lt;a href=&quot;#8-每小时追提醒停止本轮与彻底关闭&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;开启“每小时追提醒”后，每类提醒从首次到点开始按小时继续，&lt;strong&gt;可能跨夜&lt;/strong&gt;；休息日暂停。进入 App 或完成打卡都不会自动停止，需要明确操作。&lt;/p&gt;

&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;你的目的&lt;/th&gt;&lt;th&gt;操作与结果&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;停止本轮上班提醒&lt;/td&gt;&lt;td&gt;设置中点击“停止本轮上班提醒”，或长按上班通知选择“停止本轮提醒”；下个有效工作日按设置时间恢复&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;停止本轮下班提醒&lt;/td&gt;&lt;td&gt;对下班提醒执行同样操作；上班、下班分别停止&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;保留每天提醒，取消每小时追提醒&lt;/td&gt;&lt;td&gt;关闭“每小时追提醒”，保留对应上下班提醒开关&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;不再接收某类正式提醒&lt;/td&gt;&lt;td&gt;关闭“启用上班提醒”或“启用下班提醒”&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;明确停止本轮会清理对应已送达通知并取消当天后续追提醒。系统向应用回传单条通知清除操作时也会停止；“清除全部”不保证回传，因此推荐使用明确的停止按钮。&lt;/p&gt;&lt;p&gt;应用最多滚动预排 &lt;strong&gt;60 条正式通知&lt;/strong&gt;，这是两类合计的队列，不是保证 60 天。返回应用或系统允许后台刷新时会续排；长期不开应用可能耗尽队列，请留意“已安排至”。&lt;/p&gt;&lt;p&gt;iOS 不允许第三方 App 强制通知常驻且不可清除。系统中的“持续横幅”也不等于永久锁定通知中心条目。专注模式、通知摘要、后台刷新、低电量及强制退出等都会影响提醒表现。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;9. 中国节假日与调休&lt;a href=&quot;#9-中国节假日与调休&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;在“设置 → 节假日”开启“同步中国节假日与调休”，可点击“立即同步节假日”，并查看同步状态和时间。&lt;/p&gt;&lt;p&gt;提醒生效顺序为：&lt;/p&gt;&lt;ol&gt;
&lt;li&gt;已公布的放假日：不提醒，即使落在选中的周一至周五。&lt;/li&gt;
&lt;li&gt;已公布的调休上班日：提醒，即使是原本未选中的周末。&lt;/li&gt;
&lt;li&gt;其他日期：按“提醒生效的星期”判断。&lt;/li&gt;
&lt;/ol&gt;&lt;p&gt;例如内置 2026 年安排中，10 月 1—7 日休息，10 月 10 日调休上班。因此在国庆期间正式提醒没有出现，可能是休息日规则正常生效；可用 10 秒测试通知检查通知能力。&lt;/p&gt;&lt;p&gt;如果未选择任何普通星期但开启了节假日跟随，已公布的调休上班日仍会提醒。关闭节假日跟随后，仅按所选星期判断。节假日只影响提醒安排，不限制休息日手动打卡。&lt;/p&gt;&lt;p&gt;离线时继续使用内置或缓存数据。某年数据尚未取得时，不会猜测放假安排，而是暂按所选星期提醒并显示说明。数据依据国务院通知整理，但单位实际排班可能不同，需要自行决定是否启用。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;10. 导出 CSV&lt;a href=&quot;#10-导出-csv&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;进入“设置 → 数据 → 导出打卡记录（CSV）”，在系统分享面板选择“存储到‘文件’”或其他需要的目标。&lt;/p&gt;&lt;p&gt;导出文件名为 &lt;code&gt;上下班打卡记录.csv&lt;/code&gt;，包含全部历史记录，不受“记录”页面当前筛选条件限制。字段为：日期、打卡类型、时间、备注、补录、时区、位置地址、纬度、经度、定位精度（米）、定位时间。没有位置的旧记录对应字段留空。&lt;/p&gt;&lt;p&gt;文件使用 UTF-8 BOM、标准 CSV 引号转义和 CRLF 行结束，支持中文、逗号、双引号和备注内换行。照片本体不在 CSV 中。分享结束后应用清理临时导出文件，已另存或发出的副本由使用者管理。&lt;/p&gt;&lt;p&gt;当前没有 CSV 导入或恢复功能，因此 CSV 是可阅读的记录导出，不能作为含照片的完整应用备份。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;11. 清除所有数据&lt;a href=&quot;#11-清除所有数据&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;进入“设置 → 数据 → 清除所有数据”，阅读提示并确认“清除全部记录和照片”。此操作删除应用内记录（包括位置）、照片及临时导出文件，关闭提醒并恢复默认提醒设置，不能撤销。&lt;/p&gt;&lt;p&gt;需要保留记录时先导出。外部已保存的 CSV 不会随应用清除而删除；系统是否备份应用文件取决于自己的 iPhone 备份设置。卸载应用也会移除本机应用数据。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;12. 权限、网络与隐私&lt;a href=&quot;#12-权限网络与隐私&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;

&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;能力&lt;/th&gt;&lt;th&gt;何时使用&lt;/th&gt;&lt;th&gt;拒绝后的处理&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;通知&lt;/td&gt;&lt;td&gt;首次开启提醒或发送测试通知&lt;/td&gt;&lt;td&gt;到“设置 → 权限 → 打开系统设置”允许通知，再返回启用&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;相机&lt;/td&gt;&lt;td&gt;点击“拍照”时&lt;/td&gt;&lt;td&gt;允许相机后重试；也可从相册选图或不加照片&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;相册选择&lt;/td&gt;&lt;td&gt;打开系统 PhotosPicker 时&lt;/td&gt;&lt;td&gt;仅提供主动选中的项目；无需开放整个图库，遇到读取失败可重选或不加照片&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;定位&lt;/td&gt;&lt;td&gt;实时打卡或主动重新获取位置时&lt;/td&gt;&lt;td&gt;允许使用期间定位；也可关闭“附带位置”继续打卡&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;照片、备注、打卡记录和位置保存在本机，开发者不会收集或上传这些资料，不包含广告和分析 SDK。应用不会主动进行 iCloud 同步。&lt;/p&gt;&lt;p&gt;两项系统／网络行为需要区分：节假日同步从公开托管源下载 JSON，不携带打卡数据，托管方仍可看到 IP 等基础请求信息；地址查询由系统 Apple 地图服务处理坐标。核心打卡和本机记录查看不需要后端，网络不可用时节假日依赖缓存，地址查询可能退回坐标显示。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;13. 常见问题&lt;a href=&quot;#13-常见问题&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;

&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;现象&lt;/th&gt;&lt;th&gt;检查和操作&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;开了 App 却没有通知&lt;/td&gt;&lt;td&gt;上下班提醒默认关闭；开启对应开关并检查权限、“下一次提醒”和休息日安排&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;测试通知没有及时出现&lt;/td&gt;&lt;td&gt;检查系统通知权限、通知中心／锁屏／横幅、专注模式和摘要；回到设置确认测试已安排&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;已打卡仍每小时提醒&lt;/td&gt;&lt;td&gt;这是持续提醒的当前规则；使用“停止本轮上班／下班提醒”明确停止&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;清空通知栏后又提醒&lt;/td&gt;&lt;td&gt;“清除全部”可能没有通知应用停止；使用 App 内或通知长按菜单的停止按钮&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;定位一直等待或保存按钮不可点&lt;/td&gt;&lt;td&gt;等待超时说明后重试，检查权限；不需要位置时关闭“附带位置”&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;有坐标但没有地址&lt;/td&gt;&lt;td&gt;地址查询受网络和服务影响；有效坐标仍可保存&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;照片不可用&lt;/td&gt;&lt;td&gt;文件可能损坏、删除，或选择的云端照片未能读取；在详情替换照片&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;找不到刚保存的历史记录&lt;/td&gt;&lt;td&gt;检查月份、类型和备注搜索是否仍有限制条件&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;休息日能否打卡&lt;/td&gt;&lt;td&gt;可以；节假日规则控制提醒，不禁止手动记录&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;换手机后看不到数据&lt;/td&gt;&lt;td&gt;当前没有应用云同步和导入恢复；数据在原机，系统备份／迁移效果取决于 iPhone 设置&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/section&gt;&lt;/section&gt;&lt;section&gt;&lt;h2&gt;三、后续开发与重新安装&lt;a href=&quot;#三后续开发与重新安装&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;section&gt;&lt;h3&gt;1. 在 Xcode 中运行&lt;a href=&quot;#1-在-xcode-中运行&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;安装带 iOS 27 SDK 的完整 Xcode，首次打开完成许可和所需组件安装。&lt;/li&gt;
&lt;li&gt;打开 &lt;code&gt;WorkPunch.xcodeproj&lt;/code&gt;，选择共享 Scheme &lt;code&gt;WorkPunch&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;模拟器运行时选择已安装的 iOS 27 iPhone 模拟器；真机运行时连接手机、解锁并信任电脑，按系统要求开启开发者模式。&lt;/li&gt;
&lt;li&gt;真机需在 Xcode 的 Accounts 登录 Apple ID，并在 App Target 的 Signing &amp;amp; Capabilities 中选择可用 Team。给自己的新安装使用唯一 Bundle Identifier；更新当前安装并保留旧数据时，应保持原应用身份和可用签名。&lt;/li&gt;
&lt;li&gt;按 &lt;code&gt;⌘R&lt;/code&gt; 编译运行。若手机提示开发者未信任，按系统指引在“设置 → 通用 → VPN 与设备管理”完成信任。&lt;/li&gt;
&lt;/ol&gt;&lt;p&gt;个人开发签名的可用期限受 Apple 当前规则约束，到期后可能需要重新签名安装；不要为了更新而先卸载已有应用，以免删除本机记录。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;2. 运行项目检查和测试&lt;a href=&quot;#2-运行项目检查和测试&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;在项目根目录的终端执行：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;# 检查工程结构、资源和权限配置&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;python3&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Scripts/validate_project.py&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;# Mac 上的共享核心与 SwiftData 测试&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;bash&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Scripts/test_core.sh&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;# 已安装 iOS 27 模拟器的构建与测试&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;8&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;bash&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Scripts/verify.sh&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;9&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;10&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;# 列出连接设备，取得需要测试的设备标识&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;11&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;DEVELOPER_DIR&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;/Applications/Xcode.app/Contents/Developer&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;xcrun&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;devicectl&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;list&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;devices&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;12&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;13&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;# 将占位内容替换为上一步设备标识；测试期间保持手机解锁&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;14&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;bash&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;Scripts/verify_device.sh&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&amp;lt;IPHONE_UDID&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;也可在 Xcode 中按 &lt;code&gt;⌘U&lt;/code&gt;。脚本会选择完整 Xcode 并把结果写入 &lt;code&gt;TestResults/&lt;/code&gt;。真机测试会操作测试 App；Debug 的 &lt;code&gt;--uitesting&lt;/code&gt; 使用独立数据和设置，普通 UI 用例注入虚构位置，&lt;code&gt;--live-location&lt;/code&gt; 用例才请求实际定位，Release 不包含测试定位实现。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;3. 手动回归建议&lt;a href=&quot;#3-手动回归建议&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;每次涉及系统能力或签名的更新后，建议在真机完成以下检查：&lt;/p&gt;&lt;ol&gt;
&lt;li&gt;无照片打卡、有照片打卡，重启应用确认记录仍在。&lt;/li&gt;
&lt;li&gt;相机授权、打开、取消和实际拍摄；相册选择并查看全屏照片。&lt;/li&gt;
&lt;li&gt;定位允许、拒绝、不带位置保存，以及修改备注后位置保持。&lt;/li&gt;
&lt;li&gt;10 秒测试通知，分别验证后台点击和应用终止后的通知启动。&lt;/li&gt;
&lt;li&gt;修改提醒时间、停止本轮、关闭某类提醒，并查看重新安排后的状态。&lt;/li&gt;
&lt;li&gt;节假日同步失败时保留缓存、调休工作日及普通星期规则。&lt;/li&gt;
&lt;li&gt;删除弹窗取消与确认、日历状态和历史列表同步。&lt;/li&gt;
&lt;li&gt;含中文、引号、逗号和换行备注的 CSV 导出。&lt;/li&gt;
&lt;li&gt;深色模式、大字号、VoiceOver 和目标屏幕尺寸下的可读性。&lt;/li&gt;
&lt;/ol&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;4. 维护入口和参考材料&lt;a href=&quot;#4-维护入口和参考材料&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;

&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;内容&lt;/th&gt;&lt;th&gt;入口&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;工程说明与更多命令&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;README.md&quot;&gt;README.md&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;当前版本验证报告&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;TestResults/VALIDATION.md&quot;&gt;TestResults/VALIDATION.md&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;相机、通知和持续提醒修复记录&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;TestResults/VALIDATION-1.1.md&quot;&gt;TestResults/VALIDATION-1.1.md&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;定位与删除布局验证&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;TestResults/LOCATION-VALIDATION.md&quot;&gt;TestResults/LOCATION-VALIDATION.md&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;通知实现&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;WorkPunch/Services/NotificationService.swift&quot;&gt;NotificationService.swift&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;定位实现&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;WorkPunch/Services/LocationService.swift&quot;&gt;LocationService.swift&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;节假日同步&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;WorkPunch/Services/HolidayService.swift&quot;&gt;HolidayService.swift&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;工程生成器&lt;/td&gt;&lt;td&gt;&lt;a href=&quot;Scripts/generate_project.py&quot;&gt;generate_project.py&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;新增文件后可在 Xcode 中加入相应 Target，或运行 &lt;code&gt;python3 Scripts/generate_project.py&lt;/code&gt; 重新生成工程。生成器保留现有签名 Team 和 Bundle Identifier，并固定相机、相册和定位权限说明。改动系统权限后应同时检查源码配置与最终安装包。&lt;/p&gt;&lt;p&gt;节假日参考来源：&lt;a href=&quot;https://www.gov.cn/zhengce/zhengceku/202511/content_7047091.htm&quot; target=&quot;_blank&quot;&gt;国务院 2026 年放假通知&lt;/a&gt;、&lt;a href=&quot;https://github.com/NateScarlet/holiday-cn&quot; target=&quot;_blank&quot;&gt;NateScarlet/holiday-cn（MIT 许可）&lt;/a&gt;。&lt;/p&gt;&lt;/section&gt;&lt;/section&gt;&lt;/section&gt;</content:encoded></item><item><title>博客搭建过程</title><link>https://bytefun.site/posts/new-b17543c6/</link><guid isPermaLink="true">https://bytefun.site/posts/new-b17543c6/</guid><pubDate>Tue, 29 Sep 2026 02:29:08 GMT</pubDate><content:encoded>&lt;section&gt;&lt;h1&gt;Firefly 博客搭建过程与使用说明&lt;a href=&quot;#firefly-博客搭建过程与使用说明&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h1&gt;&lt;p&gt;最后更新：&lt;strong&gt;2026-09-29&lt;/strong&gt;。本文根据项目代码和已有验收记录整理；本次更新文档没有重新部署服务器，也没有发布新的正文。&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;这是一份给个人项目使用者看的说明。它记录 Firefly 博客是怎样搭建、部署和管理的，也说明日常修改网站时应该在哪里操作。&lt;/p&gt;&lt;p&gt;文档不会记录密码、SSH 私钥、数据库密码、Supabase Secret Key 或 &lt;code&gt;service_role&lt;/code&gt; key。&lt;/p&gt;&lt;/blockquote&gt;&lt;section&gt;&lt;h2&gt;先看这里：这次修改需要部署什么&lt;a href=&quot;#先看这里这次修改需要部署什么&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;

&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;想做的事&lt;/th&gt;&lt;th&gt;操作&lt;/th&gt;&lt;th&gt;何时生效&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;修改运行时配置&lt;/td&gt;&lt;td&gt;保存草稿，再发布配置&lt;/td&gt;&lt;td&gt;网站读取新配置后&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;修改标记“需要重建”的配置&lt;/td&gt;&lt;td&gt;先发布配置，再到发布中心点“重建线上内容与已发布配置…”&lt;/td&gt;&lt;td&gt;重建任务显示“已上线”后&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;修改文章、动态或“关于我”正文&lt;/td&gt;&lt;td&gt;对应内容页保存草稿，点“提交任务 → 发布…”&lt;/td&gt;&lt;td&gt;内容发布任务重建成功后&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;修改 Mac 应用按钮、表单和编辑器&lt;/td&gt;&lt;td&gt;在 Mac 编译并替换原应用&lt;/td&gt;&lt;td&gt;新版应用启动后，不需要重建网站&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;修改网站组件、样式或构建逻辑&lt;/td&gt;&lt;td&gt;生成并启用新的固定源码包，再提交网站重建&lt;/td&gt;&lt;td&gt;新代码任务部署成功后&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;&lt;strong&gt;网站重建按钮不会顺带发布未发布的文章或“关于我”草稿。&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;近期进展：视频直传已完成生产验收，顶栏视频图标已改为包含“循环播放”和“播放 / 暂停”的二级菜单。“关于我与独立页面”管理功能已编译并安装，原文已接入远程草稿，测试文字没有发布。&lt;/p&gt;&lt;p&gt;最近一次&lt;strong&gt;已有记录的生产发布&lt;/strong&gt;是 2026-09-28 19:38&amp;lt;24&amp;gt;（北京时间）的顶栏视频菜单任务。今天的应用更新不等于网站新发布。详细步骤见 &lt;a href=&quot;docs/content/deployment.md&quot;&gt;服务器部署手册&lt;/a&gt;、&lt;a href=&quot;docs/content/about-page-management.md&quot;&gt;关于我管理说明&lt;/a&gt; 和 &lt;a href=&quot;docs/content/video-menu-verification.md&quot;&gt;视频菜单验收&lt;/a&gt;。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h2&gt;1. 这个项目由什么组成&lt;a href=&quot;#1-这个项目由什么组成&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Firefly 不是只有一个网页，而是由三部分配合工作：&lt;/p&gt;&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;博客网站&lt;/strong&gt;：访客打开的 &lt;code&gt;https://bytefun.site&lt;/code&gt;，由 Astro 生成静态网页。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Supabase 后端&lt;/strong&gt;：保存登录用户、评论、网站配置、文章草稿、历史版本和资源信息。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Firefly Admin&lt;/strong&gt;：安装在 Mac 上的原生管理应用，用来改配置、写文章、上传资源和提交发布任务。&lt;/li&gt;
&lt;/ol&gt;&lt;p&gt;配置或内容保存后，不一定会马上出现在访客页面。网站有两种生效方式：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;运行时配置&lt;/strong&gt;：例如网站标题、公告、主题色、壁纸 URL、评论开关。发布配置后，网站下次读取配置即可生效。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;构建时内容&lt;/strong&gt;：例如文章正文、字体、Markdown、页面路由、RSS、站点地图和搜索索引。必须提交一次网站重建任务，服务器构建成功并切换线上目录后才生效。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;整个流程可以简单理解为：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;Mac 上编辑&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;|&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;v&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;Supabase 保存草稿和版本&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;|&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;+--&amp;gt; 运行时配置发布 ------&amp;gt; 网站读取最新配置&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;|&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;8&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;&lt;span&gt;+--&amp;gt; 内容发布/重建任务 ----&amp;gt; 腾讯云 worker 构建 ----&amp;gt; Nginx 切换网站&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/section&gt;&lt;section&gt;&lt;h2&gt;2. 使用到的技术&lt;a href=&quot;#2-使用到的技术&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;section&gt;&lt;h3&gt;网站前端&lt;a href=&quot;#网站前端&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;

&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;技术&lt;/th&gt;&lt;th&gt;在项目中的作用&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Astro 7.2.10&lt;/td&gt;&lt;td&gt;生成页面、路由和静态站点&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Svelte 5.57.0&lt;/td&gt;&lt;td&gt;登录、评论、上传等需要交互的页面组件&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;TypeScript 6.0.3&lt;/td&gt;&lt;td&gt;业务代码和类型检查&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Markdown / MDX&lt;/td&gt;&lt;td&gt;文章、动态、项目和独立页面的内容格式&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Astro Content Collections&lt;/td&gt;&lt;td&gt;定义并校验文章、动态、项目和页面字段&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Tailwind CSS 4、Stylus、PostCSS&lt;/td&gt;&lt;td&gt;页面布局和样式&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Swup&lt;/td&gt;&lt;td&gt;页面切换动画&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Pagefind&lt;/td&gt;&lt;td&gt;静态全文搜索&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Sharp&lt;/td&gt;&lt;td&gt;图片压缩和尺寸处理&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Expressive Code&lt;/td&gt;&lt;td&gt;代码块高亮、行号和折叠&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Iconify&lt;/td&gt;&lt;td&gt;网站图标&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;后端&lt;a href=&quot;#后端&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;

&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;技术&lt;/th&gt;&lt;th&gt;在项目中的作用&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Supabase PostgreSQL&lt;/td&gt;&lt;td&gt;保存账号、评论、配置、内容版本和发布任务&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Supabase Auth&lt;/td&gt;&lt;td&gt;邮箱登录和 GitHub OAuth 登录&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Row Level Security（RLS）&lt;/td&gt;&lt;td&gt;在数据库层限制普通用户和管理员的权限&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Supabase Storage&lt;/td&gt;&lt;td&gt;保存网站图片、音频、视频和私密附件、预览文件&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Supabase Realtime&lt;/td&gt;&lt;td&gt;订阅评论等实时数据变化&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Supabase Edge Functions&lt;/td&gt;&lt;td&gt;提供管理员 API、上传地址、内容预览和公开配置接口&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;JSONB&lt;/td&gt;&lt;td&gt;保存可变化的网站配置和内容快照&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;部署和管理&lt;a href=&quot;#部署和管理&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;

&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;技术&lt;/th&gt;&lt;th&gt;在项目中的作用&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;腾讯云 CVM&lt;/td&gt;&lt;td&gt;运行构建 worker 和提供网站文件&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Ubuntu Linux&lt;/td&gt;&lt;td&gt;服务器操作系统&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Node.js 22.23.0&lt;/td&gt;&lt;td&gt;执行 Astro 构建和发布 worker&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;pnpm 11.22.0&lt;/td&gt;&lt;td&gt;安装依赖和运行构建命令&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Nginx&lt;/td&gt;&lt;td&gt;提供静态页面、HTTPS 和原子目录切换&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;systemd&lt;/td&gt;&lt;td&gt;保证 &lt;code&gt;firefly-content-worker&lt;/code&gt; 后台运行并自动重启&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Let’s Encrypt / Certbot&lt;/td&gt;&lt;td&gt;HTTPS 证书&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;macOS 管理应用&lt;a href=&quot;#macos-管理应用&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;Firefly Admin 是真正的 macOS 原生应用，不是网页套壳：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;Swift 6、SwiftUI、最低支持 macOS 14。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;NavigationSplitView&lt;/code&gt; 三栏导航，使用原生 &lt;code&gt;Form&lt;/code&gt;、&lt;code&gt;List&lt;/code&gt;、&lt;code&gt;Table&lt;/code&gt;、&lt;code&gt;Sheet&lt;/code&gt; 和 &lt;code&gt;Toolbar&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;MVVM 结构，网络层使用 &lt;code&gt;URLSession&lt;/code&gt; + &lt;code&gt;Codable&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;登录令牌和本地草稿密钥放在 macOS Keychain。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;OSLog&lt;/code&gt; 记录网络和发布状态。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;WKWebView&lt;/code&gt; 显示线上预览、草稿预览和手机/平板尺寸预览。&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;&lt;/section&gt;&lt;section&gt;&lt;h2&gt;3. 第一步：整理原有博客&lt;a href=&quot;#3-第一步整理原有博客&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;开始搭建时，先检查了项目根目录、&lt;code&gt;package.json&lt;/code&gt;、&lt;code&gt;src/config&lt;/code&gt;、&lt;code&gt;src/types&lt;/code&gt;、&lt;code&gt;src/content&lt;/code&gt; 和 Astro 配置，确认原博客可以独立构建。&lt;/p&gt;&lt;p&gt;主要内容目录如下：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;src/content/posts/       文章&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;src/content/dynamic/     动态&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;src/content/projects/    项目展示&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;src/content/spec/        About、友链、留言板等独立页面&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;src/config/              网站默认配置&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;src/types/               配置类型定义&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;public/                  不需要处理、直接公开的文件&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;原有 Markdown 文件仍然保留。后台导入时会读取标题、摘要、日期、分类、标签、封面和自定义 Frontmatter；不认识的字段也会保留，避免编辑器暂时不支持某个字段时把内容弄丢。&lt;/p&gt;&lt;p&gt;文章的稳定 ID 和 URL slug 分开保存。修改 slug 会生成旧地址跳转页；撤回后页面、RSS、站点地图和搜索结果都会在下一次构建中移除。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h2&gt;4. 第二步：在本地检查和构建网站&lt;a href=&quot;#4-第二步在本地检查和构建网站&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;在 Mac 终端进入项目目录：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;cd&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;/Users/nightwind/aiWork/firefly/Firefly&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;首次安装依赖：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;pnpm&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;install&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;修改网站代码后，建议按下面顺序检查：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;pnpm&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;check&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;pnpm&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;type-check&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;pnpm&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;build&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;三个命令的含义：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;pnpm check&lt;/code&gt;：检查 Astro 页面、组件和内容集合。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pnpm type-check&lt;/code&gt;：检查 TypeScript 类型。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pnpm build&lt;/code&gt;：生成完整的 &lt;code&gt;dist/&lt;/code&gt;，同时处理图片、字体、Pagefind、RSS 和站点地图。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;本地查看效果：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;pnpm&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;dev&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;浏览器打开 &lt;code&gt;http://localhost:4321&lt;/code&gt;。&lt;code&gt;pnpm build&lt;/code&gt; 只代表本地静态构建成功，它不会自动读取 Supabase 最新配置，也不会把网站部署到服务器。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h2&gt;5. 第三步：部署到腾讯云&lt;a href=&quot;#5-第三步部署到腾讯云&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;生产服务器信息如下：&lt;/p&gt;

&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;项目&lt;/th&gt;&lt;th&gt;值&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;公网 IP&lt;/td&gt;&lt;td&gt;&lt;code&gt;xxx&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;系统&lt;/td&gt;&lt;td&gt;Ubuntu Linux x86_64&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;网站域名&lt;/td&gt;&lt;td&gt;&lt;code&gt;https://bytefun.site&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;源码包目录&lt;/td&gt;&lt;td&gt;&lt;code&gt;/opt/firefly&lt;/code&gt;（传统源码目录）&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;固定构建源码&lt;/td&gt;&lt;td&gt;&lt;code&gt;/opt/firefly-content/code/&amp;lt;代码哈希&amp;gt;/&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;构建任务目录&lt;/td&gt;&lt;td&gt;&lt;code&gt;/var/lib/firefly-content/jobs/&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;线上发布目录&lt;/td&gt;&lt;td&gt;&lt;code&gt;/var/www/firefly-managed/current&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;旧静态目录&lt;/td&gt;&lt;td&gt;&lt;code&gt;/var/www/firefly&lt;/code&gt;（保留作备份）&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;构建账号&lt;/td&gt;&lt;td&gt;&lt;code&gt;firefly-build&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;后台服务&lt;/td&gt;&lt;td&gt;&lt;code&gt;firefly-content-worker&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;section&gt;&lt;h3&gt;第一次部署做了什么&lt;a href=&quot;#第一次部署做了什么&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;备份原有博客和 Nginx 配置。&lt;/li&gt;
&lt;li&gt;在服务器安装 Node.js 和固定版本的 pnpm。&lt;/li&gt;
&lt;li&gt;上传源码并执行 &lt;code&gt;pnpm install --frozen-lockfile&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;执行检查和生产构建，把 &lt;code&gt;dist/&lt;/code&gt; 放到网站目录。&lt;/li&gt;
&lt;li&gt;配置 Nginx 和 HTTPS。&lt;/li&gt;
&lt;li&gt;用浏览器检查首页、文章、RSS、站点地图和 404 页面。&lt;/li&gt;
&lt;/ol&gt;&lt;p&gt;Nginx 当前指向 &lt;code&gt;firefly-managed/current&lt;/code&gt;，发布时只切换这个软链接。新构建失败时，线上软链接不变，原网站继续运行。&lt;/p&gt;&lt;/section&gt;&lt;/section&gt;&lt;section&gt;&lt;h2&gt;6. 第四步：初始化 Supabase&lt;a href=&quot;#6-第四步初始化-supabase&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;section&gt;&lt;h3&gt;6.1 创建项目并获取公开连接信息&lt;a href=&quot;#61-创建项目并获取公开连接信息&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;在 Supabase Dashboard 创建项目，记录：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;Project URL，例如 &lt;code&gt;https://&amp;lt;project-ref&amp;gt;.supabase.co&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;Publishable key（旧项目可能叫 anon public key）。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;应用连接时使用项目根 URL，不要把 &lt;code&gt;/rest/v1/&lt;/code&gt; 拼到 URL 末尾。Publishable key 可以放在网站和 Mac 应用中；Secret key、service role key 和数据库密码只能放在服务器端。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;6.2 初始化表和 Storage&lt;a href=&quot;#62-初始化表和-storage&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;初始 SQL 位于：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;supabase/schema.sql&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;supabase/config-versions.sql&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;supabase/migrations/&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;在新项目上应按文件名顺序执行迁移，或使用已经登录并绑定项目的 Supabase CLI。生产环境不要把一份已经执行过的旧 SQL 再次当成新迁移执行。&lt;/p&gt;&lt;p&gt;主要数据包括：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;profiles&lt;/code&gt;：用户公开资料。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;blog_comments&lt;/code&gt;：文章评论。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;user_files&lt;/code&gt;：用户文件元数据。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;site_settings&lt;/code&gt;：兼容旧版本的网站设置。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;site_config_versions&lt;/code&gt;、草稿和审计表：配置版本、发布和操作记录。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;content_*&lt;/code&gt;：文章、动态、项目、内容版本、发布任务和发布事件。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;site_assets&lt;/code&gt;：网站公开资源元数据。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;content-assets&lt;/code&gt;：内容草稿使用的私有附件桶。&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;6.3 设置管理员&lt;a href=&quot;#63-设置管理员&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;管理员角色放在 Supabase Auth 的 &lt;code&gt;app_metadata&lt;/code&gt; 中，普通用户不能自己修改：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;update&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;auth&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;users&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;set&lt;/span&gt;&lt;span&gt;&lt;span&gt; raw_app_meta_data &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;  &lt;/span&gt;&lt;span&gt;coalesce&lt;/span&gt;&lt;span&gt;(raw_app_meta_data, &lt;/span&gt;&lt;span&gt;&apos;{}&apos;&lt;/span&gt;&lt;span&gt;::jsonb) || &lt;/span&gt;&lt;span&gt;&apos;{&quot;role&quot;:&quot;admin&quot;}&apos;&lt;/span&gt;&lt;span&gt;::jsonb&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;where&lt;/span&gt;&lt;span&gt;&lt;span&gt; email &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&apos;你的管理员邮箱&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;修改角色后退出应用并重新登录。GitHub 登录需要在 Supabase Authentication 中启用 GitHub provider，并加入应用的回调地址 &lt;code&gt;firefly-admin://auth/callback&lt;/code&gt;。&lt;/p&gt;&lt;/section&gt;&lt;/section&gt;&lt;section&gt;&lt;h2&gt;7. 权限和安全是怎样工作的&lt;a href=&quot;#7-权限和安全是怎样工作的&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;所有重要写入都经过三层检查：&lt;/p&gt;&lt;ol&gt;
&lt;li&gt;Supabase Auth 检查是否登录。&lt;/li&gt;
&lt;li&gt;Edge Function 检查 &lt;code&gt;app_metadata.role&lt;/code&gt; 是否为 &lt;code&gt;admin&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;PostgreSQL RLS 再检查站点、用户和资源权限。&lt;/li&gt;
&lt;/ol&gt;&lt;p&gt;因此：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;普通用户不能读取管理员草稿、历史私密正文或发布任务。&lt;/li&gt;
&lt;li&gt;普通用户不能上传或删除网站资源。&lt;/li&gt;
&lt;li&gt;客户端绝不保存 service role key、Secret key 或数据库密码。&lt;/li&gt;
&lt;li&gt;上传接口同时检查 MIME 类型、扩展名、文件大小和文件名。&lt;/li&gt;
&lt;li&gt;文章和配置使用版本号或更新时间做并发检查，避免覆盖其他设备的修改。&lt;/li&gt;
&lt;li&gt;日志和错误提示不会输出登录令牌、私密正文或服务端密钥。&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;&lt;section&gt;&lt;h2&gt;8. 第五步：接入网站运行时配置&lt;a href=&quot;#8-第五步接入网站运行时配置&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;网站默认值仍在 &lt;code&gt;src/config/&lt;/code&gt; 中。统一的 runtime-config 模块启动时读取 Supabase 中“已发布”的配置，再覆盖本地默认值：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;本地默认配置 -&amp;gt; 读取远程已发布配置 -&amp;gt; 合并 -&amp;gt; 页面使用&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;如果网络或 Supabase 暂时不可用，网站继续使用本地配置，不会因为配置接口失败而白屏。配置会缓存并带版本号，页面通过 Swup 切换时复用同一份结果，不会每个组件重复请求。&lt;/p&gt;&lt;section&gt;&lt;h3&gt;可以直接发布后生效的配置&lt;a href=&quot;#可以直接发布后生效的配置&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;网站标题、描述和导航标题。&lt;/li&gt;
&lt;li&gt;主题色、浅色/深色/跟随系统模式。&lt;/li&gt;
&lt;li&gt;壁纸地址、遮罩和毛玻璃相关运行时设置。&lt;/li&gt;
&lt;li&gt;首页横幅文字、公告和个人资料。&lt;/li&gt;
&lt;li&gt;侧边栏布局、已构建页面开关。&lt;/li&gt;
&lt;li&gt;友链、打赏信息。&lt;/li&gt;
&lt;li&gt;评论区域开关。&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;发布后仍需要重建的配置&lt;a href=&quot;#发布后仍需要重建的配置&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;字体下载、字体子集化和代码字体。&lt;/li&gt;
&lt;li&gt;新增或修改 Astro 路由、Markdown/MDX、Content Collections。&lt;/li&gt;
&lt;li&gt;Mermaid、PlantUML、代码高亮主题等构建插件。&lt;/li&gt;
&lt;li&gt;RSS、站点地图、Pagefind 搜索索引和 SEO/OG 静态资源。&lt;/li&gt;
&lt;li&gt;需要新增模板或组件才能支持的功能。&lt;/li&gt;
&lt;li&gt;视频地址及标记为构建项的播放器配置。相关迁移和新版 &lt;code&gt;admin-assets&lt;/code&gt; 已部署；循环开关可在新版网站运行时生效。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;每个配置字段在应用中会标记“运行时生效”或“需要重建”。&lt;/p&gt;&lt;/section&gt;&lt;/section&gt;&lt;section&gt;&lt;h2&gt;9. 第六步：安装和使用 Firefly Admin&lt;a href=&quot;#9-第六步安装和使用-firefly-admin&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;已安装应用位置：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;/Users/nightwind/Applications/Firefly Admin.app&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;日常直接双击这个应用即可，不需要每次重新编译。第一次从新位置启动时，macOS 可能询问是否允许访问原有钥匙串项目；在系统弹窗中允许即可，系统密码不要写入文档或聊天。&lt;/p&gt;&lt;section&gt;&lt;h3&gt;本地重新构建应用&lt;a href=&quot;#本地重新构建应用&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;在仓库根目录运行：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;cd&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;/Users/nightwind/aiWork/firefly/Firefly&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;pnpm&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;admin:manifest&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;bash&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;FireflyAdmin/scripts/build-app.sh&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;codesign&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;--verify&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;--deep&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;--strict&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&quot;FireflyAdmin/build/Firefly Admin.app&quot;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;pnpm admin:manifest&lt;/code&gt; 用于刷新配置 Schema 和默认值，修改配置定义时需要执行；只修改 Swift 界面时通常不需要刷新它。构建脚本会自动生成并打包原项目的 About、友链说明和留言板说明，供首次接入使用。&lt;/p&gt;&lt;p&gt;&lt;strong&gt;编译完成不等于日常应用已更新。&lt;/strong&gt; 先按 Command-Q 退出旧应用，保留旧应用副本，再复制新应用到固定安装位置。复制命令见 &lt;a href=&quot;docs/content/deployment.md#12-%E6%9B%B4%E6%96%B0-macos-%E7%AE%A1%E7%90%86%E5%BA%94%E7%94%A8&quot;&gt;部署手册中的应用更新步骤&lt;/a&gt;。之后仍从 &lt;code&gt;/Users/nightwind/Applications/Firefly Admin.app&lt;/code&gt; 启动，避免误开其他旧副本。&lt;/p&gt;&lt;p&gt;本轮使用 Command Line Tools，原生编译与签名校验通过；没有完整 Xcode，不能记为 &lt;code&gt;xcodebuild&lt;/code&gt; 通过。完整 Xcode 可用时，也可以打开 &lt;code&gt;FireflyAdmin/FireflyAdmin.xcodeproj&lt;/code&gt;，选择实际的 &lt;code&gt;FireflyAdmin&lt;/code&gt; scheme。个人本机使用临时签名；对外分发才需要另行安排 Developer ID 签名、公证和更新机制。&lt;/p&gt;&lt;p&gt;重新编译后，macOS 可能再次要求读取原钥匙串。请在系统弹窗中自行允许，不要发送密码，也不要删除钥匙串或本地草稿来绕过提示。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;登录和连接&lt;a href=&quot;#登录和连接&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;打开应用的“连接设置”。&lt;/li&gt;
&lt;li&gt;输入 Supabase 项目根 URL 和 Publishable/anon key。&lt;/li&gt;
&lt;li&gt;使用邮箱登录，或使用 GitHub OAuth 登录。&lt;/li&gt;
&lt;li&gt;确认账号的角色显示为管理员。&lt;/li&gt;
&lt;li&gt;线上预览地址填写 &lt;code&gt;https://bytefun.site&lt;/code&gt;；本地预览可填写 &lt;code&gt;http://localhost:4321&lt;/code&gt;。&lt;/li&gt;
&lt;/ol&gt;&lt;p&gt;令牌保存在 Keychain；本地内容草稿使用加密文件保存，密钥也在 Keychain，并按项目、站点和账号隔离。&lt;/p&gt;&lt;/section&gt;&lt;/section&gt;&lt;section&gt;&lt;h2&gt;10. 在应用中修改网站配置&lt;a href=&quot;#10-在应用中修改网站配置&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;左侧配置页面按网站功能分组，例如“网站基础”“导航栏”“外观与主题”“壁纸”“首页与横幅”“侧边栏”“页面开关”“评论系统”“友链”“相册”和“高级配置”。&lt;/p&gt;&lt;p&gt;常见操作：&lt;/p&gt;&lt;ol&gt;
&lt;li&gt;打开一个配置分区，先同步线上已发布值。&lt;/li&gt;
&lt;li&gt;修改字段。选项较少的地方使用整块可点击的方框卡片；数字使用减号、输入框和加号；图片字段提供上传和预览。&lt;/li&gt;
&lt;li&gt;点击“保存草稿”或按 &lt;code&gt;Command + S&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;需要让访客看到时，点击“发布”，查看修改前后的差异后确认。&lt;/li&gt;
&lt;li&gt;如果字段标记“需要重建”，发布配置后进入发布中心，点击“重建线上内容与已发布配置…”。&lt;/li&gt;
&lt;/ol&gt;&lt;p&gt;“恢复默认值”只改变当前编辑值，不会自动发布；“撤销未保存修改”会恢复到上次保存状态。保存失败时，应用会保留本地内容，不会清空输入框。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h2&gt;11. 壁纸、视频壁纸、毛玻璃和调色板&lt;a href=&quot;#11-壁纸视频壁纸毛玻璃和调色板&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;section&gt;&lt;h3&gt;图片壁纸&lt;a href=&quot;#图片壁纸&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;打开“壁纸与毛玻璃”：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;选择横幅、全屏、透明覆盖或纯色背景模式。&lt;/li&gt;
&lt;li&gt;设置桌面和移动端壁纸 URL。&lt;/li&gt;
&lt;li&gt;调整遮罩、顶栏透明和模糊强度。&lt;/li&gt;
&lt;li&gt;保存并发布配置。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;图片 URL 可以从“资源管理”上传后直接复制，也可以使用已有公开 URL。清空 URL 会回到源码默认壁纸。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;视频壁纸&lt;a href=&quot;#视频壁纸&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;视频壁纸需要三个条件：&lt;/p&gt;&lt;ol&gt;
&lt;li&gt;在“资源管理”上传合法的视频资源并得到 URL。&lt;/li&gt;
&lt;li&gt;在“壁纸与毛玻璃”中打开视频开关并选择视频 URL。&lt;/li&gt;
&lt;li&gt;如果字段标记“需要重建”，发布配置后提交一次网站重建。&lt;/li&gt;
&lt;/ol&gt;&lt;p&gt;当前生产项目已部署视频迁移和新版 &lt;code&gt;admin-assets&lt;/code&gt;。视频使用“获取上传凭证 → 直接上传 Storage → 校验登记”的流程，视频字节不再经过 Edge Function。32 MiB MP4 已完成真实上传验收，约 59 秒后成功登记；进度传完还需等待登记完成。&lt;/p&gt;&lt;p&gt;应用、数据库和存储桶已取消额外写死的视频上限，但&lt;strong&gt;当前 Supabase Free 项目全局上限仍为 50 MiB&lt;/strong&gt;。更大文件可以使用其他服务的 HTTPS 视频直链，或自行升级套餐后同步调整项目限制与服务端能力值；没有自动购买升级。&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;网站访客&lt;/strong&gt;：点击顶栏视频图标展开二级菜单，选择“循环播放”“播放 / 暂停”。图标本身只展开菜单，页面底部没有控制按钮。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;站长默认设置&lt;/strong&gt;：在应用“壁纸与毛玻璃 → 循环播放视频”设置并发布。访客在菜单中修改只影响自己的当前播放。&lt;/li&gt;
&lt;li&gt;修改视频地址后按字段提示发布并重建；只上传文件不会自动替换网站壁纸。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;播放失败时检查视频 URL 能否直接打开、编码是否被浏览器支持，以及开关和地址是否已发布到本次构建。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;调色板&lt;a href=&quot;#调色板&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;网站右上角调色板入口由“调色板与显示”控制。若网站看不到入口，先确认入口开关已发布；若修改的是构建字段，再提交重建任务。&lt;/p&gt;&lt;/section&gt;&lt;/section&gt;&lt;section&gt;&lt;h2&gt;12. 文章、动态和项目管理&lt;a href=&quot;#12-文章动态和项目管理&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;section&gt;&lt;h3&gt;新建文章或动态&lt;a href=&quot;#新建文章或动态&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;打开左侧“文章管理”或“动态内容”。&lt;/li&gt;
&lt;li&gt;点击“新建”或按 &lt;code&gt;Command + N&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;填写标题、slug、摘要、正文、日期、分类、标签、封面和 SEO 信息。&lt;/li&gt;
&lt;li&gt;使用“插入”菜单添加标题、粗体、链接、列表、代码块或表格。&lt;/li&gt;
&lt;li&gt;点击“保存草稿”。编辑器会显示已保存、保存中、离线或失败状态。&lt;/li&gt;
&lt;li&gt;点击“提交任务 -&amp;gt; 发布”，或者先生成私密网站预览。&lt;/li&gt;
&lt;/ol&gt;&lt;p&gt;编辑已经上线的文章时，访客仍看到旧版本；新版本只有在构建和部署成功后才上线。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;导入已有 Markdown&lt;a href=&quot;#导入已有-markdown&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;在文章或动态列表中点击“导入”：&lt;/p&gt;&lt;ol&gt;
&lt;li&gt;选择 Firefly 项目目录，扫描 &lt;code&gt;src/content&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;查看 Frontmatter、slug、图片路径和重复项。&lt;/li&gt;
&lt;li&gt;解决冲突后导入可用项目。&lt;/li&gt;
&lt;li&gt;导出导入报告，确认失败项。&lt;/li&gt;
&lt;/ol&gt;&lt;p&gt;重复导入同一个文件不会创建重复内容；原 Markdown 和资源仍保留。MDX 文件可以只读查看和原样导出，应用不会在服务器直接执行来源不明的 MDX 组件。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;删除和批量操作&lt;a href=&quot;#删除和批量操作&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;原文件或已上线内容需要先通过实际发布任务从网站正文、归档、RSS、站点地图和搜索中移除。列表多选后可提交一个统一删除/重建任务，成功后自动移入回收站；失败不会当作删除成功。单篇操作以确认窗口提示为准，已撤回内容可以直接移入回收站。&lt;/p&gt;&lt;p&gt;本地恢复副本与服务器内容是两回事。若列表仍显示“本地恢复副本”，在该列表中使用“彻底删除”，或“全选本地副本 → 批量彻底删除…”；这只清除本机副本，不删除服务器正式版本。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;修改“关于我”及其他独立页面&lt;a href=&quot;#修改关于我及其他独立页面&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;ol&gt;
&lt;li&gt;打开左侧 &lt;strong&gt;“关于我与独立页面”→“编辑关于我”&lt;/strong&gt;，直接打开现有原文或草稿，不重复创建。&lt;/li&gt;
&lt;li&gt;编辑 Markdown 正文，新增段落、标题、图片或链接。网页正文标题是以 &lt;code&gt;#&lt;/code&gt; 开头的行；“管理标题”只用于应用列表。&lt;/li&gt;
&lt;li&gt;点 &lt;strong&gt;保存草稿 → 提交任务 → 发布…&lt;/strong&gt;，到发布中心等待服务器重建成功。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;新增页面…&lt;/strong&gt; 可接入现有 About、留言板说明、友链说明。首次接入 Markdown 时可选空白正文，原文仍在历史中，已有草稿不会被清空。当前不新增任意 URL，可信友链 MDX 只读。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;删除…&lt;/strong&gt; 明确提示影响范围。成功重建后地址返回 404，内容进入回收站；恢复后需再次发布。导航入口可另在“导航栏”移除。&lt;/li&gt;
&lt;/ol&gt;&lt;p&gt;长篇“关于我”在这里修改；头像、昵称和简短简介仍在 &lt;strong&gt;“个人资料”&lt;/strong&gt;。本轮只接入原文，没有发布测试内容。完整步骤及验收边界见 &lt;a href=&quot;docs/content/about-page-management.md&quot;&gt;关于我管理说明&lt;/a&gt;。&lt;/p&gt;&lt;/section&gt;&lt;/section&gt;&lt;section&gt;&lt;h2&gt;13. 图片、音频和相册&lt;a href=&quot;#13-图片音频和相册&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;“资源管理”支持按以下类型筛选：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;logo、favicon、wallpaper、avatar、gallery、sponsor、music-cover、other&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;可以上传、预览、改名、复制公开 URL、查看大小和删除。图片会检查类型并压缩；音频支持 MP3、M4A、WAV、OGG。已被配置、文章、草稿或历史版本引用的资源默认不能直接删除，需要先替换引用。&lt;/p&gt;&lt;p&gt;相册继续使用原有相册入口，可以调整照片顺序、封面、替代文本、说明、日期、地点和标签。私密附件放在 &lt;code&gt;content-assets&lt;/code&gt; 私有桶，不能因为 URL 难猜就当成公开保护。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h2&gt;14. 网站预览&lt;a href=&quot;#14-网站预览&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;应用提供两种预览：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;编辑器快速预览&lt;/strong&gt;：只检查 Markdown 排版，不代表最终网站模板效果。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;网站预览&lt;/strong&gt;：使用实际 Astro 模板和样式。文章草稿通过发布中心生成一个私密预览任务，再在 WKWebView 中打开。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;网站预览支持桌面、平板和手机宽度，显示预览版本和生成时间。私密预览凭证短期有效，只能访问指定版本，不会改变线上发布指针，也不会进入公开 RSS、站点地图或 Pagefind。凭证过期后重新生成预览即可。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h2&gt;15. 发布中心是怎样工作的&lt;a href=&quot;#15-发布中心是怎样工作的&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;一次正式发布按以下顺序进行：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;保存草稿&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;-&amp;gt; 校验内容和配置&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;-&amp;gt; 生成不可变快照&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;-&amp;gt; 创建发布任务&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;-&amp;gt; worker 构建&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;-&amp;gt; 检查首页、路由、RSS、站点地图和 Pagefind&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;-&amp;gt; Nginx 原子切换目录&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;8&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;-&amp;gt; 检查线上网站&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;9&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;-&amp;gt; 标记已上线&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;发布中心的状态含义：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;草稿未发布&lt;/strong&gt;：只保存了编辑内容。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;配置已发布，等待重建&lt;/strong&gt;：配置版本已经生效，但构建型改动还没有上线。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;排队中&lt;/strong&gt;：服务器已收到任务。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;构建中&lt;/strong&gt;：正在生成 Astro 网站。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;部署中&lt;/strong&gt;：产物已生成，正在检查并切换线上目录。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;已上线&lt;/strong&gt;：线上检查通过，数据库的 live 指针已更新。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;失败&lt;/strong&gt;：线上保留上一个成功版本，可查看错误摘要并重试。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;Mac 应用关闭不会中断任务，worker 在服务器上继续执行。重复点击发布会使用幂等键避免重复任务；同一站点的任务按顺序执行，旧任务不会覆盖较新的线上版本。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h2&gt;16. 配置历史、回滚和快照清理&lt;a href=&quot;#16-配置历史回滚和快照清理&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;section&gt;&lt;h3&gt;配置回滚&lt;a href=&quot;#配置回滚&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;在“快照管理”中选择历史版本，查看 JSON Diff 或可读 Diff，再点击“恢复此版本”。恢复会创建一个新的版本并留下审计记录，不会直接覆盖历史记录。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;内容回滚&lt;a href=&quot;#内容回滚&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;在发布中心选择成功的发布任务，点击“回滚至此快照”。服务器会使用当时固定的代码包、内容和资源重新构建；只有线上检查通过后才会切换。内容回滚不会自动回滚独立的 runtime-config，如需完全恢复外观，还要在配置历史中回滚对应分区。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;释放空间&lt;a href=&quot;#释放空间&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;配置快照回收站和服务器构建工作区是两个地方：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;“快照管理 → 回收站”处理配置历史记录，本身很小，不能靠删除它释放大量服务器磁盘。&lt;/li&gt;
&lt;li&gt;“快照管理 → 服务器备份 · 释放磁盘”或“存储空间 → 服务器构建备份”可扫描服务器工作区，先看计划，再确认清理。&lt;/li&gt;
&lt;li&gt;资源管理可检查未引用资源；它与服务器构建备份清理是不同操作。&lt;/li&gt;
&lt;li&gt;服务器 &lt;code&gt;/var/lib/firefly-content/jobs/&lt;/code&gt; 保存构建工作区和日志，不能在任务运行时直接删除。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;服务器清理前先查看任务状态，保留当前线上版本和约定数量的可回滚版本，再使用项目提供的清理脚本执行 dry-run。不要使用 &lt;code&gt;rm -rf /var/lib/firefly-content/*&lt;/code&gt;，否则可能删除正在运行的构建或排查所需日志。&lt;/p&gt;&lt;/section&gt;&lt;/section&gt;&lt;section&gt;&lt;h2&gt;17. 服务器日常维护&lt;a href=&quot;#17-服务器日常维护&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;以下命令在服务器 SSH 会话中执行：&lt;/p&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;Terminal window&lt;/span&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;# 查看 worker&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;systemctl&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;status&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;firefly-content-worker&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;# 查看最近日志&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;journalctl&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-u&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;firefly-content-worker&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-n&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;100&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;--no-pager&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;7&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;# 查看当前线上目录&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;8&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;readlink&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;/var/www/firefly-managed/current&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;9&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;10&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;# 查看线上发布标识&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;11&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;curl&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-fsS&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;https://bytefun.site/content-release.json&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;12&lt;/div&gt;&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;13&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;# 查看某个任务的构建日志（日志可能含私密正文，只在服务器查看）&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;14&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;tail&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;-n&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;80&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;/var/lib/firefly-content/jobs/&amp;lt;任务&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;UUID&amp;gt;/build.log&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;更新网站代码时不能直接修改已经启用的固定源码目录。正确流程是：本地检查代码、生成新的源码包和 SHA-256、上传到 &lt;code&gt;/opt/firefly-content/code/&amp;lt;新哈希&amp;gt;/&lt;/code&gt;，在 Ubuntu 上安装 frozen lockfile 依赖，完成隔离构建后，把新代码哈希设为后续任务使用的版本。旧代码包要保留，方便回滚。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h2&gt;18. 常见问题&lt;a href=&quot;#18-常见问题&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;section&gt;&lt;h3&gt;修改后网页没有变化&lt;a href=&quot;#修改后网页没有变化&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;先看字段说明：&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;“运行时生效”：确认已经保存并发布配置，刷新网站或等待缓存过期。&lt;/li&gt;
&lt;li&gt;“需要重建”：进入发布中心提交“重建线上内容与已发布配置”。&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;普通 &lt;code&gt;pnpm build&lt;/code&gt; 不会自动读取 Supabase，也不会自动部署。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;应用提示 &lt;code&gt;PGRST002&lt;/code&gt;&lt;a href=&quot;#应用提示-pgrst002&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;&lt;code&gt;Could not query the database for the schema cache&lt;/code&gt; 通常是 Supabase PostgREST 暂时无法读取数据库结构，常见原因是数据库连接暂时不可用、迁移正在执行、项目暂停，或接口缓存尚未刷新。先检查 Supabase 项目状态和 SQL 迁移，再退出重开应用；不要把 service role key 放进应用来绕过问题。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;保存草稿超时&lt;a href=&quot;#保存草稿超时&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;应用会保留当前编辑内容，并在超时后只读核对服务器版本，避免重复写入。检查网络、Supabase 状态和是否有另一个设备同时编辑。出现 409 冲突时先比较差异，再选择合并或重新加载。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;构建失败但网站还能打开&lt;a href=&quot;#构建失败但网站还能打开&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;这是预期的保护行为。worker 在构建和产物检查通过后原子切换 &lt;code&gt;current&lt;/code&gt;，再执行线上 HTTP 检查；检查失败会尝试切回上一目录，只有验证成功才标记“已上线”。若线上状态与数据库记录不一致，任务会保留保护状态，须先核对，不能直接改成成功。查看发布中心错误摘要和服务器 &lt;code&gt;build.log&lt;/code&gt; 后处理。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;壁纸或顶栏效果消失&lt;a href=&quot;#壁纸或顶栏效果消失&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;检查“壁纸与毛玻璃”中的 URL、模式、遮罩和顶栏透明设置是否已发布；涉及视频、字体或模板的字段还要重建。浏览器缓存也可能保留旧 CSS，可使用无痕窗口或强制刷新验证。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;页面、RSS 或搜索没有更新&lt;a href=&quot;#页面rss-或搜索没有更新&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;文章和动态必须完成一次真实发布任务。只有 &lt;code&gt;succeeded&lt;/code&gt; 且线上检查通过后，正文、分类、RSS、站点地图和 Pagefind 才会一起更新。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;应用启动时一直等待&lt;a href=&quot;#应用启动时一直等待&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;检查 macOS 是否弹出钥匙串授权窗口。允许 Firefly Admin 读取登录凭证和本地草稿密钥后重新启动。若应用来自不同路径，macOS 可能再次询问授权。&lt;/p&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;评论为什么没有显示想要的昵称或头像&lt;a href=&quot;#评论为什么没有显示想要的昵称或头像&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;p&gt;到网站 &lt;code&gt;/account/&lt;/code&gt; 登录，编辑公开昵称和头像地址。评论读取用户公开资料，不展示登录邮箱；尚未设置公开昵称时显示稳定的“读者-…”名称，没有头像时使用默认头像。这里的评论账号资料与应用“个人资料”中的站长侧边栏介绍不是同一项设置。&lt;/p&gt;&lt;/section&gt;&lt;/section&gt;&lt;section&gt;&lt;h2&gt;19. 当前状态和边界&lt;a href=&quot;#19-当前状态和边界&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;section&gt;&lt;h3&gt;已完成并有生产记录&lt;a href=&quot;#已完成并有生产记录&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;网站已部署到腾讯云，Nginx 和 HTTPS 正常工作。&lt;/li&gt;
&lt;li&gt;Supabase Auth、PostgreSQL、Storage、RLS、Realtime 和 Edge Functions 已接入。&lt;/li&gt;
&lt;li&gt;配置草稿、发布、历史、审计和回滚已接入。&lt;/li&gt;
&lt;li&gt;文章、动态、项目、Markdown 导入、资源管理和批量删除已接入。&lt;/li&gt;
&lt;li&gt;服务器 worker、固定源码包、构建失败保护、Nginx 原子切换和内容回滚已有生产记录。&lt;/li&gt;
&lt;li&gt;私密预览、定时发布、应用关闭后继续执行已有实现和验收记录。&lt;/li&gt;
&lt;li&gt;视频资源迁移和 &lt;code&gt;admin-assets&lt;/code&gt; 直传接口已完成生产部署，MP4 上传不再经过 Edge Function 中转。&lt;/li&gt;
&lt;li&gt;Firefly Admin macOS 应用可构建、安装和使用。&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;需要留意的事项&lt;a href=&quot;#需要留意的事项&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;2026-09-28 已补齐真实管理员 MP4 上传验收，包括原生应用上传 32 MiB 文件；公开与私密视频、并发登记、伪造格式拒绝等 5 组生产检查及 14 项评论身份检查通过，测试数据已清理。视频最大文件仍受当前 Free 项目 50 MiB 上限约束。&lt;/li&gt;
&lt;li&gt;“关于我与独立页面”已实现并安装，真实 API 接入原文且保留为 v1 草稿。本地原生编译、网站三项检查、183 项内容测试和 7 项构建映射测试通过；没有发布测试正文，也没有在生产删除真实 About 页面。最后一次列表滚动修正版的截图验收仍待补齐，不能记为全部界面验收通过。&lt;/li&gt;
&lt;li&gt;字体下载依赖外部网络。字体下载失败会让构建任务失败，线上会继续保留上一成功版本。&lt;/li&gt;
&lt;li&gt;新增网站组件、路由、字体、Markdown 内容处理或构建插件，必须生成新的固定源码包并重建网站。&lt;/li&gt;
&lt;li&gt;本项目按个人使用需求维护，没有额外建设企业级灾备、告警和自动部署体系；已有服务器备份和回滚能力仍应保留。&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;&lt;/section&gt;&lt;section&gt;&lt;h2&gt;20. 相关文件&lt;a href=&quot;#20-相关文件&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;%E9%85%8D%E7%BD%AE%E6%B8%85%E5%8D%95.md&quot;&gt;配置清单&lt;/a&gt;：查看每个配置字段及是否需要重建。&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;SUPABASE.md&quot;&gt;Supabase 说明&lt;/a&gt;：查看后端初始化和权限说明。&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;docs/content/README.md&quot;&gt;内容管理手册&lt;/a&gt;：查看文章、动态、导入和发布细节。&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;docs/content/deployment.md&quot;&gt;部署手册&lt;/a&gt;：查看服务器 worker、构建、切换和回滚操作。&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;docs/content/phase4-verification.md&quot;&gt;第四阶段生产验收&lt;/a&gt;：查看真实任务和线上验证记录。&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;docs/content/phase5-verification.md&quot;&gt;第五阶段记录&lt;/a&gt;：查看私密预览、定时发布和个人项目范围内的验收记录。&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;FireflyAdmin/README.md&quot;&gt;Firefly Admin 使用说明&lt;/a&gt;：查看 Mac 应用登录、配置、预览和资源操作。&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;docs/firefly-admin-api.md&quot;&gt;Admin API 文档&lt;/a&gt;：查看管理员接口和错误码。&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;docs/content/about-page-management.md&quot;&gt;关于我管理说明&lt;/a&gt;：正文新增、修改、删除、恢复与验证范围。&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;docs/content/video-comments-verification.md&quot;&gt;视频上传与评论验收&lt;/a&gt;：真实上传结果、评论身份和文件限制。&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;docs/content/video-menu-verification.md&quot;&gt;顶栏视频菜单验收&lt;/a&gt;：最终二级菜单的生产任务与截图。&lt;/li&gt;
&lt;/ul&gt;&lt;/section&gt;&lt;section&gt;&lt;h2&gt;21. 最常用的操作清单&lt;a href=&quot;#21-最常用的操作清单&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;section&gt;&lt;h3&gt;只改标题、壁纸、主题色或公告&lt;a href=&quot;#只改标题壁纸主题色或公告&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;打开 Firefly Admin&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;-&amp;gt; 对应配置分区&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;-&amp;gt; 修改并保存草稿&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;-&amp;gt; 发布配置&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;-&amp;gt; 如果字段要求重建，再到发布中心提交重建&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;新增并上线一篇文章&lt;a href=&quot;#新增并上线一篇文章&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;文章管理 -&amp;gt; 新建文章&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;-&amp;gt; 编辑正文和元数据&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;-&amp;gt; 保存草稿&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;-&amp;gt; 可选：生成私密网站预览&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;-&amp;gt; 提交发布任务&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;6&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;-&amp;gt; 等待“已上线”&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;服务器空间不足&lt;a href=&quot;#服务器空间不足&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;先查看发布中心是否有 building/deploying 任务&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;-&amp;gt; 打开“快照管理 -&amp;gt; 服务器备份”或“存储空间 -&amp;gt; 服务器构建备份”&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;-&amp;gt; 扫描服务器并查看清理计划（dry-run）&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;-&amp;gt; 保留当前线上版本和回滚版本&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;-&amp;gt; 再清理旧构建工作区和日志&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;/section&gt;&lt;section&gt;&lt;h3&gt;修改“关于我”并上线&lt;a href=&quot;#修改关于我并上线&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;&lt;div&gt;&lt;figure&gt;&lt;figcaption&gt;&lt;/figcaption&gt;&lt;pre&gt;&lt;code&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;1&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;关于我与独立页面 -&amp;gt; 编辑关于我&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;2&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;-&amp;gt; 修改 Markdown 正文&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;3&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;-&amp;gt; 保存草稿&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;4&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;-&amp;gt; 提交任务 -&amp;gt; 发布&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;5&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;&lt;span&gt;-&amp;gt; 等待发布中心显示“已上线”&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/figure&gt;&lt;/div&gt;&lt;p&gt;记住：&lt;strong&gt;保存草稿、发布配置、重建网站、已上线是不同状态&lt;/strong&gt;。运行时配置发布后即可由网站读取；需要重建的配置和正文，须等待相应服务器任务完成。“已保存”不代表访客已经看到改动。&lt;/p&gt;&lt;/section&gt;&lt;/section&gt;&lt;/section&gt;</content:encoded></item><item><title>Firefly Admin 生产联调</title><link>https://bytefun.site/posts/firefly-admin-phase4-verification/</link><guid isPermaLink="true">https://bytefun.site/posts/firefly-admin-phase4-verification/</guid><description>第四阶段生产构建、索引一致性与回滚验收。</description><pubDate>Fri, 18 Sep 2026 17:23:56 GMT</pubDate><content:encoded>&lt;section&gt;&lt;h2&gt;生产发布验收&lt;a href=&quot;#生产发布验收&quot;&gt;&lt;span&gt;#&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;这篇文章用于验证 Firefly Admin 到腾讯云服务器的真实构建与发布流程。&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;原生应用保存远程草稿&lt;/li&gt;
&lt;li&gt;服务器读取固定内容和配置快照&lt;/li&gt;
&lt;li&gt;Astro 生成正文、RSS、站点地图与搜索索引&lt;/li&gt;
&lt;li&gt;验收后通过发布中心回滚，保留历史版本&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;验收标记：FIREFLY_PHASE4_PRODUCTION_20260918&lt;/strong&gt;&lt;/p&gt;&lt;/section&gt;</content:encoded></item></channel></rss>