# Issue:位置临近提醒 ## 1. 功能描述 位置临近提醒模块负责为 Schedule 创建 `LOCATION_APPROACH` 类型的 Reminder。当用户进入目标 Place 的临近区域,并且当前设备网络可用时,系统触发提醒,用于表达“快到某个地点时提醒我”的场景。 典型表达包括: * 快到公司时提醒我打卡。 * 接近学校时提醒我准备下车。 * 快到医院时提醒我带上检查材料。 * 接近商场时提醒我取快递。 * 快到客户公司时提醒我提前联系客户。 位置临近提醒与普通“进入地点提醒”的区别是: * 它强调在到达目标地点前提前提醒。 * 它使用比目标地点实际范围更大的临近半径。 * 它不表示用户已经真正到达目标地点。 * 它不表示用户已经完成停车、下车、打卡等现实动作。 * 它不维护“先进入再离开”的两阶段状态。 位置临近提醒与 `LOCATION_ARRIVE_EXIT` 的区别是: ```text LOCATION_APPROACH 进入目标地点临近区域 + 当前网络可用 → 触发提醒 LOCATION_ARRIVE_EXIT 进入指定前置区域 → 稳定停留 → 等待离开 → 离开后触发提醒 ``` 本模块主要负责: * `LOCATION_APPROACH` Reminder 的创建、查询、修改和删除。 * 目标 Place 关联。 * 临近半径配置。 * 生效与失效时间配置。 * 当前设备规则同步。 * 系统地理围栏或平台等价位置能力注册。 * 进入临近区域后的网络状态校验。 * 网络可用时触发提醒。 * 前台弹窗、TTS 和系统通知触达。 * 断网暂停、权限失败和注册失败处理。 * 触发状态与触达结果记录。 * Schedule 或 Place 变化后的规则重建。 位置临近提醒依赖当前设备网络状态。 断网期间: * 不触发位置提醒。 * 不展示位置提醒通知。 * 不执行位置提醒 TTS。 * 不将该次进入区域事件记为成功触发。 * 网络恢复后不补发断网期间错过的提醒。 本模块不负责连续记录用户位置,也不负责识别用户真实的移动方式和具体动作。 ## 2. 用户 / 用户故事 目标用户:需要在接近公司、学校、医院、商场、客户现场等地点时提前收到日程提醒的移动端用户。 用户创建日程: > 明天早上八点到公司打卡,快到公司时提醒我。 系统识别到: ```text Schedule: 明天 08:00 到公司打卡 Place: 公司 Reminder: LOCATION_APPROACH 临近范围: 使用产品默认值,并在候选中明确展示 生效时间: 明天 06:00 失效时间: 明天 10:00 触发次数: 一次 网络要求: 触发时设备必须联网 ``` 用户确认候选后,系统保存 Schedule 和 Reminder。客户端同步规则并向移动操作系统注册位置临近条件。 用户第二天接近公司,进入公司临近范围,并且当前设备网络可用时收到: ```text 快到公司了,记得打卡。 ``` 如果应用正在前台且可以交互: * 展示应用内弹窗。 * 根据用户设置调用本地 TTS。 * 记录触达渠道和结果。 如果应用在后台或进程被系统回收: * 使用操作系统通知或受支持的后台触达能力。 * 按用户设置播放声音或震动。 * 不承诺主动执行 TTS。 如果用户进入公司临近范围时设备断网: * 不触发位置提醒。 * 不展示通知。 * 不执行 TTS。 * Reminder 可以进入 `suspended_offline` 状态。 * 网络恢复后不补发此次提醒。 如果网络恢复时用户仍然停留在公司临近范围内: * 系统不伪造新的进入事件。 * 系统不立即补发提醒。 * Reminder 恢复为等待状态。 * 用户需要在网络可用时重新离开并进入临近区域,才可能产生新的有效触发。 如果用户创建 Reminder 时已经位于公司临近范围: * 系统不得虚构一次“刚进入”事件。 * 系统不承诺注册完成后立即提醒。 * 候选或结果页面需要说明当前情况。 * 可以建议用户同时设置 TIME Reminder,但不得自动添加。 ## 3. 现有做法及不足 传统日历主要使用固定时间提醒。 例如: ```text 07:50 提醒用户: 十分钟后需要到公司打卡。 ``` 但固定时间提醒无法反映用户的实际移动进度: * 用户可能已经提前到公司。 * 用户可能距离公司还有很远。 * 用户可能因为路线和交通变化而提前或延后到达。 * 相同时间提醒在不同日期的实际价值不同。 简单的“到达地点提醒”也可能触发过晚。 例如: * 用户需要在到达公司前准备打开打卡应用。 * 用户需要在到学校前整理随身物品。 * 用户需要在到医院前准备证件和检查材料。 * 用户需要在到客户公司前提前联系客户。 如果系统只有进入目标地点的小范围后才提醒,用户可能已经错过准备时机。 如果使用服务端持续接收用户位置并实时计算距离,会产生以下问题: * 持续定位增加耗电。 * 后台运行容易受到系统限制。 * 服务端需要长期接收敏感位置数据。 * 用户容易误认为应用在追踪完整轨迹。 * 实现和运维成本较高。 如果直接把“快到”转换成一个固定距离,也存在问题: * 步行场景和驾车场景对“快到”的理解不同。 * 公司、医院、机场和商场的合理半径不同。 * 城市道路、建筑密度和定位精度不同。 * 用户可能不理解半径参数的实际含义。 * 一个固定值无法覆盖全部场景。 位置提醒在断网状态下继续执行,还会产生以下产品风险: * 当前设备无法确认 Reminder 是否仍为最新版本。 * Schedule、Place 或 Reminder 可能已经在服务端被修改或删除。 * 设备可能使用过期规则触发提醒。 * 本地触发状态无法及时与服务端保持一致。 * 用户可能误以为断网期间的所有业务状态仍然可靠。 * 网络恢复后可能产生重复同步或冲突。 因此,本期采用以下规则: ```text 用户表达“快到某地” → Agent 识别 LOCATION_APPROACH → 匹配或确认 Place → 使用明确的临近半径和有效时间 → 用户确认 → 客户端注册系统位置规则 → 系统检测到进入临近区域 → 校验当前网络状态 → 网络可用:继续校验并触发 → 网络不可用:不触发、不通知、不补发 ``` ## 4. 本期范围 ### Reminder 业务能力 1. 创建 `LOCATION_APPROACH` Reminder。 2. 按 ID 查询 Reminder。 3. 查询某个 Schedule 关联的位置临近提醒。 4. 修改位置临近提醒。 5. 删除位置临近提醒。 6. 启用或停用位置临近提醒。 7. Reminder 必须绑定一个 Schedule。 8. Reminder 必须绑定一个 Place。 9. 一个 Schedule 可以拥有多个不同类型的 Reminder。 10. 同一个 Schedule 可以同时具有 TIME 和 LOCATION_APPROACH Reminder。 11. Reminder 具有独立版本号。 12. Reminder 修改后旧版本失效。 13. Reminder 删除后取消当前设备系统注册。 14. Schedule 删除后取消关联 Reminder。 15. Schedule 时间变化后重新校验 Reminder 有效时间。 16. Schedule 地点变化后重新确认 Place 关联。 17. Place 修改后重新注册关联位置提醒。 18. Place 删除前展示受影响 Reminder。 19. Reminder 失败不回滚 Schedule。 20. Reminder 状态对用户可见。 21. LOCATION_APPROACH 明确标记为触发时需要网络。 22. 断网时 Reminder 暂停位置触发。 ### Place 关联 1. Reminder 必须关联用户已确认的 Place。 2. Place 至少包含名称、经纬度和地址文本。 3. 支持匹配“公司”“家”“学校”等常用地点。 4. Place 不存在时引导用户搜索和地图确认。 5. 同名 Place 不唯一时要求用户选择。 6. 不允许 Agent 仅凭名称静默猜测坐标。 7. 不允许使用其他用户的 Place。 8. 修改 Place 坐标后关联规则需要重新同步。 9. LOCATION_APPROACH 可以使用 Place 的默认临近半径。 10. 用户可以为单个 Reminder 覆盖默认半径。 ### 临近半径 1. Reminder 必须具有明确的 `approach_radius`。 2. 用户没有明确半径时,使用产品配置的默认值。 3. 默认值必须在候选中明确展示。 4. 用户可以在确认前修改半径。 5. 不将示例距离静默写成全局统一规则。 6. 半径必须位于产品允许范围内。 7. 半径过小时提示可能导致漏提醒。 8. 半径过大时提示可能过早提醒。 9. 候选优先使用用户容易理解的表达。 10. 详情页可以同时展示自然语言和米制数值。 11. 修改半径后旧系统规则必须取消。 12. 新规则注册成功前状态显示为 `pending_sync`。 ### 有效时间 1. Reminder 必须具有 `active_from`。 2. Reminder 必须具有 `expires_at`。 3. `expires_at` 必须晚于 `active_from`。 4. 用户未明确时间范围时使用产品默认规则。 5. 默认时间范围必须在候选中展示。 6. Reminder 只在有效时间内等待位置事件。 7. 有效时间开始前不触发。 8. 有效时间结束后转为 `expired`。 9. 已过期规则取消系统注册。 10. 修改 Schedule 时间时重新计算或确认有效时间。 11. 无法得到合法时间范围时不得创建正式 Reminder。 12. 用户可以手动修改有效时间。 13. 断网不会延长 Reminder 的有效时间。 14. 网络恢复时 Reminder 已过期,则直接转为 expired。 ### 网络要求 1. LOCATION_APPROACH 触发时当前设备必须联网。 2. 进入位置范围后先检查网络状态。 3. 网络不可用时不进入 triggered。 4. 网络不可用时不展示提醒通知。 5. 网络不可用时不调用 TTS。 6. 网络不可用时可以记录最小的本地诊断状态。 7. 断网期间 Reminder 可以进入 `suspended_offline`。 8. 网络恢复后重新校验 Reminder 状态和版本。 9. 网络恢复后不补发断网期间错过的进入事件。 10. 网络恢复时用户仍在范围内,不视为新的进入事件。 11. 网络恢复后需要新的有效 ENTER 事件才可以触发。 12. 网络恢复时规则已经过期,则不再恢复 active。 13. 网络恢复时 Schedule 或 Reminder 已取消,则取消系统注册。 14. 网络恢复时版本已经变化,则同步新版本。 15. 不使用缓存数据代替在线状态校验完成触发。 ### 触发次数 1. P0 默认只触发一次。 2. 核心字段使用 `trigger_limit` 或等价结构。 3. 一次性 Reminder 触发后不得重复触发。 4. 触发成功后取消系统位置注册。 5. 重复系统事件必须幂等处理。 6. 条件触发与通知触达分别记录。 7. 断网阻止的事件不增加 `trigger_count`。 8. 网络恢复后不补算断网期间的触发次数。 9. 条件触发但通知失败时,不重新伪造新的进入事件。 10. Reminder 修改后触发计数按新版本处理。 11. P0 不提供无限重复进入提醒。 ### 客户端注册与执行 1. 客户端同步待执行的 LOCATION_APPROACH Reminder。 2. 客户端向操作系统注册地理围栏或平台等价能力。 3. 注册结果上报业务层。 4. 注册成功后状态更新为 `registered`。 5. 进入有效时间且网络可用时规则处于 `active`。 6. 网络断开时规则进入 `suspended_offline`。 7. 系统报告进入临近区域后先执行网络校验。 8. 网络可用后再校验 Reminder 是否有效。 9. 校验 Schedule 和 Place 是否仍有效。 10. 校验当前版本是否为最新版本。 11. 校验是否已经达到触发次数。 12. 条件满足后状态更新为 `triggered`。 13. 触发后进入通知触达流程。 14. 客户端记录事件时间和规则版本。 15. App 启动时进行注册一致性检查。 16. App 恢复前台时进行必要校验。 17. 网络断开时更新位置 Reminder 状态。 18. 网络恢复后重新同步和校验版本。 19. 设备重启后按平台能力恢复注册。 20. 权限变化后重新校验规则。 21. 同一版本重复位置事件保持幂等。 22. 不通过高频定位替代地理围栏。 ### 通知触达 1. 只有网络可用且位置条件有效时才进入通知触达。 2. 应用前台且可交互时优先展示应用内弹窗。 3. 前台时根据用户设置调用本地 TTS。 4. TTS 失败时保留可见弹窗。 5. 应用后台时使用系统通知或受支持的后台触达能力。 6. 进程被系统回收时不承诺 TTS。 7. 通知可以使用声音和震动。 8. 通知点击进入对应 Schedule 详情。 9. 通知内容默认使用 Schedule 标题和简短提醒文本。 10. 不默认朗读完整敏感备注。 11. 记录实际触达渠道。 12. 记录触达成功或失败。 13. 避免应用内弹窗和系统通知重复打扰。 14. 断网时不进入通知触达流程。 15. 通知权限不可用时记录 `delivery_failed` 或 `failed`。 ### 权限与降级 1. 首次创建位置提醒时按需申请定位权限。 2. 需要后台位置能力时说明用途。 3. 定位权限拒绝后不注册位置 Reminder。 4. 定位权限拒绝后保留 Schedule。 5. 支持将提醒改为 TIME Reminder。 6. 通知权限拒绝后不伪装为提醒已生效。 7. 网络不可用时不伪装为位置提醒可正常触发。 8. 权限和网络失败状态对用户可见。 9. 提供系统设置入口。 10. 权限恢复后允许重新同步。 11. 地理围栏能力不可用时不使用持续高频定位兜底。 12. 麦克风或 Agent 不可用不影响已注册规则的管理。 13. 用户关闭地点提醒后取消系统注册。 ## 5. 明确不做 * 不做断网状态下的位置提醒。 * 不做已注册位置规则的离线触发。 * 不在断网时展示位置通知。 * 不在断网时执行位置提醒 TTS。 * 不在网络恢复后补发断网期间错过的提醒。 * 不把网络恢复且仍在范围内视为新的进入事件。 * 不使用本地缓存版本替代在线校验完成触发。 * 不因断网自动转为 TIME Reminder。 * 不做 LOCATION_ARRIVE_EXIT 两阶段提醒。 * 不做进入后等待离开的状态机。 * 不识别停车完成。 * 不识别用户已经下车。 * 不识别用户正在步行或驾车。 * 不识别用户真实交通方式。 * 不判断用户是否已经打卡。 * 不判断 Schedule 是否已经完成。 * 不自动修改 Schedule Execution Result。 * 不持续记录用户位置。 * 不保存连续位置轨迹。 * 不上传实时移动路线。 * 不通过服务端持续轮询位置。 * 不要求应用进程持续常驻。 * 不使用后台高频 GPS 作为默认方案。 * 不承诺在精确距离点触发。 * 不承诺精确到某一秒触发。 * 不承诺所有设备达到百分之百触发率。 * 不把“临近范围”描述为用户已经到达。 * 不自动根据 Place 名称猜测坐标。 * 不自动创建常用地点。 * 不自动为所有 Schedule 添加位置提醒。 * 不自动同时创建 TIME Reminder。 * 不做多地点任意组合。 * 不做天气或交通条件组合。 * 不做动态路线 ETA 提醒。 * 不根据实时速度动态调整半径。 * P0 不做周期性位置提醒。 * P0 不做无限重复触发。 * 不在进程死亡时承诺主动 TTS。 * 不因 Reminder 注册失败删除 Schedule。 * 不把位置事件当作执行结果。 * 不绕过 Reminder 公共业务能力直接写系统规则。 ## 6. 关键决策 | 决策点 | 备选方案 | 选择 | 理由 | | ----------- | --------------------------- | ----------------- | -------------- | | 提醒语义 | 到达地点 / 接近地点 | 接近地点 | 为用户提供提前准备时间 | | Reminder 类型 | 复用 TIME / 独立类型 | LOCATION_APPROACH | 触发条件和权限要求不同 | | 目标位置 | 名称字符串 / Place | 绑定 Place | 位置规则需要确定坐标 | | Place 坐标 | Agent 猜测 / 用户确认 | 用户确认 | 防止错误地点触发 | | 临近距离 | 全局固定 / 默认值可修改 | 产品默认值并允许修改 | 不同场景的“快到”语义不同 | | 默认值展示 | 静默使用 / 候选中展示 | 候选中明确展示 | 用户需要理解实际触发范围 | | 触发方式 | 服务端持续计算 / 系统地理围栏 | 系统地理围栏或等价能力 | 降低持续定位和隐私风险 | | 网络依赖 | 支持离线触发 / 触发时必须联网 | 触发时必须联网 | 避免过期规则和端云状态不一致 | | 断网状态 | 继续 active / 暂停位置触发 | suspended_offline | 明确表达当前不可触发 | | 断网事件 | 本地触发 / 缓存后补发 / 丢弃 | 不触发且不补发 | 避免过时提醒和重复提醒 | | 恢复网络 | 立即补发 / 根据当前位置触发 / 等待新 ENTER | 等待新 ENTER | 不伪造位置进入事实 | | 位置数据 | 连续轨迹 / 必要区域事件 | 必要区域事件 | 遵循最小数据原则 | | 应用运行 | 强制常驻 / 预注册系统规则 | 预注册系统规则 | 不依赖不可靠的进程保活 | | 触发次数 | 每次进入 / 默认一次 | 默认一次 | 降低重复打扰 | | 有效时间 | 永久有效 / 明确时间范围 | 明确时间范围 | 避免未来错误触发 | | 已在范围内 | 立即合成触发 / 不伪造事件 | 不伪造进入事件 | 保持事件事实可信 | | 定位权限失败 | 静默失败 / 状态可见并降级 | 状态可见并可改 TIME | 用户需要知道提醒没有生效 | | 注册失败 | 回滚 Schedule / 保留 Schedule | 保留 Schedule | 提醒失败不应丢失日程 | | 前台触达 | 系统通知 / 弹窗 + TTS | 弹窗 + 可配置 TTS | 提升前台感知效率 | | 后台触达 | 强制 TTS / 系统通知 | 系统通知 | 符合移动系统能力边界 | | 触发与触达 | 一个状态 / 分开记录 | 分开记录 | 条件成功不代表通知成功 | | 规则更新 | 覆盖注册 / 版本化重建 | 取消旧版本并注册新版本 | 防止旧规则残留 | | 同一事件处理 | 允许重复 / 幂等 | 幂等 | 防止重复通知 | | Agent 写入 | 直接创建 / 候选确认 | 候选确认 | 地点和半径属于重要业务事实 | | 提醒与执行结果 | 自动关联 / 完全分离 | 完全分离 | 接近地点不代表日程完成 | ## 7. 边界与异常 ### Place 边界 * Place 必须属于当前用户。 * Place 必须具有合法经纬度。 * Place 名称可以重复,但创建 Reminder 时必须唯一定位。 * 仅有地址文本而没有坐标时不能注册位置提醒。 * 用户说“公司”但没有保存 Place 时,必须进入地点确认流程。 * 存在多个“公司”时必须要求用户选择。 * 不允许使用地图搜索首条结果静默创建 Reminder。 * Place 坐标修改后,旧系统规则必须取消。 * Place 删除前必须展示受影响 Reminder。 * Place 删除后关联 Reminder 不得继续 active。 * Place 只是目标地点,不表示用户实时位置。 * “公司”和“公司停车区”可以是不同 Place。 ### 临近半径边界 * `approach_radius` 必须是正数。 * 半径必须位于产品允许的最小值和最大值之间。 * 用户没有明确半径时,使用当前产品配置默认值。 * 默认值不是 Agent 自由生成。 * 默认值必须在候选中展示。 * 用户修改半径后需要重新校验。 * 半径过小可能受定位精度影响,需要提示风险。 * 半径过大可能导致过早触发,需要提示风险。 * “快到”是临近语义,不代表精确距离测量。 * 系统触发可能受定位精度、系统调度和环境影响。 * 产品不得宣称用户一定在某个精确米数点收到提醒。 * 用户从临近区域内部创建规则时,不伪造进入事件。 * 半径变化后规则版本必须更新。 ### 时间边界 * `active_from` 和 `expires_at` 必须是明确时间点。 * `expires_at` 必须晚于 `active_from`。 * 当前时间已经晚于 `expires_at` 时不能注册规则。 * 尚未到 `active_from` 时不得触发。 * 超过 `expires_at` 后状态转为 expired。 * Schedule 修改时间后必须重新检查有效期。 * Schedule 被取消时 Reminder 取消。 * Schedule 被删除时 Reminder 取消。 * 有效时间不能永久缺省。 * 断网不会暂停或延长有效时间。 * 网络恢复时已经超过 `expires_at`,直接转为 expired。 * 时区必须使用 Schedule 和用户时区语义。 * 客户端与服务端对时间范围的判断必须一致。 ### 网络边界 * LOCATION_APPROACH 的触发必须依赖可用网络。 * 系统位置事件到达时必须先校验网络状态。 * 网络不可用时不得更新为 triggered。 * 网络不可用时不得展示通知。 * 网络不可用时不得调用 TTS。 * 网络不可用时不得增加 trigger_count。 * 断网期间可以将状态更新为 suspended_offline。 * 网络恢复后必须重新读取或同步最新 Reminder 版本。 * 网络恢复后不得补发断网期间的进入事件。 * 网络恢复时仍在临近范围内,不视为新 ENTER。 * 网络恢复后只有新的有效 ENTER 事件可以触发。 * 网络恢复时 Reminder 已取消、删除或过期,不得恢复。 * 网络恢复时规则版本改变,应取消旧注册并注册新版本。 * 网络状态抖动时需要去抖,避免频繁切换状态。 * 网络可用性判断失败时按不可用处理。 * 不使用“请求超时后默认允许触发”的策略。 * 不把只有局域网但无法访问业务服务视为有效联网。 * 具体联网判定应使用统一网络可用性能力。 ### 注册边界 * Reminder 保存成功不代表设备已经完成注册。 * 保存后初始状态可以为 pending_sync。 * 系统注册成功后更新为 registered。 * 注册成功且网络可用、有效期已开始时才能显示 active。 * 注册成功但断网时显示 suspended_offline。 * 注册失败必须显示明确状态。 * 不得把注册失败显示为 active。 * 同一 Reminder 版本不得重复创建多个系统注册。 * 新版本注册前应取消旧版本。 * 设备重启后需要按平台能力重建。 * App 恢复前台时需要执行一致性检查。 * 网络恢复后需要同步 pending 或 suspended 状态。 * 当前设备超过平台系统限制时需要明确失败。 * 不使用高频定位掩盖注册失败。 ### 触发边界 * 只有系统报告进入临近区域时才处理触发。 * 触发前必须确认网络可用。 * 触发前必须重新校验 Reminder 版本。 * 触发前必须校验 Reminder 未取消、未过期。 * 触发前必须校验 Schedule 仍然存在且有效。 * 触发前必须校验触发次数。 * 同一事件重复到达时只处理一次。 * 系统事件时间可能晚于真实进入时间。 * 产品不承诺精确到秒。 * 当前已经在范围内时不主动伪造触发。 * 断网期间收到的进入事件不缓存为待触发业务事件。 * 网络恢复后不对旧进入事件重新执行。 * LOCATION_APPROACH 不维护 inside、waiting_exit 等两阶段状态。 * 触发后一次性规则取消注册。 * 条件触发成功后状态更新为 triggered。 * 通知失败不会把状态改回 active。 * Reminder 触发不能修改 Schedule Execution Result。 ### 通知边界 * 只有在线触发成功后才能进入通知触达。 * 前台弹窗与 TTS 依赖客户端当前可交互状态。 * 后台和进程死亡时不承诺 TTS。 * 系统通知权限被关闭时可能无法完成用户可见触达。 * TTS 被关闭时仍保留弹窗或系统通知。 * TTS 失败不影响 triggered 状态。 * 通知内容不得默认包含敏感完整备注。 * 同一触发不得产生重复弹窗和重复系统通知。 * 用户点击通知后进入 Schedule 详情。 * 通知点击不表示用户完成日程。 * 用户忽略或清除通知不改变 Schedule 状态。 * 触达渠道和触达结果需要单独记录。 ### 权限异常 * 定位权限拒绝时不创建虚假的系统注册。 * 后台定位权限不足时提示具体影响。 * 通知权限拒绝时提醒状态不得显示为正常可触达。 * 用户永久拒绝权限时提供系统设置入口。 * 用户恢复权限后允许重新同步。 * 用户关闭定位服务时状态可见。 * 系统地理围栏能力不可用时返回明确错误。 * 拒绝定位权限不影响 Schedule、月历和 TIME Reminder。 * 不因定位权限失败持续弹出权限请求。 ### 断网与恢复异常 * 断网时已注册的位置规则不产生用户提醒。 * 断网时新建或修改规则保持 pending_sync。 * 断网时已注册规则显示 suspended_offline。 * suspended_offline 不得描述为正常可触发。 * 断网期间的 ENTER 事件不增加触发次数。 * 断网期间的 ENTER 事件不生成通知。 * 断网期间的 ENTER 事件不在恢复网络后补发。 * 网络恢复后执行版本和状态校验。 * 网络恢复后 Reminder 有效且未触发,可以重新进入 active。 * 网络恢复时用户仍在范围内,需要等待未来新的 ENTER。 * 网络恢复时 Reminder 已过期,转为 expired。 * 网络恢复时 Reminder 被删除或取消,取消系统注册。 * 网络恢复时存在新版本,替换旧版本注册。 * 网络反复断开时保持状态变更幂等。 * Agent 不可用不影响网络与位置规则状态校验。 ## 8. 基本概念与信息结构 | 概念 | 含义 | | ------------------------- | --------------------------------- | | LOCATION_APPROACH | 在线状态下进入目标 Place 临近区域时触发的 Reminder | | Place | 用户确认并保存的目标地点 | | Approach Radius | 用于定义“接近目标地点”的临近半径 | | Active From | Reminder 开始生效时间 | | Expires At | Reminder 结束生效时间 | | Trigger Limit | Reminder 允许触发的最大次数 | | Network Required | 表示该 Reminder 触发时必须联网 | | Network Availability | 当前设备能否访问必要业务服务 | | Reminder Version | 用于同步和替换系统注册的规则版本 | | Reminder Registration | 当前设备向操作系统注册的位置规则 | | Location Event | 操作系统提供的区域进入事件 | | Suspended Offline | 因网络不可用而暂停触发 | | Trigger Result | Reminder 的条件是否已经满足 | | Delivery Result | 弹窗、TTS 或系统通知是否成功触达 | | Pending Sync | 业务数据尚未完成当前设备同步 | | Registered | 当前设备已完成系统规则注册 | | Active | 网络可用且处于有效时间内,正在等待触发 | | Triggered | 在线状态下位置条件已满足 | | Delivery Failed | 条件满足,但用户可见触达失败 | | Failed | 规则注册或位置能力执行失败 | | Expired | 超过有效期仍未触发 | | Cancelled | Schedule、Place 或 Reminder 变化导致取消 | | Initial Inside | 注册时设备已经位于临近范围内 | | Location Privacy Boundary | 只处理必要围栏事件,不保存连续轨迹 | ```text Schedule └─ LOCATION_APPROACH Reminder ├─ Place ├─ Approach Config ├─ Network Requirement ├─ Reminder Registration ├─ Trigger Result └─ Delivery Result ``` ### LOCATION_APPROACH Reminder ```text LocationApproachReminder ├─ id ├─ user_id ├─ schedule_id ├─ place_id ├─ type ├─ approach_radius ├─ active_from ├─ expires_at ├─ trigger_limit ├─ trigger_count ├─ network_required ├─ notification_content ├─ status ├─ version ├─ created_at ├─ updated_at └─ deleted_at ``` 字段约束: * `type` 必须为 `LOCATION_APPROACH`。 * `schedule_id` 必须关联当前用户的正式 Schedule。 * `place_id` 必须关联当前用户确认的 Place。 * `approach_radius` 必须位于产品允许范围内。 * `active_from` 必须早于 `expires_at`。 * `trigger_limit` P0 默认为 1。 * `trigger_count` 不得超过 `trigger_limit`。 * `network_required` P0 固定为 true。 * 断网阻止的事件不增加 `trigger_count`。 * 已删除或取消 Reminder 不得继续触发。 ### Approach Config ```text LocationApproachConfig ├─ place_id ├─ approach_radius ├─ active_from ├─ expires_at ├─ trigger_limit ├─ network_required ├─ notification_title ├─ notification_body ├─ tts_enabled └─ tts_text ``` ### Reminder Registration ```text LocationReminderRegistration ├─ reminder_id ├─ reminder_version ├─ device_id ├─ platform_registration_id ├─ registration_status ├─ network_status ├─ registered_at ├─ last_checked_at ├─ permission_snapshot └─ error ``` ### Location Event ```text LocationApproachEvent ├─ event_id ├─ reminder_id ├─ reminder_version ├─ device_id ├─ transition ├─ occurred_at ├─ received_at ├─ network_available ├─ processing_result └─ source ``` `transition` P0 只处理: ```text ENTER ``` `processing_result` 可以包括: ```text TRIGGERED BLOCKED_OFFLINE IGNORED_EXPIRED IGNORED_CANCELLED IGNORED_OLD_VERSION IGNORED_DUPLICATE ``` ### Trigger Result ```text LocationApproachTrigger ├─ reminder_id ├─ reminder_version ├─ event_id ├─ network_verified_at ├─ triggered_at ├─ idempotency_key └─ status ``` ### 状态流转 ```text draft → pending_sync → registered → active → triggered → cancelled registered / active → suspended_offline suspended_offline → active → expired → cancelled active → expired pending_sync / registered / active / suspended_offline → failed triggered → delivery_failed ``` 说明: * `suspended_offline` 表示规则已经存在,但当前断网,不能触发位置提醒。 * `triggered` 只能在网络可用并完成规则校验后产生。 * `delivery_failed` 表示条件已经在线触发,但通知未成功触达。 * 断网期间的位置事件不能在恢复网络后转为 triggered。 ## 9. Agent 输入输出约束 * 系统中只有一个 Agent。 * Agent 可以识别位置临近提醒意图。 * Agent 可以识别“快到”“接近”“快抵达”等表达。 * Agent 必须区分 LOCATION_APPROACH 与 LOCATION_ARRIVE_EXIT。 * 用户只说“快到公司提醒我”时,优先解析为 LOCATION_APPROACH。 * Agent 不直接访问 Reminder 或 Place 数据库表。 * Agent 通过受控查询能力读取 Schedule、Place 和 Reminder。 * Agent 不自行生成经纬度。 * Agent 不仅凭地点名称决定坐标。 * Agent 匹配不到 Place 时必须进入地点确认流程。 * 同名 Place 不唯一时必须要求用户选择。 * Agent 可以使用产品配置的默认临近半径。 * Agent 使用默认值时必须在候选中明确展示。 * Agent 可以解析用户明确说出的距离。 * Agent 不能承诺在精确距离处触发。 * Agent 必须明确有效时间或使用可见默认值。 * Agent 必须明确触发次数。 * Agent 必须在候选中说明位置提醒需要网络。 * Agent 不得声称位置提醒支持断网触发。 * Agent 不得声称网络恢复后会补发提醒。 * 创建 LOCATION_APPROACH 属于业务写操作。 * 创建、修改和删除必须生成 Operation Candidate。 * 查询 Reminder 可以直接展示。 * Operation Candidate 至少包含 Schedule、Place、半径、有效时间、触发次数和网络要求。 * 用户确认前不得创建正式 Reminder。 * 用户确认后 Agent 调用确定性 Reminder 公共业务能力。 * Agent 不直接注册系统地理围栏。 * 系统注册属于客户端确定性模块。 * Agent 不根据用户当前位置声明提醒已经生效。 * Agent 不根据位置事件标记 Schedule 完成。 * Agent 不自动同时创建 TIME Reminder。 * Agent 可以建议增加 TIME Reminder,但必须由用户确认。 * Reminder 断网时,Agent 应明确说明当前暂停。 * Reminder 注册失败时,Agent 不得声称提醒已经可用。 * Agent 可以说明 Reminder 为 pending_sync、registered、active、suspended_offline 或 failed。 * 网络状态由客户端确定性能力提供。 * Agent 输出失败不影响 Reminder 正式业务状态。 ### Agent 候选输出 ```text LocationApproachCandidate ├─ operation_type ├─ schedule_id ├─ schedule_summary ├─ place_id ├─ place_summary ├─ approach_radius ├─ active_from ├─ expires_at ├─ trigger_limit ├─ network_required ├─ notification_content ├─ defaults_used[] ├─ warnings[] └─ target_version ``` `warnings` 可以包含: * 此位置提醒触发时需要网络连接。 * 断网期间不会提醒。 * 网络恢复后不会补发错过的提醒。 * 当前设备可能已经位于临近范围。 * 半径过小可能导致漏提醒。 * 半径过大可能过早提醒。 * 后台定位权限尚未开启。 * 当前规则尚未同步到设备。 * 系统位置事件可能存在延迟。 ### 确定性业务输出 ```text LocationApproachWriteResult ├─ reminder ├─ write_status ├─ sync_required ├─ registration_status ├─ network_status ├─ warnings[] └─ error ``` Agent 只能以确定性业务结果判断写入和状态,不得根据模型自身输出宣称成功。 ## 10. 验收标准 ### 创建与配置 * 可以为正式 Schedule 创建 LOCATION_APPROACH Reminder。 * Reminder 类型正确保存为 LOCATION_APPROACH。 * Reminder 必须关联 Schedule 和 Place。 * 用户未提供半径时使用产品配置默认值。 * 默认半径在候选中明确展示。 * 用户可以修改临近半径。 * 非法半径创建失败。 * 用户未提供有效时间时使用明确默认规则。 * expires_at 不晚于 active_from 时创建失败。 * P0 默认 trigger_limit 为 1。 * network_required 固定为 true。 * 候选中明确提示位置提醒需要网络。 * 候选中明确提示断网期间不会提醒。 * 所有写操作在用户确认前不落库。 * 创建成功后返回正式 Reminder ID 和版本号。 * 创建成功不等于设备注册成功。 * 未注册时状态正确显示 pending_sync。 ### 查询、修改与删除 * 可以查询 Schedule 关联的位置临近提醒。 * 可以查看 Place、半径、有效时间、网络要求和状态。 * 可以修改 Place、半径、有效时间和通知内容。 * 修改后版本号更新。 * 使用旧版本候选时修改被拒绝。 * 修改后旧系统注册被取消。 * 可以删除位置临近提醒。 * 删除后取消系统注册。 * Schedule 删除或取消后 Reminder 被取消。 * Place 修改后关联 Reminder 重新同步。 * Place 删除前展示受影响 Reminder。 ### 网络状态 * 网络可用时 LOCATION_APPROACH 可以进入 active。 * 网络断开时 active Reminder 转为 suspended_offline。 * suspended_offline 不显示为正常可触发。 * 断网期间进入临近范围不会触发提醒。 * 断网期间不展示弹窗。 * 断网期间不执行 TTS。 * 断网期间不展示系统位置通知。 * 断网期间不增加 trigger_count。 * 断网期间的 ENTER 事件不保存为待补发提醒。 * 网络恢复后不会补发断网期间错过的提醒。 * 网络恢复时仍在范围内不会立即触发。 * 网络恢复后需要新的有效 ENTER 事件。 * 网络恢复后重新校验 Reminder 版本和状态。 * 网络恢复时 Reminder 已过期则转为 expired。 * 网络恢复时 Reminder 已取消则不恢复 active。 * 网络状态反复变化时状态迁移保持幂等。 * 网络可用性无法确定时按断网处理。 ### 权限与注册 * 首次使用位置提醒时按需申请定位权限。 * 定位权限拒绝后不注册位置规则。 * 定位权限拒绝后 Schedule 保留。 * 后台定位权限不足时显示明确状态。 * 通知权限拒绝后不显示为正常可触达。 * 提供系统设置入口。 * 权限恢复后可以重新同步。 * 客户端可以向系统注册位置临近规则。 * 注册成功后状态为 registered。 * 注册失败时状态为 failed。 * 注册失败时 Schedule 不回滚。 * 同一 Reminder 版本只存在一个有效系统注册。 * App 启动后可以校验注册一致性。 * 设备重启后按平台能力恢复注册。 * 不使用持续高频定位替代注册失败。 ### 位置触发 * 网络可用且进入目标 Place 临近区域时可以触发 Reminder。 * 有效时间开始前不触发。 * 有效时间结束后不触发。 * 已取消或删除 Reminder 不触发。 * 已达到 trigger_limit 后不再次触发。 * 同一系统事件重复到达时只触发一次。 * 旧版本事件不触发新版本 Reminder。 * 触发成功后状态更新为 triggered。 * 一次性触发后取消系统注册。 * 触发后不修改 Schedule Execution Result。 * 注册时已在临近范围内时不伪造进入事件。 * 产品不承诺精确距离或精确到秒触发。 * LOCATION_APPROACH 不进入 waiting_exit 状态。 * LOCATION_APPROACH 不识别停车或下车动作。 ### 通知触达 * 只有在线触发成功后才进入通知流程。 * 前台可交互时可以展示应用内弹窗。 * TTS 开启时可以调用本地 TTS。 * TTS 关闭或失败时不影响弹窗。 * 后台时使用系统通知或平台支持的触达方式。 * 进程死亡时不承诺 TTS。 * 系统通知点击进入对应 Schedule。 * 同一触发不产生重复弹窗和系统通知。 * 条件触发和通知触达分别记录。 * 通知失败时记录 delivery_failed。 * 用户忽略通知不改变 Schedule 状态。 * 通知内容不默认展示完整敏感备注。 ### Agent 与业务边界 * Agent 可以识别“快到公司时提醒我”。 * Agent 可以区分位置临近和到达后离开提醒。 * Agent 不直接生成 Place 坐标。 * Agent 不直接注册系统规则。 * Agent 不直接写 Reminder 数据库。 * Agent 使用默认半径和时间时在候选中展示。 * Agent 明确告知该提醒需要网络。 * Agent 不声称断网可以触发。 * Agent 不声称网络恢复后可以补发。 * 创建、修改和删除需要候选确认。 * 查询操作不需要确认。 * 未确认前不改变 Reminder。 * Agent 不根据位置事件标记日程完成。 * Agent 不自动添加 TIME Reminder。 * 写入失败时 Agent 不声称创建成功。 * 注册失败时 Agent 不声称提醒已经生效。 * 所有正式结果以确定性业务能力返回为准。 ### 数据与隐私 * 系统不保存连续位置轨迹。 * 系统不向服务端持续上传实时位置。 * 系统只处理完成 Reminder 所必需的区域事件。 * 断网阻止的区域事件不作为未来提醒任务保存。 * Place 数据访问受到用户归属校验。 * 位置事件日志不包含不必要的完整轨迹信息。 * 用户删除 Place 时关联规则得到处理。 * 用户删除 Reminder 后设备注册被取消。 * 位置数据不能用于本 Proposal 范围外的用户画像。 * 提醒触发记录不能被用作 Schedule 已完成证据。 * 位置权限和网络要求说明清晰可见。
Issue:位置临近提醒
1. 功能描述
位置临近提醒模块负责为 Schedule 创建
LOCATION_APPROACH类型的 Reminder。当用户进入目标 Place 的临近区域,并且当前设备网络可用时,系统触发提醒,用于表达“快到某个地点时提醒我”的场景。典型表达包括:
位置临近提醒与普通“进入地点提醒”的区别是:
位置临近提醒与
LOCATION_ARRIVE_EXIT的区别是:本模块主要负责:
LOCATION_APPROACHReminder 的创建、查询、修改和删除。位置临近提醒依赖当前设备网络状态。
断网期间:
本模块不负责连续记录用户位置,也不负责识别用户真实的移动方式和具体动作。
2. 用户 / 用户故事
目标用户:需要在接近公司、学校、医院、商场、客户现场等地点时提前收到日程提醒的移动端用户。
用户创建日程:
系统识别到:
用户确认候选后,系统保存 Schedule 和 Reminder。客户端同步规则并向移动操作系统注册位置临近条件。
用户第二天接近公司,进入公司临近范围,并且当前设备网络可用时收到:
如果应用正在前台且可以交互:
如果应用在后台或进程被系统回收:
如果用户进入公司临近范围时设备断网:
suspended_offline状态。如果网络恢复时用户仍然停留在公司临近范围内:
如果用户创建 Reminder 时已经位于公司临近范围:
3. 现有做法及不足
传统日历主要使用固定时间提醒。
例如:
但固定时间提醒无法反映用户的实际移动进度:
简单的“到达地点提醒”也可能触发过晚。
例如:
如果系统只有进入目标地点的小范围后才提醒,用户可能已经错过准备时机。
如果使用服务端持续接收用户位置并实时计算距离,会产生以下问题:
如果直接把“快到”转换成一个固定距离,也存在问题:
位置提醒在断网状态下继续执行,还会产生以下产品风险:
因此,本期采用以下规则:
4. 本期范围
Reminder 业务能力
LOCATION_APPROACHReminder。Place 关联
临近半径
approach_radius。pending_sync。有效时间
active_from。expires_at。expires_at必须晚于active_from。expired。网络要求
suspended_offline。触发次数
trigger_limit或等价结构。trigger_count。客户端注册与执行
registered。active。suspended_offline。triggered。通知触达
delivery_failed或failed。权限与降级
5. 明确不做
6. 关键决策
7. 边界与异常
Place 边界
临近半径边界
approach_radius必须是正数。时间边界
active_from和expires_at必须是明确时间点。expires_at必须晚于active_from。expires_at时不能注册规则。active_from时不得触发。expires_at后状态转为 expired。expires_at,直接转为 expired。网络边界
注册边界
触发边界
通知边界
权限异常
断网与恢复异常
8. 基本概念与信息结构
LOCATION_APPROACH Reminder
字段约束:
type必须为LOCATION_APPROACH。schedule_id必须关联当前用户的正式 Schedule。place_id必须关联当前用户确认的 Place。approach_radius必须位于产品允许范围内。active_from必须早于expires_at。trigger_limitP0 默认为 1。trigger_count不得超过trigger_limit。network_requiredP0 固定为 true。trigger_count。Approach Config
Reminder Registration
Location Event
transitionP0 只处理:processing_result可以包括:Trigger Result
状态流转
说明:
suspended_offline表示规则已经存在,但当前断网,不能触发位置提醒。triggered只能在网络可用并完成规则校验后产生。delivery_failed表示条件已经在线触发,但通知未成功触达。9. Agent 输入输出约束
Agent 候选输出
warnings可以包含:确定性业务输出
Agent 只能以确定性业务结果判断写入和状态,不得根据模型自身输出宣称成功。
10. 验收标准
创建与配置
查询、修改与删除
网络状态
权限与注册
位置触发
通知触达
Agent 与业务边界
数据与隐私