Token导航 LogoToken导航

Agent Skill · 效率

minimax-fullstack-dev(极小极大全栈开发)

minimax-fullstack-dev 用于辅助前端页面、组件、样式和交互逻辑开发,适合在 OpenClaw 中需要维护前端项目、生成组件或检查界面实现时使用。可结合来源仓库、安装命令和原始 README 继续核验具体用法。安装前建议确认权限范围、维护状态,以及是否会触发联网、命令执行或文件读写。

minimax-fullstack-dev 是效率类 Agent Skill,可用宿主为 OpenClaw,通过ClawHub获取,权限为接触敏感数据;许可证为 MIT-0,第三方扫描已通过,按安装量在效率类的 21,003 个 Skill 里排第 8,459。

总安装 7,050周安装 328GitHub Stars 公开资料未说明下载 2,647核验 2026-05-01

安装说明

本站只整理中文说明,不托管安装包,也不代用户安装。
GitHub
许可证
MIT-0
版本
1.0.0

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:minimax-fullstack-dev(极小极大全栈开发)
来源仓库:https://github.com/daidai8910g/minimax-fullstack-dev
安装命令:
openclaw skills install minimax-fullstack-dev
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。该命令会通过 OpenClaw 从第三方来源获取 Skill;本站只展示命令,不托管安装包,也不自动执行。

ClawHubOpenClaw
openclaw skills install minimax-fullstack-dev

这个 Skill 是做什么的

效率类 Skill 把重复的整理、汇总、转换工作交给助手完成,减少手工复制粘贴。

minimax-fullstack-dev 提供前后端集成与 REST API 架构设计指南,支持全栈应用开发。适用于快速搭建可扩展服务系统,涵盖数据库建模、安全策略与部署流程。集成现代开发工具链,提升团队协作效率与代码可维护性。

安装命令:openclaw skills install minimax-fullstack-dev;作为开发参考技能调用。生产环境部署前应完成压力测试与安全扫描,避免未授权访问漏洞。

上手步骤

4 步
  1. 1

    确认自己的宿主工具

    公开资料标注支持 OpenClaw;先确认自己用的是其中之一,再按对应工具的 Skills 目录放置。

  2. 2

    拿到安装命令

    可以直接复制的命令是 openclaw skills install minimax-fullstack-dev;命令里的占位符换成自己的路径或密钥再执行。

  3. 3

    安装后重启宿主

    命令执行完要完全退出宿主工具再打开,让新装的 Skill 被重新扫描到,否则列表里可能看不到。

  4. 4

    按最小权限试用

    它需要接触敏感数据,先在测试目录或测试账号里跑,确认没问题再放到正式项目。

常见问题

6 条

minimax-fullstack-dev 怎么安装?

在终端执行 openclaw skills install minimax-fullstack-dev。装完完全退出宿主工具再打开,让它重新扫描本地 Skill。

minimax-fullstack-dev 支持哪些 AI 工具?

公开资料标注支持 OpenClaw。其他工具只要能读取本地 Skill 目录,一般也能手动放进去,但要自己确认触发方式是否一致。

minimax-fullstack-dev 需要什么权限?

权限级别是接触敏感数据。该 Skill 可能接触密钥、Token、环境变量或敏感配置,应进入高风险复核队列,默认不自动发布。

minimax-fullstack-dev 是免费的吗?

来源标注的许可证是 MIT-0。本站不代收任何费用,也不托管安装包;能否商用、要不要署名,以许可证原文为准。

minimax-fullstack-dev 用的人多吗?

公开数据是累计安装 7,050 次,近一周安装 328 次,下载 2,647 次。这些数字来自第三方目录统计,只能当作热度参考,不代表质量或安全性。

minimax-fullstack-dev 安全吗?

第三方扫描结果为通过,但这只覆盖已知的静态检查项,不能替代自己读一遍源码和安装命令。

值得选的地方和要先想清楚的地方

值得选的地方

  • 专注 OpenClaw 一种宿主,触发方式和使用习惯不用来回切换。
  • 许可证明确为 MIT-0,商用和分发边界好判断。
  • 第三方扫描已通过,常见的高风险行为没有命中。

先想清楚的地方

  • 需要接触敏感数据,装到常用环境前要先评估影响面。
  • 第三方目录整理,版本更新和行为细节以来源仓库为准。

适不适合你

更适合

  • 已经在用 OpenClaw,想直接扩展它能力的人。
  • 需要处理效率类任务、又不想每次都手写提示词的人。
  • 需要许可证清楚、并且有第三方扫描结果的团队项目。

