跳转至

02 - 功能需求清单(Web SaaS PRD)

本文件描述学校内网 Web SaaS 目标形态。数据隔离以「组织 → 工作区 → 成员」为准,完整的权限与 schema 见 03-architecture.md 和 04-database.md。

优先级:P0 为首个可用闭环必需;P1 为内网正式试用必需;P2 为验证价值后再投入的增强项。

1. 身份、工作区与权限

功能点 需求描述 优先级
登录与账户管理 使用邮箱/密码或 OAuth(CC98/GitHub)登录,better-auth 管理 session;开放注册关闭,新用户须 8 位邀请码(admin 批量生成于 /admin/invites);首个管理员由部署配置初始化;CAS/LDAP 仍预留不接入。 P0
默认个人工作区 用户首次开户时原子创建个人工作区与 owner 成员关系。用户不需理解多租户概念即可上传、归档和导出自己的票据。 P0
工作区切换 已加入多个工作区的用户可在页头切换当前空间;所有业务请求带当前工作区上下文,切换后刷新列表、指标与 SSE 订阅状态。 P0
共享工作区 管理员/owner 可创建项目、部门或出差共享空间,邀请成员并分配 owner / manager / member / viewer。个人空间默认仅本人可见。 P1
权限与审计 Prisma scope、PostgreSQL RLS 与同工作区复合外键共同防止越权;管理员排障读取他人数据需说明原因并写 access_audit。 P0
工作区生命周期 支持归档工作区;删除作为异步、可审计的受限操作,已报销发票与审计记录不得静默物理删除。 P2

2. 上传、邮箱与任务管道

两个输入源统一进入 /data/invoice/{workspace_id}/uploads/ 与 parse_task 队列,不能形成两套解析逻辑。

功能点 需求描述 优先级
网页上传 投递区支持多选/拖拽上传 PDF、JPG、JPEG、PNG,也可拖入文件夹并递归导入其中支持的文件;目录树仅用于发现文件,展开后按普通文件统一分类与归档,不保存相对路径。客户端按每批最多 20 个文件依次提交,显示扫描状态、上传进度和每个文件的受理结果。上传完成事件替代桌面版文件稳定检测。 P0
输入校验 限制扩展名、文件大小和空文件;临时上传写入临时名后原子 rename,再创建 workspace_file 与任务。 P0
工作区文件防重 同一工作区内按 (workspace_id, blob_id) 去重,重复文件返回 DUPLICATE_FILE;命中文件的原发票/附件已软删时恢复该记录并提示(撤销删除而非重复);不得通过跨工作区哈希命中泄露文件是否存在。 P0
任务状态与重试 UI 展示 pending / processing / done / failed / duplicate / skipped(skipped = OFD/XML 等不支持解析的附属格式,不进 OCR);网络、限流等可恢复错误按 30 秒/2 分钟/10 分钟重试,超过上限标记失败并允许人工重试。 P0
邮箱自动拉取 worker cron 按工作区邮箱账户轮询 IMAP over SSL;附件流式写入 uploads 后复用上传管道。支持 QQ、163、Gmail、企业邮箱。 P1
邮件筛选与增量 支持发件人白名单、主题关键词和扩展名白名单(.ofd/.xml 电子发票附属格式直接跳过不入库);以 UIDVALIDITY + UID 水位增量拉取,mail_account_id + message_id 兜底防重;已处理邮件默认只标记 \\Seen。 P1
财务门户账户 以浙大计财处门户为首接入源:账户密码信封加密托管,worker 按账户轮询现场登录(验证码自动识别、4 次锁定内换码重试),登录态会话即弃;失败落 last_error,连续失败达到阈值时通知账户创建者。 P1
历史回溯 首次配置可设置回溯天数,默认 0(仅此后的新邮件)。 P2

3. OCR、分类与附件

