Files
junhong_cmp_fiber/openspec/AGENTS.md
huang d66323487b refactor: align framework cleanup with new bootstrap flow
Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
2025-11-19 12:47:25 +08:00

31 KiB
Raw Blame History

OpenSpec Instructions

Instructions for AI coding assistants using OpenSpec for spec-driven development.

TL;DR Quick Checklist

  • Search existing work: openspec spec list --long, openspec list (use rg only for full-text search)
  • Decide scope: new capability vs modify existing capability
  • Pick a unique change-id: kebab-case, verb-led (add-, update-, remove-, refactor-)
  • Scaffold: proposal.md, tasks.md, design.md (only if needed), and delta specs per affected capability
  • Write deltas: use ## ADDED|MODIFIED|REMOVED|RENAMED Requirements; include at least one #### Scenario: per requirement
  • Validate: openspec validate [change-id] --strict and fix issues
  • Request approval: Do not start implementation until proposal is approved

Three-Stage Workflow

Stage 1: Creating Changes

Create proposal when you need to:

  • Add features or functionality
  • Make breaking changes (API, schema)
  • Change architecture or patterns
  • Optimize performance (changes behavior)
  • Update security patterns

Triggers (examples):

  • "Help me create a change proposal"
  • "Help me plan a change"
  • "Help me create a proposal"
  • "I want to create a spec proposal"
  • "I want to create a spec"

Loose matching guidance:

  • Contains one of: proposal, change, spec
  • With one of: create, plan, make, start, help

Skip proposal for:

  • Bug fixes (restore intended behavior)
  • Typos, formatting, comments
  • Dependency updates (non-breaking)
  • Configuration changes
  • Tests for existing behavior

Workflow

  1. Review openspec/project.md, openspec list, and openspec list --specs to understand current context.
  2. Choose a unique verb-led change-id and scaffold proposal.md, tasks.md, optional design.md, and spec deltas under openspec/changes/<id>/.
  3. Draft spec deltas using ## ADDED|MODIFIED|REMOVED Requirements with at least one #### Scenario: per requirement.
  4. Run openspec validate <id> --strict and resolve any issues before sharing the proposal.

Stage 2: Implementing Changes

Track these steps as TODOs and complete them one by one.

  1. Read proposal.md - Understand what's being built
  2. Read design.md (if exists) - Review technical decisions
  3. Read tasks.md - Get implementation checklist
  4. Implement tasks sequentially - Complete in order
  5. Confirm completion - Ensure every item in tasks.md is finished before updating statuses
  6. Update checklist - After all work is done, set every task to - [x] so the list reflects reality
  7. Approval gate - Do not start implementation until the proposal is reviewed and approved

Stage 3: Archiving Changes

After deployment, create separate PR to:

  • Move changes/[name]/changes/archive/YYYY-MM-DD-[name]/
  • Update specs/ if capabilities changed
  • Use openspec archive <change-id> --skip-specs --yes for tooling-only changes (always pass the change ID explicitly)
  • Run openspec validate --strict to confirm the archived change passes checks

Before Any Task

Context Checklist:

  • Read relevant specs in specs/[capability]/spec.md
  • Check pending changes in changes/ for conflicts
  • Read openspec/project.md for conventions
  • Run openspec list to see active changes
  • Run openspec list --specs to see existing capabilities

Before Creating Specs:

  • Always check if capability already exists
  • Prefer modifying existing specs over creating duplicates
  • Use openspec show [spec] to review current state
  • If request is ambiguous, ask 12 clarifying questions before scaffolding

Search Guidance

  • Enumerate specs: openspec spec list --long (or --json for scripts)
  • Enumerate changes: openspec list (or openspec change list --json - deprecated but available)
  • Show details:
    • Spec: openspec show <spec-id> --type spec (use --json for filters)
    • Change: openspec show <change-id> --json --deltas-only
  • Full-text search (use ripgrep): rg -n "Requirement:|Scenario:" openspec/specs

Quick Start

CLI Commands

# Essential commands
openspec list                  # List active changes
openspec list --specs          # List specifications
openspec show [item]           # Display change or spec
openspec validate [item]       # Validate changes or specs
openspec archive <change-id> [--yes|-y]   # Archive after deployment (add --yes for non-interactive runs)

# Project management
openspec init [path]           # Initialize OpenSpec
openspec update [path]         # Update instruction files

# Interactive mode
openspec show                  # Prompts for selection
openspec validate              # Bulk validation mode