不太适合

  • 环境里有大量密钥、凭证,不方便给第三方 Skill 读取的人。
  • 需要厂商级技术支持和 SLA 的生产系统。

效率类 Skill 对比

6 个同类
Skill总安装GitHub 星权限许可证扫描
github

GitHub 代码协作 · OpenClaw

7,632,918545需要联网MIT-0通过
nano-pdf

Nano PDF 文档 · OpenClaw

4,249,476231需要联网MIT-0通过
auto-updater

自动更新程序 · OpenClaw

2,964,063386操作浏览器MIT-0通过
video-frames

视频帧 · OpenClaw

2,621,304112需要联网MIT-0通过
gemini

Gemini 助手 · OpenClaw

2,547,39648需要联网MIT-0有提醒
minimax-fullstack-dev

极小极大全栈开发 · 本页

7,050—接触敏感数据MIT-0通过

按安装量取同分类前几名;数字来自第三方目录统计,只作热度参考,不代表质量结论。

SKILL.md 原文

name
fullstack-dev
description
|
license
MIT
metadata
category
full-stack
version
1.0.0
sources

Full-Stack Development Practices

MANDATORY WORKFLOW — Follow These Steps In Order

When this skill is triggered, you MUST follow this workflow before writing any code.

Step 0: Gather Requirements

Before scaffolding anything, ask the user to clarify (or infer from context):

  1. Stack: Language/framework for backend and frontend (e.g., Express + React, Django + Vue, Go + HTMX)
  2. Service type: API-only, full-stack monolith, or microservice?
  3. Database: SQL (PostgreSQL, SQLite, MySQL) or NoSQL (MongoDB, Redis)?
  4. Integration: REST, GraphQL, tRPC, or gRPC?
  5. Real-time: Needed? If yes — SSE, WebSocket, or polling?
  6. Auth: Needed? If yes — JWT, session, OAuth, or third-party (Clerk, Auth.js)?

If the user has already specified these in their request, skip asking and proceed.

Step 1: Architectural Decisions

Based on requirements, make and state these decisions before coding:

DecisionOptionsReference
Project structureFeature-first (recommended) vs layer-firstSection 1
API client approachTyped fetch / React Query / tRPC / OpenAPI codegenSection 5
Auth strategyJWT + refresh / session / third-partySection 6
Real-time methodPolling / SSE / WebSocketSection 11
Error handlingTyped error hierarchy + global handlerSection 3

Briefly explain each choice (1 sentence per decision).

Step 2: Scaffold with Checklist

Use the appropriate checklist below. Ensure ALL checked items are implemented — do not skip any.

Step 3: Implement Following Patterns

Write code following the patterns in this document. Reference specific sections as you implement each part.

Step 4: Test & Verify

After implementation, run these checks before claiming completion:

  1. Build check: Ensure both backend and frontend compile without errors
   # Backend
   cd server && npm run build
   # Frontend
   cd client && npm run build
  1. Start & smoke test: Start the server, verify key endpoints return expected responses
   # Start server, then test
   curl http://localhost:3000/health
   curl http://localhost:3000/api/<resource>
  1. Integration check: Verify frontend can connect to backend (CORS, API base URL, auth flow)
  2. Real-time check (if applicable): Open two browser tabs, verify changes sync

If any check fails, fix the issue before proceeding.

Step 5: Handoff Summary

Provide a brief summary to the user:

  • What was built: List of implemented features and endpoints
  • How to run: Exact commands to start backend and frontend
  • What's missing / next steps: Any deferred items, known limitations, or recommended improvements
  • Key files: List the most important files the user should know about

Scope

USE this skill when:

  • Building a full-stack application (backend + frontend)
  • Scaffolding a new backend service or API
  • Designing service layers and module boundaries
  • Implementing database access, caching, or background jobs
  • Writing error handling, logging, or configuration management
  • Reviewing backend code for architectural issues
  • Hardening for production
  • Setting up API clients, auth flows, file uploads, or real-time features