功能点 需求描述 优先级
百度发票 OCR 所有候选发票经 Provider 调用百度「增值税发票识别」;worker 并发 2 且队列限速 2 QPS。字段映射见 05-ocr-fields.md。 P0
Provider 抽象 所有厂商经 InvoiceProvider 接口接入;领域层不得直接发 HTTP 请求。 P0
原始返回留存 ocr_raw_json 完整按原始文本保存,支持字段映射调整后的免付费重放。 P0
组织级票据防重 OCR 后对规范化 (organization_id, invoice_num, invoice_code) 争抢唯一键;全电票空代码规范化为 ''。冲突只告知“已报销或处理中”,不泄露其他工作区记录。 P0
智能分类(分类器链) 分类器链判定 category:可插拔有序分类器,首个给出结论的生效。链序(越靠前越权威):用户规则 → 工作区规则 → 组织规则(各层 priority 升序)→ 内置高校科目词典(标准分类为浙大日常报销 48 个叶子,一级/二级 名称加门户 bCode/buCode,如 出租车 → 交通费/市内交通费 / B0402)→ 百度 ServiceType 直映(国税简称经别名表归一到科目,未映射保留原值)。全部放弃 → “未分类”。每个结论落库带 category_source 来源标记,可溯源与对比评估;预留模型判别分类器(LLM/ML 兜底未分类),实现同一契约插入链尾,ocr_raw_json 完整留存支持零成本模型重放。 P0
附件自动识别 发票 OCR 返回 282103 模板不匹配时,自动转入通用文字识别;保存全文并进入附件匹配子管道。 P1
附件匹配 金额精确相等为必要锚点(金额同时从 OCR 全文与原文件名提取,文件名可兜回 OCR 吃掉小数点的真值);再以商户、日期、商品词、文件名重叠消歧,仅唯一最高分才自动挂载。无法确定时虚拟路径落 Archive/unmatched/ 待人工配对,绝不误挂;新发票入库时反查补挂,并提供「回放重匹配」用已存 OCR 全文免费重跑匹配。 P1
人工校正与重解析 发票详情允许修正白名单字段、标记人工编辑,并选择重放 OCR 原始结果或重新调用 OCR。 P1
结构化票据识别 行程单等附件经百度「财务票据」端点(网约车行程单/火车票/机票…)结构化识别城市、起终点、每段金额;发票按票面归一出票种与专属字段。统一文档模型与端点架构见 12-receipt-ocr.md。 P1

4. 发票、批次、额度与导出

功能点 需求描述 优先级
发票与附件管理 工作区内列表、筛选、详情、受控下载;附件可手工上传、预览、删除和人工配对。主票迁移或改名时,同前缀附件随行。发票列表可按计财处报销科目一级大类(CAMPUS_TAXONOMY 13 大类)分组折叠(「类别」表头按钮切换分组/平铺),组内显示张数与金额小计,含报销规则提醒的发票在所属分类内置顶,未归类入「未分类」,不臆造科目表外的类别;学生不可用的大类(一次性安置费/外协费/基建类/接口接入)不进入分组。 P0
报销规则提醒 发票库对每张发票实时求值报销规则并随列表提示:打车发票 >200 元未附行程单、单张 >500 元需扫码验证、单张 >1000 元需固定资产认定、日用品/消耗品(含抽纸、印章、挂钩等)需走横向经费、休闲娱乐业或礼品票据(明确关键词直接严重提醒;普通餐饮排除)、票面关键字段与购货明细完整性、超过报销时限、非本市(杭州市)打车需说明、行程起点或终点疑似饭店/娱乐场所需确认。走通用决策层,规则可扩充,命中在列表操作列以提示徽章 + 悬浮明细呈现,不落库、历史发票自动重算。日用品、行程终点与模糊休闲消费可接入 System One 决策模型(TypeSafe Jev / Cloudflare Clef);模型仅把模糊休闲消费标为待人工复核,不直接判违规。 P1
归档 OCR 成功即写库并固化 archive_path 虚拟路径(Archive/unbatched/);物理文件永驻内容寻址 blob 池、永不移动,导出交付包时按路径物化。文件不经反向代理静态公开。 P0
批次管理 创建、编辑、归档批次;批次带报销类型(日常报销 / 出差 / 固定资产),在发票页勾选多张后可直接入批,并按发票类型自动分流到对应类型批次(类型不符时拆到同类型批次或新建)。入批、拆批、批次内排序均限定在同一工作区。发票类型判断:固定资产 一级大类归固定资产,其余归日常报销;出差自动判断暂未实现,需手动选择。批次状态仅 collecting → paid 单步(无审批环节),已入批发票可随时拆回归集区。批次目录是一次报销的完整文件夹。 P1
Excel 导出 以固定模板填充统计、价税分离明细和附件清单;异步生成,结果随批次落盘并通过受控端点下载。 P1
打印版 PDF 将批次内主票和附件按批次顺序合并为单个 PDF(无封面清单页);图片自动等比转为 A4 页。 P1
手动额度计划 可配置名称、适用科目、周期和分为单位的上限;个人额度关联受益人,共享项目额度归工作区;统计已用和剩余。 P1
智能组单 建批时按选票策略给出建议入批集合:优先打车 / 优先3C / 小额优先、单张上限排除大额("不要有大额")、目标额度装满;结果仅供用户确认,确认后才入批。可按时间窗口建议出差批次(待做)。走 packages/core 策略层,与规则提醒共用票面判定。 P2
OA 半自动填报 Ego-lite 复用登录态填写 OA 表单和上传材料;提交必须人工确认,默认关闭。 P2
额度自动获取 定期抓取 OA/HR 余额写 quota_snapshot,本地剩余与官方快照偏差超阈值时预警。 P2
平台用量计量 统计付费外部调用(百度 OCR、Jev/Clef 决策模型)与 token 用量,按组织/工作区/来源归因;金额与数量整数 micros。缓存命中不计费,明细 append-only 幂等(GET /usage/summary | events)。 P1
用量配额执行 组织级 provider 配额(含额度 + block/allow 策略);调用前原子预检,超限时模型回退规则、OCR 任务终态失败。与业务「报销额度」严格区分。 P1

