日期:2026-08-11
状态:暂停,待继续设计评审
目标:以 spec-kit 流程接入 LINE Pay Online API v4 Sandbox,并在设计批准后依次完成 specify -> plan -> tasks -> implement。
本文只记录已确认决策和待评审设计,不代表实现已获完整批准。不得在文档、源码、配置文件或日志中写入真实 Channel Secret。
| 议题 | 决策 |
|---|---|
| 与现有 OMG 的关系 | 方案 A:LINE Pay 与 OMG 并存,不替换 OMG |
| 支付方式编号 | 暂定 payType=8,最终在规格阶段核对现有枚举后固化 |
| API 版本 | Online API v4,Request、Check、Confirm、Retrieve、Refund 全部统一使用 /v4 |
| 环境 | 首版接入 LINE Pay Sandbox |
| 凭证模式 | 商家独立凭证,每个门店使用自己的 Channel ID / Channel Secret |
| 凭证归属 | 与现有 OMG 一致,按 pos_store 一店一套;订单通过 PosOrder.mdId 定位凭证 |
| 凭证维护者 | 平台管理员;商家端不录入、不查看 Channel Secret |
| 付款确认 | confirmUrlType=CLIENT |
| 请款方式 | Confirm 时自动请款,不实现授权/请款分离、Capture 或 Void |
| 退款范围 | 首版只支持全额退款 |
| 币种与金额 | 固定 TWD,整数金额;金额仅取服务端订单,Request/Confirm/Refund 必须一致 |
| 实现范围 | foodie_server 后端 + foodie-admin-vue 平台管理前端;用户端只交付 API 契约 |
| Sandbox 凭证 | 已具备;后续通过管理页面安全录入,不在本文记录 |
| 公网后端地址 | https://foodieapi.waimai-paotui.com |
| 用户端结果地址 | 暂留空占位,后续补充;不得硬编码虚假地址 |
LINE Pay 配置使用以下两个后端 HTTPS 地址:
confirmUrl: https://foodieapi.waimai-paotui.com/pay/line/confirm
cancelUrl: https://foodieapi.waimai-paotui.com/pay/line/cancel
它们不是用户端最终页面:
confirmUrl 只表示用户已完成 LINE Pay 认证,后端仍须调用 Confirm 或查询 API,不能直接把订单标为已支付。cancelUrl 只结束本次支付尝试,不直接取消外卖订单。项目已有 App Scheme com.twanmsdyh.app,曾提议以后使用统一入口:
com.twanmsdyh.app://payment/result?status=<success|failed|cancelled>&orderId=<orderId>
该路径尚未由用户端确认,当前仅作为候选,不得直接视为有效契约。
paymentProvider(TSP / EPI)。/v4。https://sandbox-api-pay.line.me。https://api-pay.line.me,本阶段不启用。info.paymentUrl.web;不能以 Sandbox 验证 App payment URL。paymentProvider 固定为 TSP,无法模拟 EPI;EPI 响应兼容必须列为生产前独立验收项。POST /v4/payments/request
GET /v4/payments/requests/{transactionId}/check
POST /v4/payments/{transactionId}/confirm
GET /v4/payments
POST /v4/payments/{transactionId}/refund
建议最短 Read timeout:Request 10 秒、Check/Retrieve/Refund 20 秒、Confirm 40 秒。HTTP 200 不代表业务成功,必须判断 returnCode。
请求头:
Content-Type: application/json
X-LINE-ChannelId
X-LINE-Authorization
X-LINE-Authorization-Nonce
签名使用 HMAC-SHA256,key 为 Channel Secret,结果 Base64:
GET: channelSecret + apiPath + queryString + nonce
POST: channelSecret + apiPath + exactRequestBody + nonce
关键约束:
apiPath 包含准确的 /v4 路径和路径参数,不包含 scheme 或 host。confirmUrl 是无签名的浏览器 GET 回跳,不是可信支付成功通知。orderId + transactionId + 门店 + 金额 + 币种,再由服务器 Confirm/查询取证。orderId 必须全局唯一;每次新的支付尝试使用独立 LINE orderId,不能直接复用外卖订单号。transactionId 为 19 位数字,全链路按字符串存储和返回,避免 JavaScript 精度丢失。1198 或临时错误后先调用 Retrieve 对账,不盲目重复有副作用的请求。cancelUrl 或 Check 0121 不能覆盖已通过 Confirm/Retrieve 证实的支付终态。实现与测试至少要回答以下问题:
paymentProvider。orderId 是否永久唯一,transactionId 是否始终按字符串处理。confirmUrl 到达或 cancelUrl 到达视为最终支付状态。新建 LINE Pay 凭证、支付和退款流水。只在订单取消、退款和后台查询处增加很薄的支付方式分派,不重构 OMG。
优点:边界清楚、对现有 OMG 风险较低,并能完整处理幂等、对账和审计。
建立通用 PaymentProvider 接口,并同时迁移 OMG。长期结构整洁,但超出本次范围,会扩大已运行 OMG 的回归风险。
不建独立支付/退款账本,只把交易号写入订单。无法可靠处理回跳重复、网络超时、退款恢复和审计,不满足支付安全要求。
ruoyi-system负责纯数据库能力,不引入 LINE Pay HTTP 客户端或 com.ruoyi.app.*:
pos_store_line_pay:每个 pos_store 一套加密凭证。pos_order_line_payment:每次 Request/Confirm 的独立支付流水。pos_order_line_refund:每次全额退款操作的独立流水。ruoyi-adminLinePayClient:v4 HTTP、精确 JSON/Query 签名、超时及结果码解析。LinePayService:创建、Confirm、查询、全额退款和状态机。LinePayController:用户支付接口及匿名 CLIENT 回跳接口。PosStoreLinePayController:平台管理员维护门店凭证和启用状态。LinePayReconcileTask:恢复漏回跳、Confirm 未知和 Refund 未知状态。payType 分派至 OMG 或 LINE Pay;不引用废弃支付 Controller。预定用户支付接口:
POST /pay/line/create
GET /pay/line/confirm
GET /pay/line/cancel
POST /pay/line/query
POST /pay/line/refund
create/query/refund 使用明确 DTO;需要登录的接口通过 @RequestHeader String token 获取 token。confirm/cancel 使用显式 @RequestParam,允许匿名 GET,并按重复、乱序请求设计。paymentUrl.web。foodie-admin-vue新增“LINE Pay 门店管理”,交互风格参考现有 OMG 页面,但数据和状态完全独立:
hasSecret 等脱敏状态。zh/tw/en/vi 四个 i18n 文件。updatesql/sql.md,不直接执行。foodie-admin-vue 页面。spec.md,自审并等待批准,再生成 plan.md、tasks.md,最后按 TDD 实现。