技术架构

水果供应链业财一体系统的技术架构说明。业务约束见 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 登录
审批设计器 AntV X6(原生 JS + Vite) Filament 自定义页挂载;发布编译 steps/transitions,运行时不解析 JSON;见 15
数据库 MySQL 业务库;会话/队列/缓存当前可为 database 驱动,生产可换 Redis
权限 spatie/laravel-permission + filament-shield 角色 name(key)+ label(中文);数据范围按 product_users
队列 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)│ 企微群机器人 │ 网页兜底 │
└────────────┬────────────────┬───────────────┬───────────┘
             │                │               │
┌────────────▼────────────────▼───────────────▼───────────┐
│  应用服务层                                              │
│  部门员工 │ 省市区 │ 产品 │ 仓库 │ 采购 │ 订单 │ 加工 │ 财务     │
│  消息(出站)│ AI 应用(采单/OCR)│ 数据分析                    │
└────────────┬────────────────────────────┬───────────────┘
             │                            │
┌────────────▼──────────────┐  ┌──────────▼────────────────┐
│  领域持久化(MySQL)        │  │  异步 / 外部               │
│  主数据 + 单据 + 库存流水   │  │  Queue │ Scheduler         │
│  站内消息 + 投递记录        │  │  企微/微信 API │ AI API    │
│  原始文件元数据             │  │  对象存储                   │
└───────────────────────────┘  └───────────────────────────┘

企业 H5

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;回调时更新 mobile、avatar;中间件可关 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_users 数据范围,不扩权;只读。
  • 出站推送仍走消息模块;H5 内可读站内 messages。

模块划分

模块 文档 阶段 职责
部门与员工 01 P0 企微入站同步;产品成员;权限
省市区 02 P0 省/市/区主数据;CSV 导入
产品 03 P0 产品、等级字典 grades;重量按斤
仓库 04 P0 结存流水;仓内加工单;调拨盘点;期初/报损/拆合
采购 05 P0 采购确认入库;采销关联;财务驳回
订单 06 P0 人审 → 待出库 → 出库;财务驳回冲销
生产加工 07 P0 仓内加工业务口径(表见 04)
财务 08 P0 费用申请;挂单经营费用;公司主数据;开票资料多态;发票
消息 09 P1 出站消息
数据分析 10 P1 单据金额+挂单费用+费用申请盈亏、预警、对账导出
AI 应用 11 P2 采单 OCR、语音、对话
库存确认契约 14 P0 确认与财务驳回→流水

边界

  • 改库存只经 14;stock_documents 仅期初/报损/拆合。
  • 采购与销售为独立头表;确认/驳回共用写流水服务(见 14)。
  • 买断结算不进销售单;仓间实物走调拨(规则 10)。
  • 仓内加工须已有结存;精简 process_orders 一对 from/to、同产品(多笔=多张单);只改行属性或数量;无独立降级单;后台不新开拆合。
  • AI 只进站出草稿;出站只走消息。

核心数据流

业务确认(P0)

purchases | orders | process_orders | stock_* | stock_documents
  → 确认/驳回服务(按 14 矩阵,按 source 分支)
  → 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 成功时刷新 mobile、avatar。
  • 进后台:users.status === active。不强制 panel_user,避免企微同步员工进不了后台。
  • 功能权限:laravel-permission + Filament Shield。roles.name 是代码 key(如 super_admin),roles.label 是界面中文名。后台「角色」勾资源/页面/自定义权限;员工表单赋角色。
  • 数据范围:默认限制在员工 product_users 所属产品;data.view-all 看全量。
  • 编制:employment_type 影响默认可授角色,不是独立权限包。

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

集成要点

集成 用途 注意
企微通讯录 部门、员工入站同步(回写属 P2) 关联键 wecom_dept_id / wecom_userid;编制与权限不同步
企微 OAuth / 扫码 H5/后台登录 后台 createWWLoginPanel(本机已登录可一键)+ /admin/auth/wecom/*;按 wecom_userid 登录
企微群机器人 采单 必须 @;分业务域 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_DISK(qiniu / 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。
  • kind:image / video / audio / file,限制扩展名与大小。
  • 配置:QINIU_ACCESS_KEY、QINIU_SECRET_KEY、QINIU_BUCKET、QINIU_DOMAIN、QINIU_UPLOAD_URL;MEDIA_DISK=qiniu(生产)。

访问控制

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

与业务单据的关系

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

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

依赖建议:spatie/laravel-medialibrary、filament/spatie-laravel-media-library-plugin、overtrue/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(见项目脚本)。生产:composer deploy(Envoy:filament:upgrade + livewire:publish --assets)。宝塔会把 .js 当静态文件,不把 /livewire-…/livewire.js 交给 PHP,所以 Livewire 脚本必须发到 public/vendor/livewire。

目录约定(应用侧)

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;存货成本层。