5. Web 界面与实时反馈

功能点 需求描述 优先级
应用壳与工作区上下文 登录后显示侧栏、当前工作区切换器、页头指标和通知铃铛;无权限或工作区被停用时明确提示并跳转。 P0
仪表盘与发票表格 展示上传投递区、待报销金额与张数(同口径,仅未入批)、累计已解析数、未匹配附件数、队列状态;发票表支持分页、排序、筛选、列显隐与详情跳转,表头冻结、列表区独立滚动,加载时显示 shimmer 骨架屏。 P0
任务实时反馈 worker 经 Redis 发布任务和统计事件,api 通过 SSE 推送;断线重连后补拉任务列表。 P0
批次与附件页面 提供批次详情、批次内排序、导出入口,以及附件待配对页的预览和点选挂载。 P1
财务门户页 仪表盘单独一页,不并入报销批次。显示当前门户登录人的姓名、学工号、手机号,名下项目的余额、额度、已报销,当前报销单,以及历史报销单的金额、状态、时间。当前报销单与历史报销单均内联展示预约物流进度(进度条 + 最新状态),点击弹窗看完整流转时间线。 P1
设置与凭据 邮箱账户、财务门户账号、工作区规则、额度等按权限提供设置页。敏感字段只显示已配置/掩码,空值提交不覆盖现有密文。 P1
明暗模式 支持浅色 / 深色 / 跟随系统三种外观与四档界面字号(小 / 标准 / 大 / 特大);页头提供明暗快捷切换,设置中心「外观」分区可完整选择、带实时预览;字号通过根字号驱动全站 rem 尺寸等比缩放,各档位保持协调;偏好存浏览器本地(不落库),首屏无闪烁,默认深色 + 标准字号。 P2
管理大屏 系统管理员全局大屏(system admin):用户量/新增/活跃趋势、各 API 调用与 token 成本、各功能使用;跨组织只读、零第三方图表依赖、15s 自动刷新。入口在账户菜单(仅 admin 可见)。 P1
用户与工作区管理 管理员管理账户和组织配置;owner/manager 管理共享工作区成员。 P1

6. 通知

