Use UUID models and soft deletion, persist file relationships with deduplicated monthly MinIO objects, and add admin file management. Update mini-program media handling and add local dev configuration.
本地 dev 调试
在 past-go/ 目录执行 make dev,使用 config.dev.yaml 启动,监听 :8080。
本地配置包含 AppSecret,已加入 Git 忽略;新环境可复制 config.dev.example.yaml 后填写。
管理端地址:http://localhost:8080/backend/admin/。
小程序 weapp/config/env.js 根据微信运行版本选择地址:开发版为 http://127.0.0.1:8080/api,体验版/正式版为线上地址。
开发工具需关闭合法域名校验(项目已设置);真机调试将 dev 地址改为电脑的局域网 IP。
小程序 AppID 为 wxb463820bf36dd5d6,AppSecret 仅存放在后端本地配置。
dev 继续使用当前 past-go 数据库与 MinIO bucket,并非独立测试数据。
日志和缓存写入 run/dev/data/,定时补发通知关闭。
新小程序的订阅模板和虚拟支付参数需在对应平台获取后填写,dev 配置暂时留空。
PostgreSQL / GORM 数据层(当前版本)
数据库为 192.168.100.127:5432/past-go,账号 root;连接配置见 config.example.yaml。
复制为本地 config.yaml 并填写微信配置。启动时先连接 postgres 管理库检查并创建目标库,再执行 GORM AutoMigrate。
也可以只运行迁移:
go run ./cmd/migrate -config config.yaml
模型定义在 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、数据和索引。
新增、修改、删除通过 GORM 模型执行;复杂报表通过 GORM Raw 执行,并统一过滤所有关联表及子查询中的 deleted_at。
删除保留原行及附件;活跃记录的唯一索引带 WHERE deleted_at IS NULL,删除后可以重新创建同业务键的记录。
用户对外的六位展示编号是独立业务字段,继续使用数据库序列分配;它不是 UUID 主键。情侣空间编号为 CP + 不带连字符的情侣 UUID。
本次创建的是新的 PostgreSQL 库,不会导入旧 MySQL 数据。历史备份如需迁入,需要单独完成数据转换和旧 ID 到 UUID 的关联映射。
验证:go test ./...、go vet ./...;在设置 PAST_TEST_POSTGRES_DSN 后,可运行 go test ./internal/store -run TestPostgresIntegration -v 验证真实 PostgreSQL(测试数据全部回滚)。
MinIO 配置读取 minio 节点。past_files 保存 UUID、size、suffix、content_type、object_key、md5、sha256、url、bucket 等元数据;对象键格式为 YYYY/MM/<md5>.<suffix>。同内容并发上传通过 PostgreSQL 锁和唯一索引去重,不重复上传对象。
头像、相册封面、照片、打卡图片和背景使用带外键的文件 ID 字段;日记/记忆日图片使用 past_record_file 按 position 保存多图顺序。旧接口的路径字段在数据库中仅保存 ID 镜像,响应时解析为稳定文件访问地址;新请求可直接提交 fileId、avatarFileId、coverFileId、imageFileIds 等字段。past_file_upload 独立记录每个上传用户,既保留共享去重,也保证权限与容量统计正确。
上传成功返回 fileId、path、url、file、duplicate。/api/files/:fileId 生成短期 MinIO 签名链接,维持原图片的可访问方式,不修改 bucket 的公共访问策略。删除业务关联只做逻辑删除,不删除共享对象。容量检查在内容去重后于事务内执行,同文件不会重复占用同一空间的额度。
后台 文件管理(/backend/admin/files)通过管理员接口 /api/adminFiles 查看全部文件、上传用户、预览、对象路径及元数据,支持关键词、类型、日期筛选和分页。普通用户不能调用文件管理接口。
真实 PostgreSQL/MinIO 回归:设置 PAST_TEST_POSTGRES_DSN 后运行 go test ./...。测试读取本地 config.yaml 中的 MinIO 连接,可通过 PAST_TEST_CONFIG 指定其他配置文件的绝对路径,使用隔离的 schema/bucket,测试结束清理;微信/地图外部请求使用模拟依赖。
以下保留历史说明,数据库配置与部署步骤以以上内容为准。
我们past后端(Go 版)
backend/api/index.php 的 Go 重写:Gin + GORM + PostgreSQL,管理后台(React)通过 embed 打进同一个二进制。
小程序与管理后台统一使用驼峰 /api/接口名(如 /api/periodList),请求参数与响应字段同样使用驼峰。业务值与鉴权延续现有约定。旧 PHP 风格入口继续兼容已发布客户端。
本次 Nginx 与部署说明见 deploy/README.md。
目录
cmd/server/ 入口
internal/config/ config.yaml 读取
internal/store/ GORM 数据访问、PostgreSQL 自动迁移与逻辑删除
internal/httpapi/ gin 路由、Ctx($_GET/$_POST/$input/$_FILES 等价物)、鉴权
internal/handler/ 121 个 action,按模块拆分(user/couple/timeline/album/diary/songs/checkin/period/pet/misc/admin)
internal/upload/ MinIO 上传、MD5 去重、日期目录与签名访问
internal/wechat/ access_token / 内容安全 / 订阅消息 / jscode2session
internal/geo/ 腾讯位置服务
internal/notify/ cron_notify.php 的进程内定时版
web/admin/ React 管理后台(dist/ 被 embed)
运行
cp config.example.yaml config.yaml # 填写数据库 / 微信配置
go build -o past-server ./cmd/server
./past-server -config config.yaml
运行目录布局(data_dir,默认为二进制所在目录):
data_dir/
├── uploads/ 用户上传文件(从 PHP 的 backend/uploads 原样迁移)
└── data/ access_token.cache 等
URL 映射:
| URL | 说明 |
|---|---|
/api/接口名 |
小程序、管理后台、上传统一入口 |
/backend/api/index.php?action=… |
旧客户端兼容入口 |
/backend/uploads/… |
上传文件静态服务(对应 DB 中 uploads/… 路径) |
/backend/admin/ |
管理后台 SPA |
/healthz |
健康检查 |
与 PHP 版的差异(有意为之)
见 ../dev/API_CONTRACT.md 与对比测试 ../dev/apidiff.py。已知的 PHP 原有 bug 处理:
*_add接口返回的id改为真实记录 id(PHP 返回的是 activity_log 的 id)。pet_dynamics分页可用(PHP 因LIMIT '20'语法错误恒 500)。- 宠物成就解锁可用(PHP 因
pet_dynamics.user_id=0违反外键恒 500)。 logout会真正失效 token;登录不再踢掉其它设备的 token。- 数据库迁移只在启动时执行一次(PHP 每次请求执行)。