backend-dev-guidelines
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseBackend Development Guidelines
后端开发指南
Purpose
目的
Establish consistency and best practices across Langfuse's backend packages (web, worker, packages/shared) using Next.js 14, tRPC, BullMQ, and TypeScript patterns.
使用Next.js 14、tRPC、BullMQ和TypeScript模式,在Langfuse的后端包(web、worker、packages/shared)中建立一致性和最佳实践。
When to Use This Skill
何时使用本指南
Automatically activates when working on:
- Creating or modifying tRPC routers and procedures
- Creating or modifying public API endpoints (REST)
- Creating or modifying BullMQ queue consumers and producers
- Building services with business logic
- Authenticating API requests
- Accessing resources based on entitlements
- Implementing middleware (tRPC, NextAuth, public API)
- Database operations with Prisma (PostgreSQL) or ClickHouse
- Observability with OpenTelemetry, DataDog, logger, and traceException
- Input validation with Zod v4
- Environment configuration from env variables
- Backend testing and refactoring
在进行以下工作时自动遵循本指南:
- 创建或修改tRPC路由和流程
- 创建或修改公共API端点(REST)
- 创建或修改BullMQ队列消费者和生产者
- 构建包含业务逻辑的服务
- API请求认证
- 基于权限访问资源
- 实现中间件(tRPC、NextAuth、公共API)
- 使用Prisma(PostgreSQL)或ClickHouse进行数据库操作
- 使用OpenTelemetry、DataDog、日志工具和traceException实现可观测性
- 使用Zod v4进行输入验证
- 基于环境变量配置环境
- 后端测试和重构
Quick Start
快速开始
UI: New tRPC Feature Checklist (Web)
UI:新增tRPC功能检查清单(Web)
- Router: Define in
features/[feature]/server/*Router.ts - Procedures: Use appropriate procedure type (protected, public)
- Authentication: Use JWT authorization via middlewares.
- Entitlement check: Access resources based on resource and role
- Validation: Zod v4 schema for input
- Service: Business logic in service file
- Error handling: Use traceException wrapper
- Tests: Unit + integration tests in
__tests__/ - Config: Access via env.mjs
- 路由:在中定义
features/[feature]/server/*Router.ts - 流程:使用合适的流程类型(受保护、公开)
- 认证:通过中间件使用JWT授权
- 权限检查:基于资源和角色访问资源
- 验证:使用Zod v4 schema进行输入验证
- 服务:业务逻辑编写在服务文件中
- 错误处理:使用traceException包装器
- 测试:在中编写单元测试和集成测试
__tests__/ - 配置:通过env.mjs访问配置
SDKs: New Public API Endpoint Checklist (Web)
SDK:新增公共API端点检查清单(Web)
- Route file: Create in
pages/api/public/ - Wrapper: Use +
withMiddlewarescreateAuthedProjectAPIRoute - Types: Define in
features/public-api/types/ - Authentication: Authorization via basic auth
- Validation: Zod schemas for query/body/response
- Versioning: Versioning in API path and Zod schemas for query/body/response
- Fern API Docs: Update to match TypeScript types
fern/apis/server/definition/ - Tests: Add end-to-end test in
__tests__/async/
- 路由文件:在中创建
pages/api/public/ - 包装器:使用+
withMiddlewarescreateAuthedProjectAPIRoute - 类型:在中定义
features/public-api/types/ - 认证:通过基础认证进行授权
- 验证:为查询/请求体/响应使用Zod schema
- 版本控制:在API路径和Zod schema中进行版本控制
- Fern API文档:更新以匹配TypeScript类型
fern/apis/server/definition/ - 测试:在中添加端到端测试
__tests__/async/
New Queue Processor Checklist (Worker)
新增队列处理器检查清单(Worker)
- Processor: Create in
worker/src/queues/ - Queue types: Create queue types in
packages/shared/src/server/queues - Service: Business logic in or
features/worker/src/features/ - Error handling: Distinguish between errors which should fail queue processing and errors which should result in a succeeded event.
- Queue registration: Add to WorkerManager in app.ts
- Tests: Add vitest tests in worker
- 处理器:在中创建
worker/src/queues/ - 队列类型:在中创建队列类型
packages/shared/src/server/queues - 服务:业务逻辑编写在或
features/中worker/src/features/ - 错误处理:区分应导致队列处理失败的错误和应标记为成功事件的错误
- 队列注册:在app.ts中添加到WorkerManager
- 测试:在worker中添加vitest测试
Architecture Overview
架构概述
Layered Architecture
分层架构
undefinedundefinedWeb Package (Next.js 14)
Web Package (Next.js 14)
┌─ tRPC API ──────────────────┐ ┌── Public REST API ──────────┐
│ │ │ │
│ HTTP Request │ │ HTTP Request │
│ ↓ │ │ ↓ │
│ tRPC Procedure │ │ withMiddlewares + │
│ (protectedProjectProcedure)│ │ createAuthedProjectAPIRoute│
│ ↓ │ │ ↓ │
│ Service (business logic) │ │ Service (business logic) │
│ ↓ │ │ ↓ │
│ Prisma / ClickHouse │ │ Prisma / ClickHouse │
│ │ │ │
└─────────────────────────────┘ └─────────────────────────────┘
↓
[optional]: Publish to Redis BullMQ queue
↓
┌─ Worker Package (Express) ──────────────────────────────────┐
│ │
│ BullMQ Queue Job │
│ ↓ │
│ Queue Processor (handles job) │
│ ↓ │
│ Service (business logic) │
│ ↓ │
│ Prisma / ClickHouse │
│ │
└─────────────────────────────────────────────────────────────┘
**Key Principles:**
- **Web**: tRPC procedures for UI OR public API routes for SDKs → Services → Database
- **Worker**: Queue processors → Services → Database
- **packages/shared**: Shared code for Web and Worker
See [architecture-overview.md](architecture-overview.md) for complete details.
---┌─ tRPC API ──────────────────┐ ┌── Public REST API ──────────┐
│ │ │ │
│ HTTP Request │ │ HTTP Request │
│ ↓ │ │ ↓ │
│ tRPC Procedure │ │ withMiddlewares + │
│ (protectedProjectProcedure)│ │ createAuthedProjectAPIRoute│
│ ↓ │ │ ↓ │
│ Service (business logic) │ │ Service (business logic) │
│ ↓ │ │ ↓ │
│ Prisma / ClickHouse │ │ Prisma / ClickHouse │
│ │ │ │
└─────────────────────────────┘ └─────────────────────────────┘
↓
[optional]: Publish to Redis BullMQ queue
↓
┌─ Worker Package (Express) ──────────────────────────────────┐
│ │
│ BullMQ Queue Job │
│ ↓ │
│ Queue Processor (handles job) │
│ ↓ │
│ Service (business logic) │
│ ↓ │
│ Prisma / ClickHouse │
│ │
└─────────────────────────────────────────────────────────────┘
**核心原则:**
- **Web**:UI使用tRPC流程,SDK使用公共API路由 → 服务 → 数据库
- **Worker**:队列处理器 → 服务 → 数据库
- **packages/shared**:Web和Worker共用的代码
完整细节请查看[architecture-overview.md](architecture-overview.md)。
---Directory Structure
目录结构
Web Package (/web/
)
/web/Web包(/web/
)
/web/web/src/
├── features/ # Feature-organized code
│ ├── [feature-name]/
│ │ ├── server/ # Backend logic
│ │ │ ├── *Router.ts # tRPC router
│ │ │ └── service.ts # Business logic
│ │ ├── components/ # React components
│ │ └── types/ # Feature types
├── server/
│ ├── api/
│ │ ├── routers/ # tRPC routers
│ │ ├── trpc.ts # tRPC setup & middleware
│ │ └── root.ts # Main router
│ ├── auth.ts # NextAuth.js config
│ └── db.ts # Database client
├── pages/
│ ├── api/
│ │ ├── public/ # Public REST APIs
│ │ └── trpc/ # tRPC endpoint
│ └── [routes].tsx # Next.js pages
├── __tests__/ # Jest tests
│ └── async/ # Integration tests
├── instrumentation.ts # OpenTelemetry (FIRST IMPORT)
└── env.mjs # Environment configweb/src/
├── features/ # 按功能组织的代码
│ ├── [feature-name]/
│ │ ├── server/ # 后端逻辑
│ │ │ ├── *Router.ts # tRPC路由
│ │ │ └── service.ts # 业务逻辑
│ │ ├── components/ # React组件
│ │ └── types/ # 功能类型定义
├── server/
│ ├── api/
│ │ ├── routers/ # tRPC路由集合
│ │ ├── trpc.ts # tRPC配置与中间件
│ │ └── root.ts # 主路由
│ ├── auth.ts # NextAuth.js配置
│ └── db.ts # 数据库客户端
├── pages/
│ ├── api/
│ │ ├── public/ # 公共REST API
│ │ └── trpc/ # tRPC端点
│ └── [routes].tsx # Next.js页面
├── __tests__/ # Jest测试
│ └── async/ # 集成测试
├── instrumentation.ts # OpenTelemetry(必须第一个导入)
└── env.mjs # 环境配置Worker Package (/worker/
)
/worker/Worker包(/worker/
)
/worker/worker/src/
├── queues/ # BullMQ processors
│ ├── evalQueue.ts
│ ├── ingestionQueue.ts
│ └── workerManager.ts
├── features/ # Business logic
│ └── [feature]/
│ └── service.ts
├── instrumentation.ts # OpenTelemetry (FIRST IMPORT)
├── app.ts # Express setup + queue registration
├── env.ts # Environment config
└── index.ts # Server startworker/src/
├── queues/ # BullMQ处理器
│ ├── evalQueue.ts
│ ├── ingestionQueue.ts
│ └── workerManager.ts
├── features/ # 业务逻辑
│ └── [feature]/
│ └── service.ts
├── instrumentation.ts # OpenTelemetry(必须第一个导入)
├── app.ts # Express配置 + 队列注册
├── env.ts # 环境配置
└── index.ts # 服务启动入口Shared Package (/packages/shared/
)
/packages/shared/共享包(/packages/shared/
)
/packages/shared/shared/src/
├── server/ # Server utilities
│ ├── auth/ # Authentication helpers
│ ├── clickhouse/ # ClickHouse client & schema
│ ├── instrumentation/ # OpenTelemetry helpers
│ ├── llm/ # LLM integration utilities
│ ├── redis/ # Redis queues & cache
│ ├── repositories/ # Data repositories
│ ├── services/ # Shared services
│ ├── utils/ # Server utilities
│ ├── logger.ts
│ └── queues.ts
├── encryption/ # Encryption utilities
├── features/ # Feature-specific code
├── tableDefinitions/ # Table schemas
├── utils/ # Shared utilities
├── constants.ts
├── db.ts # Prisma client
├── env.ts # Environment config
└── index.ts # Main exportsImport Paths (package.json exports):
The shared package exposes specific import paths for different use cases:
| Import Path | Maps To | Use For |
|---|---|---|
| | General types, schemas, utilities, constants |
| | Prisma client and database types |
| | Server-side utilities (queues, auth, services, instrumentation) |
| | API key management utilities |
| | Encryption and signature utilities |
Usage Examples:
typescript
// General imports - types, schemas, constants, interfaces
import {
CloudConfigSchema,
StringNoHTML,
AnnotationQueueObjectType,
type APIScoreV2,
type ColumnDefinition,
Role,
} from "@langfuse/shared";
// Database - Prisma client and types
import { prisma, Prisma, JobExecutionStatus } from "@langfuse/shared/src/db";
import { type DB as Database } from "@langfuse/shared";
// Server utilities - queues, services, auth, instrumentation
import {
logger,
instrumentAsync,
traceException,
redis,
getTracesTable,
StorageService,
sendMembershipInvitationEmail,
invalidateApiKeysForProject,
recordIncrement,
recordHistogram,
} from "@langfuse/shared/src/server";
// API key management (specific path)
import { createAndAddApiKeysToDb } from "@langfuse/shared/src/server/auth/apiKeys";
// Encryption utilities
import { encrypt, decrypt, sign, verify } from "@langfuse/shared/encryption";What Goes Where:
The shared package provides types, utilities, and server code used by both web and worker packages. It has 5 export paths that control frontend vs backend access:
| Import Path | Usage | What's Included |
|---|---|---|
| ✅ Frontend + Backend | Prisma types, Zod schemas, constants, table definitions, domain models, utilities |
| 🔒 Backend only | Prisma client instance |
| 🔒 Backend only | Services, repositories, queues, auth, ClickHouse, LLM integration, instrumentation |
| 🔒 Backend only | API key management (separated to avoid circular deps) |
| 🔒 Backend only | Database field encryption/decryption |
Naming Conventions:
- tRPC Routers: -
camelCaseRouter.tsdatasetRouter.ts - Services: in feature directory
service.ts - Queue Processors: -
camelCaseQueue.tsevalQueue.ts - Public APIs: -
kebab-case.tsdataset-items.ts
shared/src/
├── server/ # 服务端工具
│ ├── auth/ # 认证助手
│ ├── clickhouse/ # ClickHouse客户端与schema
│ ├── instrumentation/ # OpenTelemetry助手
│ ├── llm/ # LLM集成工具
│ ├── redis/ # Redis队列与缓存
│ ├── repositories/ # 数据仓库
│ ├── services/ # 共享服务
│ ├── utils/ # 服务端工具
│ ├── logger.ts
│ └── queues.ts
├── encryption/ # 加密工具
├── features/ # 功能特定代码
├── tableDefinitions/ # 表结构定义
├── utils/ # 共享工具
├── constants.ts
├── db.ts # Prisma客户端
├── env.ts # 环境配置
└── index.ts # 主导出文件导入路径(package.json exports):
共享包为不同使用场景暴露了特定的导入路径:
| 导入路径 | 对应路径 | 用途 |
|---|---|---|
| | 通用类型、schema、工具、常量 |
| | Prisma客户端和数据库类型 |
| | 服务端工具(队列、认证、服务、埋点) |
| | API密钥管理工具 |
| | 加密与签名工具 |
使用示例:
typescript
// 通用导入 - 类型、schema、常量、接口
import {
CloudConfigSchema,
StringNoHTML,
AnnotationQueueObjectType,
type APIScoreV2,
type ColumnDefinition,
Role,
} from "@langfuse/shared";
// 数据库 - Prisma客户端和类型
import { prisma, Prisma, JobExecutionStatus } from "@langfuse/shared/src/db";
import { type DB as Database } from "@langfuse/shared";
// 服务端工具 - 队列、服务、认证、埋点
import {
logger,
instrumentAsync,
traceException,
redis,
getTracesTable,
StorageService,
sendMembershipInvitationEmail,
invalidateApiKeysForProject,
recordIncrement,
recordHistogram,
} from "@langfuse/shared/src/server";
// API密钥管理(特定路径)
import { createAndAddApiKeysToDb } from "@langfuse/shared/src/server/auth/apiKeys";
// 加密工具
import { encrypt, decrypt, sign, verify } from "@langfuse/shared/encryption";代码存放规则:
共享包提供Web和Worker包共用的类型、工具和服务端代码。它有5个导出路径,用于控制前端和后端的访问权限:
| 导入路径 | 适用场景 | 包含内容 |
|---|---|---|
| ✅ 前端 + 后端 | Prisma类型、Zod schema、常量、表结构定义、领域模型、工具 |
| 🔒 仅后端 | Prisma客户端实例 |
| 🔒 仅后端 | 服务、数据仓库、队列、认证、ClickHouse、LLM集成、埋点 |
| 🔒 仅后端 | API密钥管理(分离以避免循环依赖) |
| 🔒 仅后端 | 数据库字段加密/解密 |
命名规范:
- tRPC路由:-
小驼峰Router.tsdatasetRouter.ts - 服务:功能目录下的
service.ts - 队列处理器:-
小驼峰Queue.tsevalQueue.ts - 公共API:-
短横线分隔.tsdataset-items.ts
Core Principles
核心原则
1. tRPC Procedures Delegate to Services
1. tRPC流程委托给服务
typescript
// ❌ NEVER: Business logic in procedures
export const traceRouter = createTRPCRouter({
byId: protectedProjectProcedure
.input(z.object({ traceId: z.string() }))
.query(async ({ input, ctx }) => {
// 200 lines of logic here
}),
});
// ✅ ALWAYS: Delegate to service
export const traceRouter = createTRPCRouter({
byId: protectedProjectProcedure
.input(z.object({ traceId: z.string() }))
.query(async ({ input, ctx }) => {
return await getTraceById(input.traceId);
}),
});typescript
// ❌ 错误示例:业务逻辑写在流程中
export const traceRouter = createTRPCRouter({
byId: protectedProjectProcedure
.input(z.object({ traceId: z.string() }))
.query(async ({ input, ctx }) => {
// 200行逻辑写在这里
}),
});
// ✅ 正确示例:委托给服务
export const traceRouter = createTRPCRouter({
byId: protectedProjectProcedure
.input(z.object({ traceId: z.string() }))
.query(async ({ input, ctx }) => {
return await getTraceById(input.traceId);
}),
});2. Access Config via env.mjs, NEVER process.env
2. 通过env.mjs访问配置,禁止直接使用process.env
typescript
// ❌ NEVER (except in env.mjs itself)
const dbUrl = process.env.DATABASE_URL;
// ✅ ALWAYS
import { env } from "@/src/env.mjs";
const dbUrl = env.DATABASE_URL;typescript
// ❌ 错误示例(除了env.mjs本身)
const dbUrl = process.env.DATABASE_URL;
// ✅ 正确示例
import { env } from "@/src/env.mjs";
const dbUrl = env.DATABASE_URL;3. Validate ALL Input with Zod v4
3. 使用Zod v4验证所有输入
typescript
import { z } from "zod/v4";
const schema = z.object({
email: z.string().email(),
projectId: z.string(),
});
const validated = schema.parse(input);typescript
import { z } from "zod/v4";
const schema = z.object({
email: z.string().email(),
projectId: z.string(),
});
const validated = schema.parse(input);4. Services Use Prisma Directly for Simple CRUD or Repositories for Complex Queries
4. 简单CRUD操作直接使用Prisma,复杂查询使用数据仓库
typescript
// Services use Prisma directly for simple CRUD
import { prisma } from "@langfuse/shared/src/db";
const dataset = await prisma.dataset.findUnique({
where: { id: datasetId, projectId }, // Always filter by projectId for tenant isolation
});
// Or use repositories for complex queries (traces, observations, scores)
import { getTracesTable } from "@langfuse/shared/src/server";
const traces = await getTracesTable({
projectId,
filter: [...],
limit: 1000,
});typescript
// 简单CRUD操作直接使用Prisma
import { prisma } from "@langfuse/shared/src/db";
const dataset = await prisma.dataset.findUnique({
where: { id: datasetId, projectId }, // 必须通过projectId实现租户隔离
});
// 复杂查询(追踪、观测、评分)使用数据仓库
import { getTracesTable } from "@langfuse/shared/src/server";
const traces = await getTracesTable({
projectId,
filter: [...],
limit: 1000,
});6. Observability: OpenTelemetry + DataDog (Not Sentry for Backend)
6. 可观测性:OpenTelemetry + DataDog(后端不使用Sentry)
Langfuse uses OpenTelemetry for backend observability, with traces and logs sent to DataDog.
typescript
// Import observability utilities
import {
logger, // Winston logger with OpenTelemetry/DataDog context
traceException, // Record exceptions to OpenTelemetry spans
instrumentAsync, // Create instrumented spans
} from "@langfuse/shared/src/server";
// Structured logging (includes trace_id, span_id, dd.trace_id)
logger.info("Processing dataset", { datasetId, projectId });
logger.error("Failed to create dataset", { error: err.message });
// Record exceptions to OpenTelemetry (sent to DataDog)
try {
await operation();
} catch (error) {
traceException(error); // Records to current span
throw error;
}
// Instrument critical operations (all API routes auto-instrumented)
const result = await instrumentAsync(
{ name: "dataset.create" },
async (span) => {
span.setAttributes({ datasetId, projectId });
// Operation here
return dataset;
},
);Note: Frontend uses Sentry, but backend (tRPC, API routes, services, worker) uses OpenTelemetry + DataDog.
Langfuse使用OpenTelemetry实现后端可观测性,追踪和日志发送到DataDog。
typescript
// 导入可观测性工具
import {
logger, // 带有OpenTelemetry/DataDog上下文的Winston日志工具
traceException, // 记录异常到OpenTelemetry span
instrumentAsync, // 创建埋点span
} from "@langfuse/shared/src/server";
// 结构化日志(包含trace_id、span_id、dd.trace_id)
logger.info("Processing dataset", { datasetId, projectId });
logger.error("Failed to create dataset", { error: err.message });
// 记录异常到OpenTelemetry(发送到DataDog)
try {
await operation();
} catch (error) {
traceException(error); // 记录到当前span
throw error;
}
// 为关键操作添加埋点(所有API路由自动埋点)
const result = await instrumentAsync(
{ name: "dataset.create" },
async (span) => {
span.setAttributes({ datasetId, projectId });
// 业务操作
return dataset;
},
);注意:前端使用Sentry,但后端(tRPC、API路由、服务、worker)使用OpenTelemetry + DataDog。
7. Comprehensive Testing Required
7. 必须进行全面测试
Write tests for all new features and bug fixes. See testing-guide.md for detailed examples.
Test Types:
| Type | Framework | Location | Purpose |
|---|---|---|---|
| Integration | Jest | | Full API endpoint testing |
| tRPC | Jest | | tRPC procedures with auth |
| Service | Jest | | Repository/service functions |
| Worker | Vitest | | Queue processors & streams |
Quick Examples:
typescript
// Integration Test (Public API)
const res = await makeZodVerifiedAPICall(
PostDatasetsV1Response, "POST", "/api/public/datasets",
{ name: "test-dataset" }, auth
);
expect(res.status).toBe(200);
// tRPC Test
const { caller } = await prepare(); // Creates session + caller
const response = await caller.automations.getAutomations({ projectId });
expect(response).toHaveLength(1);
// Service Test
const result = await getObservationsWithModelDataFromEventsTable({
projectId, filter: [...], limit: 1000, offset: 0
});
expect(result.length).toBeGreaterThan(0);
// Worker Test (vitest)
const stream = await getObservationStream({ projectId, filter: [] });
const rows = [];
for await (const chunk of stream) rows.push(chunk);
expect(rows).toHaveLength(2);Key Principles:
- Use unique IDs () to avoid test interference
randomUUID() - Clean up test data or use unique project IDs
- Tests must be independent and runnable in any order
- Never use in tests
pruneDatabase
为所有新功能和bug修复编写测试。详细示例请查看testing-guide.md。
测试类型:
| 类型 | 框架 | 位置 | 目的 |
|---|---|---|---|
| 集成测试 | Jest | | 完整API端点测试 |
| tRPC测试 | Jest | | 带认证的tRPC流程测试 |
| 服务测试 | Jest | | 数据仓库/服务函数测试 |
| Worker测试 | Vitest | | 队列处理器与流测试 |
快速示例:
typescript
// 集成测试(公共API)
const res = await makeZodVerifiedAPICall(
PostDatasetsV1Response, "POST", "/api/public/datasets",
{ name: "test-dataset" }, auth
);
expect(res.status).toBe(200);
// tRPC测试
const { caller } = await prepare(); // 创建会话和调用者
const response = await caller.automations.getAutomations({ projectId });
expect(response).toHaveLength(1);
// 服务测试
const result = await getObservationsWithModelDataFromEventsTable({
projectId, filter: [...], limit: 1000, offset: 0
});
expect(result.length).toBeGreaterThan(0);
// Worker测试(vitest)
const stream = await getObservationStream({ projectId, filter: [] });
const rows = [];
for await (const chunk of stream) rows.push(chunk);
expect(rows).toHaveLength(2);核心原则:
- 使用唯一ID()避免测试干扰
randomUUID() - 清理测试数据或使用唯一项目ID
- 测试必须独立,可按任意顺序运行
- 测试中禁止使用
pruneDatabase
8. Always Filter by projectId for Tenant Isolation
8. 始终通过projectId过滤实现租户隔离
typescript
// ✅ CORRECT: Filter by projectId for tenant isolation
const trace = await prisma.trace.findUnique({
where: { id: traceId, projectId }, // Required for multi-tenant data isolation
});
// ✅ CORRECT: ClickHouse queries also require projectId
const traces = await queryClickhouse({
query: `
SELECT * FROM traces
WHERE project_id = {projectId: String}
AND timestamp >= {startTime: DateTime64(3)}
`,
params: { projectId, startTime },
});typescript
// ✅ 正确示例:通过projectId过滤实现租户隔离
const trace = await prisma.trace.findUnique({
where: { id: traceId, projectId }, // 多租户数据隔离必须设置
});
// ✅ 正确示例:ClickHouse查询也需要projectId
const traces = await queryClickhouse({
query: `
SELECT * FROM traces
WHERE project_id = {projectId: String}
AND timestamp >= {startTime: DateTime64(3)}
`,
params: { projectId, startTime },
});9. Keep Fern API Definitions in Sync with TypeScript Types
9. 保持Fern API定义与TypeScript类型同步
When modifying public API types in , the corresponding Fern API definitions in must be updated to match.
web/src/features/public-api/types/fern/apis/server/definition/Zod to Fern Type Mapping:
| Zod Type | Fern Type | Example |
|---|---|---|
| | |
| | |
| | |
| Always present | | |
Source References:
Add a comment at the top of each Fern type referencing the TypeScript source file:
yaml
undefined修改中的公共API类型时,必须同步更新中对应的Fern API定义。
web/src/features/public-api/types/fern/apis/server/definition/Zod到Fern类型映射:
| Zod类型 | Fern类型 | 示例 |
|---|---|---|
| | |
| | |
| | |
| 必填 | | |
来源引用:
在每个Fern类型顶部添加注释,引用对应的TypeScript源文件:
yaml
undefinedSource: web/src/features/public-api/types/traces.ts - APITrace
Source: web/src/features/public-api/types/traces.ts - APITrace
Trace:
properties:
id: string
name:
type: nullable<string>
---Trace:
properties:
id: string
name:
type: nullable<string>
---Common Imports
常用导入
typescript
// tRPC (Web)
import { z } from "zod/v4";
import {
createTRPCRouter,
protectedProjectProcedure,
} from "@/src/server/api/trpc";
import { TRPCError } from "@trpc/server";
// Database
import { prisma } from "@langfuse/shared/src/db";
import type { Prisma } from "@prisma/client";
// ClickHouse
import {
queryClickhouse,
queryClickhouseStream,
upsertClickhouse,
} from "@langfuse/shared/src/server";
// Observability - OpenTelemetry + DataDog (NOT Sentry for backend)
import {
logger, // Winston logger with OTEL/DataDog trace context
traceException, // Record exceptions to OpenTelemetry spans
instrumentAsync, // Create instrumented spans for operations
} from "@langfuse/shared/src/server";
// Config
import { env } from "@/src/env.mjs"; // web
// or
import { env } from "./env"; // worker
// Public API (Web)
import { withMiddlewares } from "@/src/features/public-api/server/withMiddlewares";
import { createAuthedProjectAPIRoute } from "@/src/features/public-api/server/createAuthedProjectAPIRoute";
// Queue Processing (Worker)
import { Job } from "bullmq";
import { QueueName, TQueueJobTypes } from "@langfuse/shared/src/server";typescript
// tRPC(Web)
import { z } from "zod/v4";
import {
createTRPCRouter,
protectedProjectProcedure,
} from "@/src/server/api/trpc";
import { TRPCError } from "@trpc/server";
// 数据库
import { prisma } from "@langfuse/shared/src/db";
import type { Prisma } from "@prisma/client";
// ClickHouse
import {
queryClickhouse,
queryClickhouseStream,
upsertClickhouse,
} from "@langfuse/shared/src/server";
// 可观测性 - OpenTelemetry + DataDog(后端不使用Sentry)
import {
logger, // 带有OTEL/DataDog追踪上下文的Winston日志工具
traceException, // 记录异常到OpenTelemetry span
instrumentAsync, // 为操作创建埋点span
} from "@langfuse/shared/src/server";
// 配置
import { env } from "@/src/env.mjs"; // Web端
// 或
import { env } from "./env"; // Worker端
// 公共API(Web)
import { withMiddlewares } from "@/src/features/public-api/server/withMiddlewares";
import { createAuthedProjectAPIRoute } from "@/src/features/public-api/server/createAuthedProjectAPIRoute";
// 队列处理(Worker)
import { Job } from "bullmq";
import { QueueName, TQueueJobTypes } from "@langfuse/shared/src/server";Quick Reference
快速参考
HTTP Status Codes
HTTP状态码
| Code | Use Case |
|---|---|
| 200 | Success |
| 201 | Created |
| 400 | Bad Request |
| 401 | Unauthorized |
| 403 | Forbidden |
| 404 | Not Found |
| 500 | Server Error |
| 状态码 | 使用场景 |
|---|---|
| 200 | 成功 |
| 201 | 创建完成 |
| 400 | 错误请求 |
| 401 | 未授权 |
| 403 | 禁止访问 |
| 404 | 资源不存在 |
| 500 | 服务器错误 |
Example Features to Reference
参考示例功能
Reference existing Langfuse features for implementation patterns:
- Datasets () - Complete feature with tRPC router, public API, and service
web/src/features/datasets/ - Prompts () - Feature with versioning and templates
web/src/features/prompts/ - Evaluations () - Complex feature with worker integration
web/src/features/evals/ - Public API () - Middleware and route patterns
web/src/features/public-api/
参考Langfuse现有功能的实现模式:
- Datasets()- 包含tRPC路由、公共API和服务的完整功能
web/src/features/datasets/ - Prompts()- 带有版本控制和模板的功能
web/src/features/prompts/ - Evaluations()- 集成Worker的复杂功能
web/src/features/evals/ - Public API()- 中间件和路由模式
web/src/features/public-api/
Anti-Patterns to Avoid
需避免的反模式
❌ Business logic in routes/procedures
❌ Direct process.env usage (always use env.mjs/env.ts)
❌ Missing error handling
❌ No input validation (always use Zod v4)
❌ Missing projectId filter on tenant-scoped queries
❌ console.log instead of logger/traceException (OpenTelemetry)
❌ 业务逻辑写在路由/流程中
❌ 直接使用process.env(始终使用env.mjs/env.ts)
❌ 缺少错误处理
❌ 未进行输入验证(始终使用Zod v4)
❌ 租户范围查询未添加projectId过滤
❌ 使用console.log替代logger/traceException(OpenTelemetry)
Navigation Guide
导航指南
| Need to... | Read this |
|---|---|
| Understand architecture | architecture-overview.md |
| Create routes/controllers | routing-and-controllers.md |
| Organize business logic | services-and-repositories.md |
| Create middleware | middleware-guide.md |
| Database access | database-patterns.md |
| Manage config | configuration.md |
| Write tests | testing-guide.md |
| 需要... | 查看文档 |
|---|---|
| 理解架构 | architecture-overview.md |
| 创建路由/控制器 | routing-and-controllers.md |
| 组织业务逻辑 | services-and-repositories.md |
| 创建中间件 | middleware-guide.md |
| 数据库访问 | database-patterns.md |
| 管理配置 | configuration.md |
| 编写测试 | testing-guide.md |
Resource Files
资源文件
architecture-overview.md
architecture-overview.md
Three-layer architecture (tRPC/Public API → Services → Data Access), request lifecycle for tRPC/Public API/Worker, Next.js 14 directory structure, dual database system (PostgreSQL + ClickHouse), separation of concerns, repository pattern for complex queries
三层架构(tRPC/公共API → 服务 → 数据访问)、tRPC/公共API/Worker的请求生命周期、Next.js 14目录结构、双数据库系统(PostgreSQL + ClickHouse)、关注点分离、复杂查询的数据仓库模式
routing-and-controllers.md
routing-and-controllers.md
Next.js file-based routing, tRPC router patterns, Public REST API routes, layered architecture (Entry Points → Services → Repositories → Database), service layer organization, anti-patterns to avoid
Next.js文件路由、tRPC路由模式、公共REST API路由、分层架构(入口 → 服务 → 数据仓库 → 数据库)、服务层组织、需避免的反模式
services-and-repositories.md
services-and-repositories.md
Service layer overview, dependency injection patterns, singleton patterns, repository pattern for data access, service design principles, caching strategies, testing services
服务层概述、依赖注入模式、单例模式、数据访问的数据仓库模式、服务设计原则、缓存策略、服务测试
middleware-guide.md
middleware-guide.md
tRPC middleware (withErrorHandling, withOtelInstrumentation, enforceUserIsAuthed), seven tRPC procedure types (publicProcedure, authenticatedProcedure, protectedProjectProcedure, etc.), Public API middleware (withMiddlewares, createAuthedProjectAPIRoute), authentication patterns (NextAuth for tRPC, Basic Auth for Public API)
tRPC中间件(withErrorHandling、withOtelInstrumentation、enforceUserIsAuthed)、七种tRPC流程类型(publicProcedure、authenticatedProcedure、protectedProjectProcedure等)、公共API中间件(withMiddlewares、createAuthedProjectAPIRoute)、认证模式(tRPC使用NextAuth,公共API使用基础认证)
database-patterns.md
database-patterns.md
Dual database architecture (PostgreSQL via Prisma + ClickHouse via direct client), PostgreSQL CRUD operations, ClickHouse query patterns (queryClickhouse, queryClickhouseStream, upsertClickhouse), repository pattern for complex queries, tenant isolation with projectId filtering, when to use which database
双数据库架构(PostgreSQL通过Prisma + ClickHouse通过直接客户端)、PostgreSQL CRUD操作、ClickHouse查询模式(queryClickhouse、queryClickhouseStream、upsertClickhouse)、复杂查询的数据仓库模式、通过projectId过滤实现租户隔离、数据库选择策略
configuration.md
configuration.md
Environment variable validation with Zod, package-specific configs (web/env.mjs with t3-oss/env-nextjs, worker/env.ts, shared/env.ts), NEXT_PUBLIC_LANGFUSE_CLOUD_REGION usage, LANGFUSE_EE_LICENSE_KEY for enterprise features, best practices for env management
使用Zod验证环境变量、包特定配置(web/env.mjs使用t3-oss/env-nextjs,worker/env.ts,shared/env.ts)、NEXT_PUBLIC_LANGFUSE_CLOUD_REGION用法、企业版功能的LANGFUSE_EE_LICENSE_KEY、环境变量管理最佳实践
testing-guide.md
testing-guide.md
Integration tests (Public API with makeZodVerifiedAPICall), tRPC tests (createInnerTRPCContext, appRouter.createCaller), service-level tests (repository/service functions), worker tests (vitest with streams), test isolation principles, running tests (Jest for web, vitest for worker)
集成测试(公共API使用makeZodVerifiedAPICall)、tRPC测试(createInnerTRPCContext、appRouter.createCaller)、服务层测试(数据仓库/服务函数)、Worker测试(vitest处理流)、测试隔离原则、运行测试(Web端使用Jest,Worker端使用vitest)
Related Skills
相关技能
- database-verification - Verify column names and schema consistency
- skill-developer - Meta-skill for creating and managing skills
Skill Status: COMPLETE ✅
Line Count: ~540 lines
Progressive Disclosure: 7 resource files ✅
- database-verification - 验证列名和schema一致性
- skill-developer - 创建和管理技能的元技能
技能状态:已完成 ✅
行数:约540行
渐进式披露:7个资源文件 ✅