NOT for:

  • Pure frontend/UI concerns (use your frontend framework's docs)
  • Pure database schema design without backend context

Quick Start — New Backend Service Checklist

  • [ ] Project scaffolded with feature-first structure
  • [ ] Configuration centralized, env vars validated at startup (fail fast)
  • [ ] Typed error hierarchy defined (not generic Error)
  • [ ] Global error handler middleware
  • [ ] Structured JSON logging with request ID propagation
  • [ ] Database: migrations set up, connection pooling configured
  • [ ] Input validation on all endpoints (Zod / Pydantic / Go validator)
  • [ ] Authentication middleware in place
  • [ ] Health check endpoints (/health, /ready)
  • [ ] Graceful shutdown handling (SIGTERM)
  • [ ] CORS configured (explicit origins, not *)
  • [ ] Security headers (helmet or equivalent)
  • [ ] .env.example committed (no real secrets)

Quick Start — Frontend-Backend Integration Checklist

  • [ ] API client configured (typed fetch wrapper, React Query, tRPC, or OpenAPI generated)
  • [ ] Base URL from environment variable (not hardcoded)
  • [ ] Auth token attached to requests automatically (interceptor / middleware)
  • [ ] Error handling — API errors mapped to user-facing messages
  • [ ] Loading states handled (skeleton/spinner, not blank screen)
  • [ ] Type safety across the boundary (shared types, OpenAPI, or tRPC)
  • [ ] CORS configured with explicit origins (not * in production)
  • [ ] Refresh token flow implemented (httpOnly cookie + transparent retry on 401)

Quick Navigation

Need to…Jump to
Organize project folders1. Project Structure
Manage config + secrets2. Configuration
Handle errors properly3. Error Handling
Write database code4. Database Access Patterns
Set up API client from frontend5. API Client Patterns
Add auth middleware6. Auth & Middleware
Set up logging7. Logging & Observability
Add background jobs8. Background Jobs
Implement caching9. Caching
Upload files (presigned URL, multipart)10. File Upload Patterns
Add real-time features (SSE, WebSocket)11. Real-Time Patterns
Handle API errors in frontend UI12. Cross-Boundary Error Handling
Harden for production13. Production Hardening
Design API endpointsAPI Design
Design database schemaDatabase Schema
Auth flow (JWT, refresh, Next.js SSR, RBAC)references/auth-flow.md
CORS, env vars, environment managementreferences/environment-management.md

Core Principles (7 Iron Rules)

1. ✅ Organize by FEATURE, not by technical layer
2. ✅ Controllers never contain business logic
3. ✅ Services never import HTTP request/response types
4. ✅ All config from env vars, validated at startup, fail fast
5. ✅ Every error is typed, logged, and returns consistent format
6. ✅ All input validated at the boundary — trust nothing from client
7. ✅ Structured JSON logging with request ID — not console.log

1. Project Structure & Layering (CRITICAL)

Feature-First Organization

✅ Feature-first                    ❌ Layer-first
src/                                src/
  orders/                             controllers/
    order.controller.ts                 order.controller.ts
    order.service.ts                    user.controller.ts
    order.repository.ts               services/
    order.dto.ts                        order.service.ts
    order.test.ts                       user.service.ts
  users/                              repositories/
    user.controller.ts                  ...
    user.service.ts
  shared/
    database/
    middleware/

Three-Layer Architecture

Controller (HTTP) → Service (Business Logic) → Repository (Data Access)
LayerResponsibility❌ Never
ControllerParse request, validate, call service, format responseBusiness logic, DB queries
ServiceBusiness rules, orchestration, transaction mgmtHTTP types (req/res), direct DB
RepositoryDatabase queries, external API callsBusiness logic, HTTP types

Dependency Injection (All Languages)

TypeScript:

class OrderService {
  constructor(
    private readonly orderRepo: OrderRepository,    // ✅ injected interface
    private readonly emailService: EmailService,
  ) {}
}

Python:

class OrderService:
    def __init__(self, order_repo: OrderRepository, email_service: EmailService):
        self.order_repo = order_repo                 # ✅ injected
        self.email_service = email_service

Go:

type OrderService struct {
    orderRepo    OrderRepository                      // ✅ interface
    emailService EmailService
}

func NewOrderService(repo OrderRepository, email EmailService) *OrderService {
    return &OrderService{orderRepo: repo, emailService: email}
}

2. Configuration & Environment (CRITICAL)

Centralized, Typed, Fail-Fast

TypeScript:

const config = {
  port: parseInt(process.env.PORT || '3000', 10),
  database: { url: requiredEnv('DATABASE_URL'), poolSize: intEnv('DB_POOL_SIZE', 10) },
  auth: { jwtSecret: requiredEnv('JWT_SECRET'), expiresIn: process.env.JWT_EXPIRES_IN || '1h' },
} as const;

function requiredEnv(name: string): string {
  const value = process.env[name];
  if (!value) throw new Error(`Missing required env var: ${name}`);  // fail fast
  return value;
}

Python:

from pydantic_settings import BaseSettings

class Settings(BaseSettings):
    database_url: str                        # required — app won't start without it
    jwt_secret: str                          # required
    port: int = 3000                         # optional with default
    db_pool_size: int = 10
    class Config:
        env_file = ".env"

settings = Settings()                        # fails fast if DATABASE_URL missing

Rules

✅ All config via environment variables (Twelve-Factor)
✅ Validate required vars at startup — fail fast
✅ Type-cast at config layer, not at usage sites
✅ Commit .env.example with dummy values

❌ Never hardcode secrets, URLs, or credentials
❌ Never commit .env files
❌ Never scatter process.env / os.environ throughout code

3. Error Handling & Resilience (HIGH)

Typed Error Hierarchy

// Base (TypeScript)
class AppError extends Error {
  constructor(
    message: string,
    public readonly code: string,
    public readonly statusCode: number,
    public readonly isOperational: boolean = true,
  ) { super(message); }
}
class NotFoundError extends AppError {
  constructor(resource: string, id: string) {
    super(`${resource} not found: ${id}`, 'NOT_FOUND', 404);
  }
}
class ValidationError extends AppError {
  constructor(public readonly errors: FieldError[]) {
    super('Validation failed', 'VALIDATION_ERROR', 422);
  }
}
# Base (Python)
class AppError(Exception):
    def __init__(self, message: str, code: str, status_code: int):
        self.message, self.code, self.status_code = message, code, status_code

class NotFoundError(AppError):
    def __init__(self, resource: str, id: str):
        super().__init__(f"{resource} not found: {id}", "NOT_FOUND", 404)

Global Error Handler

// TypeScript (Express)
app.use((err, req, res, next) => {
  if (err instanceof AppError && err.isOperational) {
    return res.status(err.statusCode).json({
      title: err.code, status: err.statusCode,
      detail: err.message, request_id: req.id,
    });
  }
  logger.error('Unexpected error', { error: err.message, stack: err.stack, request_id: req.id });
  res.status(500).json({ title: 'Internal Error', status: 500, request_id: req.id });
});

Rules

✅ Typed, domain-specific error classes
✅ Global error handler catches everything
✅ Operational errors → structured response
✅ Programming errors → log + generic 500
✅ Retry transient failures with exponential backoff

❌ Never catch and ignore errors silently
❌ Never return stack traces to client
❌ Never throw generic Error('something')

4. Database Access Patterns (HIGH)

Migrations Always

# TypeScript (Prisma)           # Python (Alembic)              # Go (golang-migrate)
npx prisma migrate dev          alembic revision --autogenerate  migrate -source file://migrations
npx prisma migrate deploy       alembic upgrade head             migrate -database $DB up
✅ Schema changes via migrations, never manual SQL
✅ Migrations must be reversible
✅ Review migration SQL before production
❌ Never modify production schema manually

N+1 Prevention

// ❌ N+1: 1 query + N queries
const orders = await db.order.findMany();
for (const o of orders) { o.items = await db.item.findMany({ where: { orderId: o.id } }); }

// ✅ Single JOIN query
const orders = await db.order.findMany({ include: { items: true } });

Transactions for Multi-Step Writes

await db.$transaction(async (tx) => {
  const order = await tx.order.create({ data: orderData });
  await tx.inventory.decrement({ productId, quantity });
  await tx.payment.create({ orderId: order.id, amount });
});

Connection Pooling

Pool size = (CPU cores × 2) + spindle_count (start with 10-20). Always set connection timeout. Use PgBouncer for serverless.


5. API Client Patterns (MEDIUM)

The "glue layer" between frontend and backend. Choose the approach that fits your team and stack.

Option A: Typed Fetch Wrapper (Simple, No Dependencies)

// lib/api-client.ts
const BASE_URL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:3001';

class ApiError extends Error {
  constructor(public status: number, public body: any) {
    super(body?.detail || body?.message || `API error ${status}`);
  }
}

async function api<T>(path: string, options: RequestInit = {}): Promise<T> {
  const token = getAuthToken();  // from cookie / memory / context

  const res = await fetch(`${BASE_URL}${path}`, {
    ...options,
    headers: {
      'Content-Type': 'application/json',
      ...(token ? { Authorization: `Bearer ${token}` } : {}),
      ...options.headers,
    },
  });

  if (!res.ok) {
    const body = await res.json().catch(() => null);
    throw new ApiError(res.status, body);
  }

  if (res.status === 204) return undefined as T;
  return res.json();
}

export const apiClient = {
  get: <T>(path: string) => api<T>(path),
  post: <T>(path: string, data: unknown) => api<T>(path, { method: 'POST', body: JSON.stringify(data) }),
  put: <T>(path: string, data: unknown) => api<T>(path, { method: 'PUT', body: JSON.stringify(data) }),
  patch: <T>(path: string, data: unknown) => api<T>(path, { method: 'PATCH', body: JSON.stringify(data) }),
  delete: <T>(path: string) => api<T>(path, { method: 'DELETE' }),
};

Option B: React Query + Typed Client (Recommended for React)

// hooks/use-orders.ts
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import { apiClient } from '@/lib/api-client';

interface Order { id: string; total: number; status: string; }
interface CreateOrderInput { items: { productId: string; quantity: number }[] }

export function useOrders() {
  return useQuery({
    queryKey: ['orders'],
    queryFn: () => apiClient.get<{ data: Order[] }>('/api/orders'),
    staleTime: 1000 * 60,  // 1 min
  });
}

export function useCreateOrder() {
  const queryClient = useQueryClient();
  return useMutation({
    mutationFn: (data: CreateOrderInput) =>
      apiClient.post<{ data: Order }>('/api/orders', data),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ['orders'] });
    },
  });
}

