校园二手交易平台 —— 校园闲置交易与信用体系
面向高校的二手交易平台:校园身份认证(邮箱 / 学号双通道)作为发布硬前置,注册到评价的完整交易闭环与 100 分初始信用档案,单端口边缘网关交付,线上 40+ 接口 / 60+ 断言验收。
角色 独立开发:后端 / Flutter 客户端 / 生产编排 / 上线部署与线上验收 / 文档
面向高校的二手交易平台,把「注册 → 校园身份认证(两条通道)→ 发布商品(图片上传)→ 搜索 / 收藏 / 足迹 → 下单 → 卖家确认 → 完成 → 双向评价 → 信用分」做成一条完整可信的闭环,并配有举报与管理端治理(认证审核 / 举报驳回处置 / 审计日志)。
技术栈为 Spring Boot 3.3.4 + Java 21 + MyBatis-Plus + PostgreSQL 16 + Redis 7.4 + MinIO(S3 兼容私有对象存储),客户端为 Flutter 3 + GetX,生产用 Docker Compose 单端口边缘网关交付,已上线并完成真实 HTTP 全链路验收。
校园二手交易信息散落在 QQ 群、表白墙,缺少身份与信用约束:校外人员也能随意发布,交易出问题没有留痕。
交易过程没有状态跟踪:谁下单、谁确认、能否取消、评价与信用如何沉淀,全靠私下聊天。
用户上传的图片如果直连对象存储,等于把存储服务暴露在公网;同时用户内容(描述、评价)若不转义,会带来 XSS 风险。
建一条可信的交易闭环:校园身份认证作为发布硬前置,交易全程有状态、有评价、有信用沉淀。
安全与合规:对象存储不暴露公网、用户内容统一转义、Schema 有单一真相源、反代与可信 IP 配置明确。
工程可交付:一键启动、质量门禁脚本、测试与开发数据隔离、镜像可复现、上线前检查清单。
对外只保留一个边缘入口:edge nginx 暴露 8080,把 / 交给 Flutter Web 静态产物、/api 反代后端、/img 反代 MinIO,数据库、缓存与对象存储三者完全不暴露公网。
校园认证设计成两条通道写同一张表:邮箱通道做学校后缀校验与验证码核销,学号通道只填学校与学号并交给管理员人工审核,用 verify_method 区分来源,下游的发布闸门与认证标识不感知差异。
交易状态机覆盖下单、卖家确认、完成与取消,成交后双方信用 +2,评价按订单唯一;举报进入管理端处置队列,每次处置都写审计日志。
质量与测试环境自洽:后端测试用 Testcontainers 在测试 JVM 内现拉 PostgreSQL / Redis / MinIO,测试绝不读写开发库;quality-gate 脚本先探测 Docker 可用性再依次跑后端测试与前端 analyze / test。
Flutter Web / App 客户端(GetX 状态与路由、Dio 拦截器与 Token 自动刷新、Flutter Secure Storage 存放敏感凭证)访问公网 8080,由 edge nginx 作为唯一对外入口:/ 提供 Flutter Web 静态产物(SPA 深链接回退、入口文件 no-cache、带内容哈希的资源长缓存),/api 反代 Spring Boot(内网 8081:认证 / 商品 / 订单 / 评价 / 举报 / 治理 / AI),/img 反代 MinIO(9000,控制台与 S3 API 均不暴露公网)。内网为 PostgreSQL 16(Flyway V1–V13 迁移)与 Redis 7.4(会话 / 限流 / 验证码 / 分布式锁)。
对外只暴露 8080,/api 与 /img 分别反代后端与 MinIO,数据库 / 缓存 / 对象存储三者完全不暴露公网;同时区分缓存策略,带内容哈希的资源长缓存、入口文件 no-cache。
Flyway 管理全部结构变更;用 NOT VALID 外键 + 校园邮箱部分唯一索引,兼顾历史脏数据与约束强度。
后端测试用 Testcontainers 在测试 JVM 内现拉 PostgreSQL / Redis / MinIO(镜像 tag 固定,与 compose 一致),测试绝不读写开发库。
quality-gate.ps1 先探测 Docker 是否可用(不可用给中文原因并以非 0 退出,而不是把英文异常抛进日志),再依次跑后端测试与前端 analyze / test。
用户输入内容统一转义、可信 IP 与反代配置、上线前清理 Redis 中历史明文 refresh token、镜像 tag + digest 与代码版本一一对应。
不是「跑通接口就算」,而是对生产实例发真实 HTTP,按完整闭环跑 40+ 接口 / 60+ 断言,并把发现的问题与处理写进验收报告。
对象存储的对外方式
选了 边缘 nginx 反代 /img,而不是 让 MinIO 直接对公网提供访问 —— 唯一入口便于统一缓存、鉴权与可信 IP 配置,也避免把存储服务暴露出去。
代价:所有图片流量都经过网关,反代规则写错会出现「上传成功但访问 404」这类难查的缺陷。
测试数据的隔离方式
选了 Testcontainers 在测试 JVM 内现拉 PostgreSQL / Redis / MinIO,而不是 共用一个开发用数据库 —— 测试可以真连中间件,同时保证结果不受开发数据影响、也不会反向污染开发库。
代价:跑测试必须能拉取镜像,单次执行比纯内存替身更慢。
认证通道的扩展方式
选了 同一张表 + verify_method 区分来源,而不是 为人工通道单独建一张表 —— 下游只关心认证是否通过,单表能让发布闸门与信用逻辑保持一条路径。
代价:表结构与索引更复杂,迁移时还要处理历史冲突数据。
后端:mvn -B test 263 项全绿,由 Testcontainers 提供真实 PostgreSQL 16 / Redis 7.4 / MinIO;前端:flutter analyze 无问题、flutter test 210 项全部通过(仓库 README 记录的 194 是旧基线)。
线上部署(2026-09-22 验收 + 本次复核):https://trade.myiskg.com/ 已上线运行于腾讯云 CVM(4 核 / 3.6G,Ubuntu 24.04),edge nginx + app + minio + postgres + redis 五个容器全部 restart=unless-stopped;自 2026-09-24 起启用 HTTPS。首页可匿名浏览商品,体验发布与交易需注册并完成校园认证(演示邮箱可跳过真实邮件取码)。
线上验收覆盖:按「注册 → 登录 → 认证 → 发布 → 交易 → 评价 → 举报 → 治理」完整闭环,15 个业务域、40+ 接口、60+ 断言全部通过(过程中发现 1 个真实缺陷,已修复并复验)。
新功能线上端到端(2026-09-23):注册 → 提交学号材料(PENDING/MANUAL)→ 未认证发布被拒 400 → 管理员队列可见 → 驳回不写原因 400 → 驳回(REJECTED,学生看到原因)→ 重提(PENDING,原因清空)→ 通过(SUCCESS)→ 发布成功 → 审计流水 PASS_STUDENT_VERIFY,线上已执行 V13 迁移。
数据卫生:验收用的临时账号、商品、订单、评价、举报、MinIO 对象与 Redis 键全部清理,线上库仅保留开发者本人账号。
仓库:GitHub 公开仓库,32 次提交,最新提交 2026-09-23,含后端、Flutter 客户端、生产编排、部署文档与各阶段审计报告。
线上缺陷的排查顺序比经验更重要:「容器内直连正常、只有边缘访问失败」这一个对比,就把问题从存储层锁到了反代层。
演示需求不该用削弱校验来满足:把口子限定在白名单、并对开关本身加护栏,才能在可用与安全之间取得平衡。
测试与开发环境必须物理隔离:Testcontainers 加上刻意不加载 .env 的门禁脚本,才算真正把「测试不污染开发数据」落到工程上。









