Files
edgeKey/docs/development-guide.md
2026-04-30 15:05:00 +08:00

16 KiB
Raw Permalink Blame History

EdgeKey 项目开发规范指南

本指南为AI助手提供EdgeKey项目开发迭代的标准流程和规范要求确保代码质量和项目一致性。

项目架构概览

技术栈

  • 前端框架: Vue 3 + Vike文件路由 + SSR
  • 服务端: Hono路由与中间件
  • 运行时: Cloudflare Workers
  • 数据库: Cloudflare D1原生SQLite
  • ORM: PrismaCloudflare适配器
  • UI框架: Tailwind CSS + daisyUI
  • 构建工具: Vite + Bun
  • 认证: Auth.js管理员账号密码登录
  • 数据变更: Telefunc前后端同构RPC

核心约束

  1. Cloudflare Workers环境限制:

    • 禁止依赖node:fsnode:path等Node.js原生模块
    • 使用Web Crypto APIcrypto.subtle)处理签名,避免第三方加密库
    • 脚本体积限制免费版3MB引入新依赖必须经过批准
  2. 数据库特殊性:

    • 使用Cloudflare D1SQLite非传统数据库
    • 开发环境使用本地D1模拟器生产环境使用远程D1
    • 禁止使用prisma migrate dev,必须使用特定迁移工作流

开发流程规范

1. 环境准备

# 安装依赖推荐使用Bun
bun install
# 生成Prisma客户端必须
bun run db:generate
# 初始化本地数据库
bun run db:migrations:local
bun run db:seed
# 启动开发服务器
bun run dev

2. 数据库变更流程

重要: 修改数据库表结构时必须遵循以下流程:

步骤1: 修改Schema并生成迁移SQL

# 修改 prisma/schema.prisma 后使用prisma migrate diff生成SQL
bunx prisma migrate diff \
  --from-migrations prisma/migrations \
  --to-schema prisma/schema.prisma \
  --script > prisma/migrations/000X_描述.sql

步骤2: 同步到本地开发环境

bun run db:migrations:local

步骤3: 部署前同步到生产环境

bun run db:migrations:remote

禁止操作:

  • 使用prisma migrate dev
  • 反复覆盖初始化迁移文件0001_init.sql
  • 假设bun dev使用的是prisma/db.sqlite

3. 代码提交与部署

# 构建项目
bun run build
# 本地预览构建结果
bun run preview
# 部署到Cloudflare Workers
bun run deploy
# 或等效命令
bun run up

代码规范

1. 文件组织

  • 页面文件: pages/目录遵循Vike文件路由约定
  • 组件: components/目录,通用组件
  • 业务逻辑: lib/目录
  • 功能模块: modules/目录
  • 服务端: server/目录
  • 数据库: prisma/目录
  • 静态资源: assets/目录

2. 命名规范

  • Vue组件: PascalCaseAppButton.vue
  • TypeScript文件: camelCaseorder-utils.ts
  • 数据库模型: PascalCaseAdminOrder
  • 数据库字段: camelCasecreatedAtpaymentStatus

3. 组件开发规范

  • 使用<script setup>语法
  • Props定义必须包含类型和默认值
  • 事件使用emit函数触发
  • 样式优先使用Tailwind CSS类必要时使用daisyUI组件