// Usage in component:
function OrdersPage() {
  const { data, isLoading, error } = useOrders();
  const createOrder = useCreateOrder();
  if (isLoading) return <Skeleton />;
  if (error) return <ErrorBanner error={error} />;
  // ...
}

Option C: tRPC (Same Team Owns Both Sides)

// server: trpc/router.ts
export const appRouter = router({
  orders: router({
    list: publicProcedure.query(async () => {
      return db.order.findMany({ include: { items: true } });
    }),
    create: protectedProcedure
      .input(z.object({ items: z.array(orderItemSchema) }))
      .mutation(async ({ input, ctx }) => {
        return orderService.create(ctx.user.id, input);
      }),
  }),
});
export type AppRouter = typeof appRouter;

// client: automatic type safety, no code generation
const { data } = trpc.orders.list.useQuery();
const createOrder = trpc.orders.create.useMutation();

Option D: OpenAPI Generated Client (Public / Multi-Consumer APIs)

npx openapi-typescript-codegen \
  --input http://localhost:3001/api/openapi.json \
  --output src/generated/api \
  --client axios

Decision: Which API Client?

ApproachWhenType SafetyEffort
Typed fetch wrapperSimple apps, small teamsManual typesLow
React Query + fetchReact apps, server stateManual typesMedium
tRPCSame team, TypeScript both sidesAutomaticLow
OpenAPI generatedPublic API, multi-consumerAutomaticMedium
GraphQL codegenGraphQL APIsAutomaticMedium

