# yusellerserver **Repository Path**: mysymt/yusellerserver ## Basic Information - **Project Name**: yusellerserver - **Description**: 卖货的阿余后端服务 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-09-06 - **Last Updated**: 2026-09-06 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # YuSeller 后端(Gin + GORM + JWT) 进销存系统后端:单二进制、无 Redis、JWT 无状态鉴权。Web 管理服务端接口统一以 `/api/admin` 为前缀,App 端接口统一以 `/api/app` 为前缀,两端共用同一套 JWT(登录后拿到的 token 均可访问两个前缀下的接口)。 ## 目录结构 ``` server/ ├─ main.go ├─ go.mod ├─ config.dev.yaml # 开发环境:数据库 / JWT / 端口 ├─ config.prod.yaml # 正式环境(APP_ENV=prod 加载) ├─ internal/ │ ├─ config/ # 配置加载(支持多环境) │ ├─ db/ # MySQL 连接 + 自动建表 │ ├─ model/ # 业务模型(用户/商品/客户/采购/销售/库存/流水) │ ├─ middleware/ # JWT 鉴权 │ ├─ response/ # 统一返回 {code,msg,data} │ ├─ handler/ # 接口实现 │ └─ router/ # 路由 └─ scripts/ ├─ mysql-init.sql # 建库 + 完整表结构 DDL(utf8mb4) ├─ backup.sh # 每日 mysqldump 备份(保留 14 天) ├─ yu-seller.service # systemd 单元(注入 APP_ENV=prod) ├─ nginx-yu-seller.conf # Nginx 反代 + SSL └─ deploy.sh # 一键交叉编译+部署 ``` ## 多环境配置 后端通过环境变量 `APP_ENV` 选择加载 `config..yaml`,实现开发 / 正式环境隔离: | APP_ENV | 加载文件 | 典型场景 | |---------|----------|----------| | 未设置 / `dev` | `config.dev.yaml` | 本地开发(默认值) | | `prod` | `config.prod.yaml` | 服务器正式运行 | - 配置文件由 `main.go` 启动处调用 `config.LoadByEnv()` 按 `APP_ENV` 决定; - 正式环境在 `scripts/yu-seller.service` 中已通过 `Environment=APP_ENV=prod` 注入,部署后无需改代码; - 数据库口令、JWT 密钥等敏感信息按环境分文件存放;`config.prod.yaml` 中已用 `TODO` 占位,部署时填入正式值,**请勿把真实口令提交进仓库**。 - `deploy.sh` 用 `rsync` 把整个目录(含两个配置文件)同步到服务器,正式环境靠 systemd 的 `APP_ENV=prod` 选中 prod 配置。 ## 图片存储配置 商品图片(及后续可能的附件)上传后存储在本机文件系统,根目录由各环境的 `upload.path` 配置决定: | 环境 | 配置项 | 示例 | |------|--------|------| | 开发 | `config.dev.yaml` 的 `upload.path` | `/Users/xuqingshao/Downloads/uploadPath/yuseller` | | 正式 | `config.prod.yaml` 的 `upload.path` | `/www/yu-seller/uploads`(按服务器实际目录修改) | - 文件命名规则:`/YYYY/MM/DD/<时间戳>.<原扩展名>`。例如 `a.jpg` 上传后落盘为 `/Users/xuqingshao/Downloads/uploadPath/yuseller/2026/08/23/182372837283.jpg`,即存储位置下创建 `2026/08/23` 目录,文件名为 `182372837283.jpg`; - 系统仅持久化**相对路径**(如 `2026/08/23/182372837283.jpg`),登记在 `image_records.path`; - 对外通过 `GET /api/image/:fileId` 按 file_id 返回图片二进制(公开,无需 JWT),商品 `imageUrl` 即该地址。 ### 商品图片与商品一体提交(不分两步) 新增/编辑商品(`POST/PUT /api/admin/products`)时,图片与商品字段通过**同一个**请求提交,后端 `bindProduct` 兼容以下三种入参形态: 1. **`multipart/form-data`(前端现行写法,推荐)** - `product`:商品字段的 JSON 字符串(name/purchasePrice/salePrice/remark/imageUrl) - `file`:(可选)图片文件。有则保存并写入 `imageUrl`;无则沿用表单中的 `imageUrl`(编辑时留空即移除图片) 2. **JSON 包裹体**(部分调用方/调试工具直接发 raw JSON):`{"product":"<商品字段的 JSON 字符串>","file":{}}` 3. **裸 JSON 商品对象**:`{"name":"晒罗","purchasePrice":1,"salePrice":2,"remark":"","imageUrl":""}`(不带图时的纯 JSON 写法,向后兼容) > 三种形态最终都解析为同一个 `Product` 结构:`name` 为必填,缺省返回 `商品名称必填`; > 也保留独立的 `POST /api/admin/image` 上传端点(返回 `{fileId,url,path}`),供需要单独传图的场景使用。 ## 数据库准备 建表有两种方式,任选其一(都执行也不冲突): - **方式 A(推荐,零手工)**:直接启动后端,GORM `AutoMigrate` 自动建 7 张表; 首次启动 `users` 为空时自动创建管理员 **admin / admin123**。 - **方式 B(审阅/备份恢复用)**:手动执行 DDL 脚本: ```bash mysql -uroot -p < scripts/mysql-init.sql ``` 脚本创建数据库 `yu_seller`(utf8mb4)与全部表;表结构与 `internal/model` 一致。 > 注意:默认管理员密码为程序运行时 bcrypt 生成,脚本不插入账户; > 若需重置,删 `users` 表后重启后端即可重新建 admin/admin123。 ## 本地运行 ```bash # 1. 准备 MySQL 8.0,建库 yu_seller(见上「数据库准备」) # 2. 修改 config.dev.yaml 的 mysql 与 jwt.secret go mod tidy go run . # 默认 :8080 ``` ## 数据库备份(重要) 进销存数据丢不得,在服务器上配置每日自动备份: ```bash # 先修正权限,避免密码明文泄露 chmod 600 /www/yu-seller/scripts/backup.sh # 加入 crontab,每天 03:00 备份(保留 14 天) (crontab -l; echo "0 3 * * * /www/yu-seller/scripts/backup.sh >> /var/log/yu-seller-backup.log 2>&1") | crontab - ``` 备份文件位于 `/data/backups/yu-seller/yu_seller_YYYYMMDD_HHMMSS.sql.gz`。 ## 交叉编译到服务器(linux/amd64) ```bash CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o yu-seller . ``` ## 部署(详见 scripts/) ```bash # 服务器:宝塔装好 MySQL + Nginx # 1. 上传 yu-seller、config.dev.yaml、config.prod.yaml 到 /www/yu-seller # 2. cp scripts/yu-seller.service /etc/systemd/system/ && systemctl enable --now yu-seller # 3. 把 nginx-yu-seller.conf 内容放入站点配置,申请/放置 SSL # 4. 放行端口(安全组 + 宝塔防火墙) ``` ## API 一览 接口前缀约定: - **`/api/admin/*`**:Web 管理服务端接口(后台管理页面调用) - **`/api/app/*`**:App 端接口(Android 手机端调用) - 登录 `/api/auth/login` 为公共接口,登录后 token 对 `admin`、`app` 两个前缀均有效 | 方法 | 路径 | 说明 | 鉴权 | 前缀 | |------|------|------|------|------| | POST | /api/auth/login | 登录 {username,password} → {token,user} | 否 | 公共 | | GET | /api/auth/me | 当前用户 | 是 | 公共 | | GET/POST/PUT/DELETE | /api/admin/products(/:id) | 商品 CRUD(Web 管理) | 是 | admin | | GET/POST/PUT/DELETE | /api/admin/customers(/:id) | 客户 CRUD(Web 管理) | 是 | admin | | GET/POST | /api/admin/purchases | 采购(入库+库存联动)(Web 管理) | 是 | admin | | GET/POST | /api/admin/sales | 销售(出库+库存联动)(Web 管理) | 是 | admin | | GET | /api/admin/inventory | 库存(联商品信息)(Web 管理) | 是 | admin | | GET | /api/admin/flows | 库存变动流水(Web 管理) | 是 | admin | | GET | /api/app/products?keyword= | App 端商品检索 | 是 | app | | GET | /api/app/inventory | App 端库存 | 是 | app | | POST | /api/app/sale | App 端开单(扣库存+流水) | 是 | app | 返回结构统一为 `{code:0, msg:"ok", data}`;`code!=0` 表示失败。分页接口 `data={list,total}`。 > 历史版本曾使用 `/api/ys/*`(Web)与 `/api/phone/*`(App)前缀,现已统一为 `/api/admin`、`/api/app`,前端/App 调用需同步更新路径。