技术架构

水果供应链业财一体系统的技术架构说明。业务约束见 00-业务规则.md库存确认见 14-库存确认契约.md;表结构见各功能文档。

目标与原则

  • 轻量进销存 + 业财:采购、加工、库存、销售、费用/发票/请款同一业务库;唯一单号可追溯。
  • 确认契约:改库存只走 14;采销确认归档,财务驳回须冲销;AI 只出草稿。
  • 少造轮子:Laravel + Filament;spatie/laravel-permission;队列/缓存先用框架能力。
  • 分阶段:P0 进销存与费用发票请款 → P1 分析消息 → P2 AI(见 目录.md)。

技术选型

选型 说明
运行时 PHP 8.3
框架 Laravel 13 Web、队列、调度、Auth
管理端 Filament 5 PC 后台录入、审批、主数据、报表入口
企业 H5 Blade + Vite + Tailwind + Alpine 企微内打开,路径 /app,OAuth 登录
数据库 MySQL 业务库;会话/队列/缓存当前可为 database 驱动,生产可换 Redis
权限 spatie/laravel-permission + filament-shield 角色 name(key)+ label(中文);数据范围按 product_user
队列 Laravel Queue 采单解析、消息投递、夜间分析
调度 Laravel Scheduler 日终库存快照、每日分析
文件 Spatie Media Library + 七牛 MEDIA_DISK;未配齐七牛回退 public;H5 直传
企微 官方 API 群机器人收单、通讯录同步、应用消息、H5 OAuth / JS-SDK
企微语音 JS-SDK translateVoice 企业 H5 按住说话转写
微信 服务消息等 出站推送通道之一
AI OCR + 火山方舟 单据识别、字段抽取、语音草稿、H5 对话问数

逻辑架构

┌─────────────────────────────────────────────────────────┐
│  接入层                                                  │
│  Filament PC 后台 │ 企业 H5(/app)│ 企微群机器人 │ 网页兜底 │
└────────────┬────────────────┬───────────────┬───────────┘
             │                │               │
┌────────────▼────────────────▼───────────────▼───────────┐
│  应用服务层                                              │
│  部门员工 │ 产品SKU │ 仓库 │ 采购 │ 订单 │ 加工 │ 财务     │
│  消息(出站)│ AI 应用(采单/OCR)│ 数据分析                    │
└────────────┬────────────────────────────┬───────────────┘
             │                            │
┌────────────▼──────────────┐  ┌──────────▼────────────────┐
│  领域持久化(MySQL)        │  │  异步 / 外部               │
│  主数据 + 单据 + 库存流水   │  │  Queue │ Scheduler         │
│  站内消息 + 投递记录        │  │  企微/微信 API │ AI API    │
│  原始文件元数据             │  │  对象存储                   │
└───────────────────────────┘  └───────────────────────────┘

企业 H5

不另起前端仓库,挂在本 Laravel 应用内,企微工作台打开。

