Skip to content

A free, open-source SaaS app starter for React & Node.js with superpowers. Full-featured. Community-driven.

License

Notifications You must be signed in to change notification settings

yeagoo/open-saas

 
 

Repository files navigation

MKLaunch - Multi-Tenant Startup Tool Discovery Platform

基于 WaspOpen SaaS 构建的多租户工具发现站群系统,专为创建类似 findly.tools 的工具目录而设计。

🌟 特性

核心功能

  • 多租户架构 - 一套代码支持多个域名/品牌
  • 自动 Badge 巡检 - 要求工具网站展示 Badge,定期自动检查
  • 图片自动处理 - 所有图片自动转换为 AVIF 格式并上传到 Cloudflare R2
  • 防机器人保护 - 集成 Cloudflare Turnstile 验证码
  • 邮件通知 - 使用 Resend API 发送审核和通知邮件
  • 管理后台 - 完整的审核、管理和配置界面

技术栈

  • 框架: Wasp 0.18.0 (React + Node.js + Prisma)
  • 数据库: PostgreSQL
  • 缓存/队列: Redis + Bull
  • 对象存储: Cloudflare R2 (S3 兼容)
  • 图片处理: Sharp (AVIF 转换)
  • 邮件: Resend API
  • 验证码: Cloudflare Turnstile
  • UI: React + Tailwind CSS + shadcn/ui
  • 部署: Zeabur + Docker