# Debugging
openspec show [change] --json --deltas-only
openspec validate [change] --strict

Command Flags

  • --json - Machine-readable output
  • --type change|spec - Disambiguate items
  • --strict - Comprehensive validation
  • --no-interactive - Disable prompts
  • --skip-specs - Archive without spec updates
  • --yes/-y - Skip confirmation prompts (non-interactive archive)

Directory Structure

openspec/
├── project.md              # Project conventions
├── specs/                  # Current truth - what IS built
│   └── [capability]/       # Single focused capability
│       ├── spec.md         # Requirements and scenarios
│       └── design.md       # Technical patterns
├── changes/                # Proposals - what SHOULD change
│   ├── [change-name]/
│   │   ├── proposal.md     # Why, what, impact
│   │   ├── tasks.md        # Implementation checklist
│   │   ├── design.md       # Technical decisions (optional; see criteria)
│   │   └── specs/          # Delta changes
│   │       └── [capability]/
│   │           └── spec.md # ADDED/MODIFIED/REMOVED
│   └── archive/            # Completed changes

Creating Change Proposals

Decision Tree

New request?
├─ Bug fix restoring spec behavior? → Fix directly
├─ Typo/format/comment? → Fix directly  
├─ New feature/capability? → Create proposal
├─ Breaking change? → Create proposal
├─ Architecture change? → Create proposal
└─ Unclear? → Create proposal (safer)

Proposal Structure

  1. Create directory: changes/[change-id]/ (kebab-case, verb-led, unique)

  2. Write proposal.md:

## Why
[1-2 sentences on problem/opportunity]

## What Changes
- [Bullet list of changes]
- [Mark breaking changes with **BREAKING**]

## Impact
- Affected specs: [list capabilities]
- Affected code: [key files/systems]
  1. Create spec deltas: specs/[capability]/spec.md
## ADDED Requirements
### Requirement: New Feature
The system SHALL provide...

#### Scenario: Success case
- **WHEN** user performs action
- **THEN** expected result

## MODIFIED Requirements
### Requirement: Existing Feature
[Complete modified requirement]

## REMOVED Requirements
### Requirement: Old Feature
**Reason**: [Why removing]
**Migration**: [How to handle]

If multiple capabilities are affected, create multiple delta files under changes/[change-id]/specs/<capability>/spec.md—one per capability.

  1. Create tasks.md:
## 1. Implementation
- [ ] 1.1 Create database schema
- [ ] 1.2 Implement API endpoint
- [ ] 1.3 Add frontend component
- [ ] 1.4 Write tests
  1. Create design.md when needed: Create design.md if any of the following apply; otherwise omit it:
  • Cross-cutting change (multiple services/modules) or a new architectural pattern
  • New external dependency or significant data model changes
  • Security, performance, or migration complexity
  • Ambiguity that benefits from technical decisions before coding

Minimal design.md skeleton:

## Context
[Background, constraints, stakeholders]

## Goals / Non-Goals
- Goals: [...]
- Non-Goals: [...]

## Decisions
- Decision: [What and why]
- Alternatives considered: [Options + rationale]

## Risks / Trade-offs
- [Risk] → Mitigation

## Migration Plan
[Steps, rollback]

## Open Questions
- [...]

Spec File Format

Critical: Scenario Formatting

