场景拆解 用法洞察

从零搭一个社群平台:
Salonette 制作指南

群里一直在说要有个自己的地方。后来就真的做了一个。这篇把过程记下来,不是教程,更像笔记。

📌 by DMVoice 女性AI Workgroup · salonette.syneira.org · 2026.05

Salonette 是我们群的小平台。服务目前 90 来位成员,9 个投票产生的方向小组,可以发起项目、分享链接、看看彼此在做什么。从动手到上线大概 5 天,AI 帮写了大部分代码。下面把过程摊开,万一你哪天也想给自己的小群体做一个,能少走几步弯路。

先想清楚不做什么

做这种小工具最容易犯的错是想太多。投票、活动、日历、AI 摘要、聊天记录归档,每个听着都有道理,但一起做的话三个月也出不来。

所以第一版只留了四样东西:成员档案、方向小组、协作项目、链接分享。其他功能数据库层面留了位子,代码一行没碰。先能用起来再说。

有一条自己定的规矩后来帮了大忙:做就做完整的,不做就彻底不做。灰色的按钮、写着「即将上线」的空页面,这些东西放上去反而让人觉得没做完。

还有一个决定值得单独说。登录没有接 Google,也没有接微信,只用邮箱+密码。听起来很原始,但原因很实际:我们的人全是从微信群点链接进来的,微信内置浏览器不支持 Google 的登录跳转。如果用了 Google OAuth,上线当天所有人都登不进去。这种事不提前想,就是上线以后的事故。

用了哪些工具,为什么

选择为什么
前端框架 Next.js 16 (App Router) 服务端组件做读取,Server Actions 做写入,不需要单独写 API 层。Vercel 一键部署
样式 Tailwind CSS v4 用 CSS 变量定义设计系统(品牌色 Iris #7C7FCA),不需要配置文件
后端 + 数据库 Supabase (PostgreSQL) 自带认证、实时订阅、行级安全(RLS)、文件存储。免费额度够百人规模用。SQL 背景的人上手最快
认证 邮箱+密码 + 魔法链接 零第三方依赖,微信浏览器内完全可用
部署 Vercel (免费) GitHub push 自动部署,自定义域名免费 SSL
PWA 手写 sw.js 主流 PWA 库(serwist、next-pwa)和 Next.js 16 的 Turbopack 冲突,手写反而最稳

成本:第一版总成本 $0/月。Vercel 免费、Supabase 免费(50K 月活、500MB 数据库)、域名 $12/年(Porkbun)。百人以内的社群不需要花钱。

表之间的关系:这是最容易出问题的地方

7 张表,不算多。但表和表怎么连的,决定了后面写功能的时候顺不顺。这部分稍微技术一点,不感兴趣可以跳过,但如果你打算自己做类似的东西,这里值得看一眼。

members ← 核心表,每个用户一条记录 user_id → auth.users (Supabase 自带的认证系统) nickname, bio, industry[], ai_tools[]... groups ← 9 个方向小组(金融/教育/创意/健康/...) code (唯一), name, icon, color group_members ← 多对多:谁加入了哪个组 group_id → groups member_id → members role, joined_via projects ← 组内协作项目 group_id → groups initiated_by → members status: recruiting → active → completed project_members ← 多对多:谁参与了哪个项目 project_id → projects member_id → members status: pending → approved / rejected links ← 分享的链接/资源 group_id → groups posted_by → members link_bookmarks ← 私人收藏(只有自己能看) member_id → members link_id → links

关键理解:group_membersproject_members 是两张「关系表」(join table),它们的主键是两个外键的组合。这意味着一个人可以加多个组,参与多个项目,但不能重复加入同一个。

⚠️ 如果你用过 NoSQL(比如 Firebase),你可能习惯把「这个组有哪些人」直接存成一个数组。别这样做。一旦你需要查「这个人加了哪些组」、「这个组有多少人」、「谁最近加入的」,数组就废了。关系表是正道。

权限控制:谁能看什么、改什么

Supabase 有个功能叫 RLS(Row Level Security),说白了就是在数据库层面控制每一行数据谁能看、谁能改。规则写在数据库里,前端代码怎么写都绕不过去。

Salonette 的几条关键规则举例:

规则意思
membersSELECT: 所有登录用户可看成员目录对内公开(只要登录了就能看)
membersUPDATE: 只能改自己的行user_id = auth.uid()
link_bookmarksSELECT/INSERT/DELETE: 只看自己的收藏是私人的,别人看不到你收藏了什么
projectsINSERT: 必须是目标组的成员不能在没加入的组里发起项目

5 天,三步走

1
Day 1 · 打地基
项目初始化 + 数据库 + 种子数据
创建 Next.js 项目,接上 Supabase,把 7 张表的结构推上去。9 个小组的数据手动填,老成员的数据从之前的 Survey 和投票 Excel 里用 Python 脚本导入。这步看着简单,但数据干净后面才不会堵。
2
Day 2–3 · 让人进来
注册登录 + Onboarding + 小组浏览
注册页、登录页,Onboarding 区分「老成员认领已有档案」和「新人从零填写」两条路。个人档案可以编辑,9 个方向小组可以浏览和加入。到这步,人能进来了,能看到彼此了。
3
Day 4–5 · 能用起来
项目 + 链接 + 首页 + 上线
项目发起和申请,链接分享和收藏,个人首页把自己相关的内容汇总到一起。加上 PWA(可以添加到手机桌面),绑上域名,在群里发出去。

踩过的坑

下面这几个都是做的过程中真碰上的,不是假设的。记下来不是炫耀解决了什么,是因为做类似的东西大概率会踩到一样的。

⚠️ RLS 无限递归
管理员权限检查写成了「查 members 表看有没有 is_admin=true 的行」,但这个查询本身触发了 members 表的 RLS 策略,RLS 策略里又要查管理员权限——死循环。新用户注册时直接报错。
写一个 SECURITY DEFINER 函数 is_admin(),跳过 RLS 直接查。所有涉及管理员判断的策略都改成调用这个函数。
⚠️ 种子用户认领冲突
Supabase 默认有个 trigger,新用户注册时自动在 members 表创建一行。但种子用户已经有一行了(只是 user_id 为空等着被认领)。结果:重复行。
删掉自动 trigger。让 Onboarding 代码做唯一的入口——种子用户走「认领」(UPDATE),新用户走「创建」(INSERT)。
⚠️ 微信浏览器 + Google OAuth = 翻车
微信内置浏览器不支持 Google 的 OAuth 重定向。如果用 Google 登录,用户从微信群点链接进来会直接失败。
开始就不接 Google OAuth。用邮箱+密码,万事大吉。微信浏览器加一个小提示条:「建议用系统浏览器打开获得最佳体验」。
⚠️ PWA 库和 Next.js 16 不兼容
主流的 PWA 库(serwist、next-pwa)都是基于 Webpack 的,Next.js 16 默认用 Turbopack,直接冲突。Build 失败。
不用库。自己写一个 sw.js 放在 public 目录,30 行代码搞定缓存策略。简单、可控。
⚠️ 种子数据去重
从两份不同的 Excel(Survey 和投票)导入种子数据,同一个人在两份表里名字写法不同(「Junqi Zhang」vs「Junqi」),差点导入成两个人。
写一个 Python 脚本做导入,内置昵称映射表 NICKNAME_CANONICAL。30 个人的数据,人工校对一遍也就 10 分钟。不要相信自动去重。

如果你也想试试

说实话,Salonette 的代码大部分是 AI 写的。我做的事情是想清楚要什么、给谁用、什么不做,然后交给 AI 编程工具去实现——组件、数据库规则、导入脚本都是这么来的。用 Claude Code 也好,GPT Codex 也好,其他 agent 也行,工具不重要。不会写代码不是障碍,不知道自己要什么才是。

如果你也有一个小群体,也觉得现有的工具不太合适,也许可以试试自己搭一个。成本比想象的低。

项目费用
Vercel 部署免费
Supabase 后端免费(50K MAU)
域名(可选)~$12/年
AI 编程工具GPT Codex / Claude Code / 其他 agent
总计$0–$1/月 + 你已有的 AI 订阅费

回头看,几件事做对了

功能砍得狠,只留了四个模块。登录方案一开始就考虑了微信浏览器的限制,没有返工。种子数据用脚本从 Excel 导入,不是手动录的,后面改起来也方便。权限规则从第一天就写好了,不是上线以后补的。

还有一点:没有先做个简易版凑合用。想好了就直接做正式的,5 天够了。