`count(*)` })
.from(content)
.where(whereConditions.length > 0 ? and(...whereConditions) : undefined),
]);
return NextResponse.json({
success: true,
data: items,
meta: {
total: count,
page: query.page,
pageSize: query.pageSize,
},
});
} catch (error) {
return NextResponse.json(
{ success: false, error: { code: 'INVALID_QUERY', message: error.message } },
{ status: 400 }
);
}
}
export async function POST(request: NextRequest) {
try {
const session = await getServerSession();
if (!session) {
return NextResponse.json(
{ success: false, error: { code: 'UNAUTHORIZED', message: '请先登录' } },
{ status: 401 }
);
}
const body = await request.json();
const newContent = await db.insert(content).values({
...body,
id: crypto.randomUUID(),
authorId: session.user.id,
createdAt: new Date(),
updatedAt: new Date(),
}).returning();
return NextResponse.json({ success: true, data: newContent[0] }, { status: 201 });
} catch (error) {
return NextResponse.json(
{ success: false, error: { code: 'CREATE_FAILED', message: error.message } },
{ status: 500 }
);
}
}
```
---
## 管理后台设计
### 页面结构
```
/admin
├── /login # 登录页
├── /dashboard # 仪表盘
├── /content
│ ├── /news # 新闻管理
│ │ ├── / # 列表页
│ │ ├── /create # 创建页
│ │ └── /[id]/edit # 编辑页
│ ├── /products # 产品管理
│ ├── /services # 服务管理
│ └── /cases # 案例管理
├── /config
│ ├── /features # 功能开关
│ ├── /style # 样式配置
│ ├── /seo # SEO 配置
│ └── /general # 全局设置
├── /users # 用户管理
└── /logs # 操作日志
```
### 布局设计
```
┌─────────────────────────────────────────────────────────┐
│ Logo 首页 内容 配置 用户 日志 用户头像 ▼ │
├──────────┬──────────────────────────────────────────────┤
│ │ │
│ 侧边栏 │ 主内容区 │
│ │ │
│ - 新闻 │ ┌──────────────────────────────────────┐ │
│ - 产品 │ │ 页面标题 [创建] [导出] │ │
│ - 服务 │ ├──────────────────────────────────────┤ │
│ - 案例 │ │ │ │
│ │ │ 数据表格 / 表单 / 图表 │ │
│ 配置 │ │ │ │
│ - 功能 │ │ │ │
│ - 样式 │ │ │ │
│ - SEO │ └──────────────────────────────────────┘ │
│ │ │
└──────────┴──────────────────────────────────────────────┘
```
### 核心组件
#### 1. 内容编辑器
```typescript
// src/components/admin/content-editor.tsx
import { Editor } from '@tiptap/react';
import StarterKit from '@tiptap/starter-kit';
import Image from '@tiptap/extension-image';
import Link from '@tiptap/extension-link';
export function ContentEditor({ value, onChange }: ContentEditorProps) {
const editor = useEditor({
extensions: [StarterKit, Image, Link],
content: value,
onUpdate: ({ editor }) => {
onChange(editor.getHTML());
},
});
return (
);
}
```
#### 2. 配置面板
```typescript
// src/components/admin/config-panel.tsx
export function ConfigPanel({ category }: ConfigPanelProps) {
const { data: configs, isLoading } = useQuery({
queryKey: ['configs', category],
queryFn: () => fetch(`/api/v1/config/category/${category}`).then(r => r.json()),
});
return (
{configs?.map((config) => (
))}
);
}
function ConfigField({ config }: ConfigFieldProps) {
const [value, setValue] = useState(config.value);
const handleSave = async () => {
await fetch(`/api/v1/config/${config.key}`, {
method: 'PUT',
body: JSON.stringify({ value }),
});
};
return (
{typeof value === 'boolean' ? (
) : typeof value === 'number' ? (
setValue(Number(e.target.value))} />
) : (
setValue(e.target.value)} />
)}
);
}
```
#### 3. 数据表格
```typescript
// src/components/admin/data-table.tsx
import { useQuery } from '@tanstack/react-query';
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table';
export function DataTable({ type }: DataTableProps) {
const [page, setPage] = useState(1);
const { data, isLoading } = useQuery({
queryKey: ['content', type, page],
queryFn: () => fetch(`/api/v1/content?type=${type}&page=${page}`).then(r => r.json()),
});
return (
标题
分类
状态
发布时间
操作
{data?.data?.map((item) => (
{item.title}
{item.category}
{item.status}
{formatDate(item.publishedAt)}
))}
);
}
```
---
## 权限体系
### 角色定义
| 角色 | 权限范围 | 说明 |
|-----|---------|------|
| **admin** | 全部权限 | 系统管理员,可管理用户、配置、所有内容 |
| **editor** | 内容管理 | 编辑人员,可创建、编辑、发布内容 |
| **viewer** | 只读权限 | 查看者,只能查看内容和配置 |
### 权限矩阵
```typescript
const PERMISSIONS = {
admin: {
content: ['create', 'read', 'update', 'delete', 'publish'],
config: ['read', 'update'],
users: ['create', 'read', 'update', 'delete'],
logs: ['read'],
},
editor: {
content: ['create', 'read', 'update', 'publish'],
config: ['read'],
users: [],
logs: ['read'],
},
viewer: {
content: ['read'],
config: ['read'],
users: [],
logs: [],
},
} as const;
```
### 权限检查实现
```typescript
// src/lib/auth/permissions.ts
import { getServerSession } from 'next-auth';
export async function checkPermission(
resource: string,
action: string
): Promise {
const session = await getServerSession();
if (!session) return false;
const userRole = session.user.role;
const permissions = PERMISSIONS[userRole];
return permissions[resource]?.includes(action) ?? false;
}
// API Route 中使用
export async function POST(request: NextRequest) {
if (!await checkPermission('content', 'create')) {
return NextResponse.json(
{ success: false, error: { code: 'FORBIDDEN', message: '无权限' } },
{ status: 403 }
);
}
// ... 创建内容逻辑
}
```
---
## 部署策略
### 环境配置
```bash
# .env.local
DATABASE_URL="file:./data.db"
NEXTAUTH_SECRET="your-secret-key"
NEXTAUTH_URL="http://localhost:3000"
# 可选:文件上传
UPLOADTHING_SECRET="your-uploadthing-secret"
UPLOADTHING_APP_ID="your-app-id"
```
### 数据库迁移
```bash
# 生成迁移文件
npm run db:generate
# 执行迁移
npm run db:migrate
# 查看数据库
npm run db:studio
```
### 生产部署
**推荐平台**:Vercel + Vercel KV (可选)
**部署步骤**:
1. 推送代码到 GitHub
2. 在 Vercel 中导入项目
3. 配置环境变量
4. 部署成功
**数据库备份**:
```bash
# SQLite 备份
cp data.db data.db.backup
# 或使用脚本
npm run db:backup
```
---
## 实施计划
### 阶段一:基础架构(2 天)
**目标**:搭建数据库、认证系统、基础 API
**任务清单**:
- [ ] 安装依赖(Drizzle ORM、NextAuth.js、Tiptap)
- [ ] 创建数据库 schema
- [ ] 配置数据库连接
- [ ] 实现认证系统(邮箱密码 + Magic Link)
- [ ] 创建基础 API Routes
- [ ] 编写单元测试
**验收标准**:
- ✅ 数据库表创建成功
- ✅ 用户可以注册、登录
- ✅ API 基础框架可用
---
### 阶段二:内容管理(2 天)
**目标**:实现内容 CRUD 和管理界面
**任务清单**:
- [ ] 实现内容 CRUD API
- [ ] 创建管理后台布局
- [ ] 实现新闻管理界面
- [ ] 实现产品管理界面
- [ ] 实现服务管理界面
- [ ] 集成富文本编辑器
- [ ] 实现图片上传功能
**验收标准**:
- ✅ 可以创建、编辑、删除内容
- ✅ 富文本编辑器正常工作
- ✅ 图片上传成功
---
### 阶段三:配置中心(1 天)
**目标**:实现配置管理和功能开关
**任务清单**:
- [ ] 实现配置 CRUD API
- [ ] 创建功能开关界面
- [ ] 创建样式配置界面
- [ ] 创建 SEO 配置界面
- [ ] 实现配置加载器
- [ ] 前端集成配置
**验收标准**:
- ✅ 可以动态启用/禁用功能
- ✅ 配置实时生效
---
### 阶段四:高级功能(1-2 天)
**目标**:实现版本历史、操作日志、实时预览
**任务清单**:
- [ ] 实现版本历史 API
- [ ] 创建版本对比界面
- [ ] 实现内容回滚
- [ ] 实现操作日志记录
- [ ] 创建日志查询界面
- [ ] 实现实时预览功能
**验收标准**:
- ✅ 可以查看历史版本
- ✅ 可以回滚到指定版本
- ✅ 操作日志完整记录
---
### 阶段五:测试和部署(1 天)
**目标**:完善测试、性能优化、部署上线
**任务清单**:
- [ ] 编写 E2E 测试
- [ ] 性能优化(缓存、懒加载)
- [ ] 安全审计(OWASP Top 10)
- [ ] 编写部署文档
- [ ] 配置 CI/CD
- [ ] 生产环境部署
**验收标准**:
- ✅ 测试覆盖率 ≥ 80%
- ✅ 性能指标达标
- ✅ 安全检查通过
- ✅ 成功部署上线
---
## 测试策略
### 单元测试
**框架**:Vitest + Testing Library
**覆盖范围**:
- 工具函数
- React Hooks
- API 逻辑
- 数据验证
**示例**:
```typescript
// __tests__/lib/config-manager.test.ts
import { describe, it, expect } from 'vitest';
import { ConfigManager } from '@/lib/config-manager';
describe('ConfigManager', () => {
it('should load config from database', async () => {
const config = await ConfigManager.get('feature_news');
expect(config).toBeDefined();
expect(config.enabled).toBe(true);
});
});
```
### 集成测试
**框架**:Vitest + MSW (Mock Service Worker)
**覆盖范围**:
- API Routes
- 数据库操作
- 认证流程
### E2E 测试
**框架**:Playwright(已有)
**覆盖范围**:
- 用户登录流程
- 内容创建流程
- 配置更新流程
**示例**:
```typescript
// e2e/tests/admin/content.spec.ts
import { test, expect } from '@playwright/test';
test('should create news article', async ({ page }) => {
await page.goto('/admin/login');
await page.fill('input[name="email"]', 'admin@example.com');
await page.fill('input[name="password"]', 'password');
await page.click('button[type="submit"]');
await page.goto('/admin/content/news/create');
await page.fill('input[name="title"]', '测试新闻');
await page.fill('textarea[name="excerpt"]', '这是测试新闻摘要');
await page.click('button[type="submit"]');
await expect(page.locator('text=创建成功')).toBeVisible();
});
```
---
## 风险与应对
### 技术风险
| 风险 | 影响 | 概率 | 应对措施 |
|-----|------|------|---------|
| SQLite 性能瓶颈 | 高 | 低 | 监控性能,准备迁移到 PostgreSQL |
| 文件上传安全漏洞 | 高 | 中 | 严格验证文件类型、大小,使用 CDN |
| 认证系统漏洞 | 高 | 低 | 使用成熟的 NextAuth.js,定期更新 |
| 数据库迁移失败 | 中 | 低 | 完善备份策略,测试迁移脚本 |
### 业务风险
| 风险 | 影响 | 概率 | 应对措施 |
|-----|------|------|---------|
| 运营人员不会使用 | 中 | 中 | 编写详细操作手册,提供培训 |
| 内容误删 | 高 | 中 | 实现软删除、版本历史、回收站 |
| 配置错误导致网站异常 | 高 | 低 | 配置验证、预览功能、快速回滚 |
### 项目风险
| 风险 | 影响 | 概率 | 应对措施 |
|-----|------|------|---------|
| 开发周期延误 | 中 | 中 | 采用敏捷开发,优先核心功能 |
| 需求变更 | 中 | 高 | 模块化设计,预留扩展接口 |
| 技术债务累积 | 中 | 中 | 代码审查、持续重构、完善文档 |
---
## 附录
### A. 默认配置数据
```json
{
"feature_news": {
"enabled": true,
"displayCount": 6,
"categories": ["公司新闻", "产品发布", "合作动态", "行业资讯"],
"sortOrder": "desc"
},
"feature_products": {
"enabled": true,
"showPricing": true,
"featuredProducts": ["erp", "crm"]
},
"feature_services": {
"enabled": true,
"items": ["software", "cloud", "data", "security"]
},
"seo_default": {
"title": "四川睿新致远科技有限公司 - 企业数字化转型服务商",
"description": "以智慧连接数字趋势,以伙伴身份陪您成长",
"keywords": ["数字化转型", "软件开发", "云服务", "数据分析"]
}
}
```
### B. 数据库迁移脚本
```typescript
// drizzle/migrations/0001_initial.ts
import { sql } from 'drizzle-orm';
import { drizzle } from 'drizzle-orm/libsql';
export async function up(db: ReturnType) {
await db.run(sql`
CREATE TABLE users (
id TEXT PRIMARY KEY,
email TEXT UNIQUE NOT NULL,
password_hash TEXT,
name TEXT NOT NULL,
role TEXT NOT NULL DEFAULT 'editor',
avatar TEXT,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL
);
`);
// ... 其他表
}
export async function down(db: ReturnType) {
await db.run(sql`DROP TABLE users`);
// ... 删除其他表
}
```
### C. 参考资源
- [Next.js 文档](https://nextjs.org/docs)
- [Drizzle ORM 文档](https://orm.drizzle.team/docs/overview)
- [NextAuth.js 文档](https://next-auth.js.org/)
- [Tiptap 文档](https://tiptap.dev/)
- [shadcn/ui 文档](https://ui.shadcn.com/)
---
**文档版本历史**:
| 版本 | 日期 | 变更说明 | 作者 |
|-----|------|---------|------|
| v1.0 | 2026-03-08 | 初始版本 | 张翔 |
---
**审批记录**:
| 角色 | 姓名 | 日期 | 状态 |
|-----|------|------|------|
| 技术负责人 | 张翔 | 2026-03-08 | ✅ 已批准 |