Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

700 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Y-Link 文创出入库与 O2O 预订系统

Vue TypeScript Express Docker

Y-Link 是一套面向文创、非遗、门店和活动场景的库存管理系统,覆盖“线上预订、线下核销、出库开单、供货入库、库存追踪、客户反馈”流程。

系统包含两端:

  • 管理端:管理员、运营人员、供货方使用,负责商品、库存、出入库、核销、用户、配置和审计。
  • 客户端:普通用户使用,负责注册登录、商品大厅、购物车、预订下单、订单查看、个人资料和反馈。

技术栈:Vue 3、TypeScript、Element Plus、Pinia、Express、TypeORM。默认使用 SQLite,支持迁移到 MySQL。

Mobile 第一阶段状态

仓库新增了独立的 apps/mobile Expo 工程和 packages/* 跨端基础骨架。Mobile 固定使用 Node.js 22.13.1;第一阶段只提供路由占位、基础 providers、SecureStore/SQLite 包装、未配置的平台能力接口与 CI,不改变现有 Vue Web、Express 后端、数据库或部署方式。

当前 Mobile 尚未接入真实 API,也没有实现正式登录会话、服务端购物车、订单、库存、退货、相机、相册、通知或 Deep Link。未运行模拟器或真机验证时,只能依据 SQLite migration 专项测试、typecheck 与 Android JS bundle export 判断工程基础,不代表设备交互、签名 APK 或发布链路可用。

主要目录:

  • apps/mobile:独立 Expo package,使用自己的 package.jsonpackage-lock.json
  • packages/api-client:传输无关 HTTP 契约与 Native/Web adapter;
  • packages/shared-types:空白规范入口,第一阶段不迁移现有 DTO;
  • packages/domainpackages/validationpackages/design-tokens:最小共享边界骨架。

常用命令:

npm --prefix apps/mobile ci
npm --prefix apps/mobile run dependencies:check
npm --prefix apps/mobile run test:db
npm --prefix apps/mobile run typecheck
npm --prefix apps/mobile run export:android
node ./node_modules/typescript/bin/tsc -p packages/tsconfig.json --noEmit
node --experimental-strip-types --test packages/api-client/test/*.test.ts

Mobile 未启用根 npm workspaces,当前也不能直接跨目录导入 packages/*。详细边界见 docs/project-context/60-移动端工程与共享基础.md

快速入口

界面预览

登录页面

图 1:用户端登录页面 图 2:管理端登录页面
用户端登录页面 管理端登录页面

主页面

图 3:用户端主页面 图 4:管理端主页面
用户端主页面 管理端主页面

管理端部分页面预览

图 5:入库管理工作台 图 6:产品规格配置 图 7:审计日志
管理端入库管理工作台 管理端产品规格配置 管理端审计日志

用户端部分页面预览

图 8:我的订单 图 9:我的资料
用户端我的订单页面 用户端我的资料页面

推荐部署:1Panel 单镜像

新手优先使用 onebox 单镜像。它把前端、后端、Nginx 放在同一个容器里,1Panel 只需要创建一个容器。

部署前先准备:

  • 一个可访问的服务器端口,例如 9050
  • 一个初始管理员强密码,用于 INIT_ADMIN_PASSWORD
  • 两个宿主机目录,用于保存数据库和上传文件。

推荐目录:

/opt/1panel/apps/y-link/data
/opt/1panel/apps/y-link/uploads

这两个目录建议纳入日常备份。

1. 基本信息

项目 填写
名称 y-link
镜像 ghcr.io/hf-cygg/y-link-onebox:latest
备用镜像 docker.io/yemiao351/y-link-onebox:latest
网络 bridge
Entrypoint /entrypoint.sh
Command 留空

如果服务器拉取 GitHub Container Registry 慢,可改用 Docker Hub 镜像。

1Panel 操作路径通常是:容器 -> 创建容器 -> 手动输入镜像或选择已有镜像。创建时不要勾选“强制拉取镜像”,除非你明确需要重新拉取最新镜像。

2. 端口

服务器端口 容器端口 协议 说明
9050 80 tcp Web 访问入口

启动后访问:

  • 管理端:http://服务器IP:9050/login
  • 客户端:http://服务器IP:9050/client/login
  • 健康检查:http://服务器IP:9050/health

如果你使用域名和 HTTPS,在 1Panel 反向代理里把域名代理到 http://127.0.0.1:9050

端口说明:

  • 容器内固定使用 80 作为 Web 入口。
  • 服务器端口可以自定义,截图里的 9050 -> 80 是推荐写法。
  • 不需要额外暴露后端 3001,前端、API、上传文件、健康检查都会由容器内 Nginx 统一代理。

3. 挂载目录

必须挂载数据目录和上传目录,否则重建容器后会丢失数据或图片。

本机目录 容器目录 权限 保存内容
/opt/1panel/apps/y-link/data /app/data 读写 SQLite 数据库
/opt/1panel/apps/y-link/uploads /app/uploads 读写 商品图片、反馈附件等上传文件

你截图里的挂载方式是正确的:类型选“本机目录”,权限选“读写”。本机目录可以按自己的 1Panel 习惯调整,但容器目录必须保持上表一致。

目录用途:

  • /app/data/y-link.sqlite 是默认 SQLite 数据库文件。
  • /app/uploads 保存商品图片、反馈图片、附件等上传内容。
  • 迁移服务器时,复制宿主机的 datauploads 两个目录即可保留业务数据。

不要把这两个目录挂载到 /tmp 这类临时目录。

4. 环境变量

至少需要手动新增一个变量:

INIT_ADMIN_PASSWORD=请改成你自己的强密码
TZ=Asia/Shanghai
# 建议配置:永久删除订单/送货单时的二次门禁密码。
PERMANENT_DELETE_PASSWORD=请改成仅管理员知晓的删除密码
INVITE_CODE_PEPPER=请生成至少32个随机字节的教师邀请码密钥

要求:

  • 必填,不填容器会拒绝启动。
  • 不能使用 Admin@123456
  • 建议至少 8 位,并包含字母和数字。
  • 只在 1Panel 环境变量里填写,不要写进公开文档或提交到仓库。
  • PERMANENT_DELETE_PASSWORD 不影响容器启动;未配置时,系统会拒绝所有永久删除操作。修改后需重启后端容器才会生效。

可选变量:

变量 默认值 说明
INIT_ADMIN_USERNAME admin 初始管理员账号
INIT_ADMIN_DISPLAY_NAME 系统管理员 初始管理员显示名
PERMANENT_DELETE_PASSWORD 永久删除订单、订单池记录和供货方送货单时的服务端密码门禁
TZ Asia/Shanghai 容器和日志时区;国内部署建议保持此值
DB_TYPE sqlite 默认 SQLite
SQLITE_DB_PATH /app/data/y-link.sqlite SQLite 文件位置
PORT 3001 容器内后端端口,通常不用改

首次启动后,系统会自动创建管理员账号。已有管理员时不会覆盖原账号密码。

如果容器日志显示 initialized=false,通常表示数据库里已经存在管理员,系统没有再次初始化,这是正常行为。

不建议新手修改这些变量:

变量 原因
DB_SYNC 生产环境不建议长期启用自动同步结构
DB_HOST / DB_USER / DB_PASSWORD 只有 DB_TYPE=mysql 时才需要
PORT onebox 内部 Nginx 已按默认端口代理后端

5. 重启规则和资源

截图中选择“不重启”可以用于首次排错。正式使用建议改为“失败后重启”或“一直重启”。

资源限制可按服务器情况配置:

  • CPU 权重:1024 可保持默认。
  • CPU 限制:0 表示不限制。
  • 内存限制:0 表示不限制;小服务器建议至少预留 512MB 以上。

建议:

  • 首次启动排错:可先选“不重启”,方便看到真实错误日志。
  • 正式使用:建议选“失败后重启”或“一直重启”。
  • 如果服务器内存较小,不要同时跑太多同类容器。

6. 常见启动日志

正常启动会看到类似内容:

[onebox] starting backend on 127.0.0.1:3001
[onebox] starting nginx on 0.0.0.0:80
[y-link-backend] 服务启动完成

常见错误:

日志 原因 处理
INIT_ADMIN_PASSWORD is required 未配置初始管理员密码 在环境变量里添加 INIT_ADMIN_PASSWORD
refusing insecure INIT_ADMIN_PASSWORD=Admin@123456 使用了禁用弱密码 换成私有强密码
Welcome to nginx! 旧容器或旧镜像残留 删除旧容器,重新拉取 onebox 镜像
上传图片 404 未挂载或未保留 /app/uploads 增加 /app/uploads 读写挂载
日志时间显示 +0000Z 容器时区未配置,或仍在使用旧镜像 添加 TZ=Asia/Shanghai,拉取新镜像并重建容器
日志 IP 总是 10.255.0.1 容器只看到了 Docker/1Panel 的上一跳地址 确认 1Panel 反向代理传递 X-Forwarded-For,并使用新版镜像
构建时报 Docker Hub 429 Too Many Requests 构建平台匿名拉取 Docker Hub 基础镜像被限流 默认 Dockerfile 已改用公开镜像源;若平台仍受限,可设置构建参数 Y_LINK_NODE_IMAGE=你的私有 Node 20 bookworm-slim 镜像

新版 nginx 访问日志会优先显示可信代理传来的真实用户 IP,并在同一行保留 proxy="..." xff="..." real="..." 便于排查。若 xff="-" 或为空,说明上游没有把真实 IP 传给容器,应用无法凭空还原用户 IP。

6.1 容器时间与北京时间校准

TZ=Asia/Shanghai 只负责“时区显示”,真正时钟校准必须在宿主机完成(容器共享宿主机内核时钟,默认无权限直接改系统时间)。

建议在服务器执行:

timedatectl set-timezone Asia/Shanghai
timedatectl set-ntp true
timedatectl status

确认 System clock synchronized: yes 后,重启容器。
新版 onebox 启动日志会打印:

[onebox] timezone=Asia/Shanghai, now=2026-05-30 22:10:00 +0800 CST

启动成功后建议做 4 个检查:

  1. 打开 http://服务器IP:9050/health,能返回健康信息。
  2. 打开 http://服务器IP:9050/login,能看到管理端登录页。
  3. admin 和你配置的 INIT_ADMIN_PASSWORD 登录。
  4. 打开 http://服务器IP:9050/client/login,能看到客户端登录页。

7. 升级和备份

升级前先备份两个目录:

/opt/1panel/apps/y-link/data
/opt/1panel/apps/y-link/uploads

升级步骤:

  1. 停止容器。
  2. 拉取最新镜像 ghcr.io/hf-cygg/y-link-onebox:latest
  3. 用原来的端口、挂载和环境变量重建容器。
  4. 访问 /health、管理端登录页和客户端商品大厅确认可用。

只要保留 /app/data/app/uploads 对应的宿主机目录,账号、单据、商品、图片都能继续使用。

回退方式:

  1. 停止新容器。
  2. 换回旧镜像标签或旧镜像 ID。
  3. 继续挂载原来的 datauploads 目录。
  4. 启动后检查登录、商品图片、订单列表。

如果升级前已经备份目录,必要时可以恢复备份目录后再启动容器。

8. 1Panel 填写对照

按照你截图里的页面,可逐项核对:

1Panel 字段 推荐值
名称 y-link
镜像 ghcr.io/hf-cygg/y-link-onebox:latest
端口 服务器 9050,容器 80,协议 tcp
网络 bridge
挂载 1 本机 /opt/1panel/apps/y-link/data -> 容器 /app/data,读写
挂载 2 本机 /opt/1panel/apps/y-link/uploads -> 容器 /app/uploads,读写
Entrypoint /entrypoint.sh
Command 留空
环境变量 至少添加 INIT_ADMIN_PASSWORD=你的私有强密码TZ=Asia/Shanghai;建议添加 PERMANENT_DELETE_PASSWORD=你的永久删除密码
特权模式 不开启
控制台交互 不需要开启
重启规则 首次排错可不重启,正式使用建议失败后重启

截图中只有 PATHNODE_VERSIONYARN_VERSION 这类镜像自带变量还不够,必须额外添加 INIT_ADMIN_PASSWORD。如果需要启用永久删除订单/送货单,还应添加 PERMANENT_DELETE_PASSWORD;未配置时永久删除接口会明确拒绝。若希望容器日志与国内现实时间一致,也建议添加 TZ=Asia/Shanghai;旧容器需要重建后才会应用新镜像和新时区。

其他部署方式

Docker 命令启动 onebox

docker run -d --name y-link \
  -p 9050:80 \
  -e INIT_ADMIN_PASSWORD='请改成你自己的强密码' \
  -e PERMANENT_DELETE_PASSWORD='请改成仅管理员知晓的删除密码' \
  -e TZ=Asia/Shanghai \
  -v /opt/1panel/apps/y-link/data:/app/data \
  -v /opt/1panel/apps/y-link/uploads:/app/uploads \
  --restart unless-stopped \
  ghcr.io/hf-cygg/y-link-onebox:latest

双容器部署

适合需要前后端分开管理的服务器:

INIT_ADMIN_PASSWORD='请改成你自己的强密码' PERMANENT_DELETE_PASSWORD='请改成仅管理员知晓的删除密码' TZ=Asia/Shanghai docker compose -f compose.cloud.yml up -d

默认端口:

  • 前端:8080
  • 后端:3001

说明:

  • compose.cloud.yml 默认使用 SQLite,并持久化 /app/data/app/uploads
  • 不要只启动 y-link-frontend,单独前端镜像没有业务 API。
  • 如果要使用 MySQL,请确认 DB_TYPE=mysql,并填写 DB_HOSTDB_PORTDB_USERDB_PASSWORDDB_NAME

MySQL 部署建议

默认 SQLite 适合个人、小团队、轻量部署和快速上线。以下情况建议迁移到 MySQL:

  • 多人高频同时下单、核销、入库。
  • 数据量持续增长。
  • 需要更标准的备份、审计、主机迁移和运维体系。

已有 SQLite 数据时,优先使用管理端“系统管理 -> 数据库迁移”功能迁移,不建议手工拼接导入。

Onebox 先试运行、后启用 MySQL

仓库提供 compose.onebox.yml,同一套 Onebox 可分两阶段部署,不需要再启动第二套 Y-Link 应用:

# 1. 首次部署:默认只启动 Onebox + SQLite
cp .env.onebox.example .env
# 编辑 .env,至少填写 INIT_ADMIN_PASSWORD
docker compose -f compose.onebox.yml up -d ylink

# 2. 正式启用:以后再叠加同一私有网络中的 MySQL 8.4
# 先在 .env 中填写 MYSQL_PASSWORD 与 MYSQL_ROOT_PASSWORD
docker compose -f compose.onebox.yml -f compose.onebox.mysql.yml up -d mysql

MySQL 健康后,在管理端“系统管理 -> 数据库迁移”填写:host=mysqlport=3306database=y_linkuser=ylink.env 中的 MYSQL_PASSWORD。自动任务会冻结写入、生成一致性 SQLite 快照、复制并校验数据、写入运行时覆盖,然后让同一个 Onebox 计划重启到 MySQL。

如果 MySQL 不是由可选叠加文件启动:安装在 Linux 宿主机时向导可填写 host.docker.internal,远程 MySQL 则填写 Onebox 容器可访问的 DNS 名称或 IP。compose.onebox.yml 已补齐 Linux 的 host-gateway 映射;无论目标在哪里,都不要把数据库公网端口开放给所有来源。

迁移前应在 .env 中一并确认 DB_POOL_SIZEDB_CONNECT_TIMEOUT_MSDB_ACQUIRE_TIMEOUT_MSDB_IDLE_TIMEOUT_MSDB_QUEUE_LIMITDB_MAX_QUERY_MS。这些参数由 Onebox 容器持续保留,切换后同一个进程会用它们建立 MySQL 连接池;单实例默认连接池为 20,多个应用副本时必须按“实例数 × 每实例连接池”计算总连接数,并给 MySQL 运维连接留出余量。

切换到 MySQL 并产生第一笔新业务写入后,旧 SQLite 已经是历史快照,系统会禁用“直接清除覆盖/回到旧 SQLite”。如需回退,必须恢复 MySQL 备份或执行受控反向迁移,避免静默丢单。

运行边界:SQLite 模式固定为单 Onebox、单应用进程、本地持久化磁盘,100 个突发下单会进入有界写队列串行完成;需要持续百人并发写、第二个应用副本,或管理员接口 GET /api/data-maintenance/database/performancewriteCoordinator.pendingWrites、等待超时持续升高时,应迁移到 MySQL。万人浏览仍应由 Nginx/CDN 缓存吸收,不能把所有目录请求直接压到任一数据库。

新库直接使用外置 MySQL

全新部署可使用 compose.mysql.yml.env.docker.mysql.example。先创建 MySQL 8.4 的空库和专用账号,库字符集使用 utf8mb4;再复制环境变量模板并填写连接信息、管理员密码以及连接池参数。

全新空库第一次启动可临时设置 DB_SYNC=true 创建当前版本的完整实体结构;后端健康后必须立即改回 DB_SYNC=false 并重建容器。backend/sql/001_init_schema.sql 只代表历史基础结构,不能单独当作当前版本的完整初始化脚本。存量 MySQL 禁止开启 DB_SYNC=true,必须先备份、停止业务写入,在预发演练后按版本号顺序执行尚未应用的增量 SQL,再以 DB_SYNC=false 启动应用。

cp .env.docker.mysql.example .env.docker.mysql
# 编辑连接信息、强密码,并仅在确认目标库为空时临时设置 DB_SYNC=true
docker compose --env-file .env.docker.mysql -f compose.mysql.yml up -d backend
docker compose --env-file .env.docker.mysql -f compose.mysql.yml ps

# /health 正常后,把 DB_SYNC 改回 false,再重建并启动完整应用
docker compose --env-file .env.docker.mysql -f compose.mysql.yml up -d --force-recreate backend frontend

本轮高并发升级至少包含:

  • 034_high_concurrency_indexes.sql:订单、库存日志、通知收件箱和会话清理索引;
  • 035_o2o_idempotency_business_sequence.sql:O2O 下单幂等键与并发安全业务序列;
  • 036_notification_outbox.sql:通知事件领取/重试字段、索引与投递去重约束;该脚本会合并历史重复收件箱的已读状态、保留最早记录并删除重复行,必须先备份并停止所有旧/新应用进程及通知 Worker,同时预留 DDL 窗口。

通知 Outbox 对站内收件箱和数据库投递记录做唯一键去重;邮件、飞书等外部通道采用 at-least-once(至少一次) 交付。若第三方已经接收成功、但进程在写回 sent 状态前异常退出,恢复后可能再次投递;需要严格防重时,应同时为第三方通道配置其支持的幂等键或去重能力。

升级顺序固定为“备份 -> 停止应用和业务写入 -> 按 034035036 顺序执行 -> 启动新版本”。商城目录缓存复用既有 030_mall_catalog_performance_indexes.sql 与本轮 034 索引,本轮没有额外 catalog 表结构脚本。实际升级清单仍以 backend/sql/ 中“当前线上版本之后、目标版本之前”的增量脚本为准,不能只挑最后一个脚本执行。执行完成后再启动应用,并通过 /health、登录、商品查询、下单、通知重试链路验收。

相关文件:

功能概览

管理端

  • 工作台:业务数据看板、快捷入口。
  • 出库开单:商品搜索、数量录入、金额计算、单据生成。
  • 出库列表:历史单据、详情、导出、作废和删除治理。
  • 入库管理:供货方送货单、扫码入库、入库核销。
  • 商品管理:基础资料、标签、库存、线上展示、图片。
  • O2O 核销:客户预订单查询、核销、撤回和库存流水。
  • 用户中心:管理端用户、供货方用户、客户端用户。
  • 系统配置:验证码、部门、客户服务、业务规则等配置。
  • 审计日志:登录、权限拦截、关键业务操作追踪。

客户端

  • 注册登录:用户名、手机号、邮箱等账号能力。
  • 商品大厅:商品浏览、搜索、分类、加购。
  • 购物车和结算:预订下单、库存占用、订单生成。
  • 我的订单:订单列表、详情、状态查看、撤回。
  • 我的:资料维护、修改密码、反馈与客服入口。

供货方

  • 独立账号登录。
  • 录入送货单。
  • 查看历史送货单。
  • 配合管理端完成入库核销。

本地开发

环境要求

  • Node.js 20+
  • npm
  • Docker 可选,用于容器验证和 MySQL 并发验收

安装依赖

npm install
npm --prefix backend install

启动本地联调

npm run local:dev

常用命令:

命令 说明
npm run local:dev 启动本地前后端联调
npm run local:dev:status 查看本地服务状态
npm run local:dev:stop 停止本地联调
npm run build 前端类型检查和生产构建
npm --prefix backend run check 后端 TypeScript 检查
npm --prefix backend run build 后端构建

验证命令

命令 说明
npm run verify:unit:functional 单元和功能基线验证
npm --prefix backend run permission:regression:verify 后端权限回归
npm --prefix backend run release:verify 后端发布回归
npm run verify:onebox:smoke onebox 冒烟验证
npm run verify:db:concurrency SQLite 副本 + MySQL 临时库并发验收
npm run verify:performance 性能预算验证
npm run verify:all 全量质量验证

verify:db:concurrency 默认会通过 Docker 拉起 MySQL 8.4 临时环境。没有 Docker 时,可提供 VERIFY_DB_CONCURRENCY_MYSQL_* 连接到自备 MySQL。

项目结构

Y-Link
├─ src/                         前端源码
│  ├─ api/                      API 封装
│  ├─ components/               通用组件
│  ├─ router/                   路由和菜单元信息
│  ├─ store/                    Pinia 状态
│  └─ views/                    管理端和客户端页面
├─ backend/                     后端源码
│  ├─ src/config/               环境变量、数据源、启动自检
│  ├─ src/entities/             TypeORM 实体
│  ├─ src/routes/               REST 路由
│  ├─ src/services/             业务服务
│  ├─ sql/                      初始化和迁移 SQL
│  └─ scripts/                  后端验证脚本
├─ apps/mobile/                 独立 Expo Mobile 工程与 lockfile
├─ packages/                    尚未接入 Mobile 的跨端基础包骨架
├─ docker/
│  ├─ nginx/                    Nginx 配置
│  └─ onebox/                   onebox 入口脚本
├─ docs/                        使用和运维文档
├─ scripts/                     构建、验证、部署辅助脚本
├─ compose.cloud.yml            云端双容器部署
├─ compose.mysql.yml            外置 MySQL 部署
├─ Dockerfile                   前端镜像
├─ Dockerfile.onebox            单镜像
└─ README.md

关键目录说明

路径 说明
/app/data 容器内 SQLite 数据目录,必须持久化
/app/uploads 容器内上传文件目录,必须持久化
backend/sql MySQL 历史增量迁移脚本(用于给已有库补齐特定变更;全新空库请用 DB_SYNC=true 初始化,详见 .env.docker.mysql.example
backend/data 本地开发 SQLite 数据目录
apps/mobile Mobile 路由占位、providers、本地与平台能力基础
packages API client、共享类型、领域、校验与设计 token 边界
docs 使用指南、迁移手册、维护文档

安全说明

  • 初始管理员密码必须手动配置,系统不会内置默认弱密码。
  • 不要把真实密码、数据库连接、Token 写入仓库。
  • 生产环境建议使用 HTTPS 和反向代理。
  • 管理端已做登录失败风控、验证码、权限校验和审计记录。
  • SQLite 适合轻量部署;多人高并发和长期生产建议使用 MySQL。

相关文档

About

基于 Vue 3 + Express + TypeORM 的文创产品出入库与 O2O 预订系统,支持库存管理、线上预订、线下核销、供货入库与客户反馈。

Topics

Resources

Stars

4 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages