Live Dating Platform
一个仅限会员的订阅制约会产品 — 同一后端支持两个客户端,具有真正的应用内视频和语音通话功能。包含注册及经过审核的照片引导流程、带有距离和偏好过滤的滑动卡片、防竞态匹配、实时聊天、WebRTC 通话和定期计费 — 并融入了大多数约会应用迟迟未能引入的信任与安全堆栈。
01概述
一个基于单一后端构建为两个客户端的仅限会员约会平台:一个功能齐全的 Next.js web 应用(会员及管理面板),以及一个通过 Bearer 令牌与同一 API 通信的 Expo / React Native 应用。一套完整的会员旅程 — 注册、建立个人资料、通过审核设置主照片、浏览、匹配、聊天以及面对面通话 — 在 web 端和您的手机中运行得完全一致,相同的定期订阅机制同时在这两端控制着付费功能。
最有趣的部分并非滑动卡片。而在于一个处理私人用户照片、付款、陌生人之间发送消息以及实时点对点通话的消费者产品,其信任与安全及滥用控制机制 — AI 审核、私有媒体、封禁/屏蔽执行、速率限制、身份验证 — 是从数据库模式开始从头设计的,而不是在发生第一次事故后才进行后期修补。
02解决的问题
约会应用远比看起来的要复杂。在滑动卡片背后,隐藏着身份和会话安全、付款、在负载下不能重复触发的匹配引擎、实时消息传递、必须穿透 NAT 的实时通话,以及 — 往往导致大多数消费者社交产品发布失败的部分 — 安全层面:在内容上线之前的审核、绝不泄漏的私有媒体、真正有效的屏蔽和举报、削弱滥用的速率限制,以及一条通往真实年龄和身份验证的途径。如果将这些作为事后补充来构建,那你交付的将是一个隐患。
结果 一个从发布起就具备通话、审核、安全和支付机制(这些通常会被推迟实现)的订阅制约会产品 — 从第一天起就支持 web 端和原生应用,运行于同一后端。
03我们构建了什么
账户与身份
手工打造的凭据验证 — bcrypt 加上在 httpOnly cookie 中的签名 JWT (jose) — 如果未设置身份验证密钥,系统会安全关闭(fails closed)。令牌携带 tokenVersion,因此“在所有设备上注销”和封禁会立即撤销每一个活动会话。一次性、经过哈希处理且会过期的令牌用于驱动电子邮件验证和防枚举的密码重置。OAuth (Google、Facebook、Instagram) 采用授权码流程并结合 state-cookie 防止 CSRF,且通过电子邮件链接身份 — 无需 SDK。账户删除设有软删除宽限期:立即隐藏并注销,在此期间重新登录即可恢复,随后由每日定时任务进行彻底清除。
个人资料、发现与匹配
丰富的个人资料 — 代词、身高、体型、性取向、目标、兴趣和提示卡片 — 并带有一张经过审核的、受 PENDING / APPROVED / REJECTED 状态控制的主照片,以及向会员解释可见性的横幅。发现功能在性别和年龄范围上进行双向过滤,尊重偏好(目标、体型、身高、是否吸烟),并将每个城市进行地理编码为坐标以便进行距离过滤。卡片组支持喜欢 / 跳过 / 超级喜欢和撤回;匹配建立在一个规范且防竞态的配对键上,因此同时发生的相互喜欢永远不会创建两个匹配记录。周边功能包含:谁喜欢了你、谁看过了你、每日精选(每天确定性的随机推荐)、取消匹配以及假期/暂停模式。
实时聊天与实时通话
每个匹配的对话在 web 端通过 Server-Sent Events 流式传输(原生应用使用轮询),提供输入状态指示器、未读标记、已读标记,并在文本之外支持语音和视频消息。在同一个匹配频道之上,运行着真正的 WebRTC 视频和语音通话:一个信令端点在两个对等端之间中继 SDP 提议/应答和 ICE 候选者,一个 ICE 配置端点分发 STUN 以及限时的 HMAC TURN 凭据(以便即使在对称 NAT 后也能建立通话连接),并且来电会通过推送唤醒另一台设备。原生客户端运行完整的 RTCPeerConnection,支持静音、摄像头开启/关闭及前后置切换;任何一方都可以带类型原因(拒绝 / 忙碌 / 结束 / 超时)挂断。
审核与媒体管道
每一张上传的图像都会通过可插拔的 AI 审核(OpenAI 的全能审核模型):严重违反政策的会被直接拒绝,其他情况会进行风险评分并进入人工审核队列 — 系统采用失败开放(fails open)机制进入人工审核,而不是直接阻止合法的上传。被接受的图像会使用 sharp 重新编码 — 根据 EXIF 自动旋转,为保护隐私剥离 EXIF 信息,并写入为一张紧凑的主图像外加一张缩略图。
订阅与计费
用于定期月度计划的 Stripe Checkout、一个计费门户,以及一个将订阅状态 — 包括 PAST_DUE — 同步回会员的 webhook。三个层级 (FREE / PLUS / PREMIUM) 驱动了一个能力矩阵:每天的超级喜欢、谁看过了你、每日精选、撤回、已读回执、高级过滤器以及无痕浏览模式。层级独立于订阅状态进行跟踪,因此取消订阅的会员可以保留其层级直到周期结束。开发者绕过机制和本地促销代码使得整个流程无需实时 Stripe 密钥即可运行。
04信任、安全与管理面板
会员照片存放在 web 根目录之外,并且仅通过一个经过身份验证的路由提供服务,该路由会重新检查会话(封禁/被撤销的用户会被拒绝)并针对每张照片进行授权:所有者始终可以访问,否则仅限未被屏蔽或封禁的活跃会员访问 — 使用 private、nosniff,绝非任何人可读,并且防范路径遍历。跨图像、音频和视频的上传都通过魔术字节进行验证,而非依赖客户端声明的 MIME,从而杜绝了内容类型欺骗和 SVG 脚本漏洞。CSRF 防御在 SameSite=Lax 的基础上,通过对每一个发生修改的路由进行同源检查来实现;速率限制涵盖了登录、注册、上传、喜欢、消息、屏蔽、举报和通话信令。统一的安全守卫在各处强制执行屏蔽和封禁 — 浏览、喜欢、匹配、聊天、通话和媒体。会员可以进行(双向)屏蔽和举报;支持 KYC 的年龄和自拍照片验证会作为个人资料徽章呈现。管理员拥有一个独立的、非管理员访问返回 404 的、受 CSRF 保护的区域 — 包含仪表板、主照片审核队列、照片验证审查、举报分类(忽略 / 解决 / 解决并封禁)和用户工具(封禁 / 解封 / 撤销会话) — 并且每一个管理员操作都会记录在不可变的审计日志中。
05技术
06亮点
- 应用内 WebRTC 视频与语音通话 — 基于匹配频道的 SDP/ICE 信令,限时 HMAC TURN 凭据,推送唤醒的来电,带有静音和摄像头切换功能的原生对等连接。
- 两个客户端,同一后端 — 通过 Bearer 令牌 API 在 Next.js web 端和 Expo/React Native 应用上实现完整的会员旅程。
- 每次上传时的 AI 图像审核(直接拒绝 + 风险评分的人工审核队列),采用失败开放机制进入审核而非直接拦截。
- 私有、受访问控制的媒体:存放在 web 根目录之外,针对每张照片的授权,剥离 EXIF 的
sharp处理管道,针对图像/音频/视频的魔术字节验证。 - 基于规范配对键的防竞态匹配;包含喜欢 / 跳过 / 超级喜欢、撤回、谁喜欢了你、谁看过了你以及每日精选。
- 基于 SSE 的实时聊天,带有输入状态指示器、已读标记和语音/视频消息;优雅的屏蔽/封禁/过期处理机制。
- Stripe 订阅机制,具有 webhook 状态同步和 PAST_DUE 处理;FREE/PLUS/PREMIUM 能力矩阵,包括无痕模式。
- 安全关闭的凭据身份验证;
tokenVersion会话撤销;带有不可变审计日志的管理面板;支持恢复的软删除 + 清除定时任务。