单仓库混合渲染工程方案 v1.0
单仓库混编渲染方案,集成 API 服务、SPA 管理后台、ISR 官网及多域名活动落地页,使用接口优先契约与自动化提效手段维护。
架构全景总览
系统分层架构图
四大子系统对应关系
技术栈选型与职责划分
单仓目录结构规范
hehe-app/ # 单仓根目录 ├── app/ # Nuxt 4 前端渲染层(Vue 3 组件与页面) │ ├── components/ │ │ ├── client/ # 官网/H5 专用轻量组件 │ │ ├── admin/ # 管理后台专用重型组件(ECharts 等) │ │ └── shared/ # 前后台通用的极轻量组件 │ ├── composables/ │ │ ├── seo.ts # useAppSEO:SEO 注入统一入口(官网/H5 必须调用) │ │ └── auth.ts # useAuth:客户端会话状态管理 │ └── pages/ │ ├── (client)/ # 官网路由分组 → yourdomain.com │ ├── (h5)/h5/[subdomain]/ # 营销 H5 → *.yourdomain.com │ └── (admin)/admin/ # 管理后台 → admin.yourdomain.com │ ├── server/ # Nitro 服务端层(Node.js API 引擎) │ ├── middleware/ │ │ ├── 01.subdomain-rewrite.ts # 子域名动态路由重写 │ │ ├── 02.auth.ts # 全局 Auth 解析(Bearer + Cookie 双兼容) │ │ └── 03.admin.ts # Admin API 路由强拦截 │ ├── api/ │ │ ├── v1/ # 对外公开 API(api.yourdomain.com) │ │ └── admin/ # 管理员专用私有 API │ └── utils/ │ ├── auth.ts # assertUser / assertAdmin 鉴权断言 │ ├── audit.ts # writeAuditLog 操作审计日志 │ ├── ip.ts # getClientRealIP(优先 CF-Connecting-IP) │ └── analytics.ts # 数据分析埋点与上报 │ ├── supabase/migrations/ # 数据库迁移 SQL(版本控制严格管理) ├── .github/workflows/ # CI 流水线(类型/安全/性能/DB 自动化校验) ├── .cursorrules # AI Coding 强制规范(Cursor/Claude 读取) └── nuxt.config.ts # 核心配置(路由规则·渲染模式·缓存·图片)
多域名流量路由设计
Edge Middleware 核心实现
export default defineEventHandler((event) => { const host = getHeader(event, 'host') || '' const path = event.path // 跳过静态资源与内部 Nuxt 路由 if (path.startsWith('/_nuxt/') || path.startsWith('/api/')) return const ROOT_DOMAIN = useRuntimeConfig().rootDomain // 1. 官网:主域名或 www if (host === ROOT_DOMAIN || host === `www.${ROOT_DOMAIN}`) { if (!path.startsWith('/client')) event.node.req.url = `/client${path === '/' ? '' : path}` return } // 2. 管理后台 if (host.startsWith('admin.')) { if (!path.startsWith('/admin')) event.node.req.url = `/admin${path}` return } // 3. API 引擎(禁止前台路由越界) if (host.startsWith('api.')) { if (!path.startsWith('/api/v1/')) throw createError({ statusCode: 404, statusMessage: 'API Not Found' }) return } // 4. 动态营销 H5 子域名 *.yourdomain.com const parts = host.split('.') if (parts.length >= 3) { const subdomain = parts[0] if (!path.startsWith(`/h5/${subdomain}`)) event.node.req.url = `/h5/${subdomain}${path === '/' ? '' : path}` } })
混合渲染模式与边缘缓存策略
鉴权体系设计(多端兼容)
多层拦截鉴权机制
双模式 Token 解析
// assertUser: 验证用户身份(支持 Cookie + Bearer 双模式) export async function assertUser(event: any) { const user = event.context.user if (!user) throw createError({ statusCode: 401, statusMessage: 'Unauthorized' }) return user } // assertAdmin: 在 assertUser 基础上额外验证管理员角色 export async function assertAdmin(event: any) { const user = await assertUser(event) const { data: profile } = await client.from('profiles') .select('role').eq('id', user.id).single() if (profile?.role !== 'admin') throw createError({ statusCode: 403, statusMessage: 'Admin Access Forbidden' }) return user }
管理后台模块设计
核心功能模块
| 模块 | 路由 | 核心功能 |
|---|---|---|
| 数据大盘 | /admin | 用户活跃趋势;注册转化漏斗;实时数据快照 |
| 用户管理 | /admin/users | 用户列表(分页 ≤ 100);账号禁用/启用;会员等级手动调整 |
| 商品管理 | /admin/products | 商品列表;价格调整;库存状态管理;批量操作 |
| 营销活动 | /admin/campaigns | 新建/编辑/下线 H5 活动;二级子域名绑定;实时预览 |
| 审计日志 | /admin/audit-logs | 管理员所有操作记录;时间/操作人/IP 多维筛选;不可删除 |
请求耗时与系统指标采集
监控流程
性能与 SEO 优化指标
Core Web Vitals 指标目标
| 指标 | 目标值 | CI 强制阻断阈值 |
|---|---|---|
| LCP 最大内容绘制 | < 1.5s | ⛔ > 2.0s 强制打回 |
| INP 交互延迟 | < 100ms | ⚠️ > 200ms 警告 |
| CLS 布局偏移 | < 0.05 | ⛔ > 0.1 强制打回 |
| SEO 评分 Lighthouse | 100 分 | ⛔ < 95 分强制打回 |
| 无障碍 a11y | ≥ 95 分 | ⚠️ < 90 分警告 |
Cloudflare 接入方案(可选·免费)
DNS 配置规则
| 类型 | 名称 | 目标(Content) | 代理状态 |
|---|---|---|---|
| CNAME | yourdomain.com | cname.vercel-dns.com | 🟠 已代理 |
| CNAME | www | cname.vercel-dns.com | 🟠 已代理 |
| CNAME | admin | cname.vercel-dns.com | 🟠 已代理 |
| CNAME | api | cname.vercel-dns.com | 🟠 已代理 |
| CNAME | *(泛解析) | cname.vercel-dns.com | 🟠 已代理 |
数据库设计规范(Supabase 团队版)
核心数据表
-- 用户档案表(与 auth.users 关联) CREATE TABLE profiles ( id UUID PRIMARY KEY REFERENCES auth.users(id) ON DELETE CASCADE, username TEXT UNIQUE NOT NULL, role TEXT NOT NULL DEFAULT 'user' CHECK (role IN ('user', 'admin')), plan_status TEXT NOT NULL DEFAULT 'free' CHECK (plan_status IN ('free', 'pro', 'enterprise')), created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() ); -- 营销活动配置表(驱动动态 H5 渲染) CREATE TABLE marketing_campaigns ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), subdomain TEXT UNIQUE NOT NULL, title TEXT NOT NULL, config JSONB NOT NULL DEFAULT '{}', is_active BOOLEAN NOT NULL DEFAULT TRUE, created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() ); -- 必须开启 RLS(CI 门禁自动检查) ALTER TABLE profiles ENABLE ROW LEVEL SECURITY; ALTER TABLE marketing_campaigns ENABLE ROW LEVEL SECURITY; ALTER TABLE activity_logs ENABLE ROW LEVEL SECURITY;
CI/CD 自动化构建与验证门禁(GitHub 团队版)
npx vue-tsc --noEmitcurl /api/admin/users → 必须 401/403npx supabase db lintLighthouse CI Action代码生成规范与自动化校验保障
多 Agent 协作分工
| Agent | 工作范围 | 禁止触碰 |
|---|---|---|
| 前台 Agent (A) | app/pages/(client)/ app/pages/(h5)/ app/components/client/ | admin 组件 · server/ 目录 |
| 后台 UI Agent (B) | app/pages/(admin)/ app/components/admin/ | 官网/H5 样式文件 |
| API Agent (C) | server/api/ server/utils/ supabase/migrations/ | 前端 Vue 组件 |
.cursorrules 核心禁令(节选)
## 目录规范 - 严禁在根目录创建非规范的顶层目录 - 官网/H5 组件必须放在 app/components/client/ 或 shared/ - 管理端组件必须放在 app/components/admin/ 并使用局部导入 ## 安全规范 - 严禁将 SUPABASE_SERVICE_ROLE_KEY 出现在任何前端代码中 - APM 告警阈值必须配置多级梯度,防止误报干扰 ## 平台职责边界规范 - 严禁开通或使用 Vercel Postgres:数据库统一使用 Supabase PG - 严禁将 HTTP API 路由写入 Supabase Edge Functions - 限流计数器必须使用 Vercel KV,不得用 Supabase DB 表模拟 ## 数据库规范 - 严禁在 Node.js 中对 >1000 条数据做内存级 reduce/map 聚合 - 统计类 API 必须命中 Materialized View 或预聚合表 - 所有列表查询必须限制 pageSize ≤ 100 ## 审计规范 - 管理端所有写入/删除操作,必须在返回前调用 writeAuditLog() ## IP 规范 - 必须使用 getClientRealIP(event),禁止使用 getRequestIP()
本地开发沙盒配置
一键启动脚本
{
"scripts": {
"supabase:start": "supabase start",
"apm:monitor": "node scripts/test-supabase-connection.mjs",
"dev": "nuxt dev",
"dev:all": "concurrently \"npm:supabase:start\" \"npm:dev\"",
"gen:types": "supabase gen types typescript --local > app/types/database.types.ts",
"check": "vue-tsc --noEmit && eslint 'app/**/*.vue' 'server/**/*.ts'",
"test:api-safety": "vitest run server/tests/security"
}
}本地多域名仿真(/etc/hosts)
127.0.0.1 yourdomain.localhost 127.0.0.1 www.yourdomain.localhost 127.0.0.1 admin.yourdomain.localhost 127.0.0.1 api.yourdomain.localhost 127.0.0.1 promo-test.yourdomain.localhost # 测试营销 H5 子域名
项目启动检查清单
🏗️ 基础设施
💻 代码工程
🔐 安全与合规
🚀 性能
📋 平台职责确认
平台职责边界决策(Supabase vs Vercel)
6 大重叠能力裁判结果
| 重叠能力 | 选择平台 | 核心决策理由 |
|---|---|---|
| 关系型数据库 | ✅ Supabase PG | RLS 行级安全 + Auth 深度集成 + DB 分支不可替代;Vercel Postgres 不具备这些企业级能力 |
| 文件存储 | ✅ 场景分治 | 用户私密文件 → Supabase Storage(RLS);公开营销素材 → public/ 目录 + Cloudflare CDN |
| HTTP API 路由 | ✅ Vercel Nitro | 所有业务 HTTP API 由 Nuxt 4 Nitro 承接;Supabase Edge Functions 仅用于 DB 触发器增强 |
| KV 缓存(限流) | ✅ Vercel KV | Supabase 无内置 Redis;Vercel KV(Upstash Redis)直接补位 |
| 用户身份鉴权 | ✅ Supabase Auth | Vercel 无原生 Auth;Supabase Auth 提供完整 OAuth/邮箱验证并与 DB/RLS 深度集成 |
| Analytics 监控 | ✅ 两者互补 | Supabase 看后端基础设施(DB 负载);Vercel 看前端体验(Web Vitals);维度不重叠 |
职责边界全景图
🗄️ Supabase 专属领土
▲ Vercel 专属领土
🚫 灰色地带——明确禁止重复使用
AI Coding 三大平台陷阱
→ .cursorrules 约束:公开静态资产走 public/ 目录,用户上传走 Supabase Storage,禁止引入 Vercel Blob。
→ .cursorrules 约束:所有 HTTP API 路由只能在 /server/api/ 下,严禁写 Supabase Edge Function 承接 HTTP 路由。
→ .cursorrules 约束:Service Role Key 只能存放在 Vercel 服务端专用环境变量(非 NUXT_PUBLIC_ 前缀)。
自动化开发辅助与调试技巧 (v1.0 增补)
一、人机协同与类型契约 (Type & Contract)
1. 端到端全自动类型闭环
2. AI 友好自动脚手架生成器
运行本地 scripts/scaffolder.mjs,为 AI 搭建严格符合架构规范的前后端“毛坯房”,规避 AI 因理解大上下文产生的幻觉。
node scripts/scaffolder.mjs billing # [OK] Created API: server/api/v1/billing/index.post.ts # [OK] Created Page: app/pages/(client)/billing.vue
3. UnoCSS × AI 审美护城河
在 unocss.config.ts 中将高质感视觉设计(如 Glassmorphism 玻璃拟态卡片、现代微动效按钮、深色渐变背景)固化为别名 Shortcuts,禁止 AI 任意硬编码颜色,通过 .cursorrules 指引 AI 拼装出 Apple/Stripe 级别的极致现代设计。
// shortcuts 示例 shortcuts: { 'glass-card': 'bg-white/70 backdrop-blur-md border border-white/20 shadow-lg rounded-2xl', 'btn-premium': 'bg-brand-primary hover:bg-brand-primary/90 text-white px-6 py-3 rounded-xl transition-all duration-200 hover:-translate-y-0.5 shadow-md' }
二、离线沙盒与安全栅栏 (Sandbox & Security)
4. 本地零依赖快速沙盒引擎 (Mock Mode)
无需启动庞大笨重的 Supabase Docker 镜像。在 /server/utils/db.ts 中通过 MOCK_DB=true 开启内存/JSON 伪装层。支持高铁、咖啡厅、笔记本低电量等移动办公场景下秒级冷启动,预览流转,精细联调时再切回真实 DB。
export function getDB(event: any) { if (process.env.MOCK_DB === 'true') { return getLocalMockDB() // 返回内存伪装层 } return dbClient // 返回真实 Supabase Client }
5. SQL 注释驱动 RLS 与安全测试环
-- @rls: enable 等元数据声明,本地校验脚本强制 AI 必须同步编写安全策略。rls.test.ts,模拟不同权限的越权请求,100% 阻断 AI 因不理解 RLS policy 而导致的写表越权和漏配漏洞。三、多端融合与全球合规 (Cross-platform & Compliance)
6. Capacitor 移动端融合架构 (多端同源)
在 Nuxt 单仓中直接引入 Capacitor,免去重写 React Native/Flutter 带来的人力耗费。打包 App 路由为 Native 壳,配合 Vercel 静态导出,在合规红线内实现 Bug 修复的秒级热更新。
# 安装 Capacitor 并创建原生壳 npm i @capacitor/core @capacitor/cli @capacitor/ios @capacitor/android npx cap init "MyApp" "com.myapp.app" --web-dir=.output/public npx cap sync
7. 全球合规与安全基线
cookieconsent 声明,仅在用户同意后才初始化第三方分析统计,彻底规避欧盟巨额罚款风险。- 禁止套壳直连:严禁直接加载远程 Vercel URL 作为 App 主内容(违反 Guideline 4.2 最小功能网页套壳禁令)。必须将静态资源构建后使用
npx cap sync打包进 Native 本地包体内。 - 热更新界限:热更新只能用于修复 Bug 和 UI 微调。严禁通过热更新更改 App 核心特征/主要功能(违反 Guideline 2.5.2),更不得绕过审核上架违规功能,否则面临直接下架或封号风险。
- 支付双轨制限制:iOS 原生 App 中严禁使用 Stripe 等第三方支付绕过 App 内购买 (IAP)(违反 Guideline 3.1.1)。针对数字虚拟商品,必须走 Apple IAP 支付,或者做成“Reader App(仅提供登录消费,去掉 App 内购买按钮)”。
四、AI 运维与全球化 (AI Ops & Localization)
8. GitHub Actions AI 自愈 (Self-Healing CI)
当 CI 步骤如 ESLint 或 TypeScript 校验失败时,触发 AI Healer 机器人,自动读取最后一次运行报错日志,调用大模型 API 修复文件并自动 Push 回分支。人类只需专注核心商业逻辑。
# ci-self-heal step 核心逻辑 if: failure() && github.event_name == 'pull_request' run: | node scripts/ai_healer.js git commit -am "style: [AI Auto-Heal] fix issues" && git push
9. LLM 全自动 i18n 提取与语义化翻译
借助 @nuxtjs/i18n,配合扫描脚本自动提取代码中的 $t() Key,使用大模型扮演多语言本地化专家,进行地道、专业的产品语义翻译(如 locales/en.json、locales/ja.json 自动写入),告别生硬机翻。
node scripts/auto-translate.mjs # 1. 扫描 app/ 目录提取未翻译 $t() Key # 2. 调用 LLM 翻译为地道多国语言,自动对齐写入 locales/*.json
10. 零配置 Telemetry 极简监控
| 监控维度 | 选型 | 提效原理解析 |
|---|---|---|
| 异常采集 | Sentry (Nuxt SDK) | Nitro Server 中统一拦截,崩溃错误秒级捕获,无需编写臃肿逻辑。 |
| 全局日志流 | Axiom | 零部署零维护。Vercel 产生的控制台日志自动导流,每月 500GB 免费,配合 SQL 级多维搜索。 |
| 用户行为分析 | Vercel Web Analytics | 开箱即用,隐私合规,无需配置庞大的 Google Analytics 自定义埋点。 |
三方支付系统集成 (Stripe Checkout)
Stripe Checkout 支付流程
Webhook 安全验证
// Stripe Webhook 签名验证(策略层自动从 DB 读取密钥) const strategy = getPaymentStrategy('stripe') const result = await strategy.verifyWebhook(rawBody, signature) // 支持事件类型:checkout.session.completed / charge.refunded
数据库表设计
| 表名 | 核心字段 | 用途 |
|---|---|---|
| orders | order_no, amount, currency, status, payment_intent_id | 订单全生命周期追踪(pending→paid→refunded) |
| activity_logs | category, user_id, action, ip, metadata, created_at | 统一日志(auth/admin/system),JSONB metadata 灵活扩展 |
移动端用户认证体系
认证流程全链路
支持的登录方式对照
| 登录方式 | Provider | 实现机制 | 适用场景 |
|---|---|---|---|
| Email + Password | Supabase signUp / signInWithPassword | 通用注册登录 | |
| Supabase OAuth (signInWithOAuth) | 海外主流用户 | ||
| Supabase OAuth (signInWithOAuth) | 东南亚/拉美用户 | ||
| Apple | apple | Supabase OAuth (signInWithOAuth) | iOS 用户(App Store 审核要求) |
| Anonymous | anonymous | Supabase signInAnonymously + device_id | 先浏览后登录 |
Token 生命周期管理
Access Token (1h)
短期有效 JWT,存储在 sb-access-token Cookie。每次 API 请求由 server middleware 验证。过期后自动用 Refresh Token 续期。
Refresh Token (30d)
长期有效 token,存储在 sb-refresh-token Cookie。Supabase SDK 自动在 access_token 过期前调用 refreshSession()。
Device ID (365d)
设备指纹,存储在 device-id Cookie。用于匿名用户标识和行为数据关联,绑定账号后迁移到 user_id。
匿名→绑定数据迁移策略
数据库表设计
| 表名 | 关键字段 | RLS 策略 |
|---|---|---|
| profiles | avatar_url, display_name, auth_provider, provider_id, device_id, is_anonymous, email_verified | 用户读写自己,admin 全权限 |
handle_new_user() 触发器函数,新用户通过 Supabase Auth 注册时自动在 profiles 表创建记录,无需前端额外处理。