功能点 需求描述 优先级
站内通知 站内通知始终启用并按 recipient_user_id 持久化;SSE 实时下发、支持未读筛选和批量已读。页面打开且浏览器已授权时同步弹出桌面通知,不建设 Web Push。 P0
业务提醒 缺少行程单/购货明细/票面字段、待扫码验证、待固定资产认定时通知发票上传者与工作区 owner/manager;材料提醒正文标明工作区、票号、商户或票面内容、金额、源文件上传时间(北京时间、精确到分钟)和具体问题,管理者个人频道及共享频道额外标明上传人。飞书材料卡片采用清晰的文字层级:彩色标题区「📌 发票材料提醒」,正文首行以略大字号加粗「问题类型 · 发票内容」;详情各字段配一个含义明确的表情,问题字段写出具体触发理由并按“问题 → 上传人 → 上传时间”排列,金额数值和具体问题加粗,其余字段保持普通字重。卡片不展示冗长票号,底部蓝色「查看详情」按钮跳转到 Clip 对应工作区和发票。财务门户报销进度变化或出现新项目号时通知账户创建者与 owner/manager。首次门户同步只建基线,不推送历史项目或进度。 P0
材料证明附件 上传者或工作区管理者可在发票检查面板直接上传 PDF/JPG/PNG 证明文件,文件按现有 blob 与附件权限体系挂载当前发票,再随材料状态操作记录为证明;同文件重复上传不制造多份附件。 P0
Webhook 频道 普通用户可全局配置个人钉钉/飞书机器人,只接收发给本人的事件;共享频道仅保留工作区级,组织级退役。频道可分别订阅「缺材料 / 审核进度 / 新项目」,密钥 AES-256-GCM 信封加密保存。 P1
可靠投递 业务事件以 PostgreSQL outbox 和唯一 dedupe_key 持久化;站内通知按收件人展开,个人频道按收件人投递,共享频道每事件只投递一次。Webhook 失败指数退避重试,限速只延迟、不丢弃;站内通知始终兜底。 P1

钉钉材料提醒与飞书共用标题、票面摘要、表情、加粗重点和字段顺序,有详情链接时使用带「查看详情」按钮的原生 actionCard。钉钉支持加签自定义机器人,以及无需旧机器人签名的自动化流程 Webhook;后者需配置 Text 参数和后续群消息源数据解析。

7. 非功能需求

项目 要求
数据安全 发票、附件和导出物仅经受控 API 下载;业务表启用 PostgreSQL RLS;密钥与授权码信封加密,禁止出现在日志、异常栈和接口响应。
数据一致性 PostgreSQL 是唯一事实源;归档/入批/挂载纯写库无文件副作用,上传/导出/回收先写库后动文件;Redis 可丢可重建。
数据口径 金额只存分且 API 也传 integer;发票日期为 YYYY-MM-DD;OCR 原始响应不截断、不重排。
可观测性 api/worker 输出脱敏结构化日志;任务、邮件拉取、通知失败有可查询状态;健康检查供部署系统调用。
性能与并发 OCR 队列固定限速 2 QPS;普通列表用工作区前缀索引和 offset 分页;SSE 经 Caddy 反代即时 flush。
备份与恢复 每日 pg_dump 与 /data 卷快照;恢复演练覆盖数据库、文件和加密主密钥。

8. 明确不在当前范围

  • OA 自动提交与无人值守报销审批;自动化仅允许“填写后人工确认提交”。
  • 完整审批流、成本中心分摊、跨组织共享工作区;如需引入,先补充产品规则与独立领域模型。
  • 公有云多租户运营、计费和自助注册;本期是学校内网单组织部署。

通知设置提供统一「通知配置指南(Webhook)」入口,在新标签页打开该指南,保留当前配置表单。指南正文由文档站持有(docs/usage/webhooks.md,站点路径 /usage/webhooks/),以 Markdown 维护、免登录可读,包含飞书和钉钉自定义机器人、安全设置、Clip 字段说明、测试与常见问题;Web 内的 /help/webhooks 只做跳转(目标由构建期 NEXT_PUBLIC_DOCS_URL 注入)。

通知渠道仅提供个人与工作区级,组织级渠道退役。工作区级配置说明:想让多个工作区的提醒发送到同一个群,请在各工作区分别创建通知渠道,填写同一个机器人 Webhook 地址和签名密钥;各渠道独立订阅和停用。