[update] init
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
schema: spec-driven
|
||||
created: 2026-05-17
|
||||
@@ -0,0 +1,188 @@
|
||||
## Context
|
||||
|
||||
用户给出的 Python 实现包含两个核心函数:
|
||||
|
||||
- `generate_sign(secret, timestamp)`:签名字符串为 `timestamp + "\n" + secret`,把这个完整字符串作为 HMAC key,消息体为空字节数组,算法为 SHA-256,结果做 Base64 编码。
|
||||
- `push_markdown(markdown_content, webhook_id, secret)`:构造飞书 interactive markdown 卡片,加上 `timestamp` 和 `sign`,10 秒超时 POST 到飞书 webhook,HTTP 200 且响应 JSON `code == 0` 表示成功。
|
||||
|
||||
当前 Android 工程是 Java + Android Gradle Plugin 7.2.2,`minSdkVersion=21`、`targetSdkVersion=30`。工程没有 Kotlin、Retrofit、OkHttp 或协程依赖。为了把需求做小、做稳,首版应选择 Java + OkHttp + `org.json`,不引入 Retrofit 接口层。
|
||||
|
||||
## Goals / Non-Goals
|
||||
|
||||
**Goals:**
|
||||
|
||||
- 先形成完整 spec,不直接写代码。
|
||||
- Android 侧等价实现 Python 已有飞书 webhook 推送协议。
|
||||
- 推送模块独立于短信接收模块,方便单元测试和手动测试。
|
||||
- 网络请求后台执行,避免阻塞主线程和短信广播处理。
|
||||
- 提供清晰的本地诊断结果,让用户知道是签名、配置、网络、HTTP、JSON 还是飞书业务错误。
|
||||
- 推送内容包含短信原文,便于当前调试远端接收结果。
|
||||
|
||||
**Non-Goals:**
|
||||
|
||||
- 不改造服务端协议。
|
||||
- 不做重试队列、离线持久化队列或 WorkManager 长任务调度。
|
||||
- 不把网络发送成功作为短信接收成功的前置条件。
|
||||
- 不把 webhook secret 写死到源码或提交到版本库。
|
||||
- 不要求本轮编译。
|
||||
|
||||
## API Strategy
|
||||
|
||||
### 1. Android 签名算法保持 Python 等价
|
||||
|
||||
Python 逻辑的关键点不是常见的“secret 作为 key、timestamp 作为 message”,而是:
|
||||
|
||||
- `string_to_sign = f"{timestamp}\n{secret}"`
|
||||
- HMAC key 为 `string_to_sign.encode("utf-8")`
|
||||
- HMAC message 为空字节数组
|
||||
- digest 为 SHA-256
|
||||
- 输出 Base64 字符串
|
||||
|
||||
Android 侧应实现:
|
||||
|
||||
- `String stringToSign = timestampSeconds + "\n" + secret;`
|
||||
- `Mac mac = Mac.getInstance("HmacSHA256");`
|
||||
- `mac.init(new SecretKeySpec(stringToSign.getBytes(StandardCharsets.UTF_8), "HmacSHA256"));`
|
||||
- `byte[] signData = mac.doFinal(new byte[0]);`
|
||||
- `Base64.encodeToString(signData, Base64.NO_WRAP);`
|
||||
|
||||
签名单元测试必须固定 `secret` 和 `timestamp`,用 Python 参考算法生成期望值,防止迁移时误用 key/message。
|
||||
|
||||
### 2. 请求体保持 Python 结构
|
||||
|
||||
请求 JSON:
|
||||
|
||||
```json
|
||||
{
|
||||
"msg_type": "interactive",
|
||||
"card": {
|
||||
"elements": [
|
||||
{
|
||||
"tag": "markdown",
|
||||
"content": "..."
|
||||
}
|
||||
]
|
||||
},
|
||||
"timestamp": "秒级时间戳字符串",
|
||||
"sign": "Base64签名"
|
||||
}
|
||||
```
|
||||
|
||||
Android 侧用 `JSONObject` / `JSONArray` 构造,避免手写 JSON 字符串。`timestamp` 保持字符串类型,与 Python 实现一致。请求头设置 `Content-Type: application/json; charset=utf-8`。
|
||||
|
||||
### 3. 网络库选择 OkHttp
|
||||
|
||||
首版推荐 OkHttp,而不是 Retrofit:
|
||||
|
||||
- 当前需求只有一个动态 webhook URL 的 POST。
|
||||
- Retrofit 更适合多接口、固定 baseUrl、声明式 API;这里会引入额外抽象但收益有限。
|
||||
- OkHttp 可以直接设置 10 秒 connect/read/write/call timeout,并明确拿到 HTTP 状态码和响应体。
|
||||
- Java 工程接入成本低,测试时可用 `MockWebServer`,也可以先只做纯 Java 请求体和响应解析测试。
|
||||
|
||||
如果后续服务器接口变多,再引入 Retrofit。
|
||||
|
||||
### 4. 线程模型
|
||||
|
||||
`BroadcastReceiver.onReceive` 生命周期短,不能同步执行网络请求。后续实现应采用:
|
||||
|
||||
- `FeishuWebhookClient.pushMarkdownAsync(...)` 提交到后台 `ExecutorService`。
|
||||
- `SmsReceiver` 在验证码解析成功、保存本地结果后,只触发异步推送,不等待网络结果。
|
||||
- 推送结果写入 `SharedPreferences` 或轻量状态 store,并通过本地广播刷新 UI。
|
||||
- 若未来需要保证进程退出后仍发送,可另起 change 引入 WorkManager;本轮不做。
|
||||
|
||||
### 5. 配置策略
|
||||
|
||||
首版本地配置文件:
|
||||
|
||||
- `webhook_id`
|
||||
- `secret`
|
||||
- `enabled`
|
||||
- `sendFullSmsBodyForDebug`,默认 false
|
||||
- 最近一次推送状态、时间、错误类型和错误摘要
|
||||
|
||||
飞书 webhook 配置保存到 `/sdcard/Android/data/{applicationId}/config/feishu.json`。如果 `feishu.json` 不存在,app 生成默认模板 `/sdcard/Android/data/{applicationId}/config/def_config_feishu.json`,但不把模板当作生效配置。这样调试时可以直接改 `feishu.json`,不需要重新编译 Android 代码。
|
||||
|
||||
最近一次推送状态仍可保存在 `SharedPreferences`,因为它不是动态调试配置。UI 展示时 secret 必须掩码,不在日志中打印。
|
||||
|
||||
### 6. 推送内容策略
|
||||
|
||||
验证码解析成功时,默认 markdown 内容建议包含:
|
||||
|
||||
- 验证码:解析出的 code。
|
||||
- 来源:`system_sms_broadcast` / `sms_inbox_*`。
|
||||
- 发送方:掩码后的 sender。
|
||||
- 时间:本地格式化时间。
|
||||
- 解析策略和置信度:便于诊断。
|
||||
|
||||
默认包含完整短信原文,便于远端调试确认。仍不建议在 logcat 打印完整正文。
|
||||
|
||||
### 7. 响应解析和错误分类
|
||||
|
||||
成功条件:
|
||||
|
||||
- HTTP status 为 200。
|
||||
- 响应体是 JSON。
|
||||
- JSON `code` 为数字 0。
|
||||
|
||||
错误分类:
|
||||
|
||||
- `disabled`:用户未开启推送。
|
||||
- `missing_config`:缺少 `webhook_id` 或 `secret`。
|
||||
- `sign_error`:HMAC 算法或 key 初始化失败。
|
||||
- `network_error`:DNS、连接失败、TLS、Socket 异常等。
|
||||
- `timeout`:请求超过 10 秒。
|
||||
- `http_error`:HTTP status 非 200。
|
||||
- `invalid_json`:响应不是合法 JSON。
|
||||
- `api_error`:飞书返回 `code != 0`,记录 code 和 msg。
|
||||
|
||||
日志策略:
|
||||
|
||||
- 可以记录错误类型、HTTP status、飞书 code/msg。
|
||||
- 不记录 secret、sign、完整 webhook URL。
|
||||
- 不默认记录完整 markdown 内容。
|
||||
|
||||
## Privacy Boundaries
|
||||
|
||||
- 默认仅上传验证码和必要诊断摘要。
|
||||
- 飞书推送默认包含完整短信正文;开启推送即表示允许验证码短信离开设备。
|
||||
- 不上传联系人通讯录、短信历史或设备标识。
|
||||
- 本地保存 secret 时使用 `SharedPreferences` 只满足个人调试场景;如需更严格保护,应另起 change 使用 Android Keystore 加密。
|
||||
- 推送到飞书意味着验证码会离开设备,UI 应让用户明确知道远端推送已开启。
|
||||
|
||||
## Test Strategy
|
||||
|
||||
单元测试:
|
||||
|
||||
- `generateSign` 固定输入输出测试。
|
||||
- 请求 JSON 构造测试,验证字段名、类型和嵌套结构。
|
||||
- webhook URL 拼接测试,防止多余斜杠和空 id。
|
||||
- 响应解析测试:
|
||||
- `{"code":0,"msg":"success"}` 成功。
|
||||
- `{"code":19021,"msg":"invalid sign"}` 返回 `api_error`。
|
||||
- 空响应、HTML、非法 JSON 返回 `invalid_json`。
|
||||
- 配置缺失测试。
|
||||
|
||||
手动验证:
|
||||
|
||||
- 在 UI 输入 webhook id 和 secret,点击“测试推送”。
|
||||
- 使用真实飞书机器人确认收到 markdown 卡片。
|
||||
- 故意填错 secret,确认 UI 显示飞书业务错误而不是短信接收失败。
|
||||
- 断网或飞行模式下测试 `network_error`/`timeout`。
|
||||
- 收到真实验证码短信后,确认本地结果先保存,远端推送状态独立更新。
|
||||
|
||||
## Rollout Plan
|
||||
|
||||
1. 完成本 OpenSpec 并 validate。
|
||||
2. 新增 OkHttp 依赖和 `INTERNET` 权限。
|
||||
3. 实现签名、请求体构造、响应解析和异步发送模块。
|
||||
4. 增加 JSON 配置 store 和最近推送状态。
|
||||
5. 在 `MainActivity` 增加配置、测试发送和状态展示。
|
||||
6. 将验证码解析成功后的推送接入异步链路。
|
||||
7. 增加聚焦单元测试,不要求本轮编译。
|
||||
|
||||
## Open Questions
|
||||
|
||||
- webhook id 和 secret 是否只用于本机调试,还是需要后续提供导入/导出配置。
|
||||
- 默认推送内容是否只发验证码,还是需要包含发送方掩码和解析策略。
|
||||
- 是否需要推送所有收到的字符串,还是只在验证码解析成功时推送。
|
||||
- 如果网络失败,是否需要后续补发;本轮建议不做持久化补发队列。
|
||||
@@ -0,0 +1,67 @@
|
||||
## Why
|
||||
|
||||
当前 `SmsReceive` 已经具备短信验证码接收、解析、存储和本地诊断能力。新需求是在收到字符串内容后,把它发送到服务器。用户已经给出 Python 参考实现,目标服务器实际是飞书机器人 webhook:构造 interactive markdown 卡片,使用 `timestamp + "\n" + secret` 生成 HmacSHA256 + Base64 签名,然后 POST 到 `https://open.feishu.cn/open-apis/bot/v2/hook/{webhook_id}`。
|
||||
|
||||
这次变更的重点不是重新设计服务端协议,而是把 Python 中已经验证过的请求协议等价迁移到 Android,并与当前短信接收链路解耦。Android 侧应提供一个可测试、可诊断、可复用的发送模块,后续可以由 `SmsReceiver`、手动测试按钮或其它业务入口调用。
|
||||
|
||||
## What Changes
|
||||
|
||||
- 新增飞书 webhook 推送规格,覆盖:
|
||||
- 签名算法:保持与 Python `generate_sign(secret, timestamp)` 完全一致。
|
||||
- 请求体:保持 `msg_type=interactive`,卡片元素为 markdown content。
|
||||
- URL:`https://open.feishu.cn/open-apis/bot/v2/hook/{webhook_id}`。
|
||||
- 网络请求:Android 侧使用 OkHttp 作为首选实现,避免为了一个简单 POST 引入 Retrofit 接口层。
|
||||
- 线程模型:所有网络请求必须在后台线程执行,不能阻塞 `BroadcastReceiver.onReceive` 或主线程。
|
||||
- 结果判断:HTTP 200 且响应 JSON `code == 0` 才视为成功。
|
||||
- 失败诊断:区分签名失败、参数缺失、HTTP 非 200、响应 JSON 异常、飞书业务错误码、网络异常和超时。
|
||||
- 新增轻量配置入口:
|
||||
- `webhook_id`、`secret` 不写死在代码中。
|
||||
- 实际配置从 `/sdcard/Android/data/{applicationId}/config/feishu.json` 读取,便于动态调试。
|
||||
- 如果 `feishu.json` 不存在,则生成默认模板 `/sdcard/Android/data/{applicationId}/config/def_config_feishu.json`。
|
||||
- 后续实现可接入当前短信结果:
|
||||
- 成功解析验证码后,可以把验证码摘要、来源、时间和发送方掩码作为 markdown 内容推送。
|
||||
- 按调试需求推送完整短信原文,便于确认服务端收到的内容与本机短信一致。
|
||||
|
||||
## Capabilities
|
||||
|
||||
### New Capabilities
|
||||
|
||||
- `feishu-webhook-push`: 定义 Android 侧飞书机器人 webhook 推送能力,包括签名、请求体、网络执行、响应解析、错误诊断和隐私边界。
|
||||
|
||||
### Modified Capabilities
|
||||
|
||||
- `sms-code-capture`: 后续实现可以在验证码解析成功后触发推送,但短信捕获本身不依赖网络成功。
|
||||
- `sms-receiver-delivery-diagnostics`: 后续诊断应区分“短信接收/解析成功”和“远端推送成功/失败”,避免把网络失败误判为短信接收失败。
|
||||
|
||||
## Impact
|
||||
|
||||
- 预期后续会修改:
|
||||
- `app/build.gradle`:新增 OkHttp 依赖,必要时新增 JSON 解析依赖或使用 `org.json`。
|
||||
- `app/src/main/AndroidManifest.xml`:新增 `android.permission.INTERNET`。
|
||||
- `app/src/main/java/com/smsreceive/app/`:新增飞书推送相关 Java 类,例如 `FeishuWebhookClient`、`FeishuWebhookConfigStore`、`FeishuWebhookPushResult`。
|
||||
- `MainActivity`:新增 JSON 配置路径展示、配置输入、测试发送和最近推送结果展示。
|
||||
- `SmsReceiver` 或统一结果处理层:在验证码解析成功后触发异步推送。
|
||||
- 推荐技术选择:
|
||||
- 网络库:OkHttp。
|
||||
- JSON 构造/解析:优先使用 Android 自带 `org.json`,降低依赖数量。
|
||||
- 签名:`javax.crypto.Mac` + `SecretKeySpec` + `android.util.Base64.NO_WRAP`。
|
||||
- 异步执行:小型 `ExecutorService` 或现有轻量后台执行器,不引入协程/RxJava。
|
||||
- 隐私影响:
|
||||
- 默认推送验证码摘要、来源、发送方掩码、时间和短信原文。
|
||||
- 不在 logcat 打印 secret、sign、完整 webhook URL 或完整短信正文。
|
||||
|
||||
## Validation
|
||||
|
||||
- OpenSpec 文档结构完整,包含 `proposal.md`、`design.md`、`tasks.md` 和 capability spec。
|
||||
- 方案必须能解释以下问题:
|
||||
- Python 签名算法如何在 Android 中等价实现。
|
||||
- 为什么首选 OkHttp 而不是 Retrofit。
|
||||
- 为什么网络请求不能直接在 `BroadcastReceiver.onReceive` 内同步执行。
|
||||
- 如何判断推送成功,以及失败时如何诊断。
|
||||
- 哪些短信内容可以上传,哪些默认不上传。
|
||||
- 后续代码完成后:
|
||||
- 签名单元测试使用固定 `secret` 和 `timestamp` 对比 Python 算法输出。
|
||||
- 请求体构造测试验证 JSON 字段与 Python 参考实现一致。
|
||||
- 响应解析测试覆盖 `code == 0`、业务错误码、非 JSON 响应。
|
||||
- 不要求本轮编译;代码完成后通知用户即可。
|
||||
- 每次 commit 或 push 前必须检查 diff,避免引入非预期 EOF newline 变化。
|
||||
@@ -0,0 +1,96 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Generate Feishu webhook signatures equivalent to the Python reference
|
||||
The app SHALL generate Feishu webhook signatures with the same algorithm and input layout as the provided Python implementation.
|
||||
|
||||
#### Scenario: Signature is generated for a timestamp and secret
|
||||
- **WHEN** the app signs a request with a second-level timestamp and secret
|
||||
- **THEN** it MUST build the signing key as `timestamp + "\n" + secret`
|
||||
- **AND** it MUST use HmacSHA256 with an empty message body
|
||||
- **AND** it MUST return a Base64 encoded signature without inserted line breaks
|
||||
|
||||
#### Scenario: Signing fails
|
||||
- **WHEN** the HMAC algorithm or key initialization fails
|
||||
- **THEN** the app MUST return a structured `sign_error`
|
||||
- **AND** it MUST NOT attempt to send the webhook request
|
||||
|
||||
### Requirement: Send interactive markdown cards to Feishu webhook
|
||||
The app SHALL send markdown content to the Feishu bot webhook using the same request structure as the Python reference.
|
||||
|
||||
#### Scenario: Markdown content is sent
|
||||
- **WHEN** push is enabled and webhook configuration is valid
|
||||
- **THEN** the app MUST POST JSON to `https://open.feishu.cn/open-apis/bot/v2/hook/{webhook_id}`
|
||||
- **AND** the JSON body MUST contain `msg_type` as `interactive`
|
||||
- **AND** the JSON body MUST contain a card element with `tag` as `markdown` and `content` as the markdown string
|
||||
- **AND** the JSON body MUST contain `timestamp` as a string and `sign` as the generated signature
|
||||
|
||||
#### Scenario: Webhook configuration is missing
|
||||
- **WHEN** push is requested without a webhook id or secret
|
||||
- **THEN** the app MUST return a structured `missing_config` result
|
||||
- **AND** it MUST NOT perform a network request
|
||||
|
||||
### Requirement: Execute webhook network requests off the main and broadcast threads
|
||||
The app SHALL avoid blocking UI and SMS broadcast handling while sending webhook requests.
|
||||
|
||||
#### Scenario: SMS receiver triggers a push
|
||||
- **WHEN** a verification code is parsed successfully in `SmsReceiver`
|
||||
- **THEN** the app MUST save the local capture result first
|
||||
- **AND** it MUST dispatch the webhook push asynchronously
|
||||
- **AND** it MUST NOT wait for the network request before returning from broadcast handling
|
||||
|
||||
#### Scenario: User sends a test push
|
||||
- **WHEN** the user taps a test push action in the UI
|
||||
- **THEN** the app MUST run the network request on a background executor
|
||||
- **AND** it MUST update the latest push status when the request completes
|
||||
|
||||
### Requirement: Classify webhook push results
|
||||
The app SHALL classify success and failure states so SMS receiving diagnostics remain separate from network diagnostics.
|
||||
|
||||
#### Scenario: Feishu returns success
|
||||
- **WHEN** the HTTP status is 200 and the response JSON contains `code` equal to 0
|
||||
- **THEN** the app MUST record the push as successful
|
||||
|
||||
#### Scenario: HTTP status is not successful
|
||||
- **WHEN** the webhook response HTTP status is not 200
|
||||
- **THEN** the app MUST record an `http_error` with the HTTP status code
|
||||
|
||||
#### Scenario: Response is not valid JSON
|
||||
- **WHEN** the webhook response body cannot be parsed as JSON
|
||||
- **THEN** the app MUST record an `invalid_json` result
|
||||
|
||||
#### Scenario: Feishu returns a business error
|
||||
- **WHEN** the webhook response JSON contains `code` not equal to 0
|
||||
- **THEN** the app MUST record an `api_error`
|
||||
- **AND** it MUST include the Feishu `code` and `msg` when available
|
||||
|
||||
#### Scenario: Network request fails or times out
|
||||
- **WHEN** OkHttp reports an I/O failure
|
||||
- **THEN** the app MUST record `network_error` or `timeout` according to the failure type
|
||||
|
||||
### Requirement: Keep webhook configuration private while pushing complete SMS content
|
||||
The app SHALL avoid exposing webhook secrets while sending complete SMS content for debugging.
|
||||
|
||||
#### Scenario: Runtime config is loaded
|
||||
- **WHEN** the app needs Feishu webhook settings
|
||||
- **THEN** it MUST read them from `/sdcard/Android/data/{applicationId}/config/feishu.json`
|
||||
- **AND** changing that JSON file MUST NOT require recompiling Android code
|
||||
|
||||
#### Scenario: Runtime config file is missing
|
||||
- **WHEN** `/sdcard/Android/data/{applicationId}/config/feishu.json` does not exist
|
||||
- **THEN** the app MUST create `/sdcard/Android/data/{applicationId}/config/def_config_feishu.json`
|
||||
- **AND** it MUST keep remote push disabled until a valid `feishu.json` is provided or saved
|
||||
|
||||
#### Scenario: Configuration is displayed or logged
|
||||
- **WHEN** the app displays or logs webhook configuration
|
||||
- **THEN** it MUST mask the secret
|
||||
- **AND** it MUST NOT log the generated signature or full webhook URL
|
||||
|
||||
#### Scenario: Verification code push content is built
|
||||
- **WHEN** the app builds markdown content from a parsed SMS result
|
||||
- **THEN** it MUST include the verification code and minimal diagnostics such as source, masked sender, time, strategy, and confidence
|
||||
- **AND** it MUST include the full original SMS body
|
||||
|
||||
#### Scenario: Webhook push is disabled
|
||||
- **WHEN** a verification code is parsed while push is disabled
|
||||
- **THEN** the app MUST keep local SMS capture behavior unchanged
|
||||
- **AND** it MUST record or report that remote push was skipped because it is disabled
|
||||
@@ -0,0 +1,67 @@
|
||||
## 1. Spec And Context Validation
|
||||
|
||||
- [x] 1.1 阅读 Python 参考实现,确认签名、请求体、URL、超时和成功判定
|
||||
- [x] 1.2 阅读当前 Android 工程结构,确认 Java、Gradle、权限和短信接收链路现状
|
||||
- [x] 1.3 生成飞书 webhook 推送 OpenSpec proposal、design、tasks 和 capability spec
|
||||
- [x] 1.4 用 `npx openspec validate add-feishu-webhook-push` 校验规格结构
|
||||
- [x] 1.5 后续提交或 push 前检查 diff,避免引入非预期 EOF newline 变化
|
||||
|
||||
## 2. Dependencies And Manifest
|
||||
|
||||
- [x] 2.1 在 `app/build.gradle` 新增 OkHttp 依赖
|
||||
- [x] 2.2 在 `AndroidManifest.xml` 新增 `android.permission.INTERNET`
|
||||
- [x] 2.3 不引入 Retrofit、RxJava、协程或 WorkManager
|
||||
|
||||
## 3. Signing And Request Model
|
||||
|
||||
- [x] 3.1 新增签名方法,使用 `timestamp + "\n" + secret` 作为 HMAC key,空消息体,HmacSHA256,Base64 NO_WRAP
|
||||
- [x] 3.2 新增请求体构造方法,输出与 Python 参考实现一致的 interactive markdown JSON
|
||||
- [x] 3.3 新增 webhook URL 拼接方法,处理空 id 和首尾空格
|
||||
- [x] 3.4 避免在日志中输出 secret、sign 和完整 webhook URL
|
||||
|
||||
## 4. Network Client
|
||||
|
||||
- [x] 4.1 新增 `FeishuWebhookClient`
|
||||
- [x] 4.2 使用 OkHttp POST JSON
|
||||
- [x] 4.3 设置 10 秒请求超时
|
||||
- [x] 4.4 HTTP 200 且响应 JSON `code == 0` 时返回成功
|
||||
- [x] 4.5 分类返回配置缺失、签名失败、网络异常、超时、HTTP 错误、JSON 解析失败和飞书业务错误
|
||||
- [x] 4.6 网络请求只在后台线程执行
|
||||
|
||||
## 5. Config And State
|
||||
|
||||
- [x] 5.1 新增 `FeishuWebhookConfigStore`,通过 `/sdcard/Android/data/{applicationId}/config/feishu.json` 保存 enabled、webhook id、secret 和 debug 上传开关
|
||||
- [x] 5.2 新增最近推送状态,包含时间、成功状态、错误类型和错误摘要
|
||||
- [x] 5.3 UI 展示 secret 时使用掩码
|
||||
- [x] 5.4 默认推送完整短信原文,便于远端调试
|
||||
- [x] 5.5 `feishu.json` 不存在时生成默认模板 `def_config_feishu.json`
|
||||
|
||||
## 6. UI And Manual Test
|
||||
|
||||
- [x] 6.1 在 `MainActivity` 增加飞书推送配置区域
|
||||
- [x] 6.2 增加 webhook id 和 secret 输入入口
|
||||
- [x] 6.3 增加启用/停用远端推送开关
|
||||
- [x] 6.4 增加“测试推送”按钮,发送固定 markdown 测试内容
|
||||
- [x] 6.5 展示最近一次推送结果,并与短信接收结果分开
|
||||
|
||||
## 7. SMS Flow Integration
|
||||
|
||||
- [x] 7.1 验证码解析成功后构造默认 markdown 摘要
|
||||
- [x] 7.2 `SmsReceiver` 保存本地结果后触发异步推送
|
||||
- [x] 7.3 推送失败不影响本地短信捕获、解析和 UI 刷新
|
||||
- [x] 7.4 默认推送内容包含验证码、来源、发送方掩码、时间、解析摘要和短信原文
|
||||
|
||||
## 8. Tests
|
||||
|
||||
- [x] 8.1 增加签名单元测试,固定输入输出对齐 Python 实现
|
||||
- [x] 8.2 增加请求体构造测试
|
||||
- [x] 8.3 增加响应解析测试,覆盖成功、业务错误和非法 JSON
|
||||
- [x] 8.4 增加配置缺失测试
|
||||
- [x] 8.5 不要求本轮编译;代码完成后通知用户
|
||||
|
||||
## 9. Delivery Criteria
|
||||
|
||||
- [x] 9.1 OpenSpec validate 通过
|
||||
- [x] 9.2 相关上下文逻辑分析通过
|
||||
- [x] 9.3 相关测试通过
|
||||
- [x] 9.4 代码实现完成后通知用户,不强制编译
|
||||
Reference in New Issue
Block a user