一键导入
implement-api
Implements backend APIs using Bun, Hono, Drizzle ORM, tRPC v11, better-auth. Load this skill when BE agent needs implementation details.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Implements backend APIs using Bun, Hono, Drizzle ORM, tRPC v11, better-auth. Load this skill when BE agent needs implementation details.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
全流程自動模式:從當前狀態一路推進到 DONE,無需人為干預確認。自動推進 MANUAL 節點、派發 Agent、處理失敗回滾,直到項目完成。支持傳入需求描述,自動注入後續流程。
快速修復模式:徹底分析問題後直接寫修復代碼。不走 pipeline,不生成文檔。適用於緊急 bug 修復或小範圍改動。
统一的 Jira 问题处理中心。提供:ensureConnected() 确保连接可用(MCP/curl 双通道 + 多源凭证 + 缓存)、getIssue() 获取完整 ticket 上下文(含图片分析)、writeBack() 回写结果到 Jira。被 autopilot/hotfix/feature 调用,所有 Jira 相关逻辑集中在此。
增量功能模式:等同於 /autopilot feature,跳過 Arch/Design 階段,適合在現有項目上添加新功能。
Universal environment checker. Detects missing tools, services, and configurations BEFORE starting any work phase. Always asks user before installing anything. Used by Designer (Stitch), FE, and BE agents. Modules: A = Stitch MCP (Designer), B = Backend env (BE), C = Frontend env (FE).
Implements frontend features using Next.js 15, React 19, shadcn/ui, Tailwind v4, tRPC/TanStack Query. Load this skill when FE agent needs implementation details.
| name | implement-api |
| description | Implements backend APIs using Bun, Hono, Drizzle ORM, tRPC v11, better-auth. Load this skill when BE agent needs implementation details. |
⚠️ 存量项目适配说明:以下技术规范是全新项目的默认推荐。 若目标项目已有后端代码,以
docs/arch-decision.md中确认的现有技术栈为准, 本规范中的 Bun/Hono/Drizzle/better-auth 作为参考,不得强行替换现有框架。 存量项目中,ORM、认证、路由框架须与现有代码保持一致。
运行时 Bun 1.x
后端框架 Hono(轻量、边缘友好)或 Elysia(Bun 原生,Eden 类型推断)
ORM Drizzle ORM(无 generate 步骤,Schema=类型)
数据库 PostgreSQL 16+(Neon/Supabase serverless 可选)
缓存/队列 Redis / Upstash(BullMQ)
接口 tRPC v11(全栈项目推荐)
验证 Zod v4(与 Drizzle/tRPC 深度集成)
认证 better-auth(TS 原生)
邮件 Resend + React Email
代码质量 Biome
测试 Bun test + Hono test helper
src/
├── db/
│ ├── schema.ts # Drizzle schema(类型即 Schema)
│ ├── index.ts # db client
│ └── migrations/
├── routes/v1/ # Hono 路由(REST 方案)
├── trpc/routers/ # tRPC routers(全栈方案)
├── services/ # 业务逻辑层
├── middleware/
│ ├── auth.ts
│ ├── validate.ts
│ └── rate-limit.ts
└── lib/
├── auth.ts # better-auth 配置
├── errors.ts # 统一错误类型
└── env.ts # Zod 环境变量验证
// db/schema.ts
import { pgTable, text, timestamp, decimal, index } from 'drizzle-orm/pg-core'
import { createInsertSchema, createSelectSchema } from 'drizzle-zod'
import { z } from 'zod/v4'
import { relations } from 'drizzle-orm'
export const users = pgTable('users', {
id: text('id').primaryKey().$defaultFn(() => crypto.randomUUID()),
email: text('email').notNull().unique(),
name: text('name'),
role: text('role', { enum: ['user', 'admin'] }).default('user').notNull(),
createdAt: timestamp('created_at', { withTimezone: true }).defaultNow().notNull(),
updatedAt: timestamp('updated_at', { withTimezone: true })
.defaultNow().$onUpdate(() => new Date()),
}, (t) => [
index('users_email_idx').on(t.email),
])
// 自动生成 Zod schema(无需手写)
export const insertUserSchema = createInsertSchema(users, {
email: (s) => s.email({ message: '请输入有效邮箱' }),
})
export const selectUserSchema = createSelectSchema(users)
export type InsertUser = z.infer<typeof insertUserSchema>
export type SelectUser = z.infer<typeof selectUserSchema>
// routes/v1/orders.ts
import { Hono } from 'hono'
import { zValidator } from '@hono/zod-validator'
import { z } from 'zod/v4'
import { db } from '@/db'
import { orders, insertOrderSchema } from '@/db/schema'
import { authMiddleware } from '@/middleware/auth'
import { AppError } from '@/lib/errors'
import { eq, and, desc, sql } from 'drizzle-orm'
const app = new Hono()
.get('/', authMiddleware, zValidator('query', z.object({
page: z.coerce.number().int().positive().default(1),
limit: z.coerce.number().int().min(1).max(100).default(20),
})), async (c) => {
const { page, limit } = c.req.valid('query')
const userId = c.get('userId')
const [items, [{ count }]] = await Promise.all([
db.select().from(orders).where(eq(orders.userId, userId))
.orderBy(desc(orders.createdAt)).limit(limit).offset((page - 1) * limit),
db.select({ count: sql<number>`count(*)` }).from(orders).where(eq(orders.userId, userId)),
])
return c.json({ data: items, meta: { page, limit, total: count } })
})
.post('/', authMiddleware, zValidator('json', insertOrderSchema), async (c) => {
const userId = c.get('userId')
const data = c.req.valid('json')
const [order] = await db.insert(orders).values({ ...data, userId }).returning()
return c.json({ data: order }, 201)
})
export default app
// trpc/routers/order.ts
import { z } from 'zod/v4'
import { router, protectedProcedure } from '@/trpc/trpc'
import { db } from '@/db'
import { orders, insertOrderSchema } from '@/db/schema'
import { eq, desc } from 'drizzle-orm'
export const orderRouter = router({
list: protectedProcedure
.input(z.object({ page: z.number().default(1), limit: z.number().default(20) }))
.query(async ({ ctx, input }) => {
const items = await db.select().from(orders)
.where(eq(orders.userId, ctx.user.id))
.orderBy(desc(orders.createdAt))
.limit(input.limit).offset((input.page - 1) * input.limit)
return { data: items }
}),
create: protectedProcedure
.input(insertOrderSchema)
.mutation(async ({ ctx, input }) => {
const [order] = await db.insert(orders)
.values({ ...input, userId: ctx.user.id }).returning()
return { data: order }
}),
})
// lib/auth.ts
import { betterAuth } from 'better-auth'
import { drizzleAdapter } from 'better-auth/adapters/drizzle'
import { db } from '@/db'
import * as schema from '@/db/schema'
export const auth = betterAuth({
database: drizzleAdapter(db, { provider: 'pg', schema }),
emailAndPassword: { enabled: true, requireEmailVerification: true },
socialProviders: {
github: { clientId: process.env.GITHUB_CLIENT_ID!, clientSecret: process.env.GITHUB_CLIENT_SECRET! },
},
session: { expiresIn: 60 * 60 * 24 * 7 },
rateLimit: { window: 60, max: 10 },
})
// lib/errors.ts
export class AppError extends Error {
constructor(
public message: string,
public statusCode: number,
public code: string,
public details?: unknown
) { super(message) }
static notFound = (r: string) => new AppError(`${r} not found`, 404, 'NOT_FOUND')
static unauthorized = () => new AppError('Unauthorized', 401, 'UNAUTHORIZED')
static forbidden = () => new AppError('Forbidden', 403, 'FORBIDDEN')
static validation = (d: unknown) => new AppError('Validation failed', 400, 'VALIDATION_ERROR', d)
}
// Hono 全局错误中间件
app.onError((err, c) => {
if (err instanceof AppError) {
return c.json({ error: { code: err.code, message: err.message, details: err.details } }, err.statusCode as any)
}
return c.json({ error: { code: 'INTERNAL_ERROR', message: 'Internal server error' } }, 500)
})
// lib/env.ts
import { z } from 'zod/v4'
const envSchema = z.object({
DATABASE_URL: z.url(),
BETTER_AUTH_SECRET: z.string().min(32),
NODE_ENV: z.enum(['development', 'production', 'test']),
REDIS_URL: z.string().optional(),
})
export const env = envSchema.parse(process.env)
// 若缺少必需变量,启动时立即报错
docs/arch-decision.md 和 docs/security-baseline.mddb/schema.ts)docs/api-spec.md,与 FE 对齐接口格式BE 实现完成后:
→ 下一步:implement-feature(在同一 fullstack-engineer context 中继续 FE 实现)
→ 遇到 Bug:systematic-debugging