`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 | ✅ 已批准 |