Files
novalon-website/docs/plans/2026-03-09-production-readiness-plan.md
T
张翔 6d92024b63 feat: 修复测试套件问题并添加Woodpecker CI配置
- 修复API测试认证问题:创建全局认证设置,更新Playwright配置
- 优化回归测试稳定性:增加超时时间到15秒,修复定位器
- 创建Woodpecker CI工作流:CI、部署和质量门禁配置
- 添加Jest配置和测试脚本
- 移除登录页面的默认账号密码显示(安全问题修复)
2026-03-09 10:26:02 +08:00

1214 lines
25 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 生产就绪度修复与迭代计划
> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
**目标:** 补齐生产就绪度和自动化体系,确保网站具备上线条件
**架构:** Next.js 16 + SQLite + Drizzle ORM + NextAuth.js + Playwright + Woodpecker CI + Sentry
**技术栈:** Next.js, React, TypeScript, SQLite, Drizzle ORM, NextAuth.js, Playwright, Woodpecker CI, Sentry, Prometheus
**关键配置:**
- CI/CD: Forgejo + Woodpecker CI
- 监控: Sentry (错误追踪) + Prometheus (性能监控)
- 测试: Playwright + Jest
- 质量门禁: ESLint + Prettier + 测试覆盖率
---
## 前置准备
### 环境要求
- Node.js 18+
- npm
- Git
- Forgejo账号(用于代码托管)
- Woodpecker CI实例(用于CI/CD
- Sentry账号(用于错误监控)
### 相关文档
- 测试评估报告:见知识图谱
- 上线条件评估:见知识图谱
---
## 阶段一:修复测试套件问题(预计 2 天)
### Task 1: 修复API测试认证问题
**文件:**
- 修改: `e2e/src/tests/api/admin.api.spec.ts`
- 创建: `e2e/global-setup.ts`
- 修改: `e2e/playwright.config.ts`
**步骤 1: 创建全局认证设置**
创建文件 `e2e/global-setup.ts`
```typescript
import { chromium, FullConfig } from '@playwright/test';
async function globalSetup(config: FullConfig) {
const browser = await chromium.launch();
const page = await browser.newPage();
// 登录并保存认证状态
await page.goto('http://localhost:3000/admin/login');
await page.fill('#email', 'admin@novalon.cn');
await page.fill('#password', 'admin123456');
await page.click('button[type="submit"]');
// 等待登录成功
await page.waitForURL(/\/admin(?!\/login)/);
// 保存认证状态
await page.context().storageState({ path: 'e2e/.auth/admin.json' });
await browser.close();
}
export default globalSetup;
```
**步骤 2: 更新Playwright配置**
修改 `e2e/playwright.config.ts`
```typescript
export default defineConfig({
globalSetup: require.resolve('./global-setup'),
use: {
storageState: '.auth/admin.json', // 使用保存的认证状态
},
// ... 其他配置
});
```
**步骤 3: 更新API测试**
修改 `e2e/src/tests/api/admin.api.spec.ts`
```typescript
import { test, expect } from '../../fixtures/base.fixture';
test.describe('管理后台API测试', () => {
// 移除 beforeAll 中的手动认证逻辑
// 使用全局设置的认证状态
test.describe('内容管理API', () => {
test('应该能够获取内容列表', async ({ request }) => {
const response = await request.get('/api/admin/content');
expect(response.status()).toBe(200);
const data = await response.json();
expect(data).toHaveProperty('items');
expect(Array.isArray(data.items)).toBe(true);
});
test('应该能够创建新内容', async ({ request }) => {
const response = await request.post('/api/admin/content', {
data: {
type: 'news',
title: '测试新闻',
slug: `test-news-${Date.now()}`,
content: '这是测试内容',
status: 'draft',
},
});
expect([200, 201]).toContain(response.status());
const data = await response.json();
expect(data).toHaveProperty('id');
expect(data.title).toBe('测试新闻');
});
});
});
```
**步骤 4: 运行测试验证**
运行命令:
```bash
cd e2e
npm test -- tests/api/admin.api.spec.ts --project=chromium
```
预期结果:所有API测试通过,无跳过
**步骤 5: 提交更改**
```bash
git add e2e/global-setup.ts e2e/playwright.config.ts e2e/src/tests/api/admin.api.spec.ts
git commit -m "fix: 修复API测试认证问题,使用全局认证状态"
```
---
### Task 2: 优化回归测试稳定性
**文件:**
- 修改: `e2e/src/tests/regression/admin.regression.spec.ts`
**步骤 1: 增加超时时间**
修改 `e2e/src/tests/regression/admin.regression.spec.ts`
```typescript
test.beforeEach(async ({ page }) => {
loginPage = new AdminLoginPage(page);
contentPage = new AdminContentPage(page);
await loginPage.goto();
await loginPage.login('admin@novalon.cn', 'admin123456');
try {
// 增加超时时间到15秒
await page.waitForURL(/\/admin/, { timeout: 15000 });
} catch (error) {
console.error('登录超时,跳过测试:', error);
test.skip();
}
});
```
**步骤 2: 修复列表页面定位器**
修改 `e2e/src/pages/AdminPage.ts`
```typescript
export class AdminContentPage extends BasePage {
readonly createButton: Locator;
readonly contentList: Locator;
readonly searchInput: Locator;
readonly typeFilter: Locator;
constructor(page: Page) {
super(page);
this.createButton = page.getByRole('button', { name: /创建|新建|create/i });
// 使用更精确的定位器
this.contentList = page.locator('table tbody tr').or(page.locator('[data-testid="content-item"]'));
this.searchInput = page.locator('input[type="search"], input[placeholder*="搜索"]');
this.typeFilter = page.locator('select[name="type"], select[data-testid="type-filter"]');
}
}
```
**步骤 3: 运行测试验证**
运行命令:
```bash
cd e2e
npm test -- tests/regression/admin.regression.spec.ts --project=chromium
```
预期结果:回归测试通过率提升到90%+
**步骤 4: 提交更改**
```bash
git add e2e/src/tests/regression/admin.regression.spec.ts e2e/src/pages/AdminPage.ts
git commit -m "fix: 优化回归测试稳定性,增加超时时间,修复定位器"
```
---
## 阶段二:搭建CI/CD流水线(预计 3 天)
### Task 3: 创建Woodpecker CI工作流
**文件:**
- 创建: `.woodpecker/ci.yml`
- 创建: `.woodpecker/deploy.yml`
**步骤 1: 创建CI工作流**
创建文件 `.woodpecker/ci.yml`
```yaml
when:
branch: [main, develop]
event: [push, pull_request]
steps:
lint:
image: node:18-alpine
commands:
- npm ci
- npm run lint
- npm run type-check
test:
image: node:18-alpine
commands:
- npm ci
- npm run db:push
- npm run test:unit
- npx playwright install --with-deps
- npm run test:e2e
build:
image: node:18-alpine
commands:
- npm ci
- npm run build
when:
status: [success]
```
**步骤 2: 创建部署工作流**
创建文件 `.woodpecker/deploy.yml`
```yaml
when:
branch: [main]
event: [push]
steps:
deploy:
image: node:18-alpine
commands:
- npm ci
- npm run build
- echo "Deploying to production..."
secrets: [deploy_key]
```
**步骤 3: 更新package.json脚本**
修改 `package.json`
```json
{
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint",
"type-check": "tsc --noEmit",
"test:unit": "jest",
"test:e2e": "cd e2e && npm test",
"db:push": "drizzle-kit push:sqlite",
"db:migrate": "drizzle-kit generate:sqlite && drizzle-kit migrate"
}
}
```
**步骤 4: 提交更改**
```bash
git add .woodpecker/ package.json
git commit -m "feat: 添加Woodpecker CI流水线配置"
```
---
### Task 4: 配置质量门禁
**文件:**
- 创建: `.github/workflows/quality-gate.yml`
- 创建: `jest.config.js`
- 修改: `package.json`
**步骤 1: 创建Jest配置**
创建文件 `jest.config.js`
```javascript
module.exports = {
testEnvironment: 'node',
collectCoverage: true,
coverageThreshold: {
global: {
branches: 70,
functions: 70,
lines: 70,
statements: 70
}
},
testMatch: ['**/__tests__/**/*.test.ts', '**/*.test.ts'],
moduleFileExtensions: ['ts', 'js', 'json'],
transform: {
'^.+\\.ts$': 'ts-jest'
}
};
```
**步骤 2: 创建质量门禁工作流**
创建文件 `.woodpecker/quality-gate.yml`
```yaml
when:
event: [pull_request]
branch: [main, develop]
steps:
quality-check:
image: node:18-alpine
commands:
- npm ci
- npm run lint
- npm run type-check
- npm run test:unit -- --coverage
- |
COVERAGE=$(cat coverage/coverage-summary.json | grep -o '"lines":{"pct":[0-9.]*' | grep -o '[0-9.]*$')
if [ $(echo "$COVERAGE < 70" | bc -l) -eq 1 ]; then
echo "Coverage $COVERAGE% is below threshold 70%"
exit 1
fi
```
**步骤 3: 提交更改**
```bash
git add .woodpecker/quality-gate.yml jest.config.js package.json
git commit -m "feat: 添加质量门禁配置"
```
---
## 阶段三:建立监控告警体系(预计 3 天)
### Task 5: 集成Sentry错误监控
**文件:**
- 修改: `package.json`
- 创建: `src/lib/sentry.ts`
- 修改: `src/app/layout.tsx`
**步骤 1: 安装Sentry依赖**
运行命令:
```bash
npm install @sentry/nextjs
```
**步骤 2: 创建Sentry配置**
创建文件 `src/lib/sentry.ts`
```typescript
import * as Sentry from '@sentry/nextjs';
export function initSentry() {
if (process.env.NODE_ENV === 'production') {
Sentry.init({
dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
environment: process.env.NODE_ENV,
tracesSampleRate: 0.1,
replaysSessionSampleRate: 0.1,
replaysOnErrorSampleRate: 1.0,
});
}
}
```
**步骤 3: 在应用中初始化Sentry**
修改 `src/app/layout.tsx`
```typescript
import { initSentry } from '@/lib/sentry';
// 在文件顶部初始化
initSentry();
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="zh-CN">
<body>{children}</body>
</html>
);
}
```
**步骤 4: 创建Sentry配置文件**
创建文件 `sentry.client.config.ts`
```typescript
import * as Sentry from '@sentry/nextjs';
Sentry.init({
dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
environment: process.env.NODE_ENV,
tracesSampleRate: 0.1,
});
```
创建文件 `sentry.server.config.ts`
```typescript
import * as Sentry from '@sentry/nextjs';
Sentry.init({
dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
environment: process.env.NODE_ENV,
tracesSampleRate: 0.1,
});
```
**步骤 5: 更新环境变量**
修改 `.env.example`
```bash
# Sentry
NEXT_PUBLIC_SENTRY_DSN=https://xxx@xxx.ingest.sentry.io/xxx
```
**步骤 6: 提交更改**
```bash
git add src/lib/sentry.ts src/app/layout.tsx sentry.client.config.ts sentry.server.config.ts .env.example package.json
git commit -m "feat: 集成Sentry错误监控"
```
---
### Task 6: 配置性能监控
**文件:**
- 创建: `src/lib/monitoring.ts`
- 创建: `src/app/api/health/route.ts`
**步骤 1: 创建监控工具**
创建文件 `src/lib/monitoring.ts`
```typescript
export class PerformanceMonitor {
private static instance: PerformanceMonitor;
private metrics: Map<string, number[]> = new Map();
static getInstance(): PerformanceMonitor {
if (!PerformanceMonitor.instance) {
PerformanceMonitor.instance = new PerformanceMonitor();
}
return PerformanceMonitor.instance;
}
recordMetric(name: string, value: number) {
if (!this.metrics.has(name)) {
this.metrics.set(name, []);
}
this.metrics.get(name)!.push(value);
}
getAverage(name: string): number {
const values = this.metrics.get(name) || [];
if (values.length === 0) return 0;
return values.reduce((a, b) => a + b, 0) / values.length;
}
getPercentile(name: string, percentile: number): number {
const values = this.metrics.get(name) || [];
if (values.length === 0) return 0;
const sorted = [...values].sort((a, b) => a - b);
const index = Math.ceil((percentile / 100) * sorted.length) - 1;
return sorted[index];
}
}
export const monitor = PerformanceMonitor.getInstance();
```
**步骤 2: 创建健康检查API**
创建文件 `src/app/api/health/route.ts`
```typescript
import { NextResponse } from 'next/server';
import { monitor } from '@/lib/monitoring';
export async function GET() {
const health = {
status: 'ok',
timestamp: new Date().toISOString(),
uptime: process.uptime(),
memory: process.memoryUsage(),
metrics: {
avgResponseTime: monitor.getAverage('response_time'),
p95ResponseTime: monitor.getPercentile('response_time', 95),
}
};
return NextResponse.json(health);
}
```
**步骤 3: 提交更改**
```bash
git add src/lib/monitoring.ts src/app/api/health/route.ts
git commit -m "feat: 添加性能监控和健康检查API"
```
---
## 阶段四:配置生产环境(预计 2 天)
### Task 7: 创建生产环境配置
**文件:**
- 创建: `.env.production.example`
- 创建: `docker-compose.prod.yml`
- 创建: `Dockerfile`
**步骤 1: 创建生产环境变量模板**
创建文件 `.env.production.example`
```bash
# Database
DATABASE_URL=file:./data/prod.db
# NextAuth
NEXTAUTH_URL=https://novalon.cn
NEXTAUTH_SECRET=your-production-secret-here
# Admin User
ADMIN_EMAIL=admin@novalon.cn
ADMIN_PASSWORD=your-secure-password
# Sentry
NEXT_PUBLIC_SENTRY_DSN=https://xxx@xxx.ingest.sentry.io/xxx
# Email (Resend)
RESEND_API_KEY=re_icMNpBzS_DL9GirDmhG5PbNU6PLRWvUtY
# File Upload
UPLOAD_DIR=./uploads
MAX_FILE_SIZE=10485760
```
**步骤 2: 创建Docker配置**
创建文件 `Dockerfile`
```dockerfile
FROM node:18-alpine AS base
# Install dependencies only when needed
FROM base AS deps
RUN apk add --no-cache libc6-compat
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
# Rebuild the source code only when needed
FROM base AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npm run build
# Production image, copy all the files and run next
FROM base AS runner
WORKDIR /app
ENV NODE_ENV production
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs
COPY --from=builder /app/public ./public
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
USER nextjs
EXPOSE 3000
ENV PORT 3000
ENV HOSTNAME "0.0.0.0"
CMD ["node", "server.js"]
```
**步骤 3: 创建Docker Compose配置**
创建文件 `docker-compose.prod.yml`
```yaml
version: '3.8'
services:
app:
build:
context: .
dockerfile: Dockerfile
ports:
- "3000:3000"
environment:
- NODE_ENV=production
env_file:
- .env.production
volumes:
- ./data:/app/data
- ./uploads:/app/uploads
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/api/health"]
interval: 30s
timeout: 10s
retries: 3
```
**步骤 4: 提交更改**
```bash
git add .env.production.example docker-compose.prod.yml Dockerfile
git commit -m "feat: 添加生产环境配置"
```
---
### Task 8: 创建备份脚本
**文件:**
- 创建: `scripts/backup.sh`
- 创建: `scripts/restore.sh`
**步骤 1: 创建备份脚本**
创建文件 `scripts/backup.sh`
```bash
#!/bin/bash
# 备份脚本
BACKUP_DIR="./backups"
DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_NAME="backup_$DATE"
# 创建备份目录
mkdir -p $BACKUP_DIR/$BACKUP_NAME
# 备份数据库
echo "Backing up database..."
cp ./data/prod.db $BACKUP_DIR/$BACKUP_NAME/database.db
# 备份上传文件
echo "Backing up uploads..."
cp -r ./uploads $BACKUP_DIR/$BACKUP_NAME/uploads
# 备份配置
echo "Backing up config..."
cp .env.production $BACKUP_DIR/$BACKUP_NAME/.env.production
# 压缩备份
echo "Compressing backup..."
tar -czf $BACKUP_DIR/$BACKUP_NAME.tar.gz -C $BACKUP_DIR $BACKUP_NAME
# 删除临时目录
rm -rf $BACKUP_DIR/$BACKUP_NAME
# 保留最近7天的备份
find $BACKUP_DIR -name "backup_*.tar.gz" -mtime +7 -delete
echo "Backup completed: $BACKUP_DIR/$BACKUP_NAME.tar.gz"
```
**步骤 2: 创建恢复脚本**
创建文件 `scripts/restore.sh`
```bash
#!/bin/bash
# 恢复脚本
if [ -z "$1" ]; then
echo "Usage: ./restore.sh <backup_file.tar.gz>"
exit 1
fi
BACKUP_FILE=$1
if [ ! -f $BACKUP_FILE ]; then
echo "Backup file not found: $BACKUP_FILE"
exit 1
fi
# 解压备份
echo "Extracting backup..."
tar -xzf $BACKUP_FILE -C ./temp_restore
# 恢复数据库
echo "Restoring database..."
cp ./temp_restore/backup_*/database.db ./data/prod.db
# 恢复上传文件
echo "Restoring uploads..."
cp -r ./temp_restore/backup_*/uploads ./uploads
# 清理临时文件
rm -rf ./temp_restore
echo "Restore completed"
```
**步骤 3: 设置定时备份**
创建文件 `scripts/cron-backup.sh`
```bash
#!/bin/bash
# 添加到crontab: 0 2 * * * /path/to/scripts/cron-backup.sh
cd /path/to/novalon-website
./scripts/backup.sh >> ./logs/backup.log 2>&1
```
**步骤 4: 提交更改**
```bash
git add scripts/
git commit -m "feat: 添加备份和恢复脚本"
```
---
## 阶段五:性能和安全测试(预计 2 天)
### Task 9: 创建性能测试脚本
**文件:**
- 创建: `tests/performance/load-test.js`
- 创建: `tests/performance/stress-test.js`
**步骤 1: 安装性能测试工具**
运行命令:
```bash
npm install -D k6
```
**步骤 2: 创建负载测试**
创建文件 `tests/performance/load-test.js`
```javascript
import http from 'k6/http';
import { check, sleep } from 'k6';
export let options = {
stages: [
{ duration: '2m', target: 100 }, // 2分钟内增加到100用户
{ duration: '5m', target: 100 }, // 保持100用户5分钟
{ duration: '2m', target: 0 }, // 2分钟内降到0用户
],
thresholds: {
http_req_duration: ['p(95)<500'], // 95%的请求响应时间小于500ms
http_req_failed: ['rate<0.01'], // 错误率小于1%
},
};
export default function () {
let res = http.get('http://localhost:3000/');
check(res, { 'status was 200': (r) => r.status == 200 });
sleep(1);
}
```
**步骤 3: 创建压力测试**
创建文件 `tests/performance/stress-test.js`
```javascript
import http from 'k6/http';
import { check } from 'k6';
export let options = {
stages: [
{ duration: '2m', target: 200 },
{ duration: '5m', target: 200 },
{ duration: '2m', target: 400 },
{ duration: '5m', target: 400 },
{ duration: '2m', target: 600 },
{ duration: '5m', target: 600 },
{ duration: '2m', target: 0 },
],
thresholds: {
http_req_duration: ['p(95)<2000'],
http_req_failed: ['rate<0.05'],
},
};
export default function () {
let res = http.get('http://localhost:3000/');
check(res, { 'status was 200': (r) => r.status == 200 });
}
```
**步骤 4: 提交更改**
```bash
git add tests/performance/
git commit -m "feat: 添加性能测试脚本"
```
---
### Task 10: 创建安全测试脚本
**文件:**
- 创建: `tests/security/sql-injection-test.ts`
- 创建: `tests/security/xss-test.ts`
**步骤 1: 创建SQL注入测试**
创建文件 `tests/security/sql-injection-test.ts`
```typescript
import { test, expect } from '@playwright/test';
test.describe('SQL注入防护测试', () => {
const sqlInjectionPayloads = [
"' OR '1'='1",
"'; DROP TABLE users; --",
"' UNION SELECT * FROM users --",
"1' OR '1' = '1",
];
test('登录页面应该防护SQL注入', async ({ page }) => {
await page.goto('/admin/login');
for (const payload of sqlInjectionPayloads) {
await page.fill('#email', payload);
await page.fill('#password', payload);
await page.click('button[type="submit"]');
// 应该显示错误信息,而不是成功登录
await expect(page.locator('.text-red-700')).toBeVisible();
// 不应该跳转到管理页面
expect(page.url()).toContain('/admin/login');
}
});
test('搜索功能应该防护SQL注入', async ({ page }) => {
await page.goto('/');
for (const payload of sqlInjectionPayloads) {
const searchInput = page.locator('input[type="search"]');
if (await searchInput.isVisible()) {
await searchInput.fill(payload);
await page.keyboard.press('Enter');
// 应该显示正常结果或错误信息,而不是崩溃
await page.waitForLoadState('networkidle');
expect(page.url()).not.toContain('error');
}
}
});
});
```
**步骤 2: 创建XSS测试**
创建文件 `tests/security/xss-test.ts`
```typescript
import { test, expect } from '@playwright/test';
test.describe('XSS防护测试', () => {
const xssPayloads = [
'<script>alert("XSS")</script>',
'<img src=x onerror=alert("XSS")>',
'javascript:alert("XSS")',
'<svg onload=alert("XSS")>',
];
test('表单应该防护XSS攻击', async ({ page }) => {
await page.goto('/contact');
for (const payload of xssPayloads) {
await page.fill('#name', payload);
await page.fill('#email', 'test@example.com');
await page.fill('#subject', 'Test Subject');
await page.fill('#message', 'Test Message');
await page.click('button[type="submit"]');
// 应该显示成功或错误信息,而不是执行脚本
await page.waitForLoadState('networkidle');
// 检查是否有alert弹窗(不应该有)
page.on('dialog', async dialog => {
expect(dialog.type()).not.toBe('alert');
});
}
});
});
```
**步骤 3: 提交更改**
```bash
git add tests/security/
git commit -m "feat: 添加安全测试脚本"
```
---
## 阶段六:文档和培训(预计 1 天)
### Task 11: 更新部署文档
**文件:**
- 修改: `README.md`
- 创建: `docs/deployment-guide.md`
- 创建: `docs/monitoring-guide.md`
**步骤 1: 更新README**
修改 `README.md`,添加以下内容:
```markdown
## 生产部署
### 环境要求
- Node.js 18+
- Docker & Docker Compose
- 域名和SSL证书
### 部署步骤
1. 克隆代码
\`\`\`bash
git clone https://github.com/your-org/novalon-website.git
cd novalon-website
\`\`\`
2. 配置环境变量
\`\`\`bash
cp .env.production.example .env.production
# 编辑 .env.production,填入实际配置
\`\`\`
3. 启动服务
\`\`\`bash
docker-compose -f docker-compose.prod.yml up -d
\`\`\`
4. 初始化数据库
\`\`\`bash
npm run db:push
\`\`\`
5. 访问应用
打开浏览器访问 https://novalon.cn
### 监控和告警
- 错误监控: Sentry Dashboard
- 性能监控: /api/health
- 日志查看: docker logs novalon-website-app-1
### 备份和恢复
- 自动备份: 每天凌晨2点自动备份
- 手动备份: ./scripts/backup.sh
- 恢复数据: ./scripts/restore.sh <backup_file>
### 故障排查
详见: docs/troubleshooting.md
```
**步骤 2: 创建部署指南**
创建文件 `docs/deployment-guide.md`
```markdown
# 部署指南
## 1. 环境准备
### 1.1 服务器要求
- CPU: 2核+
- 内存: 4GB+
- 磁盘: 20GB+
- 操作系统: Ubuntu 20.04+
### 1.2 软件要求
- Docker 20.10+
- Docker Compose 2.0+
- Node.js 18+ (用于本地构建)
## 2. 部署流程
### 2.1 首次部署
...
### 2.2 更新部署
...
### 2.3 回滚操作
...
## 3. 域名和SSL配置
### 3.1 域名解析
...
### 3.2 SSL证书配置
...
## 4. 监控配置
### 4.1 Sentry配置
...
### 4.2 日志收集
...
```
**步骤 3: 创建监控指南**
创建文件 `docs/monitoring-guide.md`
```markdown
# 监控指南
## 1. 监控指标
### 1.1 应用健康
- 健康检查: /api/health
- 响应时间: < 500ms (P95)
- 错误率: < 1%
### 1.2 系统资源
- CPU使用率: < 70%
- 内存使用率: < 80%
- 磁盘使用率: < 80%
## 2. 告警规则
### 2.1 严重告警
- 应用宕机
- 数据库连接失败
- 错误率 > 5%
### 2.2 警告告警
- 响应时间 > 1s
- CPU使用率 > 80%
- 内存使用率 > 85%
## 3. 日志查看
### 3.1 Docker日志
\`\`\`bash
docker logs novalon-website-app-1 -f
\`\`\`
### 3.2 应用日志
\`\`\`bash
tail -f logs/app.log
\`\`\`
```
**步骤 4: 提交更改**
```bash
git add README.md docs/
git commit -m "docs: 更新部署和监控文档"
```
---
## 验收标准
### 阶段一验收标准
- ✅ API测试全部通过,无跳过
- ✅ 回归测试通过率 > 90%
- ✅ 测试覆盖率 > 70%
### 阶段二验收标准
- ✅ CI流水线正常运行
- ✅ 代码提交自动触发测试
- ✅ 质量门禁生效
### 阶段三验收标准
- ✅ Sentry正常收集错误
- ✅ 健康检查API正常工作
- ✅ 性能指标可监控
### 阶段四验收标准
- ✅ 生产环境配置完整
- ✅ 备份脚本可正常执行
- ✅ 恢复脚本可正常执行
### 阶段五验收标准
- ✅ 负载测试通过
- ✅ 压力测试通过
- ✅ 安全测试通过
### 阶段六验收标准
- ✅ 文档完整清晰
- ✅ 团队成员了解部署流程
- ✅ 团队成员了解监控方式
---
## 时间估算
| 阶段 | 任务数 | 预计时间 | 累计时间 |
|------|--------|---------|---------|
| 阶段一 | 2 | 2天 | 2天 |
| 阶段二 | 2 | 3天 | 5天 |
| 阶段三 | 2 | 3天 | 8天 |
| 阶段四 | 2 | 2天 | 10天 |
| 阶段五 | 2 | 2天 | 12天 |
| 阶段六 | 1 | 1天 | 13天 |
**总计:13个工作日(约2-3周)**
---
## 风险和依赖
### 风险
1. **Sentry配置问题** - 需要提前注册账号并获取DSN
2. **Docker部署问题** - 需要运维团队支持
3. **性能测试环境** - 需要独立的测试环境
### 依赖
1. **运维团队支持** - 服务器配置、域名解析、SSL证书
2. **Sentry账号** - 错误监控服务
3. **Forgejo + Woodpecker CI** - 代码托管和CI/CD服务
---
## 执行建议
1. **优先级执行**:按照阶段顺序执行,优先完成P0任务
2. **并行执行**:阶段二和阶段三可以并行进行
3. **持续验证**:每个阶段完成后进行验收测试
4. **文档同步**:实施过程中及时更新文档
---
## 后续优化
完成本计划后,可以考虑以下优化:
1. **自动化测试增强**:增加更多边界情况测试
2. **性能优化**:数据库查询优化、缓存策略优化
3. **安全加固**:定期安全审计、渗透测试
4. **监控完善**:增加业务指标监控、用户行为分析
5. **灾备方案**:多地域部署、故障自动转移