📋 前置要求

  • Node.js 18+
  • PostgreSQL 14+
  • Redis 7+
  • Wasp CLI (curl -sSL https://get.wasp-lang.dev/installer.sh | sh)

🚀 快速开始

1. 克隆并安装

git clone <your-repo>
cd mklaunch/template/app
npm install

2. 配置环境变量

复制 .env.server.example.env.server 并填写配置:

cp .env.server.example .env.server

关键环境变量:

  • DATABASE_URL - PostgreSQL 连接字符串
  • REDIS_URL - Redis 连接字符串
  • R2_* - Cloudflare R2 凭证
  • RESEND_API_KEY - Resend 邮件 API 密钥
  • TURNSTILE_* - Cloudflare Turnstile 密钥

3. 初始化数据库

wasp db migrate-dev
wasp db seed  # 可选:添加示例数据

4. 启动开发服务器

wasp start

应用将在 http://localhost:3000 启动。

🏢 多租户配置

租户数据模型

每个租户包含:

  • primaryDomain - 主域名
  • extraDomains - 额外域名(JSON 数组)
  • theme - 主题配置(颜色、Logo、Favicon)
  • seo - SEO 配置(标题、描述、关键词)
  • locale - 语言设置(默认 zh-CN)

域名解析

系统通过 Host 头自动识别租户:

  1. 从 HTTP 请求的 Host 头提取域名
  2. 查询匹配的 Tenant(支持 primaryDomain 和 extraDomains)
  3. 将租户信息注入请求上下文(req.tenant
  4. 所有数据库查询自动过滤 tenantId

添加新租户

// 通过 Prisma 或管理后台创建
await prisma.tenant.create({
  data: {
    name: "My Tool Directory",
    primaryDomain: "tools.example.com",
    extraDomains: ["www.tools.example.com"],
    theme: {
      primaryColor: "#667eea",
      logo: "https://...",
      favicon: "https://..."
    },
    seo: {
      title: "My Tool Directory",
      description: "Discover the best tools...",
      keywords: "tools, directory, saas"
    },
    locale: "zh-CN"
  }
});

🎫 Badge 系统

Badge 要求

工具提交时必须在其网站上展示 Badge:

<a href="https://yourdomain.com/" target="_blank" rel="noopener">
  <img src="https://yourdomain.com/static/badges/powered-by.svg" 
       alt="Powered by YourBrand" />
</a>

巡检机制

  • 即时校验: 提交时立即检查 Badge
  • 定期巡检: 根据 CRON 配置定期检查(默认:每天 3AM 和 3PM)
  • 失败策略:
    • 第一次失败:发送警告邮件
    • 连续两次失败:自动下线工具并发送通知
  • 重试: 指数退避,最多 3 次

配置巡检频率

.env.server 中设置 CRON 表达式:

# 每天 3AM 和 3PM(默认)
BADGE_CHECK_CRON=0 3,15 * * *

# 每周一和周四上午 10 点
BADGE_CHECK_CRON=0 10 * * 1,4

# 每 6 小时
BADGE_CHECK_CRON=0 */6 * * *

📷 图片处理

所有图片自动处理流程:

  1. 上传/提供 URL - Logo 或封面图片
  2. 下载原图 - 系统下载原始图片
  3. 转换 AVIF - 使用 Sharp 转换(quality: 80, effort: 4)
  4. 上传 R2 - 存储到 Cloudflare R2
  5. 记录数据库 - 在 Asset 表中记录

支持两种上传方式:

  • 服务端转存 - 提供图片 URL,服务端下载转换上传
  • 前端直传 - 获取预签名 URL,前端直接上传到 R2

R2 配置

  1. 在 Cloudflare Dashboard 创建 R2 bucket
  2. 生成 API 令牌
  3. 配置环境变量:
    • R2_ACCOUNT_ID
    • R2_ACCESS_KEY_ID
    • R2_SECRET_ACCESS_KEY
    • R2_BUCKET
    • R2_PUBLIC_BASE_URL

📧 邮件模板

使用 Resend API 发送以下邮件:

  • 审核通过 - 工具被批准并上线
  • 审核驳回 - 工具被拒绝及原因
  • Badge 警告 - 第一次检测不到 Badge
  • 工具下线 - Badge 连续失败,工具被下线

配置 Resend

  1. Resend 注册账户
  2. 验证发件域名
  3. 生成 API 密钥
  4. 配置环境变量:
    RESEND_API_KEY=re_xxxxx
    MAIL_FROM=Support <[email protected]>

🔐 安全特性

  • Cloudflare Turnstile - 防止机器人提交
  • 速率限制 - Redis 实现的智能限流
    • 提交:5 次/5 分钟(按 IP)
    • 登录:5 次/5 分钟(按 IP)
    • API:10 次/分钟(可配置)
  • 租户隔离 - 所有查询强制 tenantId 过滤
  • HTTPS Only - 生产环境强制 HTTPS

🎨 自定义主题

每个租户可独立配置主题:

{
  "primaryColor": "#667eea",
  "logo": "https://cdn.example.com/logo.avif",
  "favicon": "https://cdn.example.com/favicon.ico",
  "customCSS": "/* optional */"
}

📊 SEO 功能

每个租户独立生成:

  • /sitemap.xml - 自动生成 XML Sitemap
  • /robots.txt - 自定义爬虫规则
  • /rss.xml - 最新工具 RSS Feed
  • /llms.txt - LLM 抓取说明
  • Open Graph / Twitter Card meta 标签
  • JSON-LD 结构化数据

🔧 管理后台

访问 /admin 进入管理后台(需要管理员权限):

功能模块

  • Dashboard - 统计概览
  • 审核队列 - 批准/驳回提交
  • 工具管理 - 编辑、批量操作、手动复检
  • 租户配置 - 域名、主题、SEO 设置
  • 批量导入 - CSV/JSON 导入工具

角色权限

  • Owner - 完全控制
  • Admin - 管理工具和审核

🚢 部署

参见 DEPLOYMENT.md 了解详细的部署指南。

Zeabur 快速部署

Zeabur 原生支持 Node.js/Wasp 项目,部署非常简单:

  1. 推送代码到 GitHub

    git push origin main
  2. 在 Zeabur 创建项目

  3. 部署应用

    • 选择 "Deploy from GitHub"
    • 选择你的仓库
    • Zeabur 自动检测并构建
  4. 添加服务(一键部署)

    • PostgreSQL: Marketplace → PostgreSQL → Deploy
    • Redis: Marketplace → Redis → Deploy
    • 环境变量自动注入!
  5. 配置其他环境变量

    • R2 凭证
    • Resend API Key
    • Turnstile 密钥
  6. 运行数据库迁移

    • 使用 Zeabur Console 或 Web SQL

详细步骤请查看 DEPLOYMENT.md

📝 API 端点

公开 API

  • GET /health - 健康检查
  • GET /outbound/:toolId - 外链跳转(统计点击)
  • POST /jobs/badge-cron - Badge 巡检触发(Cron)

认证 API

  • GET /upload/presign - 获取上传预签名 URL

Wasp Operations

  • getTools - 获取工具列表(支持分页、筛选、搜索)
  • getToolBySlug - 获取单个工具
  • getCategories - 获取分类列表
  • getTags - 获取标签列表
  • submitTool - 提交新工具

🐛 故障排查

常见问题

1. Turnstile 验证失败

  • 检查 TURNSTILE_SITE_KEYTURNSTILE_SECRET_KEY
  • 开发环境自动跳过验证

2. Badge 检查总是失败

  • 确保 Badge 在页面 HTML 中可见
  • 检查 <a> 标签没有 rel="nofollow"
  • 确保图片 URL 可访问

3. 图片上传失败

  • 检查 R2 凭证配置
  • 确认 bucket 权限正确
  • 检查图片大小(< 10MB)和格式

4. 邮件未发送

  • 检查 RESEND_API_KEY
  • 确认发件域名已验证
  • 查看服务器日志

5. Redis 连接失败

  • 检查 REDIS_URL 格式
  • 确认 Redis 服务运行中
  • 检查网络连接

📚 更多资源

📄 许可证

MIT

🤝 贡献

欢迎提交 Issues 和 Pull Requests!


注意: 这是一个生产就绪的模板,但在实际部署前请:

  • 修改所有默认配置和密钥
  • 配置生产环境数据库备份
  • 设置监控和日志系统
  • 进行安全审计
  • 配置 CDN 和缓存策略

About

A free, open-source SaaS app starter for React & Node.js with superpowers. Full-featured. Community-driven.

Resources

License

Contributing

Stars

Watchers

Forks

Packages

No packages published

Languages

  • TypeScript 57.6%
  • MDX 34.0%
  • JavaScript 3.4%
  • Astro 2.7%
  • Shell 1.3%
  • CSS 0.8%
  • Dockerfile 0.2%