Skip to content

Latest commit

 

History

History
82 lines (53 loc) · 7.04 KB

File metadata and controls

82 lines (53 loc) · 7.04 KB

系统架构与共享契约 v0.1

已采用 Expo/React Native + Supabase Auth/Postgres/Edge Functions,成熟项目比较见 BACKEND-RESEARCH.md。客户端手工流程在本地运行;云服务代码已实现,但真实托管服务与模型调用尚未验证。不整仓复制 Supabase。移动端同一份 React Native UI 可输出浏览器验证版,浏览器验证不代表 iOS 真机或商店审核已经通过。

flowchart LR
  U[用户] --> APP[Expo iPhone App / 本地浏览器预览]
  APP --> LOCAL[设备本地范围/请求/回复]
  APP -->|邮箱验证码| AUTH[Supabase Auth]
  APP -->|显式同意 + JWT + 文本| EDGE[analyze Edge Function]
  EDGE --> QUOTA[Postgres 原子用量限制]
  EDGE --> MODEL[服务端模型提供商]
  MODEL --> VALIDATE[结构和原文引用校验]
  VALIDATE -->|仅建议| APP
  U -->|确认结论 + 工时/费率| APP
  APP -->|确定性计算| REPLY[可编辑回复/手动复制]
Loading

文件所有权和落地

  • src/domain.ts:root 维护共享契约、报价与引用验证,测试在 tests/domain.test.ts
  • app/src/components/src/theme.tssrc/store.tsx:前端 agent 维护。
  • src/cloud.ts:后端 agent 维护客户端云 API 与 Auth,前端按导出契约调用。
  • supabase/tests/backend*:后端 agent 维护;根目录依赖由 root 安装。
  • docs/、品牌素材、上架资料:研究/设计 agent 与 root 按分工维护。

共享 TS 契约

Clause { id: string; text: string }

Verdict = 'included' | 'additional' | 'clarify'

Analysis { verdict: Verdict; summary: string; evidence: { clauseId: string; quote: string }[]; questions: string[]; source: 'ai' | 'manual'; warnings: string[] }

Project { id; name; client; clauses: Clause[]; createdAt: string; sample?: boolean }

SavedReply { id; projectId; projectName; request: string; decision: Verdict; text: string; amountCents: number | null; createdAt: string; scopeSnapshot: Clause[]; analysisSnapshot?: Analysis; sample?: boolean }

parseClauses(text)validateAnalysis(raw, clauses)calculateQuote(hoursText, rateText)buildReply({ projectName, request, decision, hours, rate, note? }) 由 domain 导出。calculateQuote 返回整数分,无效值抛出可展示错误。draft 模板不调模型。

保存时复制当前范围为 scopeSnapshot,复制审阅建议/人工标记的引用、问题和警告为 analysisSnapshot;最终 decision 独立保存。快照与之后的页面编辑分离。旧本地记录允许没有 analysisSnapshot,不补造历史依据。示例项目的 sample 标记传递到保存记录。

amountCents 只记录未修改模板的结构化金额。最终正文相对生成模板发生自定义修改时(比较时忽略首尾空白),保存为 null,历史页显示“Edited reply · amount not recorded”,不从自由文本猜测金额,也不继续显示旧金额。例如工时 4、时薪 75 生成 30000 分;把正文费用改成 $500 后,正文仍可保存/复制,但独立金额为未知,不能计作 $300 或 $500 的收入。重新生成并保留模板原文时可再次记录确定金额。

可选浏览器工具

src/web-tools.tsx 在浏览器暴露兼容的 document.modelContext.registerTool 时注册只读 calculate_scopepatch_estimate;原生端或不支持的浏览器不注册,注册失败不阻塞应用。输入仅为人工提供的 hours/rate 十进制字符串,复用 calculateQuote,返回整数分、USD 格式与 calculated_only 状态。

这个 WebMCP 计算器不调用 AI,不估算工时、不判断范围、不读取项目正文,也不保存、发送或收费。它不是可代替用户完成审阅/发送的 agent 接口。是否能被特定浏览器宿主发现需要另外验证。

云 API 契约

前端 src/cloud.ts 导出:

  • isCloudConfigured(): boolean
  • getSession() → Promise<Session|null>;onAuthChange(callback) → unsubscribe
  • sendOtp(email)verifyOtp(email, token)signOut()deleteAccount(){ localSessionCleared: boolean }。云删除失败才抛错,云已删除但本地会话清除异常独立提示并允许重试。
  • analyzeRequest({ clauses, request, consent: true }) → Promise

POST /functions/v1/analyze,JWT 必须经过服务端 getUser 验证。请求 JSON { clauses, request, consent: true }。用户 ID 只取验证过的 JWT,不取 body。最大 30 clauses,每条 2000 字符、合计 12000 字符,请求 4000 字符,body 64KB。每账号每天最多 20 次、两次间隔至少 10 秒(私测工程额度,不是付费权益),单次 quota RPC 通过数据库事务与行锁原子预占;已预占并发出的失败仍占一次额度。模型超时 25 秒,不自动重试;客户端总等待上限 45 秒。

响应 { analysis };未配置 503,未登录 401,无同意 400,超额度 429,无效输入 400,模型失败 502/504。模型密钥只在 Edge secrets;客户端仅用 Supabase URL 与 publishable/anon key。允许的浏览器 origin 从部署配置读取,native 无 origin 走 JWT。日志不记原始范围和请求。

POST /functions/v1/delete-account:验证登录用户,删除其云资料/用量和 Auth 身份,客户端随后清本地数据和会话。不得使用用户提供的 userId 删除任意账号。

数据库

Auth auth.users → 自有 profiles / projects / scope_versions / change_requests / replies(按版本扩展)与 ai_usage

每张含业务内容的表必须包含 owner_id,开启 RLS,SELECT/INSERT/UPDATE/DELETE 都限制 auth.uid() = owner_id,并保证父对象同属一个 owner,不能只保护最外层表。快照不可覆盖历史。ai_usage 客户端不可写;仅服务端 service role 调受限制 RPC,撤销 public/anon/authenticated 执行权限。账号删除以外键级联清理。

MVP 保存路径是本地,云表不意味着已完成同步。当前预留的云 replies.amount_cents 为非空,未来接入同步前必须迁移为兼容本地未知金额的语义;不能把 null 转成 0 或旧估价。业务内容的 RLS、复合外键、quota 权限和删除级联已通过本地真实 Postgres 测试;真实托管环境双账号、JWT 过期与刷新、多连接并发仍待验证,见 QA.md

部署与演进

  1. 本地 Expo 先跑无密钥手工闭环;导出 web 预览用于评审。
  2. 新建用户自己拥有的 Supabase 项目,选目标市场附近区域,应用 SQL 与 Edge functions,配置模型 secrets、允许 origin、认证发信服务。
  3. 在真实模型上跑评测集,真实 iPhone 私测,确认隐私披露。
  4. 只有付费/复用信号出现后再做云同步与 IAP。数字功能收费采用 StoreKit/RevenueCat 的商店内购路线,服务端校验交易/通知并做幂等权益,不相信客户端 isPro。
  5. App Store 需用户自己的开发者账号、签名与审核材料;EAS 配置随代码提供,实际提交和费用未产生。

不预设服务器月费/模型固定价格;单位经济以实时价、实际 token 与调用量核算。试点预算和退出阈值见验证计划。