CORRECT (use #### headers):

#### Scenario: User login success
- **WHEN** valid credentials provided
- **THEN** return JWT token

WRONG (don't use bullets or bold):

- **Scenario: User login**  ❌
**Scenario**: User login     ❌
### Scenario: User login      ❌

Every requirement MUST have at least one scenario.

Requirement Wording

  • Use SHALL/MUST for normative requirements (avoid should/may unless intentionally non-normative)

Delta Operations

  • ## ADDED Requirements - New capabilities
  • ## MODIFIED Requirements - Changed behavior
  • ## REMOVED Requirements - Deprecated features
  • ## RENAMED Requirements - Name changes

Headers matched with trim(header) - whitespace ignored.

When to use ADDED vs MODIFIED

  • ADDED: Introduces a new capability or sub-capability that can stand alone as a requirement. Prefer ADDED when the change is orthogonal (e.g., adding "Slash Command Configuration") rather than altering the semantics of an existing requirement.
  • MODIFIED: Changes the behavior, scope, or acceptance criteria of an existing requirement. Always paste the full, updated requirement content (header + all scenarios). The archiver will replace the entire requirement with what you provide here; partial deltas will drop previous details.
  • RENAMED: Use when only the name changes. If you also change behavior, use RENAMED (name) plus MODIFIED (content) referencing the new name.

Common pitfall: Using MODIFIED to add a new concern without including the previous text. This causes loss of detail at archive time. If you arent explicitly changing the existing requirement, add a new requirement under ADDED instead.

Authoring a MODIFIED requirement correctly:

  1. Locate the existing requirement in openspec/specs/<capability>/spec.md.
  2. Copy the entire requirement block (from ### Requirement: ... through its scenarios).
  3. Paste it under ## MODIFIED Requirements and edit to reflect the new behavior.
  4. Ensure the header text matches exactly (whitespace-insensitive) and keep at least one #### Scenario:.

Example for RENAMED:

## RENAMED Requirements
- FROM: `### Requirement: Login`
- TO: `### Requirement: User Authentication`

Troubleshooting

Common Errors

"Change must have at least one delta"

  • Check changes/[name]/specs/ exists with .md files
  • Verify files have operation prefixes (## ADDED Requirements)

"Requirement must have at least one scenario"

  • Check scenarios use #### Scenario: format (4 hashtags)
  • Don't use bullet points or bold for scenario headers

Silent scenario parsing failures

  • Exact format required: #### Scenario: Name
  • Debug with: openspec show [change] --json --deltas-only

Validation Tips

# Always use strict mode for comprehensive checks
openspec validate [change] --strict

# Debug delta parsing
openspec show [change] --json | jq '.deltas'

# Check specific requirement
openspec show [spec] --json -r 1

Happy Path Script

# 1) Explore current state
openspec spec list --long
openspec list
# Optional full-text search:
# rg -n "Requirement:|Scenario:" openspec/specs
# rg -n "^#|Requirement:" openspec/changes

# 2) Choose change id and scaffold
CHANGE=add-two-factor-auth
mkdir -p openspec/changes/$CHANGE/{specs/auth}
printf "## Why\n...\n\n## What Changes\n- ...\n\n## Impact\n- ...\n" > openspec/changes/$CHANGE/proposal.md
printf "## 1. Implementation\n- [ ] 1.1 ...\n" > openspec/changes/$CHANGE/tasks.md

# 3) Add deltas (example)
cat > openspec/changes/$CHANGE/specs/auth/spec.md << 'EOF'
## ADDED Requirements
### Requirement: Two-Factor Authentication
Users MUST provide a second factor during login.

#### Scenario: OTP required
- **WHEN** valid credentials are provided
- **THEN** an OTP challenge is required
EOF

# 4) Validate
openspec validate $CHANGE --strict

Multi-Capability Example

openspec/changes/add-2fa-notify/
├── proposal.md
├── tasks.md
└── specs/
    ├── auth/
    │   └── spec.md   # ADDED: Two-Factor Authentication
    └── notifications/
        └── spec.md   # ADDED: OTP email notification

auth/spec.md

## ADDED Requirements
### Requirement: Two-Factor Authentication
...

notifications/spec.md

## ADDED Requirements
### Requirement: OTP Email Notification
...

Best Practices

Simplicity First

  • Default to <100 lines of new code
  • Single-file implementations until proven insufficient
  • Avoid frameworks without clear justification
  • Choose boring, proven patterns

Complexity Triggers

Only add complexity with:

  • Performance data showing current solution too slow
  • Concrete scale requirements (>1000 users, >100MB data)
  • Multiple proven use cases requiring abstraction

Clear References

  • Use file.ts:42 format for code locations
  • Reference specs as specs/auth/spec.md
  • Link related changes and PRs

Capability Naming

  • Use verb-noun: user-auth, payment-capture
  • Single purpose per capability
  • 10-minute understandability rule
  • Split if description needs "AND"

Change ID Naming

  • Use kebab-case, short and descriptive: add-two-factor-auth
  • Prefer verb-led prefixes: add-, update-, remove-, refactor-
  • Ensure uniqueness; if taken, append -2, -3, etc.

Tool Selection Guide

Task Tool Why
Find files by pattern Glob Fast pattern matching
Search code content Grep Optimized regex search
Read specific files Read Direct file access
Explore unknown scope Task Multi-step investigation

Error Recovery

Change Conflicts

  1. Run openspec list to see active changes
  2. Check for overlapping specs
  3. Coordinate with change owners
  4. Consider combining proposals

Validation Failures

  1. Run with --strict flag
  2. Check JSON output for details
  3. Verify spec file format
  4. Ensure scenarios properly formatted

Missing Context

  1. Read project.md first
  2. Check related specs
  3. Review recent archives
  4. Ask for clarification

Quick Reference

Stage Indicators

  • changes/ - Proposed, not yet built
  • specs/ - Built and deployed
  • archive/ - Completed changes

File Purposes

  • proposal.md - Why and what
  • tasks.md - Implementation steps
  • design.md - Technical decisions
  • spec.md - Requirements and behavior

CLI Essentials

openspec list              # What's in progress?
openspec show [item]       # View details
openspec validate --strict # Is it correct?
openspec archive <change-id> [--yes|-y]  # Mark complete (add --yes for automation)

Remember: Specs are truth. Changes are proposals. Keep them in sync.


Project-Specific Development Guidelines

以下是本项目的开发规范,所有 AI 助手在创建提案和实现代码时必须遵守。

语言要求

必须遵守:

  • 永远用中文交互
  • 注释必须使用中文
  • 文档必须使用中文
  • 日志消息必须使用中文
  • 用户可见的错误消息必须使用中文
  • 变量名、函数名、类型名必须使用英文(遵循 Go 命名规范)
  • Go 文档注释doc comments for exported APIs可以使用英文以保持生态兼容性但中文注释更佳

核心开发原则

技术栈遵守

必须遵守 (MUST):

  • 开发时严格遵守项目定义的技术栈Fiber + GORM + Viper + Zap + Lumberjack.v2 + Validator + sonic JSON + Asynq + PostgreSQL
  • 禁止使用原生调用或绕过框架的快捷方式(禁止 database/sql 直接调用、禁止 net/http 替代 Fiber、禁止 encoding/json 替代 sonic
  • 所有 HTTP 路由和中间件必须使用 Fiber 框架
  • 所有数据库操作必须通过 GORM 进行
  • 所有配置管理必须使用 Viper
  • 所有日志记录必须使用 Zap + Lumberjack.v2
  • 所有 JSON 序列化优先使用 sonic仅在必须使用标准库的场景才使用 encoding/json
  • 所有异步任务必须使用 Asynq
  • 必须使用 Go 官方工具链:go fmtgo vetgolangci-lint
  • 必须使用 Go Modules 进行依赖管理

理由:

一致的技术栈使用确保代码可维护性、团队协作效率和长期技术债务可控。绕过框架的"快捷方式"会导致代码碎片化、难以调试、性能不一致和安全漏洞。

代码质量标准

架构分层:

  • 代码必须遵循项目分层架构:Handler → Service → Store → Model
  • Handler 层只能处理 HTTP 请求/响应,不得包含业务逻辑
  • Service 层包含所有业务逻辑,支持跨模块调用
  • Store 层统一管理所有数据访问,支持事务处理
  • Model 层定义清晰的数据结构和 DTO
  • 所有依赖通过结构体字段进行依赖注入(不使用构造函数模式)

错误和响应处理:

  • 所有公共错误必须在 pkg/errors/ 中定义,使用统一错误码
  • 所有 API 响应必须使用 pkg/response/ 的统一格式
  • 所有常量必须在 pkg/constants/ 中定义和管理
  • 所有 Redis key 必须通过 pkg/constants/ 中的 Key 生成函数统一管理

代码注释和文档:

  • 必须为所有导出的函数、类型和常量编写 Go 风格的文档注释(// FunctionName does something...
  • 代码注释implementation comments应该使用中文
  • 日志消息应该使用中文
  • 用户可见的错误消息必须使用中文(通过 pkg/errors/ 的双语消息支持)
  • Go 文档注释doc comments for exported APIs可以使用英文以保持生态兼容性但中文注释更佳
  • 变量名、函数名、类型名必须使用英文(遵循 Go 命名规范)

Go 代码风格要求:

  • 必须使用 gofmt 格式化所有代码
  • 必须遵循 Effective GoGo Code Review Comments
  • 变量命名必须使用 Go 风格:userID(不是 userId)、HTTPServer(不是 HttpServer
  • 缩写词必须全部大写或全部小写:URLIDHTTP(导出)或 urlidhttp(未导出)
  • 包名必须简短、小写、单数、无下划线:userorderpkg(不是 usersuserServiceuser_service
  • 接口命名应该使用 -er 后缀:ReaderWriterLogger(不是 ILoggerLoggerInterface

常量管理规范:

  • 业务常量(状态码、类型枚举等)必须定义在 pkg/constants/constants.go 或按模块分文件
  • Redis key 必须使用函数生成,不允许硬编码字符串拼接
  • Redis key 生成函数必须遵循命名规范:Redis{Module}{Purpose}Key(params...)
  • Redis key 格式必须使用冒号分隔:{module}:{purpose}:{identifier}
  • 禁止在代码中直接使用 magic numbers未定义含义的数字字面量
  • 禁止在代码中硬编码字符串字面量URL、状态码、配置值、业务规则等
  • 当相同的字面量值在 3 个或以上位置使用时,必须提取为常量
  • 已定义的常量必须被使用,禁止重复硬编码相同的值

函数复杂度和职责分离:

  • 函数长度不得超过合理范围(通常 50-100 行,核心逻辑建议 ≤ 50 行)
  • 超过 100 行的函数必须拆分为多个小函数,每个函数只负责一件事
  • main() 函数只做编排orchestration不包含具体实现逻辑
  • main() 函数中的每个初始化步骤应该提取为独立的辅助函数
  • 编排函数必须清晰表达流程,避免嵌套的实现细节
  • 必须遵循单一职责原则Single Responsibility Principle

Go 语言惯用设计原则

核心理念:写 Go 味道的代码,不要写 Java 味道的代码

包组织:

  • 包结构必须扁平化,避免深层嵌套(最多 2-3 层)
  • 包必须按功能组织,不是按层次组织
  • 包名必须描述功能,不是类型(http 不是 httputilshandlers

推荐的 Go 风格结构:

internal/
├── user/          # user 功能的所有代码
│   ├── handler.go # HTTP handlers
│   ├── service.go # 业务逻辑
│   ├── store.go   # 数据访问
│   └── model.go   # 数据模型
├── order/
└── sim/

接口设计:

  • 接口必须小而专注1-3 个方法),不是大而全
  • 接口应该在使用方定义,不是实现方(依赖倒置)
  • 接口命名应该使用 -er 后缀:ReaderWriterStorer
  • 禁止使用 I 前缀或 Interface 后缀
  • 禁止创建只有一个实现的接口(除非明确需要抽象)

错误处理:

  • 错误必须显式返回和检查不使用异常panic/recover
  • 错误处理必须紧跟错误产生的代码
  • 必须使用 errors.Is()errors.As() 检查错误类型
  • 必须使用 fmt.Errorf() 包装错误,保留错误链
  • 自定义错误应该实现 error 接口
  • panic 只能用于不可恢复的程序错误

结构体和方法:

  • 结构体必须简单直接不是类class的替代品
  • 禁止为每个字段创建 getter/setter 方法
  • 必须直接访问导出的字段(大写开头)
  • 必须使用组合composition而不是继承inheritance
  • 构造函数应该命名为 NewNewXxx,返回具体类型
  • 禁止使用构造器模式Builder Pattern除非真正需要

并发模式:

  • 必须使用 goroutines 和 channels不是线程和锁大多数情况
  • 必须使用 context.Context 传递取消信号
  • 必须遵循"通过通信共享内存,不要通过共享内存通信"
  • 应该使用 sync.WaitGroup 等待 goroutines 完成
  • 应该使用 sync.Once 确保只执行一次
  • 禁止创建线程池类Go 运行时已处理)

命名约定:

  • 变量名必须简短且符合上下文(短作用域用短名字:i, j, k;长作用域用描述性名字)
  • 缩写词必须保持一致的大小写:URL, HTTP, ID(不是 Url, Http, Id
  • 禁止使用匈牙利命名法或类型前缀:strName, arrUsers
  • 禁止使用下划线连接(除了测试和包名)
  • 方法接收者名称应该使用 1-2 个字母的缩写,全文件保持一致

严格禁止的 Java 风格模式:

  1. 过度抽象(不需要的接口、工厂、构造器)
  2. Getter/Setter直接访问导出字段
  3. 继承层次(使用组合,不是嵌入)
  4. 异常处理(使用错误返回,不是 panic/recover
  5. 单例模式(使用包级别变量或 sync.Once
  6. 线程池(直接使用 goroutines
  7. 深层包嵌套(保持扁平结构)
  8. 类型前缀(IService, AbstractBase, ServiceImpl
  9. Bean 风格(不需要 POJO/JavaBean 模式)
  10. 过度 DI 框架(简单直接的依赖注入)

测试标准

测试要求:

  • 所有核心业务逻辑Service 层)必须有单元测试覆盖
  • 所有 API 端点必须有集成测试覆盖
  • 所有数据库操作应该有事务回滚测试
  • 测试必须使用 Go 标准测试框架(testing 包)
  • 测试文件必须与源文件同目录,命名为 *_test.go
  • 测试函数必须使用 Test 前缀:func TestUserCreate(t *testing.T)
  • 基准测试必须使用 Benchmark 前缀:func BenchmarkUserCreate(b *testing.B)

测试性能要求:

  • 测试必须可独立运行,不依赖外部服务(使用 mock 或 testcontainers
  • 单元测试必须在 100ms 内完成
  • 集成测试应该在 1s 内完成
  • 测试覆盖率应该达到 70% 以上(核心业务代码必须 90% 以上)

测试最佳实践:

  • 测试必须使用 table-driven tests 处理多个测试用例
  • 测试必须使用 t.Helper() 标记辅助函数

数据库设计原则

核心规则:

  • 数据库表之间禁止建立外键约束Foreign Key Constraints
  • GORM 模型之间禁止使用 ORM 关联关系(foreignKeyreferenceshasManybelongsTo 等标签)
  • 表之间的关联必须通过存储关联 ID 字段手动维护
  • 关联数据查询必须在代码层面显式执行,不依赖 ORM 的自动加载或预加载
  • 模型结构体只能包含简单字段,不应包含其他模型的嵌套引用
  • 数据库迁移脚本禁止包含外键约束定义
  • 数据库迁移脚本禁止包含触发器用于维护关联数据
  • 时间字段(created_atupdated_at)的更新必须由 GORM 自动处理,不使用数据库触发器

设计理由:

  1. 灵活性:业务逻辑完全在代码中控制,不受数据库约束限制
  2. 性能:无外键约束意味着无数据库层面的引用完整性检查开销
  3. 简单直接:显式的关联数据查询使数据流向清晰可见
  4. 可控性:开发者完全掌控何时查询关联数据、查询哪些关联数据
  5. 可维护性:数据库 schema 更简单,迁移更容易
  6. 分布式友好:在微服务和分布式数据库场景下更容易扩展

API 设计规范

统一响应格式:

所有 API 响应必须使用统一的 JSON 格式:

{
  "code": 0,
  "message": "success",
  "data": {},
  "timestamp": "2025-11-10T15:30:00Z"
}

API 设计要求:

  • 所有错误响应必须包含明确的错误码和错误消息(中英文双语)
  • 所有 API 端点必须遵循 RESTful 设计原则
  • 所有分页 API 必须使用统一的分页参数:pagepage_sizetotal
  • 所有时间字段必须使用 ISO 8601 格式RFC3339
  • 所有货币金额必须使用整数表示(分为单位),避免浮点精度问题
  • 所有布尔字段必须使用 true/false,不使用 0/1
  • API 版本必须通过 URL 路径管理(如 /api/v1/...

错误处理规范

统一错误处理:

  • 所有 API 错误响应必须使用统一的 JSON 格式(通过 pkg/errors/ 全局 ErrorHandler
  • 所有 Handler 层错误必须通过返回 error 传递给全局 ErrorHandler禁止手动构造错误响应
  • 所有业务错误必须使用 pkg/errors.New()pkg/errors.Wrap() 创建 AppError,并指定错误码
  • 所有错误码必须在 pkg/errors/codes.go 中统一定义和管理

Panic 处理:

  • 所有 Panic 必须被 Recover 中间件自动捕获,转换为 500 错误响应
  • 禁止在业务代码中主动 panic(除非遇到不可恢复的编程错误)
  • 禁止在 Handler 中直接使用 c.Status().JSON() 返回错误响应

错误日志:

  • 所有错误日志必须包含完整的请求上下文Request ID、路径、方法、参数等
  • 5xx 服务端错误必须自动脱敏,只返回通用错误消息,原始错误仅记录到日志
  • 4xx 客户端错误可以返回具体业务错误消息(如"用户名已存在"

错误码分类:

  • 0: 成功
  • 1000-1999: 客户端错误4xx HTTP 状态码,日志级别 Warn
  • 2000-2999: 服务端错误5xx HTTP 状态码,日志级别 Error

访问日志规范

核心要求:

  • 所有 HTTP 请求必须被记录到 access.log,无例外
  • 访问日志必须记录完整的请求参数query 参数 + request body
  • 访问日志必须记录完整的响应参数response body
  • 请求/响应 body 必须限制大小为 50KB超过部分截断并标注 ... (truncated)
  • 访问日志必须通过统一的 Logger 中间件(pkg/logger/Middleware())记录
  • 任何中间件的短路返回(认证失败、限流拒绝、参数验证失败等)禁止绕过访问日志

必需字段:

访问日志必须包含以下字段:

  • method: HTTP 方法
  • path: 请求路径
  • query: Query 参数字符串
  • status: HTTP 状态码
  • duration_ms: 请求耗时(毫秒)
  • request_id: 请求唯一 ID
  • ip: 客户端 IP
  • user_agent: 用户代理
  • user_id: 用户 ID认证后有值否则为空
  • request_body: 请求体(限制 50KB
  • response_body: 响应体(限制 50KB

日志配置:

  • 访问日志应该使用 JSON 格式,便于日志分析和监控
  • 访问日志文件必须配置自动轮转(基于大小或时间)

性能要求

性能指标:

  • API 响应时间P95必须 < 200ms数据库查询 < 50ms
  • API 响应时间P99必须 < 500ms
  • 批量操作必须使用批量查询/插入,避免 N+1 查询问题
  • 所有数据库查询必须有适当的索引支持
  • 列表查询必须实现分页,默认 page_size=20,最大 page_size=100
  • 异步任务必须用于非实时操作(批量同步、分佣计算等)

资源限制:

  • 内存使用API 服务)应该 < 500MB正常负载
  • 内存使用Worker 服务)应该 < 1GB正常负载
  • 数据库连接池必须配置合理(MaxOpenConns=25, MaxIdleConns=10, ConnMaxLifetime=5m
  • Redis 连接池必须配置合理(PoolSize=10, MinIdleConns=5

并发处理:

  • 并发操作应该使用 goroutines 和 channels不是线程池模式
  • 必须使用 context.Context 进行超时和取消控制
  • 必须使用 sync.Pool 复用频繁分配的对象(如缓冲区)

文档规范

文档结构要求:

  • 每个功能完成后必须在 docs/ 目录创建总结文档
  • 总结文档路径必须遵循规范:docs/{feature-id}/ 对应 specs/{feature-id}/
  • 总结文档文件名必须使用中文命名(例如:功能总结.md使用指南.md架构说明.md
  • 总结文档内容必须使用中文编写
  • 每次添加新功能总结文档时必须同步更新 README.md

README.md 更新要求:

  • README.md 中的功能描述必须简短精炼,让首次接触项目的开发者能快速了解
  • README.md 的功能描述应该控制在 2-3 句话以内
  • 使用中文,便于中文开发者快速理解
  • 提供到详细文档的链接
  • 按功能模块分组(如"核心功能"、"中间件"、"业务模块"等)

提案创建检查清单

在创建 OpenSpec 提案时,请确保:

  1. 技术栈合规: 提案中的技术选型必须符合项目技术栈要求
  2. 架构分层: 设计必须遵循 Handler → Service → Store → Model 分层
  3. 错误处理: 错误处理方案必须使用统一的 pkg/errors/ 系统
  4. 常量管理: 新增常量必须定义在 pkg/constants/
  5. Go 风格: 代码设计必须遵循 Go 惯用法,避免 Java 风格
  6. 测试要求: 提案必须包含测试计划(单元测试 + 集成测试)
  7. 性能考虑: 需要考虑性能指标和资源限制
  8. 文档计划: 提案必须包含文档更新计划
  9. 中文优先: 所有文档、注释、日志必须使用中文

实现检查清单

在实现 OpenSpec 提案时,请确保:

  1. 代码格式: 所有代码已通过 gofmt 格式化
  2. 代码检查: 所有代码已通过 go vetgolangci-lint 检查
  3. 测试覆盖: 核心业务逻辑测试覆盖率 ≥ 90%
  4. 性能测试: API 响应时间符合性能指标要求
  5. 错误处理: 所有错误已正确处理和记录
  6. 文档更新: README.md 和功能文档已更新
  7. 迁移脚本: 数据库变更已创建迁移脚本
  8. 日志记录: 关键操作已添加访问日志和业务日志
  9. 代码审查: 代码已通过团队审查