6. Authentication & Middleware (HIGH)

Full reference: references/auth-flow.md — JWT bearer flow, automatic token refresh, Next.js server-side auth, RBAC pattern, backend middleware order.

Standard Middleware Order

Request → 1.RequestID → 2.Logging → 3.CORS → 4.RateLimit → 5.BodyParse
       → 6.Auth → 7.Authz → 8.Validation → 9.Handler → 10.ErrorHandler → Response

JWT Rules

✅ Short expiry access token (15min) + refresh token (server-stored)
✅ Minimal claims: userId, roles (not entire user object)
✅ Rotate signing keys periodically

❌ Never store tokens in localStorage (XSS risk)
❌ Never pass tokens in URL query params

RBAC Pattern

function authorize(...roles: Role[]) {
  return (req, res, next) => {
    if (!req.user) throw new UnauthorizedError();
    if (!roles.some(r => req.user.roles.includes(r))) throw new ForbiddenError();
    next();
  };
}
router.delete('/users/:id', authenticate, authorize('admin'), deleteUser);

Auth Token Automatic Refresh

// lib/api-client.ts — transparent refresh on 401
async function apiWithRefresh<T>(path: string, options: RequestInit = {}): Promise<T> {
  try {
    return await api<T>(path, options);
  } catch (err) {
    if (err instanceof ApiError && err.status === 401) {
      const refreshed = await api<{ accessToken: string }>('/api/auth/refresh', {
        method: 'POST',
        credentials: 'include',  // send httpOnly cookie
      });
      setAuthToken(refreshed.accessToken);
      return api<T>(path, options);  // retry
    }
    throw err;
  }
}

7. Logging & Observability (MEDIUM-HIGH)

Structured JSON Logging

