LiYuan Studio 官网。
- 前端:React + TypeScript + Vite,部署在 Cloudflare Pages
- 后端 API:Hono + Mongoose + TypeScript,部署在 Vercel
- 数据库:MongoDB Atlas
.
├── api/ # Vercel Serverless Functions 入口
├── server/ # Hono + Mongoose 后端源码
├── scripts/ # 仓库级脚本(如密钥泄漏扫描)
├── src/ # React 前端源码
├── .env.example # 前端环境变量示例
└── vercel.json # Vercel 部署配置
npm install仓库使用 npm workspaces,会同时安装 server/ 的依赖。
# 前端
cp .env.example .env
# 本地一般保持 VITE_API_BASE_URL=/api,让 Vite 代理到后端
# 后端
cp server/.env.example server/.env
# 编辑 server/.env,填入本地 MongoDB/Atlas、API_KEY、JWT_SECRET、CORS_ORIGIN、APP_URL本地开发可以不配置邮件服务:保持 EMAIL_PROVIDER= 为空,注册时后端会在控制台打印邮箱验证链接。不要把 .env、API Key、token、密码或真实数据库连接提交到仓库。
若数据库里还留着旧的示例「最新动态」/种子博客,可在配置好 server/.env 后执行:
npm run cleanup-mock:api -- --confirmnpm run devnpm run dev 会先启动后端 API 并等待 /api/health,再启动 Vite。前端默认在 http://localhost:5173,后端默认在 http://localhost:3000/api。
| 脚本 | 说明 |
|---|---|
npm run dev |
同时启动后端 API 和 Vite 前端 |
npm run dev:web |
仅启动 Vite 前端 |
npm run build |
前端 TypeScript 检查并构建 |
npm run dev:api |
启动 Hono 后端开发服务器 |
npm run build:api |
编译后端 TypeScript |
npm run build:deploy-console |
检查独立灰度发布控制台 |
npm run test:deploy-console |
测试灰度发布控制台 |
npm run seed:api |
已停用示例种子数据(no-op,便于兼容旧脚本) |
npm run cleanup-mock:api -- --confirm |
删除旧种子新闻/博客与测试账号等 mock 数据(必须显式确认) |
npm run check:secrets |
扫描仓库中可能的密钥泄漏 |
POST /api/auth/register/send-code— 发送注册验证码,body:{ email, password, displayName }POST /api/auth/register/verify— 验证注册验证码并完成注册,body:{ email, code }POST /api/auth/login— 登录,body:{ email, password }GET /api/auth/me— 当前用户;浏览器使用 HttpOnly 会话 Cookie,受信任服务可使用Authorization: Bearer <opaque-session-token>
注册分为两步:先发送 6 位数字验证码到邮箱,验证通过后才会在数据库创建用户。新用户默认 role=tourist 且 emailVerified=true。密码只保存 bcrypt hash;验证码和会话令牌只以 SHA-256 hash 保存到数据库。登录会话在每次成功调用 /auth/me 时滚动续期 30 天。
第一位管理员需要在 MongoDB Atlas 中手动把对应用户文档的 role 改为 admin。前端不会决定用户是否为管理员;管理员权限以后端持久会话和 role 为准。
生产发布分为私有预发布、部署到生产、账号灰度、全量观察和稳定化五个阶段。LA 管理员在独立控制台验收候选后,将候选部署到生产,再按账号名单和固定比例逐步开放。配置和操作说明见 docs/gray-deployment.md。灰度控制台独立部署,不会进入官网构建产物。
保持现有构建流程:
npm run build生产构建继续使用同源 API:
VITE_API_BASE_URL=/api
Cloudflare Pages Function 根据 wrangler.jsonc 中固定的
API_UPSTREAM_ORIGIN=https://liyuanstudio-com-web.vercel.app 转发 /api/*。
在 Vercel Project 的环境变量中配置:
MONGODB_URIAPI_KEYJWT_SECRETCORS_ORIGIN,包含生产前端域名;如果同时使用 apex 和 www,配置为https://liyuanstudio.com,https://www.liyuanstudio.comAPP_URL,生产前端地址;如果正式站以 www 访问,配置为https://www.liyuanstudio.comEMAIL_PROVIDER=resendRESEND_API_KEYEMAIL_FROM
生产邮件使用 Resend。请在 Resend 配置发信域名,并在 Cloudflare DNS 中添加 Resend 要求的 DNS 记录,等域名验证通过后再启用生产注册邮件。
浏览器只访问主站同源的 /api/*;Vercel 原始地址只作为 Cloudflare Pages
Function 的固定服务端上游。上线此变更后,旧跨域 Cookie 不做迁移,现有用户需重新登录一次。
GET /api/news— 新闻列表GET /api/news/:slug— 单条新闻GET /api/blog— 博客列表GET /api/blog/:slug— 单篇博客
POST /api/news/POST /api/blog— 创建PATCH /api/news/:id/PATCH /api/blog/:id— 更新DELETE /api/news/:id/DELETE /api/blog/:id— 删除
- 所有敏感信息均通过环境变量注入,代码中无真实默认值。
- 登录会话使用 MongoDB 中的高熵随机令牌哈希;浏览器 Cookie 不保存 JWT。
- 后端
API_KEY使用恒定时间比较,防止时序攻击。 npm run check:secrets会扫描.env文件、MongoDB URI、API Key、JWT secret、Resend key、token、密码等常见模式。- 不要提交
.env、真实 API Key、token、密码、Resend key 或 MongoDB 连接串。