From abe543d4b2e03562d82663b1252db95cc84a605a Mon Sep 17 00:00:00 2001 From: Blizzard Date: Wed, 4 Nov 2026 21:32:39 +0800 Subject: [PATCH] docs: document Linux and BaoTa deployment workflow Add a root README and a current deployment guide covering local setup, versioned Linux packaging, manual BaoTa updates with backups and rollback, production verification, and miniapp API_BASE configuration. --- README.md | 23 +++ past-go/README.md | 8 +- past-go/deploy/README.md | 331 +++++++++++++++++++++++++++++++-------- 3 files changed, 295 insertions(+), 67 deletions(-) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..8df7491 --- /dev/null +++ b/README.md @@ -0,0 +1,23 @@ +# 我们 past + +微信小程序、Go 后端与管理端共用此仓库。Go 模块位于 `past-go/`,不是仓库根目录;管理端构建后嵌入后端二进制。 + +| 目录 | 用途 | +| --- | --- | +| `weapp/` | 微信小程序 | +| `past-go/` | Go 后端、配置模板和 Makefile | +| `past-go/web/admin/` | React 管理端 | +| `deploy/linux/` | 当前生产 systemd 服务和 Nginx 配置参考 | + +## 开发与部署 + +**协同开发请先阅读 [Linux / 宝塔部署文档](past-go/deploy/README.md)**:包含首次准备、本地开发、打包上传、备份更新、线上验证和回滚命令。 + +- [后端配置与业务说明](past-go/README.md) +- [Windows 部署说明](past-go/deploy/windows/README.md)(当前生产环境使用 Linux) + +生产域名:`https://we.sundynix.cn`;管理端:`https://we.sundynix.cn/backend/admin/login`。 + +小程序 `weapp/config/env.js` 只导出 `API_BASE`,不自动判断环境。开发时手动填本机或局域网地址,上传体验版、正式版前改成 `https://we.sundynix.cn/api`。 + +真实 `config.yaml`、`config.dev.yaml` 和支付证书不会随 Git 下发。新成员需向项目负责人领取配置与证书,或从示例文件配置自己的开发环境;现有服务器更新时保留线上配置、证书及数据。 diff --git a/past-go/README.md b/past-go/README.md index 2503bf6..8a3fdd5 100644 --- a/past-go/README.md +++ b/past-go/README.md @@ -1,3 +1,7 @@ +# 我们 past 后端 + +开发、打包、宝塔更新、验证与回滚步骤见 **[Linux / 宝塔部署文档](deploy/README.md)**。仓库总览见 [根目录 README](../README.md)。以下为配置与业务说明。 + # 微信支付 API v3 空间会员通过微信小程序 `wx.requestPayment` 支付,服务端使用官方 `wechatpay-go` SDK(与 plant-go 同样采用微信支付公钥验签模式)。线上域名为 `we.sundynix.cn`。 @@ -8,7 +12,7 @@ 接口: -- `POST /api/storageCreateOrder`:传 `planKey: month/year`;价格由服务端收费设置决定。先持久化订单,再调用预下单,返回 `outTradeNo` 与 `payment` 签名参数。 +- `POST /api/storageCreateOrder`:传服务端当前上架套餐的 `planKey`(见 `storageInfo`),并携带页面取得的 `expectedPriceCents` 和 `expectedPlanVersion`;价格由服务端收费设置决定。先持久化订单,再调用预下单,返回 `outTradeNo` 与 `payment` 签名参数。 - `GET /api/storageOrderStatus?outTradeNo=...`:仅允许查询本人订单,必要时向微信主动查单并补开通。 - `POST https://we.sundynix.cn/api/wechatPayNotify`:无需用户登录,通过微信支付签名校验、APIv3 AES-GCM 解密后核对商户、AppID、付款人、金额和币种;数据库事务提交后返回 204。 @@ -57,7 +61,7 @@ MinIO 配置读取 `minio` 节点。`past_files` 保存 UUID、size、suffix、c 头像、相册封面、照片、打卡图片和背景使用带外键的文件 ID 字段;日记/记忆日图片使用 `past_record_file` 按 position 保存多图顺序。旧接口的路径字段在数据库中仅保存 ID 镜像,响应时解析为稳定文件访问地址;新请求可直接提交 `fileId`、`avatarFileId`、`coverFileId`、`imageFileIds` 等字段。`past_file_upload` 独立记录每个上传用户,既保留共享去重,也保证权限与容量统计正确。 -上传成功返回 `fileId`、`path`、`url`、`file`、`duplicate`。`/api/files/:fileId` 生成短期 MinIO 签名链接,维持原图片的可访问方式,不修改 bucket 的公共访问策略。删除业务关联只做逻辑删除,不删除共享对象。容量检查在内容去重后于事务内执行,同文件不会重复占用同一空间的额度。 +上传成功返回 `fileId`、`path`、`url`、`file`、`duplicate`。`/api/files/:fileId` 由后端通过短期 MinIO 签名请求代理读取文件,返回稳定访问地址,并提供图片缓存与 ETag 条件请求,不修改 bucket 的公共访问策略。删除业务关联只做逻辑删除,不删除共享对象。容量检查在内容去重后于事务内执行,同文件不会重复占用同一空间的额度。 后台 **文件管理**(`/backend/admin/files`)通过管理员接口 `/api/adminFiles` 查看全部文件、上传用户、预览、对象路径及元数据,支持关键词、类型、日期筛选和分页。普通用户不能调用文件管理接口。 diff --git a/past-go/deploy/README.md b/past-go/deploy/README.md index e784f34..1c0a483 100644 --- a/past-go/deploy/README.md +++ b/past-go/deploy/README.md @@ -1,98 +1,299 @@ -# PostgreSQL / GORM 数据层(当前版本) +# Linux / 宝塔部署文档 -数据库为 `192.168.100.127:5432/past-go`,账号 `root`;连接配置见 `config.example.yaml`。 -复制为本地 `config.yaml` 并填写微信配置。启动时先连接 `postgres` 管理库检查并创建目标库,再执行 GORM AutoMigrate。 -也可以只运行迁移: +本文是当前部署入口,适用于 PostgreSQL + Redis + MinIO + 微信支付 API v3。以下操作在本地构建后,通过宝塔「文件」上传,再在宝塔「终端」手动执行;不需要配置计划任务,也不要求开发人员拥有 SSH。 -```sh -go run ./cmd/migrate -config config.yaml +## 1. 当前环境与目录 + +| 项目 | 当前生产值 | +| --- | --- | +| 系统 / 架构 | Ubuntu 24,Linux amd64 | +| 服务器 | `103.231.12.59` | +| 域名 | `https://we.sundynix.cn` | +| API | `https://we.sundynix.cn/api` | +| 管理端 | `https://we.sundynix.cn/backend/admin/login` | +| 部署目录 | `/home/workspace` | +| systemd 服务 | `past-go.service` | +| 后端监听 | `127.0.0.1:8081`,由 Nginx 代理 | +| PostgreSQL | 服务器本机 `127.0.0.1:5432`,数据库 `past-go` | +| Redis | 服务器本机,具体认证、DB 和前缀以线上配置为准 | +| 文件存储 | MinIO,连接和 bucket 以线上配置为准 | +| Nginx 站点配置目录 | `/www/server/panel/vhost/nginx/` | + +服务器目录: + +```text +/home/workspace/ +├── past-server # Linux 可执行文件,内含管理端静态资源 +├── config.yaml # 生产配置,不在 Git 中 +├── cert/ # 微信支付私钥、公钥及可选商户证书 +├── log/YYYY-MM-DD/ # zap 按日期、级别生成的日志 +└── backups/ # 每次更新的旧程序、配置、数据库备份与发布包 ``` -模型定义在 `internal/model/models.go`,所有模型嵌入 `BaseModel`:`Id string`、`CreatedAt`、`UpdatedAt`、`DeletedAt`。 -主键与关联 ID 使用 PostgreSQL `uuid` 类型;主键默认 `gen_random_uuid()`,不自增。 -表名统一为 `past_` + 单数 snake_case(例如 `User` → `past_user`、`DiaryComment` → `past_diary_comment`);字段按 `UserId` → `user_id` 命名。 -启动时会将旧 `past-` 前缀的表无损重命名为 `past_`,保留 UUID、数据和索引。 +管理端无需单独部署到 Nginx 网站根目录。上传图片保存在 MinIO,不能通过清理服务器本地文件夹来清理用户文件。 -新增、修改、删除通过 GORM 模型执行;复杂报表通过 GORM Raw 执行,并统一过滤所有关联表及子查询中的 `deleted_at`。 -删除保留原行及附件;活跃记录的唯一索引带 `WHERE deleted_at IS NULL`,删除后可以重新创建同业务键的记录。 -用户对外的六位展示编号是独立业务字段,继续使用数据库序列分配;它不是 UUID 主键。情侣空间编号为 `CP` + 不带连字符的情侣 UUID。 +## 2. 首次拉取与本地开发 -本次创建的是新的 PostgreSQL 库,不会导入旧 MySQL 数据。历史备份如需迁入,需要单独完成数据转换和旧 ID 到 UUID 的关联映射。 +本地需要 Git、Go(以 `past-go/go.mod` 的版本为准)、make、Node.js 和 npm。当前管理端 Vite 要求 Node `^20.19.0 || >=22.12.0`;实际依赖以锁文件和安装时提示为准。 -验证:`go test ./...`、`go vet ./...`;在设置 `PAST_TEST_POSTGRES_DSN` 后,可运行 `go test ./internal/store -run TestPostgresIntegration -v` 验证真实 PostgreSQL(测试数据全部回滚)。 +从仓库根目录执行: -以下保留历史说明,数据库配置与部署步骤以以上内容为准。 +```bash +cd past-go +cp config.dev.example.yaml config.dev.yaml +# 编辑 config.dev.yaml,补齐自己的开发配置,再继续: +make web +make dev +``` ---- +首次拉取没有 `web/admin/dist`,必须先执行 `make web`,否则 Go 的 `go:embed` 编译会报资源不存在。`make dev` 构建本机程序并使用 `config.dev.yaml` 启动,默认监听 `:8080`。 -# 20261008 原权限兼容与抽烟功能 +本地管理端:`http://127.0.0.1:8080/backend/admin/login`。 -## 当前行为 +开发配置需要填写: -- 日记、相册、记忆日、歌曲和普通打卡恢复原版按情侣成员作者查询;历史 couple_id 不再成为新增过滤条件。未绑定展示方式恢复原版。 -- 姨姨继续使用 period_records、period_daily_records、period_sex_records,恢复原版共享记录、来源选择和可见开关。启动不复制或切换姨姨表。此前创建的 personal_period_* 表保留,但本版不读写。 -- 照片响应保持原始 uploads/... 路径,不签名、不改成 /backend/uploads/...;上传静态文件恢复原访问方式,兼容正式版小程序。 -- 抽烟使用独立的 smoking_wallets 和 smoking_entries;消耗一支扣一支、买烟和别人递烟加库存、撤销操作保持事务和幂等。库存随账号保留。 -- 72 小时解绑冷静期继续保留:双方同意后开始计时,期间可取消,到期解除绑定且保留记录。其他数据权限按原版运行。 +- PostgreSQL:地址、端口、数据库、账号密码。启动会检查并创建目标库、执行 GORM AutoMigrate;账号需要对应权限。 +- Redis:地址、认证、DB、`key_prefix`。Redis 是启动依赖,连接失败时后端不会启动。 +- MinIO:endpoint、access/secret key、bucket、SSL 配置;文件通过 `/api/files/:fileId` 访问。 +- 微信:AppID、AppSecret、订阅消息模板 ID;AppSecret 只放后端。 +- `tencent_map_key`:用于地址解析等地图功能,沿用负责人提供的配置。 +- 微信支付:需要联调支付时填写商户配置和证书路径,否则在开发配置中关闭 `wechat_pay.enabled`。 -## 部署 +模板当前指向团队内网 PostgreSQL,不能将其误当成本机空库。团队需明确开发库和 bucket 的归属;使用独立环境时同时调整数据库、MinIO bucket、Redis DB 或前缀。不要把开发测试账号或配置导入生产环境。 -1. 在宝塔备份当前数据库和 uploads,保存原可运行 exe;停止现有 Go 服务。 -2. 仅替换 past-server.exe,保留现有 config.yaml、data_dir、uploads、data 和数据库。无需重新配置 Nginx,已正常工作的 uploads 转发继续使用。 -3. 启动时补齐抽烟表和冷静期字段;仅迁移旧抽烟库存与流水。smoking_records_v1=done 后不会重复;已经完成 account_records_v1 的环境也不会重新导入库存。不存在姨姨数据迁移。 -4. 先验证正式版日记、相册、照片、记忆日、歌曲、普通打卡和姨姨记录,再用新版小程序验证抽烟。 -5. 新版小程序的姨姨页面已同步恢复共享方式;抽烟需要上传新版小程序才能显示。 +开发前后可执行: -Go 全套和前端回归在本机执行;尚未在生产数据库或微信真机运行本版。历史 binlog 和检查报告显示原记录在库,不应通过清表或倒放日志部署本版。 +```bash +# 当前目录为仓库内的 past-go/ +go test ./... +go vet ./... +node --test ../weapp/tests/*.test.cjs +``` -以下为 20261005 历史说明,当前部署以以上步骤为准。 +真实 PostgreSQL / MinIO 测试是额外集成检查,配置方式见 [后端 README](../README.md)。普通 `go test ./...` 未设置集成环境变量时会跳过这部分测试。 ---- +## 3. 生产配置与首次准备 -# 20261005 UI 精修与驼峰 API 更新 +现有服务器更新直接进入第 4 节,不要重新初始化数据库或覆盖配置。 -## 部署顺序 +新服务器需准备 PostgreSQL、Redis、Nginx,以及可用的 MinIO bucket。由负责人提供真实生产 `config.yaml` 和支付证书;Git 中只有示例,不能直接用示例覆盖线上文件。 -1. 停止现有服务,备份原程序;用新 Windows AMD64 `past-server.exe` 替换程序。保留当前 `config.yaml`、`uploads`、`data` 和数据库。示例配置仅供参考,不要覆盖现有配置。 -2. 启动新程序。本次没有新增数据库迁移,保留此前生理期共享功能的数据结构。 -3. 如果上一版 `/api`、`/api/` 转发已配置并能访问,这次无需再改 Nginx:驼峰路径继续走同一段转发。附带配置已按你提供的 Nginx 使用 `127.0.0.1:8081`;保留现有 `/backend/` 与 uploads 缓存配置。 -4. 检查并重新加载 Nginx,已有配置不变时可以跳过。若调整配置,在你当前 Nginx 机器上检查后重新加载。 -5. 浏览器访问 `https://we.sundynix.cn/api` 应返回 API 名称与版本。未登录访问 `/api/coupleInfo` 应返回 401 JSON,不能是 Nginx HTML 404。 -6. 管理后台仍从 `/backend/admin/` 进入,新后台已嵌入程序,刷新页面、重新登录后确认 Network 请求为 `/api/adminStats` 等驼峰路径。 -7. 微信开发者工具打开包里的 `weapp`;request/uploadFile 合法域名仍为 `https://we.sundynix.cn`。重新编译、真机预览,再上传小程序新版本。 +关键配置: -## 接口规则 +```yaml +listen: "127.0.0.1:8081" +data_dir: "/home/workspace" +debug: false +``` -- 请求地址:`/api/接口名`,例如 `/api/periodList`、`/api/diaryList?page=1&pageSize=20`。 -- 小程序、管理后台、上传统一使用新路径;不再附加 GET `_t`。 -- 例:`POST /api/periodUpdate`,JSON `{ "id": "314", "cycleLength": 25, "periodLength": 5, "startDate": "2026-09-27", "endDate": "2026-10-01" }`。 -- 路径、查询参数、JSON 请求与响应字段统一 lowerCamelCase,例如 `cycleLength`、`periodVisible`、`canAccess`。Multipart 表单字段同样为驼峰。字段值、请求方法和鉴权延续原业务约定。 -- 后端及两个客户端在网络边界转换字段名,内部数据库和页面数据模型保持既有结构。旧 PHP 入口与带下划线的旧路径继续兼容。API 响应 `Cache-Control: no-store`;后台请求使用 `cache: no-store`。 -- Bearer、上传 token 与后台同源 Cookie 仍有效。上传继续携带兼容 Android 的 token/action 表单项。 -- 原 PHP 风格入口继续兼容已发布旧小程序。媒体与后台静态地址仍在 `/backend/` 下。 +其他节点按环境填写 `db`、`redis`、`minio`、`wechat`、`wechat_pay` 和地图 key。生产 Redis 使用独立前缀,例如 `past-go:prod:`。 -## 小程序验证 +当前 AppID 为 `wxb463820bf36dd5d6`。操作通知和打卡提醒共用模板: -- Android 与 iPhone:标题与微信胶囊不重叠,首屏和底部内容不被遮挡。 -- 首页:未绑定显示注册天数和邀请入口,绑定后显示在一起天数;解绑后首页、我的立即按接口更新。 -- 三个底部入口:首页、记录、我的;详情返回与发布、编辑流程正常。 -- 日记和相册:首次加载、空列表、网络失败分别展示;创建相册与上传照片正常。 -- 姨姨:对方可见单独操作;关闭自己的开关不能把自己锁住,权限由 API 判断。双方都有绑定前数据时仍选择唯一记录。 -- 改周期、持续天数、开始和结束日期保存后,重新进入展示服务端最新值。 +```yaml +wechat: + # appid、secret 使用负责人提供的真实值 + notify_template_id: "K_iQMwE_jre0j6QDVL78DZz7wiR1SKVY5h2YJCK6uPU" +``` -本地已检查 WXML/WXSS 编译、JS 语法、请求/上传 URL 与导航尺寸、Go 测试与管理后台构建;未替代真实微信设备和线上数据库联调。 +模板字段为 `thing1`、`time2`、`thing3`;若更换 AppID 或模板,需要同时更新后端配置和 `weapp/utils/subscribe.js`,并在对应小程序后台确认模板存在。 -## 本次 UI 精修 +微信支付回调应配置为: -小程序首页聚焦双人天数、四个入口和最近记录;记录页分组;日记、相册使用标题旁操作按钮;姨姨选中日期后展开当天操作;个人中心与设置分组。管理后台统一侧栏、页头、统计卡、列表、表格、弹层与登录页,沿用现有组件库。 +```text +https://we.sundynix.cn/api/wechatPayNotify +``` +支付证书路径相对于配置文件解析。商户私钥和微信支付公钥需要与配置匹配,`certificate_path` 是可选的商户证书校验配置。 -## Redis 与 zap(Linux) +systemd 模板在仓库根目录的 [`deploy/linux/past.service`](../../deploy/linux/past.service)。首次部署时复制到 `/etc/systemd/system/past-go.service`,执行: -服务器需安装 Redis 并启用 `redis-server.service`。Redis 仅监听本机 `127.0.0.1:6379` / `::1:6379`,服务配置通过 `redis.addr`、`password`、`db` 和 `key_prefix` 指定。生产前缀为 `past-go:prod:`,避免与开发缓存混用。systemd 服务依赖 PostgreSQL 与 Redis,更新后执行 `systemctl daemon-reload` 和 `systemctl restart past-go`。 +```bash +systemctl daemon-reload +systemctl enable past-go +``` -`data_dir: /home/workspace` 时,zap 自动创建 `/home/workspace/log/YYYY-MM-DD/`,按级别记录 JSON 日志,HTTP 访问日志不记录请求正文、认证头或查询参数。保留天数、文件大小、压缩备份数量由 `log` 配置指定。旧 `data/go-server.log` 与 `data/access_token.cache` 不再读写。 +服务使用 `www:www` 运行:程序权限 `750 root:www`,配置建议 `600 www:www`;`cert/` 及其私钥必须可被 `www` 读取,运行目录必须允许 `www` 创建日志和临时文件。程序上传并完成配置后,再执行 `systemctl start past-go`。 -若 Ubuntu Redis 提示 `libjemalloc.so.2: failed to map segment`,先检查 `ldd /usr/bin/redis-server`:当前服务器的 `/usr/local/lib` 中有同名库,通过 Redis 的 systemd drop-in 设置 `Environment=LD_LIBRARY_PATH=/usr/lib/x86_64-linux-gnu` 使用系统自带库,保留原有 `NoExecPaths` 等沙箱限制。 +新数据库会初始化管理员 `past / past`;已有数据库正常启动不会重置管理员密码。 -已有管理员可通过 `past-server -config config.yaml -reset-admin` 显式重置为 `past / past`;新数据库也使用该默认账号。普通启动不会重置密码。 +## 4. 本地生成 Linux 发布包 + +以下命令从仓库根目录开始。默认目标是当前生产 Linux amd64;不要将 macOS 本机构建的程序上传到 Linux。 + +```bash +cd past-go +past_version="$(date +%Y%m%d-%H%M%S)-$(git rev-parse --short HEAD)" + +# 重新构建管理端并嵌入后端,避免后台静态资源仍是旧版。 +make all GOOS=linux GOARCH=amd64 VERSION="$past_version" +go test ./... +go vet ./... +node --test ../weapp/tests/*.test.cjs + +past_package="dist/releases/$past_version" +mkdir -p "$past_package" +cp dist/past-server-linux-amd64 "$past_package/past-server" +printf '%s\n' "$past_version" > "$past_package/VERSION" +(cd "$past_package" && shasum -a 256 past-server > SHA256SUMS) +tar -czf dist/past-release.tar.gz -C "$past_package" \ + past-server VERSION SHA256SUMS +``` + +产物:`past-go/dist/past-release.tar.gz`。建议提交代码后打包,使版本号中的提交 ID 可以追溯;发布时记录是否含未提交改动。 + +只修改后端或管理端,需要更新服务器二进制;只修改小程序页面,则重新编译、上传小程序即可。涉及接口变更时,先部署兼容的新后端,再上传小程序。 + +## 5. 宝塔上传与更新现有服务器 + +在宝塔「文件」进入 `/home/workspace`,上传上一节生成的 `past-release.tar.gz`。先确认上传成功,再进入宝塔「终端」。 + +下面的命令**仅适用于第 4 节生成的发布包格式**,不要直接用于历史 `past-server.new + manifest.json` 发布包。数据库参数应与服务器现有 `config.yaml` 一致;命令会交互询问数据库密码,不会改动线上配置、证书或已有业务数据。 + +在宝塔终端整段粘贴执行: + +```bash +bash <<'DEPLOY' +set -euo pipefail +umask 077 +cd /home/workspace + +# 根据现有 config.yaml 核对这四项。 +past_db_host=127.0.0.1 +past_db_port=5432 +past_db_name=past-go +past_db_user=root + +test -f past-release.tar.gz +test -f past-server +test -f config.yaml +mkdir -p backups +past_backup=$(mktemp -d /home/workspace/backups/release-XXXXXX) +mkdir "$past_backup/release" +cp -a past-server "$past_backup/past-server.before" +cp -a config.yaml "$past_backup/config.before.yaml" +read -r -s -p 'PostgreSQL password: ' past_db_password < /dev/tty +printf '\n' +PGPASSWORD="$past_db_password" pg_dump \ + -h "$past_db_host" -p "$past_db_port" -U "$past_db_user" \ + -d "$past_db_name" -Fc --no-owner --no-acl \ + -f "$past_backup/database.before.dump" +unset past_db_password + +tar -xzf past-release.tar.gz -C "$past_backup/release" \ + past-server VERSION SHA256SUMS +(cd "$past_backup/release" && sha256sum -c SHA256SUMS) +past_version=$(cat "$past_backup/release/VERSION") +install -o root -g www -m 750 \ + "$past_backup/release/past-server" ./past-server.next + +past_switched=0 +rollback() { + past_status=$? + if [ "$past_switched" = 1 ]; then + echo '部署失败,恢复原程序' + systemctl stop past-go || true + cp -a "$past_backup/past-server.before" ./past-server.next + mv -f ./past-server.next ./past-server + systemctl start past-go || true + fi + exit "$past_status" +} +trap rollback EXIT + +past_switched=1 +systemctl stop past-go +mv -f ./past-server.next ./past-server +systemctl start past-go + +past_ready=0 +for attempt in $(seq 1 40); do + if curl -fsS --max-time 2 http://127.0.0.1:8081/healthz | grep -qx 'ok'; then + past_ready=1 + break + fi + sleep 1 +done +test "$past_ready" = 1 +./past-server -version | grep -Fx "past-server $past_version" +systemctl is-active --quiet past-go +past_switched=0 + +mv past-release.tar.gz "$past_backup/" +echo "部署成功:$past_version" +echo "备份目录:$past_backup" +systemctl is-active past-go +DEPLOY +``` + +出现 `部署成功` 和 `active` 才表示本机启动检查通过。启动等待期间短暂出现 `curl: (7)` 是轮询结果;若最终失败,应检查错误和服务日志,不能只凭文件已上传就判断部署完成。 + +该命令备份 PostgreSQL 的一致性快照,并在更新失败时恢复旧程序。**不会自动回滚数据库迁移**;涉及不兼容表结构变更的版本,需单独制定数据库迁移、停写和恢复方案。不要在上线失败后直接覆盖或恢复正在写入的生产数据库。 + +## 6. 上线验证与排查 + +```bash +/home/workspace/past-server -version +systemctl status past-go --no-pager +curl -fsS http://127.0.0.1:8081/healthz +curl -fsS https://we.sundynix.cn/healthz +curl -I https://we.sundynix.cn/ +journalctl -u past-go -n 100 --no-pager +``` + +核对以下功能: + +- 公网 `/healthz` 返回 `ok`,根路径跳转管理端登录页。 +- 管理员可登录,公告、存储套餐和文件列表能正常加载。 +- 已绑定用户的记录功能正常;未绑定用户点击记录、更多、存储入口会提示邀请绑定,后端记录接口返回绑定权限错误。 +- 图片能访问;稳定文件地址 `/api/files/:fileId` 保留缓存与条件请求能力。 +- 打卡页能读取账号保存的抽烟显示开关,位置在「我的 → 更多」。 +- 涉及支付改动时,用负责人指定的测试套餐和真实微信用户验证支付回调、主动查单与权益到账;不要依靠前端支付成功提示判断入账。 + +启动失败优先检查 PostgreSQL、Redis、MinIO、支付证书路径与文件权限。业务日志在 `/home/workspace/log/YYYY-MM-DD/`;`journalctl` 可看到服务启动阶段的错误。 + +Nginx 只有在域名、监听端口或代理规则变化时才需调整。通过宝塔「文件」编辑 `/www/server/panel/vhost/nginx/` 内实际站点配置,保留 SSL 和证书续签配置,不在网站表单中覆盖整份配置。代理规则参考 [`deploy/linux/nginx-past.conf`](../../deploy/linux/nginx-past.conf)。修改后执行: + +```bash +/www/server/nginx/sbin/nginx -t +# 只有上一条检查成功后,才执行: +/www/server/nginx/sbin/nginx -s reload +``` + +## 7. 手动回滚程序 + +选择本次更新输出的真实备份目录。确认本版数据库仍兼容旧程序后,在宝塔终端执行: + +```bash +past_backup='/home/workspace/backups/替换为实际备份目录' +test -f "$past_backup/past-server.before" && \ + install -o root -g www -m 750 \ + "$past_backup/past-server.before" /home/workspace/past-server.rollback && \ + systemctl stop past-go && \ + mv -f /home/workspace/past-server.rollback /home/workspace/past-server && \ + systemctl start past-go +systemctl status past-go --no-pager +curl -fsS http://127.0.0.1:8081/healthz +``` + +备份中的 `config.before.yaml` 和 `database.before.dump` 留作必要时人工恢复,不在程序回滚时默认覆盖配置或数据库。 + +## 8. 小程序发布 + +微信开发者工具打开仓库内 `weapp/`。`weapp/config/env.js` 仅导出 `API_BASE`,不会自动区分开发版、体验版和正式版: + +```js +// 本地开发或真机联调:填写开发机地址。 +const API_BASE = 'http://192.168.100.3:8080/api'; +module.exports = { API_BASE }; +``` + +上传体验版或正式版前,将这一行改为: + +```js +const API_BASE = 'https://we.sundynix.cn/api'; +``` + +重新编译,确认小程序 AppID、接口地址和隐私协议配置,真机验证后再上传。在微信后台配置正式 request / uploadFile / downloadFile 合法域名 `https://we.sundynix.cn`;若某功能直接访问其他域名的对象或外部图片,需要同时核对该实际域名的配置。 + +每次发布同时记录后端版本、小程序版本和验证结果,避免协同开发时把本地测试地址随代码上传到正式版。