// ✅ Structured — parseable, filterable, alertable
logger.info('Order created', {
  orderId: order.id, userId: user.id, total: order.total,
  items: order.items.length, duration_ms: Date.now() - startTime,
});
// Output: {"level":"info","msg":"Order created","orderId":"ord_123",...}

// ❌ Unstructured — useless at scale
console.log(`Order created for user ${user.id} with total ${order.total}`);

Log Levels

LevelWhenProduction?
errorRequires immediate attention✅ Always
warnUnexpected but handled✅ Always
infoNormal operations, audit trail✅ Always
debugDev troubleshooting❌ Dev only

Rules

✅ Request ID in every log entry (propagated via middleware)
✅ Log at layer boundaries (request in, response out, external call)
❌ Never log passwords, tokens, PII, or secrets
❌ Never use console.log in production code

8. Background Jobs & Async (MEDIUM)

Rules

✅ All jobs must be IDEMPOTENT (same job running twice = same result)
✅ Failed jobs → retry (max 3) → dead letter queue → alert
✅ Workers run as SEPARATE processes (not threads in API server)

❌ Never put long-running tasks in request handlers
❌ Never assume job runs exactly once

Idempotent Job Pattern

async function processPayment(data: { orderId: string }) {
  const order = await orderRepo.findById(data.orderId);
  if (order.paymentStatus === 'completed') return;  // already processed
  await paymentGateway.charge(order);
  await orderRepo.updatePaymentStatus(order.id, 'completed');
}

9. Caching Patterns (MEDIUM)

Cache-Aside (Lazy Loading)

async function getUser(id: string): Promise<User> {
  const cached = await redis.get(`user:${id}`);
  if (cached) return JSON.parse(cached);

  const user = await userRepo.findById(id);
  if (!user) throw new NotFoundError('User', id);

  await redis.set(`user:${id}`, JSON.stringify(user), 'EX', 900);  // 15min TTL
  return user;
}

Rules

✅ ALWAYS set TTL — never cache without expiry
✅ Invalidate on write (delete cache key after update)
✅ Use cache for reads, never for authoritative state

❌ Never cache without TTL (stale data is worse than slow data)
Data TypeSuggested TTL
User profile5-15 min
Product catalog1-5 min
Config / feature flags30-60 sec
SessionMatch session duration

10. File Upload Patterns (MEDIUM)

Option A: Presigned URL (Recommended for Large Files)

Client → GET /api/uploads/presign?filename=photo.jpg&type=image/jpeg
Server → { uploadUrl: "https://s3.../presigned", fileKey: "uploads/abc123.jpg" }
Client → PUT uploadUrl (direct to S3, bypasses your server)
Client → POST /api/photos { fileKey: "uploads/abc123.jpg" }  (save reference)

Backend:

app.get('/api/uploads/presign', authenticate, async (req, res) => {
  const { filename, type } = req.query;
  const key = `uploads/${crypto.randomUUID()}-${filename}`;
  const url = await s3.getSignedUrl('putObject', {
    Bucket: process.env.S3_BUCKET, Key: key,
    ContentType: type, Expires: 300,  // 5 min
  });
  res.json({ uploadUrl: url, fileKey: key });
});

Frontend:

async function uploadFile(file: File) {
  const { uploadUrl, fileKey } = await apiClient.get<PresignResponse>(
    `/api/uploads/presign?filename=${file.name}&type=${file.type}`
  );
  await fetch(uploadUrl, { method: 'PUT', body: file, headers: { 'Content-Type': file.type } });
  return apiClient.post('/api/photos', { fileKey });
}

Option B: Multipart (Small Files < 10MB)

// Frontend
const formData = new FormData();
formData.append('file', file);
formData.append('description', 'Profile photo');
const res = await fetch('/api/upload', { method: 'POST', body: formData });
// Note: do NOT set Content-Type header — browser sets boundary automatically

Decision

MethodFile SizeServer LoadComplexity
Presigned URLAny (recommended > 5MB)None (direct to storage)Medium
Multipart< 10MBHigh (streams through server)Low
Chunked / Resumable> 100MBMediumHigh

11. Real-Time Patterns (MEDIUM)

Option A: Server-Sent Events (SSE) — One-Way Server → Client

Best for: notifications, live feeds, streaming AI responses.

Backend (Express):

