{"id":49778796,"url":"https://github.com/can4hou6joeng4/mall-saas","last_synced_at":"2026-05-11T18:01:34.670Z","repository":{"id":357116008,"uuid":"1235212631","full_name":"can4hou6joeng4/mall-saas","owner":"can4hou6joeng4","description":"多租户 SaaS 电商样板：NestJS + Fastify + Prisma + PG RLS + 三前端 + W3C Trace + OpenTelemetry","archived":false,"fork":false,"pushed_at":"2026-05-11T11:03:21.000Z","size":1607,"stargazers_count":0,"open_issues_count":16,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-11T12:43:28.041Z","etag":null,"topics":["ecommerce","fastify","monorepo","multi-tenant","nestjs","open-source","opentelemetry","postgresql","prisma","react","row-level-security","saas","typescript"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/can4hou6joeng4.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-11T05:45:17.000Z","updated_at":"2026-05-11T11:02:17.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/can4hou6joeng4/mall-saas","commit_stats":null,"previous_names":["can4hou6joeng4/mall-saas"],"tags_count":34,"template":false,"template_full_name":null,"purl":"pkg:github/can4hou6joeng4/mall-saas","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/can4hou6joeng4%2Fmall-saas","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/can4hou6joeng4%2Fmall-saas/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/can4hou6joeng4%2Fmall-saas/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/can4hou6joeng4%2Fmall-saas/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/can4hou6joeng4","download_url":"https://codeload.github.com/can4hou6joeng4/mall-saas/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/can4hou6joeng4%2Fmall-saas/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32906515,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-11T17:09:15.040Z","status":"ssl_error","status_checked_at":"2026-05-11T17:08:45.420Z","response_time":120,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ecommerce","fastify","monorepo","multi-tenant","nestjs","open-source","opentelemetry","postgresql","prisma","react","row-level-security","saas","typescript"],"created_at":"2026-05-11T18:00:57.205Z","updated_at":"2026-05-11T18:01:34.646Z","avatar_url":"https://github.com/can4hou6joeng4.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n\n# mall-saas\n\n**多租户 SaaS 电商样板 · AI Agent 端到端可演进的工程参考**\n\n\u003e NestJS 11 + Fastify + Prisma 7 + PostgreSQL Row-Level Security · 三前端（admin / store / storefront）\u003cbr/\u003e\n\u003e + W3C Trace Context + OpenTelemetry · 34 个里程碑 · 完整 CI/CD/可观测闭环\n\n[![ci](https://github.com/can4hou6joeng4/mall-saas/actions/workflows/ci.yml/badge.svg)](https://github.com/can4hou6joeng4/mall-saas/actions/workflows/ci.yml)\n[![release](https://github.com/can4hou6joeng4/mall-saas/actions/workflows/release.yml/badge.svg)](https://github.com/can4hou6joeng4/mall-saas/actions/workflows/release.yml)\n[![codeql](https://github.com/can4hou6joeng4/mall-saas/actions/workflows/codeql.yml/badge.svg)](https://github.com/can4hou6joeng4/mall-saas/actions/workflows/codeql.yml)\n[![pages](https://github.com/can4hou6joeng4/mall-saas/actions/workflows/pages.yml/badge.svg)](https://can4hou6joeng4.github.io/mall-saas/)\n[![codecov](https://codecov.io/gh/can4hou6joeng4/mall-saas/branch/main/graph/badge.svg)](https://codecov.io/gh/can4hou6joeng4/mall-saas)\n\u003cbr/\u003e\n[![license](https://img.shields.io/github/license/can4hou6joeng4/mall-saas?style=flat-square\u0026color=blue)](./LICENSE)\n[![release](https://img.shields.io/github/v/release/can4hou6joeng4/mall-saas?style=flat-square\u0026color=success)](https://github.com/can4hou6joeng4/mall-saas/releases)\n[![stars](https://img.shields.io/github/stars/can4hou6joeng4/mall-saas?style=flat-square\u0026logo=github)](https://github.com/can4hou6joeng4/mall-saas/stargazers)\n[![GHCR](https://img.shields.io/badge/ghcr.io-mall--api-blue?style=flat-square\u0026logo=docker)](https://github.com/can4hou6joeng4/mall-saas/pkgs/container/mall-api)\n[![discussions](https://img.shields.io/github/discussions/can4hou6joeng4/mall-saas?style=flat-square\u0026logo=github)](https://github.com/can4hou6joeng4/mall-saas/discussions)\n[![good first issue](https://img.shields.io/github/issues/can4hou6joeng4/mall-saas/good%20first%20issue?label=good%20first%20issue\u0026style=flat-square\u0026color=7057ff)](https://github.com/can4hou6joeng4/mall-saas/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22)\n[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](https://github.com/can4hou6joeng4/mall-saas/pulls)\n\n[Quickstart](#-quickstart) · [架构](#-架构) · [Tech Stack](#%EF%B8%8F-tech-stack) · [部署](#-部署) · [多租户隔离](#-多租户数据隔离核心设计) · [里程碑链](#-里程碑链) · [Roadmap](./ROADMAP.md) · [相关项目](#-相关项目)\n\n**中文** | [English](./README.en.md)\n\n\u003c/div\u003e\n\n\u003e 一个面向小团队的多租户 SaaS 商城工程样板，强调**租户数据隔离（Row-Level Security）+ 可观测（trace 全链路贯穿）+ 端到端可验证**。\n\n---\n\n## 💡 为什么用 mall-saas？\n\n写新 SaaS 时，每次都要重做这些\"看不见的地基\"：多租户、RLS、JWT refresh、订单状态机、支付 webhook、库存预占、可观测、CI/CD。**mall-saas 把这套基础设施做完整给你看**：\n\n- 📐 **生产级 RLS 多租户**：PG Row-Level Security + `mall_app` 非超管角色 + AsyncLocalStorage 双重隔离，DB 层做最后防线——即使代码 bug 忘了 `WHERE tenant_id` 也跨不了租户。\n- 🔭 **可观测开箱即用**：W3C Trace Context（M24）+ OpenTelemetry SDK 自动 instrumentation（M34）+ pino traceId 贯穿 + `/metrics` Prometheus。\n- 🛒 **三前端拉齐**：admin（超管） / store（商家） / storefront（消费者）共用 OpenAPI 类型 codegen + 401 自动 refresh + storefront i18n 中英双语。\n- ✅ **每个里程碑可复跑**：34 个 `vX.Y.0-m{N}` tag，每个都附 `scripts/m{N}-acceptance.sh` 端到端验收脚本——CI 也跑同一份。\n- 🚀 **生产部署一条龙**：`docker-compose.prod.yml` 双 stage 镜像 + `service_completed_successfully` 串联迁移 + 推 tag 自动 GHCR release（amd64 + arm64）。\n\n\u003e 适合谁：(1) 想看完整 SaaS 工程参考的开发者；(2) 起步多租户产品的小团队；(3) 学习 RLS / OTel / trace 一体化的工程实践者。\n\n## 🧭 导航\n\n[Quickstart](#-quickstart) · [架构](#-架构) · [Tech Stack](#%EF%B8%8F-tech-stack) · [常用命令](#-常用命令) · [部署](#-部署) · [多租户隔离](#-多租户数据隔离核心设计) · [里程碑链](#-里程碑链) · [目录结构](#-目录结构) · [贡献 \u0026 路线图](#-贡献--路线图) · [相关项目](#-相关项目)\n\n## 📐 架构\n\n```mermaid\ngraph LR\n  subgraph Frontends\n    A[admin\u003cbr/\u003e超管平台]\n    S[store\u003cbr/\u003e商家后台]\n    SF[storefront\u003cbr/\u003e消费者]\n  end\n\n  subgraph Backend\n    API[NestJS + Fastify\u003cbr/\u003eOpenAPI 3.1]\n  end\n\n  subgraph Data\n    PG[(PostgreSQL 16\u003cbr/\u003eRow-Level Security)]\n    R[(Redis 7\u003cbr/\u003erefresh whitelist\u003cbr/\u003e+ BullMQ)]\n  end\n\n  subgraph Observability\n    OTEL[OpenTelemetry SDK\u003cbr/\u003e→ OTLP / Console]\n    MET[/metrics\u003cbr/\u003ePrometheus/]\n    LOG[pino\u003cbr/\u003etraceId 贯穿]\n  end\n\n  A -- BFF /admin/* --\u003e API\n  S -- BFF /store/* --\u003e API\n  SF -- /products /cart /orders --\u003e API\n  API -- mall_app role\u003cbr/\u003e受 RLS 约束 --\u003e PG\n  API --\u003e R\n  API --\u003e OTEL\n  API --\u003e MET\n  API --\u003e LOG\n```\n\n## 🛠️ Tech Stack\n\n| 层 | 选型 |\n|----|------|\n| 后端 | NestJS 11 · Fastify 5 · Prisma 7 · Zod 校验 · BullMQ 队列 · pino 结构化日志 |\n| 鉴权 | JWT access + refresh 双 token · Redis whitelist · scope=tenant/platform 区分 |\n| 数据隔离 | PG Row-Level Security + `mall_app` 非超管角色 · AsyncLocalStorage 透传 tenantId |\n| 支付 | StripeProvider + MockProvider 抽象，HMAC webhook 签名 + 幂等回调 |\n| 可观测 | W3C Trace Context（M24）· OpenTelemetry SDK + auto-instrumentation（M34） |\n| i18n | Accept-Language → BusinessException 字典（M17）· storefront 中英文切换（M33） |\n| 三前端 | Vite 6 + React 18 + TanStack Query + React Router 6 · openapi-typescript codegen |\n| 构建 | pnpm workspace + turbo · ESLint + Prettier · exactOptionalPropertyTypes |\n| 测试 | vitest（138 e2e + 单测）· Playwright（admin/store/storefront 浏览器级 4 用例） |\n| CI | GitHub Actions · shellcheck · turbo cache · acceptance-smoke · CodeQL · Codecov · GHCR release |\n| 部署 | docker compose（postgres + redis + api + migrate stage）· `.env.prod.example` |\n\n## 🚀 Quickstart\n\n依赖：Node 22+、pnpm 9+、Docker。\n\n```bash\n# 1. 起依赖（postgres + redis）\ndocker compose up -d\n\n# 2. 装依赖 + 应用迁移\ncp .env.example .env\npnpm install\npnpm --filter @mall/api exec prisma migrate deploy\n\n# 3. 起后端\npnpm --filter @mall/api dev\n# → http://localhost:3000/healthz\n# → http://localhost:3000/docs（Swagger UI）\n# → http://localhost:3000/metrics（Prometheus）\n\n# 4. 起三前端（每个开新终端）\npnpm --filter @mall/admin dev       # http://localhost:5173\npnpm --filter @mall/store dev       # http://localhost:5174\npnpm --filter @mall/storefront dev  # http://localhost:5175\n```\n\n\u003e 📖 **在线 API 文档**：\u003chttps://can4hou6joeng4.github.io/mall-saas/\u003e（GitHub Pages 自动跟随 `apps/api/openapi.json` 更新）\n\n## 📚 常用命令\n\n| 命令 | 作用 |\n|------|------|\n| `pnpm test` | 全工作区单测 + 后端 e2e |\n| `pnpm test:coverage` | 同上 + v8 覆盖率（上传 Codecov） |\n| `pnpm lint` | ESLint（max-warnings=0）|\n| `pnpm typecheck` | TypeScript 严格模式 |\n| `pnpm build` | 构建所有 workspace |\n| `pnpm --filter @mall/storefront exec playwright test` | 浏览器级 e2e |\n| `bash scripts/m{N}-acceptance.sh` | 单个里程碑端到端验收（M2~M34） |\n\n## 🐳 部署\n\n生产单机部署（docker compose）：\n\n```bash\ncp .env.prod.example .env.prod\n# 填入强随机 JWT_SECRET / POSTGRES_PASSWORD / PAYMENT_MOCK_SECRET ...\ndocker compose -f docker-compose.prod.yml --env-file .env.prod up -d --build\n```\n\n镜像也会在每次推 `v*` tag 时自动构建并发布到 [GHCR](https://github.com/can4hou6joeng4/mall-saas/pkgs/container/mall-api)（amd64 + arm64 多架构）：\n\n```bash\ndocker pull ghcr.io/can4hou6joeng4/mall-api:latest\n```\n\n## 🔒 多租户数据隔离（核心设计）\n\n1. **JWT 携带 `tenantId`**——所有 tenant-scope 请求由 `Auth` 中间件解析后存入 AsyncLocalStorage。\n2. **PG 角色双账号**：`mall`（superuser，跑迁移）/ `mall_app`（运行时，受 RLS 约束）。\n3. **每张业务表都有 RLS policy**：`USING (tenant_id = current_setting('app.tenant_id')::int)`。\n4. **每次事务前 `SET LOCAL app.tenant_id = $1`**（`PrismaService.withTenant()` 封装）。\n5. 即使代码 bug 忘了 WHERE tenant_id，DB 层也会拒绝跨租户读写——**最后一道防线**。\n\n## 🏁 里程碑链\n\n完整 34 个里程碑（v0.2-m2 → v0.34-m34），每个都自带可复跑的 `scripts/m{N}-acceptance.sh`：\n\n| 阶段 | 里程碑示例 |\n|------|----------|\n| 后端骨架（M2 – M10） | RLS · 多租户 · 商品 · 订单 · 支付 · JWT refresh |\n| 业务能力（M11 – M17） | 购物车 · 预占库存 · Stripe · 优惠券 · 文件存储 · i18n |\n| 三前端（M18 – M23） | admin Playwright · storefront · 401 自动 refresh · store 详情 · 消费者支付 |\n| 可观测 \u0026 部署（M24 – M30） | W3C trace · 生产 compose · admin tenant/payment 详情 · 用户管理 · GHCR release |\n| 工程化（M31 – M34） | 优惠券拉通 · 三前端 Playwright · storefront i18n · OpenTelemetry SDK |\n\n每个里程碑都遵循同一节奏：feature 分支 → 后端 + e2e → 前端 + jsdom → acceptance 脚本 → ff-merge → tag → GitHub Release。\n\n📖 详细 release notes 见 [CHANGELOG.md](./CHANGELOG.md) 或 [Releases 页](https://github.com/can4hou6joeng4/mall-saas/releases)。\n\n## 📂 目录结构\n\n```\n.\n├── apps/\n│   ├── api/           NestJS 后端（OpenAPI 3.1, Prisma, BullMQ, OTel）\n│   ├── admin/         超管平台前端\n│   ├── store/         商家后台前端\n│   └── storefront/    消费者前端（i18n 中英）\n├── packages/\n│   └── shared/        共享品牌类型（TenantId 等）\n├── scripts/\n│   └── m*-acceptance.sh  每个里程碑的端到端验收脚本\n├── docker-compose.yml         dev 用：postgres + redis\n├── docker-compose.prod.yml    prod 用：postgres + redis + migrate + api\n└── .github/workflows/\n    ├── ci.yml         shellcheck + 全工作区 + docker-smoke + acceptance-smoke + Codecov\n    ├── codeql.yml     代码安全扫描（每周一定时）\n    ├── pages.yml      自动发布 Swagger UI 到 GitHub Pages\n    └── release.yml    on push tag v* → 构建并推送 GHCR\n```\n\n## 🤝 贡献 \u0026 路线图\n\n- 想参与？读 [CONTRIBUTING.md](./CONTRIBUTING.md)。\n- 行为准则：[CODE_OF_CONDUCT.md](./CODE_OF_CONDUCT.md)。\n- 安全漏洞披露：[SECURITY.md](./SECURITY.md)。\n- 未来方向：[ROADMAP.md](./ROADMAP.md)。\n- 完整变更日志：[CHANGELOG.md](./CHANGELOG.md)。\n- 喜欢这个项目？欢迎 [Star ⭐](https://github.com/can4hou6joeng4/mall-saas/stargazers) / [开 Discussion 💬](https://github.com/can4hou6joeng4/mall-saas/discussions) / 提 [Issue](https://github.com/can4hou6joeng4/mall-saas/issues/new/choose)。\n\n## 🔗 相关项目\n\nmall-saas 是 [@can4hou6joeng4](https://github.com/can4hou6joeng4) 围绕 **AI Agent + 工程化开源** 的一部分。以下是同体系下的其它项目：\n\n| 项目 | 简介 | Stack |\n|------|------|-------|\n| [boss-agent-cli](https://github.com/can4hou6joeng4/boss-agent-cli) ⭐ | 专为 AI Agent 设计的 BOSS 直聘双端 CLI——schema 驱动 · JSON 信封 · 求职/招聘工作流 · MCP 集成 · AI 简历优化 | Python · MCP |\n| [OpenCLI](https://github.com/can4hou6joeng4/OpenCLI) | 让任意网站 / Electron / 本地工具变成 AI Agent 可发现 + 可调用的 CLI（AGENT.md 一体化） | JavaScript |\n| [TokenIsland](https://github.com/can4hou6joeng4/TokenIsland) | macOS 灵动岛实时展示 Claude Code / Codex CLI agent 状态与今日 token 消耗 | Swift |\n| [landing-craft](https://github.com/can4hou6joeng4/landing-craft) | Claude Code skill：57 套城市灵感设计 + GSAP 动效，一键生成视觉冲击力强的 Landing Page | HTML |\n| [legal-extractor](https://github.com/can4hou6joeng4/legal-extractor) | 法律文书智能提取工具 | Go |\n| [@can4hou6joeng4](https://github.com/can4hou6joeng4) | 个人主页：AI Agent Developer · Full Stack Engineer · Open Source Maintainer | — |\n\n\u003e 想看作者完整 portfolio：\u003chttps://developer-portfolio-opal-six.vercel.app\u003e\n\n## 📄 License\n\n[MIT](./LICENSE) © 2026 [can4hou6joeng4](https://github.com/can4hou6joeng4)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcan4hou6joeng4%2Fmall-saas","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcan4hou6joeng4%2Fmall-saas","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcan4hou6joeng4%2Fmall-saas/lists"}