4. Telefunc使用规范

  • Telefunc函数放在对应页面目录下.telefunc.ts结尾
  • 函数命名: on[Action](如onCreateOrderonUpdateProduct
  • 返回类型必须明确声明

5. 日志规范

使用项目内置的logger模块:

import { logger } from '@/lib/logger';

// 信息日志
logger.info('操作成功', { userId: 123, action: 'create_order' });
// 警告日志
logger.warn('库存不足', { productId: 456, stock: 2 });
// 错误日志
logger.error('支付失败', error, { orderId: 'ORD001' });
// 创建子日志记录器(带默认上下文)
const orderLogger = logger.child({ module: 'order', service: 'create' });
orderLogger.info('订单创建开始', { orderNo: 'ORD001' });

日志级别使用原则:

  • info: 业务流程关键节点、重要操作记录
  • warn: 可恢复的异常、资源不足、配置问题
  • error: 不可恢复的错误、系统异常

Cloudflare Workers限制:

  • console.debug不会出现在Cloudflare Dashboard中
  • 统一使用infowarnerror三个级别

日志上下文自动注入:

  • 请求上下文requestId、method、path、cfRay自动注入
  • 错误对象自动序列化包含name、message、stack、code、statusCode、details
  • 支持AppError和普通Error的序列化

日志格式示例:

{
  "timestamp": "2024-01-01T00:00:00.000Z",
  "level": "error",
  "requestId": "abc123",
  "method": "POST",
  "path": "/api/orders",
  "cfRay": "xyz789",
  "message": "支付失败",
  "error": {
    "name": "AppError",
    "message": "支付网关返回错误",
    "stack": "...",
    "code": "PAYMENT_GATEWAY_ERROR",
    "statusCode": 400,
    "details": { "provider": "bepusdt", "orderId": "ORD001" }
  },
  "module": "payment",
  "service": "verify"
}

架构设计规范

1. 中间件使用

  • 请求上下文: 通过createRequestContextrunWithRequestContext管理
  • 数据库注入: 通过prismaMiddleware注入Prisma实例
  • 认证: 通过authjsSessionMiddleware处理会话
  • API路由: 独立的Hono子应用优先于页面路由

2. 错误处理

使用项目内置的错误处理机制:

import { AppError, toAppError, badRequestError, notFoundError, conflictError, unauthorizedError } from '@/lib/app-error';

// 使用预定义的错误工厂函数
throw notFoundError('订单不存在', 'ORDER_NOT_FOUND');
throw badRequestError('购买数量不合法', 'ORDER_QUANTITY_INVALID');
throw conflictError('数据已存在,请检查是否重复', 'UNIQUE_CONSTRAINT');
throw unauthorizedError('请先登录管理员账号');

// 或使用通用AppError
throw new AppError('自定义错误消息', {
  code: 'CUSTOM_ERROR',
  statusCode: 400,
  details: { field: 'value' }
});

// 转换未知错误自动处理Prisma错误、Telefunc错误等
try {
  // 业务逻辑
} catch (error) {
  const appError = toAppError(error);
  logger.error('操作失败', appError);
  throw appError;
}

// 断言条件
assertCondition(order != null, notFoundError('订单不存在'));

// 获取错误消息兼容字符串、Error、AppError
const message = getErrorMessage(error, '未知错误');

错误工厂函数:

  • badRequestError(): 400 - 请求参数错误
  • unauthorizedError(): 401 - 未授权
  • forbiddenError(): 403 - 禁止访问
  • notFoundError(): 404 - 资源不存在
  • conflictError(): 409 - 数据冲突
  • rateLimitError(): 429 - 请求过于频繁
  • externalServiceError(): 502 - 外部服务错误
  • internalServerError(): 500 - 服务器内部错误

错误转换规则:

  • Prisma P2002错误 → 冲突错误(唯一约束冲突)
  • Telefunc Abort错误 → 自动提取错误信息
  • "Unauthorized"错误 → 未授权错误
  • 其他错误 → 内部服务器错误

错误响应格式:

// toErrorResponsePayload() 返回标准格式
{
  message: string;  // 用户友好的错误消息expose为false时返回通用消息
  code?: string;    // 错误代码
  statusCode: number; // HTTP状态码
}

3. 实用工具函数

项目提供多个实用工具函数:

import { formatMoney, parseMoney } from '@/lib/utils/money';
import { getOrderStatusLabel, getOrderStatusType } from '@/lib/utils/order-status';
import { formatDate, formatRelativeTime } from '@/lib/utils/time';
import { generateOrderNo, generateQueryToken } from '@/lib/utils/order';
import { hashPassword, verifyPassword } from '@/lib/utils/crypto';
import { detectDeviceType } from '@/lib/utils/device';

// 金额处理(单位:分)
const formatted = formatMoney(1000); // '10.00'
const cents = parseMoney('10.00'); // 1000

// 订单状态标签
const label = getOrderStatusLabel('PAID'); // '已支付'
const type = getOrderStatusType('PAID'); // 'success'

// 时间格式化
const dateStr = formatDate(new Date()); // '2024-01-01'
const relative = formatRelativeTime(new Date()); // '刚刚'

// 订单号生成
const orderNo = generateOrderNo(); // 'ORD20240101001'
const queryToken = generateQueryToken(); // 32位随机字符串

// 密码处理使用bcrypt
const hash = await hashPassword('password123');
const isValid = await verifyPassword('password123', hash);

// 设备检测
const device = detectDeviceType(request); // 'mobile' | 'desktop'

4. 常量和类型定义

项目定义的常量和类型:

// 常量定义
import { PAYMENT_PROVIDERS } from '@/lib/constants/payment';
import { ORDER_QUERY_TOKEN_LENGTH } from '@/lib/constants/order';
import { PRODUCT_STATUS, ORDER_STATUS } from '@/lib/constants/product';

// 类型定义
import type { Order, OrderStatus, PaymentStatus } from '@/lib/types/order';
import type { Product, ProductStatus } from '@/lib/types/product';
import type { SiteSetting } from '@/lib/types/site';
import type { CommonResponse, PaginatedResponse } from '@/lib/types/common';

数据库枚举类型:

  • AdminStatus: ACTIVE, DISABLED
  • CategoryStatus: ACTIVE, DISABLED
  • ProductStatus: DRAFT, ACTIVE, INACTIVE
  • ProductDeliveryType: CARD_AUTO, MANUAL
  • ProductStockMode: FINITE, UNLIMITED
  • CardStatus: UNUSED, LOCKED, SOLD, DISABLED
  • ContactType: EMAIL, QQ, TELEGRAM, OTHER
  • OrderStatus: PENDING, PAID, DELIVERED, CLOSED, FAILED
  • PaymentStatus: UNPAID, PAID, FAILED
  • DeliveryStatus: NOT_DELIVERED, DELIVERED, FAILED
  • EmailChannel: API, SMTP, CLOUDFLARE
  • EmailScene: TEST, ORDER_PAID, DELIVERY_SUCCESS, DELIVERY_FAILED

5. 重要项目文件

以下是开发时需要了解的关键文件:

核心配置文件:

  • package.json: 项目依赖和脚本命令
  • vite.config.ts: Vite构建配置包含Vike、Vue、Tailwind、Telefunc插件
  • wrangler.jsonc: Cloudflare Workers部署配置包含D1数据库绑定
  • prisma/schema.prisma: 数据库模型定义

服务端入口:

  • server/entry.ts: 服务端主入口Hono应用、中间件链
  • server/authjs-handler.ts: Auth.js认证处理器
  • server/prisma-middleware.ts: Prisma D1注入中间件
  • server/telefunc-handler.ts: Telefunc RPC处理器

核心库文件:

  • lib/logger.ts: 日志模块(自动注入请求上下文、错误序列化)
  • lib/app-error.ts: 错误处理模块AppError类、错误工厂函数
  • lib/request-context.ts: 请求上下文管理AsyncLocalStorage

业务模块:

  • modules/payment/: 支付相关(适配器、服务、路由)
  • modules/email/: 邮件相关(模板、发送、日志)
  • modules/order/: 订单管理
  • modules/inventory/: 库存管理

前端页面:

  • pages/: Vike文件路由目录
  • components/: 通用Vue组件
  • assets/: 静态资源

6. Telefunc使用模式

Telefunc提供前后端同构的数据变更RPC

// pages/admin/orders/createOrder.telefunc.ts
import { getContext } from 'telefunc';
import type { PrismaClient } from '../../generated/prisma/client';
import { badRequestError } from '../../lib/app-error';
import { logger } from '../../lib/logger';
import { validateOrderInput } from '../../lib/validators/order';

export async function onCreateOrder(input: {
  productId: number;
  quantity: number;
  contactValue: string;
}) {
  // 获取上下文自动包含Prisma实例
  const { prisma } = getContext() as { prisma: PrismaClient };
  
  // 验证输入
  const validated = validateOrderInput(input);
  
  // 业务逻辑
  const order = await prisma.order.create({
    data: {
      orderNo: generateOrderNo(),
      productId: input.productId,
      quantity: validated.quantity,
      contactValue: validated.contactValue,
      // ... 其他字段
    }
  });
  
  logger.info('订单创建成功', { orderNo: order.orderNo });
  return { orderNo: order.orderNo };
}

Telefunc约定:

  • 函数放在页面目录下,以.telefunc.ts结尾
  • 命名规范: on[Action](如onCreateOrderonUpdateProduct
  • 通过getContext()获取请求上下文包含prisma实例
  • 返回值自动序列化为JSON
  • 错误会自动转换为Telefunc Abort格式

本地开发与生产环境差异:

  • 本地开发: 使用Wrangler D1模拟器
  • 生产环境: 使用Cloudflare远程D1
  • 数据库绑定: env.DB在两个环境中都可用
  • Prisma配置: 运行时使用env.DBCLI使用DATABASE_URL

文档维护

1. 更新README.md

重大功能变更后更新README.md中的功能特性和项目截图。

2. 更新组件文档

新增或修改公共组件时,更新docs/components.md

3. 更新支付网关文档

新增支付网关时,更新docs/payment-gateway-guide.md

代码审查要点

1. 安全性

  • 密码是否使用bcrypt加密
  • API密钥是否硬编码
  • SQL注入防护Prisma自动处理

2. 性能

  • 数据库查询是否优化
  • 是否有N+1查询问题
  • 静态资源是否优化

3. 可维护性

  • 代码是否有适当注释
  • 是否遵循项目架构规范
  • 是否有重复代码

参考资源

  1. 项目文档:

    • README.md: 项目概述和快速开始
    • docs/components.md: 组件使用指南
    • docs/payment-gateway-guide.md: 支付网关开发指南
  2. 官方文档:

  3. 工具文档:

    • Wrangler: Cloudflare CLI
    • Bun: JavaScript运行时和包管理器

重要提醒: 在进行任何修改前,请确保理解项目架构和约束条件。对于不确定的操作,建议先在开发环境测试,确认无误后再部署到生产环境。

快速参考

常用命令

# 开发
bun install                    # 安装依赖
bun run dev                    # 启动开发服务器
bun run build                  # 构建项目
bun run preview                # 预览构建结果

# 数据库
bun run db:generate            # 生成Prisma客户端
bun run db:migrations:local    # 应用迁移到本地D1
bun run db:migrations:remote   # 应用迁移到远程D1
bun run db:seed                # 本地种子数据
bun run db:seed:remote         # 远程种子数据
bun run db:studio              # Prisma Studio

# 部署
bun run deploy                 # 部署到Cloudflare Workers
bun run up                     # 构建并部署
bun run types                  # 生成Wrangler类型

常见模式

// 1. 日志记录
import { logger } from '@/lib/logger';
logger.info('操作成功', { key: 'value' });
logger.error('操作失败', error);

// 2. 错误处理
import { notFoundError, badRequestError } from '@/lib/app-error';
throw notFoundError('资源不存在');

// 3. 输入验证
import { validateOrderInput } from '@/lib/validators/order';
const data = validateOrderInput(input);

// 4. Telefunc函数
import { getContext } from 'telefunc';
const { prisma } = getContext() as { prisma: PrismaClient };

// 5. 数据库查询
const orders = await prisma.order.findMany({
  where: { status: 'PAID' },
  include: { product: true },
  skip: 0,
  take: 20
});

项目结构速查

edgeKey/
├── pages/           # Vike页面路由
├── components/      # Vue组件
├── lib/             # 核心库logger、error、utils
├── modules/         # 业务模块payment、email、order
├── server/          # 服务端Hono、中间件
├── prisma/          # 数据库模型和迁移
├── assets/          # 静态资源
└── docs/            # 文档

关键约束速查

  • 禁止使用node:fsnode:path等Node.js原生模块
  • 禁止使用prisma migrate dev
  • 使用Web Crypto API处理签名
  • 使用项目内置的logger模块
  • 遵循数据库迁移工作流
  • 生产环境必须配置AUTH_SECRET