432 lines
9.0 KiB
Markdown
432 lines
9.0 KiB
Markdown
# 后端功能实施方案
|
||
|
||
## 概述
|
||
|
||
以下功能需要后端服务支持,目前应用是纯前端应用(使用 IndexedDB 本地存储)。要实现这些功能,需要搭建后端服务。
|
||
|
||
---
|
||
|
||
## 1. 多用户系统
|
||
|
||
### 需求分析
|
||
- 支持多个用户注册和登录
|
||
- 每个用户可以创建和管理自己的家族树
|
||
- 用户可以邀请其他用户协作编辑同一个家族树
|
||
|
||
### 技术方案
|
||
|
||
#### 后端技术栈选择
|
||
- **Node.js + Express** 或 **Next.js API Routes**
|
||
- **数据库**: PostgreSQL / MongoDB
|
||
- **认证**: NextAuth.js / Auth0 / Supabase Auth
|
||
|
||
#### 数据模型
|
||
|
||
```typescript
|
||
// 用户表
|
||
interface User {
|
||
id: string
|
||
email: string
|
||
name: string
|
||
avatar?: string
|
||
createdAt: string
|
||
updatedAt: string
|
||
}
|
||
|
||
// 家族树表
|
||
interface FamilyTree {
|
||
id: string
|
||
name: string // 家族名称,如"李氏家族"
|
||
ownerId: string // 创建者
|
||
rootMemberId: string
|
||
createdAt: string
|
||
updatedAt: string
|
||
}
|
||
|
||
// 家族成员表(扩展现有 FamilyMember)
|
||
interface FamilyMember {
|
||
// ... 现有字段
|
||
treeId: string // 所属家族树
|
||
}
|
||
|
||
// 用户-家族树关系表(协作者)
|
||
interface TreeCollaborator {
|
||
id: string
|
||
treeId: string
|
||
userId: string
|
||
role: 'owner' | 'editor' | 'viewer'
|
||
invitedBy: string
|
||
invitedAt: string
|
||
}
|
||
```
|
||
|
||
#### API 端点
|
||
|
||
```typescript
|
||
// 用户认证
|
||
POST /api/auth/register
|
||
POST /api/auth/login
|
||
POST /api/auth/logout
|
||
GET /api/auth/me
|
||
|
||
// 家族树管理
|
||
GET /api/trees // 获取用户的所有家族树
|
||
POST /api/trees // 创建新家族树
|
||
GET /api/trees/:id // 获取家族树详情
|
||
PUT /api/trees/:id // 更新家族树
|
||
DELETE /api/trees/:id // 删除家族树
|
||
|
||
// 协作者管理
|
||
GET /api/trees/:id/collaborators
|
||
POST /api/trees/:id/invite // 邀请协作者
|
||
DELETE /api/trees/:id/collaborators/:userId
|
||
```
|
||
|
||
---
|
||
|
||
## 2. 云端同步
|
||
|
||
### 需求分析
|
||
- 数据自动同步到云端
|
||
- 多设备数据同步
|
||
- 离线编辑,在线时自动同步
|
||
- 冲突检测和解决
|
||
|
||
### 技术方案
|
||
|
||
#### 同步策略
|
||
|
||
**1. 实时同步(推荐)**
|
||
- 使用 WebSocket 或 Server-Sent Events
|
||
- 每次操作立即同步到服务器
|
||
- 其他客户端实时接收更新
|
||
|
||
**2. 定时同步**
|
||
- 每隔一定时间(如 30 秒)同步一次
|
||
- 适合网络不稳定的场景
|
||
|
||
**3. 混合模式**
|
||
- 在线时实时同步
|
||
- 离线时本地存储
|
||
- 重新联网时批量同步
|
||
|
||
#### 数据同步流程
|
||
|
||
```typescript
|
||
// 同步记录表
|
||
interface SyncRecord {
|
||
id: string
|
||
treeId: string
|
||
userId: string
|
||
action: 'create' | 'update' | 'delete'
|
||
entityType: 'member' | 'photo' | 'story'
|
||
entityId: string
|
||
data: any
|
||
timestamp: string
|
||
synced: boolean
|
||
}
|
||
|
||
// 同步 API
|
||
POST /api/sync/push // 推送本地更改
|
||
GET /api/sync/pull // 拉取远程更改
|
||
GET /api/sync/status // 获取同步状态
|
||
```
|
||
|
||
#### 冲突解决策略
|
||
|
||
1. **最后写入优先(Last Write Wins)**
|
||
- 简单但可能丢失数据
|
||
|
||
2. **版本控制**
|
||
- 每条记录有版本号
|
||
- 冲突时提示用户选择
|
||
|
||
3. **操作转换(Operational Transformation)**
|
||
- 复杂但最准确
|
||
- 类似 Google Docs 的协作编辑
|
||
|
||
#### 实现示例(使用 Supabase)
|
||
|
||
```typescript
|
||
// lib/sync.ts
|
||
import { createClient } from '@supabase/supabase-js'
|
||
|
||
const supabase = createClient(
|
||
process.env.NEXT_PUBLIC_SUPABASE_URL!,
|
||
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
|
||
)
|
||
|
||
// 推送本地更改到云端
|
||
export async function pushChanges(changes: SyncRecord[]) {
|
||
const { data, error } = await supabase
|
||
.from('sync_records')
|
||
.insert(changes)
|
||
|
||
if (error) throw error
|
||
return data
|
||
}
|
||
|
||
// 从云端拉取更改
|
||
export async function pullChanges(treeId: string, lastSyncTime: string) {
|
||
const { data, error } = await supabase
|
||
.from('sync_records')
|
||
.select('*')
|
||
.eq('treeId', treeId)
|
||
.gt('timestamp', lastSyncTime)
|
||
.order('timestamp', { ascending: true })
|
||
|
||
if (error) throw error
|
||
return data
|
||
}
|
||
|
||
// 实时订阅更改
|
||
export function subscribeToChanges(treeId: string, callback: (change: any) => void) {
|
||
return supabase
|
||
.channel(`tree:${treeId}`)
|
||
.on('postgres_changes', {
|
||
event: '*',
|
||
schema: 'public',
|
||
table: 'family_members',
|
||
filter: `treeId=eq.${treeId}`
|
||
}, callback)
|
||
.subscribe()
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 3. 权限管理
|
||
|
||
### 需求分析
|
||
- 不同用户有不同的操作权限
|
||
- 支持角色:所有者、编辑者、查看者
|
||
- 细粒度权限控制
|
||
|
||
### 权限模型
|
||
|
||
```typescript
|
||
// 角色定义
|
||
enum Role {
|
||
OWNER = 'owner', // 所有者:完全控制
|
||
EDITOR = 'editor', // 编辑者:可以增删改
|
||
VIEWER = 'viewer' // 查看者:只读
|
||
}
|
||
|
||
// 权限定义
|
||
interface Permission {
|
||
canView: boolean
|
||
canCreate: boolean
|
||
canUpdate: boolean
|
||
canDelete: boolean
|
||
canInvite: boolean
|
||
canExport: boolean
|
||
canManageSettings: boolean
|
||
}
|
||
|
||
// 角色权限映射
|
||
const rolePermissions: Record<Role, Permission> = {
|
||
owner: {
|
||
canView: true,
|
||
canCreate: true,
|
||
canUpdate: true,
|
||
canDelete: true,
|
||
canInvite: true,
|
||
canExport: true,
|
||
canManageSettings: true,
|
||
},
|
||
editor: {
|
||
canView: true,
|
||
canCreate: true,
|
||
canUpdate: true,
|
||
canDelete: false,
|
||
canInvite: false,
|
||
canExport: true,
|
||
canManageSettings: false,
|
||
},
|
||
viewer: {
|
||
canView: true,
|
||
canCreate: false,
|
||
canUpdate: false,
|
||
canDelete: false,
|
||
canInvite: false,
|
||
canExport: true,
|
||
canManageSettings: false,
|
||
},
|
||
}
|
||
```
|
||
|
||
### 权限检查中间件
|
||
|
||
```typescript
|
||
// middleware/auth.ts
|
||
import { NextRequest, NextResponse } from 'next/server'
|
||
|
||
export async function requireAuth(req: NextRequest) {
|
||
const token = req.headers.get('authorization')
|
||
if (!token) {
|
||
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
|
||
}
|
||
|
||
// 验证 token
|
||
const user = await verifyToken(token)
|
||
if (!user) {
|
||
return NextResponse.json({ error: 'Invalid token' }, { status: 401 })
|
||
}
|
||
|
||
return user
|
||
}
|
||
|
||
export async function requirePermission(
|
||
userId: string,
|
||
treeId: string,
|
||
permission: keyof Permission
|
||
) {
|
||
// 获取用户在该家族树的角色
|
||
const collaborator = await db.treeCollaborators.findFirst({
|
||
where: { userId, treeId }
|
||
})
|
||
|
||
if (!collaborator) {
|
||
throw new Error('No access to this tree')
|
||
}
|
||
|
||
const permissions = rolePermissions[collaborator.role]
|
||
if (!permissions[permission]) {
|
||
throw new Error(`Permission denied: ${permission}`)
|
||
}
|
||
|
||
return true
|
||
}
|
||
```
|
||
|
||
### 前端权限控制
|
||
|
||
```typescript
|
||
// hooks/usePermissions.ts
|
||
import { useAuth } from './useAuth'
|
||
import { useFamilyTree } from './useFamilyTree'
|
||
|
||
export function usePermissions() {
|
||
const { user } = useAuth()
|
||
const { currentTree } = useFamilyTree()
|
||
|
||
const [permissions, setPermissions] = useState<Permission>()
|
||
|
||
useEffect(() => {
|
||
if (user && currentTree) {
|
||
fetchPermissions(user.id, currentTree.id).then(setPermissions)
|
||
}
|
||
}, [user, currentTree])
|
||
|
||
return permissions
|
||
}
|
||
|
||
// 使用示例
|
||
function MemberForm() {
|
||
const permissions = usePermissions()
|
||
|
||
if (!permissions?.canCreate) {
|
||
return <div>您没有权限添加成员</div>
|
||
}
|
||
|
||
return <form>...</form>
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 推荐的实施方案
|
||
|
||
### 方案 A:使用 Supabase(最简单)
|
||
|
||
**优点**:
|
||
- 开箱即用的认证、数据库、实时订阅
|
||
- 无需自己搭建后端
|
||
- 免费额度足够个人使用
|
||
- 自动处理权限和 RLS(Row Level Security)
|
||
|
||
**步骤**:
|
||
1. 创建 Supabase 项目
|
||
2. 设计数据库表结构
|
||
3. 配置 RLS 规则
|
||
4. 集成 Supabase 客户端
|
||
5. 迁移现有 IndexedDB 数据
|
||
|
||
### 方案 B:使用 Next.js API Routes + PostgreSQL
|
||
|
||
**优点**:
|
||
- 完全控制后端逻辑
|
||
- 可以部署在 Vercel
|
||
- 适合需要复杂业务逻辑的场景
|
||
|
||
**步骤**:
|
||
1. 添加 API Routes
|
||
2. 配置数据库(Vercel Postgres / Neon)
|
||
3. 实现认证逻辑(NextAuth.js)
|
||
4. 实现同步 API
|
||
5. 添加权限中间件
|
||
|
||
### 方案 C:使用 Firebase
|
||
|
||
**优点**:
|
||
- Google 生态系统
|
||
- 实时数据库
|
||
- 免费额度较大
|
||
|
||
**步骤**:
|
||
1. 创建 Firebase 项目
|
||
2. 配置 Firestore
|
||
3. 设置 Firebase Auth
|
||
4. 配置安全规则
|
||
5. 集成 Firebase SDK
|
||
|
||
---
|
||
|
||
## 估算工作量
|
||
|
||
| 功能 | 使用 Supabase | 自建后端 |
|
||
|------|--------------|----------|
|
||
| 多用户系统 | 2-3 天 | 5-7 天 |
|
||
| 云端同步 | 3-5 天 | 7-10 天 |
|
||
| 权限管理 | 2-3 天 | 5-7 天 |
|
||
| **总计** | **1-2 周** | **3-4 周** |
|
||
|
||
---
|
||
|
||
## 下一步行动
|
||
|
||
1. **选择技术方案**:推荐 Supabase(快速、简单)
|
||
2. **数据迁移计划**:设计从 IndexedDB 到云端的迁移方案
|
||
3. **逐步实施**:
|
||
- 第一阶段:多用户系统
|
||
- 第二阶段:云端同步
|
||
- 第三阶段:权限管理
|
||
|
||
---
|
||
|
||
## 注意事项
|
||
|
||
1. **数据安全**:
|
||
- 使用 HTTPS
|
||
- 加密敏感数据
|
||
- 定期备份
|
||
|
||
2. **性能优化**:
|
||
- 使用缓存
|
||
- 分页加载
|
||
- 图片 CDN
|
||
|
||
3. **用户体验**:
|
||
- 离线优先
|
||
- 乐观更新
|
||
- 友好的错误提示
|
||
|
||
---
|
||
|
||
**建议**:如果您想快速实现这些功能,我推荐使用 Supabase。我可以帮您:
|
||
1. 设计 Supabase 数据库结构
|
||
2. 实现认证和权限
|
||
3. 添加实时同步功能
|
||
|
||
是否需要我开始实施?
|