约定
入口 /app(企微 OAuth);根路径 / 进后台,若带 OAuth code/state 则转发 H5 回调
技术 Blade 视图 + Vite 8 + Tailwind + Alpine.js(按需 Chart 等)
布局 resources/views/layouts/*-app.blade.php + 独立 css/js entry(如 h5-app
页面 resources/views/h5/(或业务子目录);Controller 如 App\Http\Controllers\H5\* / WeCom\*
鉴权 企微 OAuth → 绑定 users.wecom_userid → Session;回调时更新 mobileavatar;中间件可关 H5(维护页)
JS-SDK /app/wecom/js-sdk-config;拍照、选图、语音识别translateVoice
权限 同一套 laravel-permission + 产品数据范围;H5 只暴露业务员能力子集
上传 七牛直传(token 接口);后台走 Spatie Media Library
语音录单 所有 H5 业务表单可语音 → 方舟草稿 → 人工确认后提交
对话 /app/chat;自然语言查权限内业务数据(只读)

典型路由

路由 用途
/app 企微入口 / OAuth
/app/wecom/callback OAuth 回调
/app/home 首页(待办、入口)
/app/chat 对话问数(自然语言查本人相关数据)
/app/... 单据查看、简易录入、站内消息、审批待办等
/app/wecom/js-sdk-config JS-SDK 签名

后台仍用 Filament(/admin);H5 不做完整主数据治理,复杂配置回 PC。

边界

  • 群机器人采单 ≠ H5:采单走 AI 应用;H5 做人机操作、查看与对话问数
  • 对话查询严格套用角色权限 + product_user 数据范围,不扩权;只读。
  • 出站推送仍走消息模块;H5 内可读站内 messages

模块划分

模块 文档 阶段 职责
部门与员工 01 P0 企微入站同步;产品成员;权限
产品 SKU 03 P0 产品、SKU、单位
仓库 04 P0 结存流水;调拨降级盘点;期初/报损/拆合
采购 05 P0 确认归档;采销关联;财务看板
订单 06 P0 确认归档;财务驳回
生产加工 07 P0 工单确认出入库
财务 08 P0 费用单多态;开票资料多态;发票;请款;报销
消息 09 P1 出站消息
数据分析 10 P1 单据金额+费用单盈亏、预警、对账导出
AI 应用 11 P2 采单 OCR、语音、对话
库存确认契约 14 P0 确认与财务驳回→流水

边界

  • 改库存只经 14;stock_documents 仅期初/报损/拆合。
  • 买断走订单 + related_purchase_id;仓间实物走调拨。
  • 改 SKU 计加工费走加工;同 SKU 换包装走拆合;同仓 SKU 变换走降级。
  • AI 只进站出草稿;出站只走消息。

核心数据流

业务确认(P0)

purchases / orders / process_orders / stock_* / stock_documents
  → 确认服务(按 14 矩阵)
  → stock_ledgers(source_* 必填)
  → stocks

采单落库(P2)

企微 @ / 网页 / H5 语音
  → inbound_messages → OCR + 方舟 → 草稿
  → 人工确认写入业务单
  → 再经业务确认走 14(禁止解析直接写 stocks)

语音 / 对话问数见 AI 文档;属 P2。

出站通知

业务事件 / 分析任务 / 审批
  → messages(站内必留)
  → message_deliveries(inbox / wecom / wechat …)
  → 按 message_subscriptions 发送或 skipped

日终

Scheduler(夜间)
  → stock_snapshots
  → analysis_runs → profit_daily / alerts / replenish / statements
  → 摘要写入 messages → 多平台投递

权限与数据范围

  • 认证:后台 Filament;企业 H5 企微 OAuth(绑定 wecom_userid)。二者同一 users 表。OAuth 成功时刷新 mobileavatar
  • 进后台users.status === active。不强制 panel_user,避免企微同步员工进不了后台。
  • 功能权限:laravel-permission + Filament Shield。roles.name 是代码 key(如 super_admin),roles.label 是界面中文名。后台「角色」勾资源/页面/自定义权限;员工表单赋角色。
  • 数据范围:默认限制在员工 product_user 所属产品;data.view-all 看全量。
  • 编制employment_type 影响报销制度与默认可授角色,不是独立权限包。

细节见 01-部门与员工.md

集成要点

集成 用途 注意
企微通讯录 部门、员工入站同步(回写属 P2) 关联键 wecom_dept_id / wecom_userid;编制与权限不同步
企微 OAuth H5/后台登录 回调 upsert 员工,并更新手机号、头像
企微群机器人 采单 必须 @;分业务域 bot;官方 API only
企微 JS-SDK 语音 H5 语音转写 translateVoice;需可信域名与签名
火山方舟 LLM 抽字段 / 整理草稿 / 对话问数 VOLCENGINE_ARK_*;写单未确认不入账;对话只读
微信服务消息等 出站 message_deliveries,失败可重试
AI OCR 图片/PDF 识字 与方舟串联:OCR 文本 → 方舟结构化
文件(七牛 / 本地) 单据原件、报销凭证、导出附件 见下节「文件管理」

文件管理

业务附件统一用 Spatie Media Library 做元数据与多态挂载;物理文件优先 七牛,本地开发可回退 public

分层

做法 说明
元数据 media 表;Model InteractsWithMedia;自定义 App\Models\Media 预览/下载鉴权 URL
默认盘 MEDIA_DISKqiniu / public);七牛未配齐 AK/SK/Bucket/Domain 时回退 public MediaDisk::name()
后台上传 Filament SpatieMediaLibraryFileUpload;预览/下载走应用内鉴权路由,不裸奔私有链 全局配置上传组件
H5 上传 浏览器向应用要 uploadToken + key,再直传七牛;服务端只校验 key 前缀与扩展名后挂到业务单 QiniuUpload + UploadController
CDN 图 列表缩略用七牛 imageView2 / imageslim 拼查询参数 listThumbUrl

直传约定

H5/前端
  → GET/POST /app/.../upload-token?ext=&kind=
  → 七牛 upload_url + token + 预定 key
  → 直传成功
  → 业务提交时带 key / url,服务端校验后 addMedia 或写附件字段
  • key 形态{业务前缀}/{Ymd}/{random}.{ext}(如 docs/20260331/xxxx.jpg),拒绝非托管 key。
  • kindimage / video / audio / file,限制扩展名与大小。
  • 配置QINIU_ACCESS_KEYQINIU_SECRET_KEYQINIU_BUCKETQINIU_DOMAINQINIU_UPLOAD_URLMEDIA_DISK=qiniu(生产)。

访问控制

  • 公有盘:可直接 CDN URL。
  • 需鉴权:走 media.preview / media.download(校验当前用户对父模型的查看权)。
  • 采单 OCR 原件、报销凭证等敏感附件默认按业务单权限访问,长期归档不删库只标状态。

与业务单据的关系

场景 挂载方式
采购/订单/加工附件、出入库凭证图 单据 Model Media Collection(如 attachments
报销发票/支付截图 expense_claims collection
AI 采单原图/PDF inbound_messages.attachment_paths 或 Media 挂采单记录
对账单/导出 Excel PDF 生成后可落存储,路径写入结果表

不做:自建文件中台第二套库表替代 Spatie;H5 大文件不经 Laravel 中转上传(避免撑爆 PHP)。

依赖建议:spatie/laravel-medialibraryfilament/spatie-laravel-media-library-pluginovertrue/laravel-filesystem-qiniu

部署与运行

组件 建议
Web PHP-FPM / Octane(按量)+ Nginx
Worker queue:work(解析、投递、分析)
Scheduler schedule:run 每分钟(宿主机 cron)
DB MySQL 8+;生产独立备份
缓存/队列 初期 database;并发上来后 Redis
环境 .env:DB、队列、企微、VOLCENGINE_ARK_*MEDIA_DISK / QINIU_*

本地:composer setup / php artisan dev(见项目脚本)。

目录约定(应用侧)

app/
  Models/Media.php       # 扩展 Spatie Media(预览/下载 URL)
  Support/
    MediaDisk.php        # MEDIA_DISK 解析与七牛回退
    QiniuUpload.php      # 直传 token、key、缩略图
  Http/Controllers/
    WeCom/
    H5/
    Media/               # preview / download
    H5/QiniuUploadController.php
  Filament/
resources/
  views/h5/
  css|js/                # 含七牛直传、企微语音等
docs/

不强制 DDD 分层。H5 / 文件 / 企微按上文约定实现(/app、MediaDisk、QiniuUpload、h5-app 布局)。

非功能指标(架构侧)

  • 白天录单与夜间分析隔离(队列 + 调度错峰)。
  • 库存流水可追溯到来源单号;结存与流水一致。
  • 消息站内不因外发失败丢失。
  • 敏感字段按产品成员与权限过滤。
  • 导出 Excel/PDF 异步生成大文件,避免拖死请求。

演进

  1. P0:主数据 + 14(含驳回冲销)+ 采销归档 + 加工仓库 + 费用单/开票资料/发票/请款报销。
  2. P1:夜间分析、消息推送、账期对账、回款强闭环。
  3. P2:AI 采单/语音、H5 对话问数。
  4. 按需:Redis;MEDIA_DISK=qiniu;存货成本层。