# 架构与技术决策记录(ADR) > 状态:Accepted > 决策日期:2026-09-03 > 决策人:产品负责人 > 背景:项目正式启动第一版(第一迭代「真实登录纵切」),基于 `iteration-1-reports/` 六份开工前分析报告确认以下决策。 ## ADR-001 升级 Spring Boot 3 后再开发业务代码 **决策**:在编写第一迭代业务代码之前,先将 `patbond-api` 从 Spring Boot 2.7 升级到 Spring Boot 3(JDK 17 基线),升级工作时间盒为 1-2 天。 **理由**: - 当前业务代码不足 10 个类,迁移成本处于历史最低点;随业务增长成本只会上升。 - 本迭代要新引入的 JWT、Flyway(PostgreSQL 16+)、Testcontainers、springdoc 在 Boot 2.7 下均为降级选型,按 2.7 编写等于主动制造返工。 - Spring Boot 2.7 / Spring Cloud 2021 已进入旧技术代际(开发计划第 11 节风险 8)。 **影响**:`javax.*` → `jakarta.*` 命名空间迁移;依赖版本随 Boot 3 BOM 统一管理。 ## ADR-002 MVP 阶段移除 Nacos,微服务化阶段再引入服务发现 **决策**:MVP 阶段从 `patbond-api` 移除 Nacos(服务发现与配置中心)。`patbond-auth` 调用 `patbond-user` 改为通过配置注入的静态地址: ```java @FeignClient(name = "patbond-user", url = "${patbond.user-service.url}") ``` **理由**: - MVP 只有 auth/user 两个服务,服务发现解决的是「服务多、地址动态」的问题,当前并不存在。 - 移除后干净检出即可启动,消除本地开发和 CI 对 Nacos 实例的硬依赖。 - 升级 Boot 3 后原 Spring Cloud Alibaba 2021 版本线不再兼容,移除可避免本迭代被版本配套拖住。 **回补路线(重要)**:本决策是阶段性的,不是永久放弃。在后续真正拆分微服务(多服务、多实例、地址动态)时,重新引入服务发现: 1. 选用与当时 Spring Boot / Spring Cloud 版本配套的 Spring Cloud Alibaba 版本线(Boot 3 对应 2022/2023+,不得沿用 2021 坐标)。 2. 加回 discovery 依赖与注册配置,删除 Feign 的 `url` 属性即可切回服务发现,调用方接口代码无需改动。 3. 届时同步评估配置中心是否一并启用。 **影响**:开发计划第 5.1、5.2、5.3 节中涉及 Nacos 的环境要求与启动步骤在 MVP 阶段不再适用,以本决策为准。 ## ADR-003 Token 有效期与多设备策略 **决策**: - Access token 有效期 15 分钟。 - Refresh token 有效期 30 天,每次刷新即轮换(rotation),旧 token 立即失效。 - 允许多设备并行会话;退出仅撤销当前会话。 - 上述值实现为配置项,不硬编码。 ## ADR-004 首版登录方式仅账号 + 密码 **决策**:第一版仅支持用户名 + 密码注册登录。不实现手机号登录、短信验证码和第三方登录,但凭证数据模型(`identity.user_credentials`)保留扩展能力,登录页 UI 预留不渲染的扩展区。 ## ADR-005 品牌色以 iOS 设计手稿为正典 **决策**:产品视觉以 `AI宠物_iOS_UI设计稿.html`(珊瑚橙主色 `#FF6F4C`、奶油底、暖色系)为品牌正典。`patbond-flutter` 当前的靛蓝 `#4F46E5` 主题属早期脚手架占位实现,正式启动后迁移到手稿色系。 **补充规范**(详见 `iteration-1-reports/04-ui-login-design-spec.md`): - 主题以语义 token 组织(primary / canvas / ink / error 等),集中在单一主题文件。 - 新增 error 色 `#D0342C`(设计稿与现有主题均缺失)。 - 实心按钮使用加深的 `primaryStrong #D6431A` 以满足 WCAG AA 对比度;原珊瑚橙 `#FF6F4C` 用于装饰与非文字承载场景。 ## ADR-006 测试与交付容器化策略 **决策**(2026-09-04): - 自动化测试中的数据库一律通过 Testcontainers 使用 Docker 临时容器(`postgres:18`,版本基线见 ADR-008),不依赖开发者本机数据库;每次测试在干净实例上执行全量 Flyway 迁移。 - 最终交付将提供 Docker 镜像/编排包(对应开发计划 M6 的容器镜像项)。 - 开发者本人手动测试/联调时可使用自己本机的 PostgreSQL,连接信息经环境变量注入,不入库。 **理由**:测试可复现、与目标版本(PostgreSQL 16)对齐、不受本机数据库账号/版本差异影响;交付形态与测试基础设施统一到 Docker。 ## ADR-007 部署形态:容器化应用 + 分阶段数据库策略 **决策**(2026-09-04): - 应用(auth、user 及后续模块)以 Docker 容器交付部署,**容器保持无状态**:文件走对象存储、会话在数据库,任何状态不落容器本地。 - **MVP 阶段**:数据库使用 Docker 容器运行 PostgreSQL(数据挂载 volume 持久化),与应用同机以 docker compose 编排;配套每日 `pg_dump` 备份到独立存储,并演练过恢复流程。 - **规模化阶段**:当用户量与数据重要性上升后,数据库迁移至云托管数据库(RDS 类)或独立数据库服务器,应用容器不动。 - 数据库连接信息始终经环境变量注入(`PATBOND_DB_URL` 等),保证迁移数据库时应用层零改动。 **理由**:双人团队运维预算有限,容器数据库 + volume + 备份在 MVP 阶段完全够用,且与 Testcontainers 测试、Docker 交付包(ADR-006)同一体系;把高可用、故障转移等重运维在需要时外包给云托管,是成本与可靠性的最优路径。守住「应用无状态」这一条纪律,数据库放哪都可随时更换。 **注意**:数据库大版本升级即使在 Docker 中也需要数据迁移(`pg_upgrade` 或 dump/restore),属 ADR 级决策,不随镜像标签随意变更;小版本安全更新随镜像自动跟进。 ## ADR-008 PostgreSQL 版本基线定为 18 **决策**(2026-09-04):数据库版本基线从开发计划最初的「PostgreSQL 16+」明确定为 **PostgreSQL 18**。Testcontainers 测试镜像、未来的 compose 编排与交付镜像统一锁 `postgres:18`。 **理由**: - 项目尚无生产数据,大版本选择处于零成本窗口;一旦有数据,大版本升级即为一次真实迁移(见 ADR-007 注意事项)。 - PostgreSQL 18 已是发布满一年的稳定版本,与团队本机开发库(18.6)一致,消除本机与基线的版本偏差。 - 不违背开发计划「16+」的原始约束。 **验证**:切换当日 `./mvnw clean test` 全量 37 测试在 postgres:18(18.6)容器上通过,Flyway V1 baseline 迁移执行无兼容问题。 **影响**:后续大版本变更须以新 ADR 决策并附全量测试验证;数据库特性使用以 18 为可用上限参考。 ## ADR-009 M2 宠物健康档案新建 patbond-pet 模块 **决策**(2026-09-07):宠物与健康档案域在 `patbond-api` 内新建独立 Maven 模块 `patbond-pet` 承载,不并入 `patbond-user`。 **背景**:开工评估中 PM(iteration-2/01)建议新建模块,后端评估(iteration-2/02)建议 user 内独立包。用户裁定采用新建模块方案,为后续微服务化(ADR-002 预留方向)保持模块边界清晰。 ## ADR-010 照片/附件剪出 M2 **决策**(2026-09-07):宠物头像上传、疫苗证书与健康事件附件等 media 能力不进入 M2。头像 M2 阶段使用占位/预设方案。 **理由**:对象存储供应商未定(第一迭代 D4 遗留);后端 media 仅有表结构、上传流程零代码(iteration-2/02 评估)。待对象存储选型拍板后另立迭代实现。 ## ADR-011 分支策略:dev 为日常主干,master 为发布分支 **决策**(2026-09-07): - 日常开发一律只推 `dev` 分支。 - `master` 保留作为发布分支:正式版本发布时由 `dev` 合并至 `master`。 - 契约先行提交顺序沿用 iteration-2/08 规范:doc(openapi 独立提交)→ api → flutter;波次收尾三仓 commit + push + CI 绿才算闭环。 **备注**:iteration-2/08 建议的「Flyway 迁移、契约破坏性变更、依赖升级、两人并行期四类改动走短命分支 + PR 合入 dev」与本决策兼容,作为推荐实践保留,PR 目标分支为 `dev`。 ## ADR-012 M2 北极星指标与产品假设 **决策**(2026-09-07):采纳 iteration-2/06 定稿: - 北极星 = **7 日回访记录率**(分母:当 ISO 周产生生命周期首条 `health_record_create_succeeded` 的去重用户;分子:其中在首记日之后第 1–7 个 UTC 自然日内再次创建成功者;不含首记当日;首记日 +8 天出数)。 - 产品假设 H1–H4 及其判定阈值按 06 号报告冻结,上线前不再调整判定线。 - M2 不启动 A/B;按 06 号报告 8 项前置条件推进,目标 M3 末全绿、M4 首实验。 ## ADR-013 废弃 health_record_action 保留位 **决策**(2026-09-07):从后端 EventDictionary 白名单直接移除 `health_record_action`(客户端零引用,废弃零成本)。M2 事件按字典 v2(iteration-2/06)以具体事件落地。 **备注**:后续如出现新埋点需求,按 v1「结果编码进事件名」惯例新增具体事件,不复活通用 actionType 设计(多套指标共享分母、枚举扩充相互污染)。 ## ADR-014 设计债 DEBT-1 随 M2 偿还 **决策**(2026-09-07):TagPill 文字对比债(DEBT-1)随 M2 偿还,采用 iteration-2/05 的深变体映射方案(一行映射表 + 可选 `inkColor` 参数,既有调用零参数回归)。DEBT-2(muted 次级文字对比不足)M2 内按 05 号报告以既有正典色 `inkSoft` 局部规避,全局翻修另立决策。 ## ADR-015 照护人邀请流程后置出 M2 **决策**(2026-09-07):owner/caregiver/viewer 权限模型与校验进入 M2,但照护人邀请/绑定流程后置到后续迭代;M2 权限校验以测试数据覆盖三角色场景验证。 ## ADR-016 对象存储:自托管 MinIO 起步,预留迁云 **决策**(2026-09-08):M3 媒体存储采用**自托管 MinIO**(部署在现有腾讯云服务器,随 compose 编排),S3 兼容 API + 预签名直传;代码经存储适配层隔离供应商,本地开发与 Testcontainers 用同一 MinIO 镜像,三环境零分叉。 **背景**:现有腾讯云服务器仅含本地盘、未购对象存储(用户确认);后端评估(iteration-3/02)指出 Feed 图片下行将受限于单机公网带宽——此约束**接受为当前限制**并作为迁移触发条件:当图片下行带宽成为可感知瓶颈或预算允许时,迁移至云对象存储(COS 类,S3 API 兼容、适配层保证仅换配置与凭证)。本地磁盘直存方案违反 ADR-007 无状态容器纪律,排除。 ## ADR-017 社区模块归属与作者信息取数 **决策**(2026-09-08): - 社区域新建 Maven 模块 `patbond-community`(:8084),沿 ADR-009 先例(新模块 + 共库 + patbond-user 单迁移链)。 - media 上传流程实现在 `patbond-user`(横切基础能力、与 V1 media schema 同源,避免业务模块被反向依赖)。 - Feed/评论的作者公开信息(昵称/头像)由 community 模块**跨 schema 只读** identity 域取数(同库零网络开销);微服务化拆库时改为内部批量接口,与单迁移链同一演进逻辑。 ## ADR-018 M3 范围裁剪 **决策**(2026-09-08):M3 MVP = 图片媒体上传闭环 + 帖子草稿/发布/删除 + 公共 Feed 游标分页 + 单层评论 + 点赞/收藏幂等 + Flutter 三页(home/create/post_detail)替换 demo 与乐观更新回滚。关注做最小数据接口(follow/unfollow + 数量);**话题首版剪出**;评论仅单层不做楼中楼。视频后置。 ## ADR-019 写接口幂等形态按域选择 **决策**(2026-09-08):二元状态互动(点赞/收藏/关注)用 **PUT/DELETE 语义幂等**(重复调用同终态,无键管理);创建型写入(发帖/评论/媒体登记)用**表内幂等列(request_hash)**。M2 的 Idempotency-Key 键派生机制在 pets 域维持不变,不回改。 ## ADR-020 M3 埋点与实验决策 **决策**(2026-09-08): - Feed 曝光采用**聚合 `feed_viewed`**(浏览段聚合),否决逐卡曝光(量级测算 7~14 个月击穿分区阈值且接收端无限流背压,见 iteration-3/06);逐帖曝光留 backlog 待 M4+ 排序实验走服务端日志。 - 事件字典 v3 增量 19 事件 + `experiment_exposed` 提前进字典(A/B 前置 #5 顺带变绿)。 - 北极星保持「7 日回访记录率」不变,复评点 = M3 收官 + H7 读数。 - 埋点队列三项遗留(30s 定时冲刷、上传退避、anonymousId 持久化)升为 M3 第一波必做。 ## ADR-021 Git 工作流修订(修订 ADR-011) **决策**(2026-09-08): - ADR-011 中「master」统一更正为 **main**(远端实际分支名;master 从未存在于远端)。 - PR 触发条件由「改动类别」改为「情形」:仅**两人并行同仓期间**与**首次发布后影响 main 的变更**强制走 PR;其余直推 dev + CI 绿(M2 全程直推零风险事件的机制归因见 iteration-3/08)。 - M3 末执行首次 dev→main 发布(8 步 checklist 见 iteration-3/08);patbond-api 远端 main 与 dev 历史不相干,届时经 Gitea 平台删除重建 main,禁止 force push 缝合。 - 对象存储凭证(MinIO AK/SK)防泄漏:CI 兜底 grep 在第一波、**先于凭证进开发机**落地。 - E2E 烟囱不进 push 门禁,保持波次手动 + 可选 workflow_dispatch。 ## ADR-022 M3.5 体验补齐的范围与关键决策 **决策**(2026-09-10,用户实测反馈后拍板): - **首页 demo 裁剪范围**:本迭代**仅做问候语真实化**(改用真实昵称)。天气与位置(需接外部服务,含 key 与配额管理)、圈子入口(实为话题,ADR-018 已剪出)、促销卡(属 M5 服务域)三项**留待对应里程碑**;保留期间须在代码注释与迭代报告显式标注为「刻意保留的 demo 占位」,避免后续实测重复反馈。 - **昵称不设唯一约束**:`identity.users.nickname` 维持现状(仅 `ck_users_nickname` 的 btrim + 1~32 长度校验),**允许重名**,靠 userId 区分(社区产品常规做法)。加唯一约束需迁移,且会破坏本迭代零迁移前提。 - **注册流程不加昵称输入**:沿 ADR-004 的最小注册面,注册仍只收用户名/手机号/密码;昵称在资料页设置,未设置时展示层回退 username(回退逻辑已在 `/internal/users/profiles` 的 SQL 层实现,M3 T3-05 交付)。 - **宠物头像的写权限为 WRITE 档**(owner + caregiver 均可改,ADR-015 三档权限模型下):头像属日常照护信息,与体重/疫苗记录同档;viewer 只读。 - **本迭代零 Flyway 迁移**:开工审计确认所需列均已存在——`identity.users.nickname` 与 `avatar_asset_id`(V1)、`pet_health.pets.avatar_asset_id`(V3)、`community.posts.like_count` 等冗余列(V5);`media.assets.purpose` 无 CHECK 约束、白名单为配置项 `MediaProperties.allowedPurposes`,新增 `user_avatar`/`pet_avatar` 只改配置与契约枚举。下一个 Flyway 版本号 V6 留给后续真正需要建表的迭代。 - **获赞总数走读侧实时聚合**(`SUM(like_count)` over 本人未删帖),**不引入新冗余列**:写侧维护成本高于读侧聚合收益,且数据量级远未到瓶颈。端点为新增的 `GET /api/v1/me/community-stats`,不并入既有 `follow-stats`(后者主体是「某用户的关注数」,混入「我的获赞」会造成主体歧义)。 **版本号**:本迭代交付按 **v0.4.0** 发布(新增端点与字段属功能增量,非纯补丁)。