app.get('/api/events', authenticate, (req, res) => {
  res.writeHead(200, {
    'Content-Type': 'text/event-stream',
    'Cache-Control': 'no-cache',
    Connection: 'keep-alive',
  });
  const send = (event: string, data: unknown) => {
    res.write(`event: ${event}\
data: ${JSON.stringify(data)}\
\
`);
  };
  const unsubscribe = eventBus.subscribe(req.user.id, (event) => {
    send(event.type, event.payload);
  });
  req.on('close', () => unsubscribe());
});

Frontend:

function useServerEvents(userId: string) {
  useEffect(() => {
    const source = new EventSource(`/api/events?userId=${userId}`);
    source.addEventListener('notification', (e) => {
      showToast(JSON.parse(e.data).message);
    });
    source.onerror = () => { source.close(); setTimeout(() => /* reconnect */, 3000); };
    return () => source.close();
  }, [userId]);
}

Option B: WebSocket — Bidirectional

Best for: chat, collaborative editing, gaming.

Backend (ws library):

import { WebSocketServer } from 'ws';
const wss = new WebSocketServer({ server: httpServer, path: '/ws' });
wss.on('connection', (ws, req) => {
  const userId = authenticateWs(req);
  if (!userId) { ws.close(4001, 'Unauthorized'); return; }
  ws.on('message', (raw) => handleMessage(userId, JSON.parse(raw.toString())));
  ws.on('close', () => cleanupUser(userId));
  const interval = setInterval(() => ws.ping(), 30000);
  ws.on('pong', () => { /* alive */ });
  ws.on('close', () => clearInterval(interval));
});

Frontend:

function useWebSocket(url: string) {
  const [ws, setWs] = useState<WebSocket | null>(null);
  useEffect(() => {
    const socket = new WebSocket(url);
    socket.onopen = () => setWs(socket);
    socket.onclose = () => setTimeout(() => /* reconnect */, 3000);
    return () => socket.close();
  }, [url]);
  const send = useCallback((data: unknown) => ws?.send(JSON.stringify(data)), [ws]);
  return { ws, send };
}

Option C: Polling (Simplest, No Infrastructure)

function useOrderStatus(orderId: string) {
  return useQuery({
    queryKey: ['order-status', orderId],
    queryFn: () => apiClient.get<Order>(`/api/orders/${orderId}`),
    refetchInterval: (query) => {
      if (query.state.data?.status === 'completed') return false;
      return 5000;
    },
  });
}

Decision

MethodDirectionComplexityWhen
PollingClient → ServerLowSimple status checks, < 10 clients
SSEServer → ClientMediumNotifications, feeds, AI streaming
WebSocketBidirectionalHighChat, collaboration, gaming

12. Cross-Boundary Error Handling (MEDIUM)

API Error → User-Facing Message

// lib/error-handler.ts
export function getErrorMessage(error: unknown): string {
  if (error instanceof ApiError) {
    switch (error.status) {
      case 401: return 'Please log in to continue.';
      case 403: return 'You don\'t have permission to do this.';
      case 404: return 'The item you\'re looking for doesn\'t exist.';
      case 409: return 'This conflicts with an existing item.';
      case 422:
        const fields = error.body?.errors;
        if (fields?.length) return fields.map((f: any) => f.message).join('. ');
        return 'Please check your input.';
      case 429: return 'Too many requests. Please wait a moment.';
      default: return 'Something went wrong. Please try again.';
    }
  }
  if (error instanceof TypeError && error.message === 'Failed to fetch') {
    return 'Cannot connect to server. Check your internet connection.';
  }
  return 'An unexpected error occurred.';
}

React Query Global Error Handler

const queryClient = new QueryClient({
  defaultOptions: {
    mutations: { onError: (error) => toast.error(getErrorMessage(error)) },
    queries: {
      retry: (failureCount, error) => {
        if (error instanceof ApiError && error.status < 500) return false;
        return failureCount < 3;
      },
    },
  },
});

Rules

✅ Map every API error code to a human-readable message
✅ Show field-level validation errors next to form inputs
✅ Auto-retry on 5xx (max 3, with backoff), never on 4xx
✅ Redirect to login on 401 (after refresh attempt fails)
✅ Show "offline" banner when fetch fails with TypeError

❌ Never show raw API error messages to users ("NullPointerException")
❌ Never silently swallow errors (show toast or log)
❌ Never retry 4xx errors (client is wrong, retrying won't help)

Integration Decision Tree

Same team owns frontend + backend?
│
├─ YES, both TypeScript
│   └─ tRPC (end-to-end type safety, zero codegen)
│
├─ YES, different languages
│   └─ OpenAPI spec → generated client (type safety via codegen)
│
├─ NO, public API
│   └─ REST + OpenAPI → generated SDKs for consumers
│
└─ Complex data needs, multiple frontends
    └─ GraphQL + codegen (flexible queries per client)

Real-time needed?
│
├─ Server → Client only (notifications, feeds, AI streaming)
│   └─ SSE (simplest, auto-reconnect, works through proxies)
│
├─ Bidirectional (chat, collaboration)
│   └─ WebSocket (need heartbeat + reconnection logic)
│
└─ Simple status polling (< 10 clients)
    └─ React Query refetchInterval (no infrastructure needed)

13. Production Hardening (MEDIUM)

Health Checks

app.get('/health', (req, res) => res.json({ status: 'ok' }));           // liveness
app.get('/ready', async (req, res) => {                                   // readiness
  const checks = {
    database: await checkDb(), redis: await checkRedis(), 
  };
  const ok = Object.values(checks).every(c => c.status === 'ok');
  res.status(ok ? 200 : 503).json({ status: ok ? 'ok' : 'degraded', checks });
});

Graceful Shutdown

process.on('SIGTERM', async () => {
  logger.info('SIGTERM received');
  server.close();              // stop new connections
  await drainConnections();    // finish in-flight
  await closeDatabase();
  process.exit(0);
});

Security Checklist

✅ CORS: explicit origins (never '*' in production)
✅ Security headers (helmet / equivalent)
✅ Rate limiting on public endpoints
✅ Input validation on ALL endpoints (trust nothing)
✅ HTTPS enforced
❌ Never expose internal errors to clients

Anti-Patterns

#❌ Don't✅ Do Instead
1Business logic in routes/controllersMove to service layer
2process.env scattered everywhereCentralized typed config
3console.log for loggingStructured JSON logger
4Generic Error('oops')Typed error hierarchy
5Direct DB calls in controllersRepository pattern
6No input validationValidate at boundary (Zod/Pydantic)
7Catching errors silentlyLog + rethrow or return error
8No health check endpoints/health + /ready
9Hardcoded config/secretsEnvironment variables
10No graceful shutdownHandle SIGTERM properly
11Hardcode API URL in frontendEnvironment variable (NEXT_PUBLIC_API_URL)
12Store JWT in localStorageMemory + httpOnly refresh cookie
13Show raw API errors to usersMap to human-readable messages
14Retry 4xx errorsOnly retry 5xx (server failures)
15Skip loading statesSkeleton/spinner while fetching
16Upload large files through API serverPresigned URL → direct to S3
17Poll for real-time dataSSE or WebSocket
18Duplicate types frontend + backendShared types, tRPC, or OpenAPI codegen

Common Issues

Issue 1: "Where does this business rule go?"

Rule: If it involves HTTP (request parsing, status codes, headers) → controller. If it involves business decisions (pricing, permissions, rules) → service. If it touches the database → repository.

Issue 2: "Service is getting too big"

Symptom: One service file > 500 lines with 20+ methods.

Fix: Split by sub-domain. OrderService → OrderCreationService + OrderFulfillmentService + OrderQueryService. Each focused on one workflow.

Issue 3: "Tests are slow because they hit the database"

Fix: Unit tests mock the repository layer (fast). Integration tests use test containers or transaction rollback (real DB, still fast). Never mock the service layer in integration tests.


Reference Documents

This skill includes deep-dive references for specialized topics. Read the relevant reference when you need detailed guidance.

Need to…Reference
Write backend tests (unit, integration, e2e, contract, performance)references/testing-strategy.md
Validate a release before deployment (6-gate checklist)references/release-checklist.md
Choose a tech stack (language, framework, database, infra)references/technology-selection.md
Build with Django / DRF (models, views, serializers, admin)references/django-best-practices.md
Design REST/GraphQL/gRPC endpoints (URLs, status codes, pagination)references/api-design.md
Design database schema, indexes, migrations, multi-tenancyreferences/db-schema.md
Auth flow (JWT bearer, token refresh, Next.js SSR, RBAC, middleware order)references/auth-flow.md
CORS config, env vars per environment, common CORS issuesreferences/environment-management.md

平台分布

OpenClaw

92.71%
按下载量换算2,454

安全审计

VirusTotal

通过

ClawScan

通过

Static analysis

通过

权限和风险

接触敏感数据

该 Skill 可能接触密钥、Token、环境变量或敏感配置,应进入高风险复核队列,默认不自动发布。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。目前只有一个公开来源,建议同时核对源仓库。

继续浏览同类 Skills