mcpField
S
system-architecture

system-architecture

github.com/hieutrtr开发8120 次安装39 周前更新
代码仓库

关于 system-architecture

面向进行模块、服务或重大功能设计的开发者,提供 Python/React 分层架构、数据库与状态管理决策指引,并通过 architecture.md 和 ADR 记录决策。

主要功能

  1. 01分层架构与依赖方向规则
  2. 02架构方案评估流程
  3. 03数据库设计与迁移建议
  4. 04React 状态管理指引
  5. 05输出架构文档与 ADR

适用场景

  1. 01规划新模块或子系统
  2. 02评估数据库结构变更
  3. 03选择前端状态管理方案

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/hieutrtr/ai1-skills --skill system-architecture

安装后在 Claude Code 中输入/system-architecture确认已加载。

附带文件references/architecture-decision-record-template.mdreferences/layer-responsibilities.md

详细介绍

系统架构

适用场景

在以下情况下启用此技能:

  • 设计需要做出结构性决策的新模块、服务或重大功能
  • 在不同架构方案之间做出选择(例如,逻辑应放在哪里、数据流应如何组织)
  • 规划数据库架构变更或重构现有架构
  • 决定前端状态管理方案(服务端状态与客户端状态、Context 与 Store)
  • 评估新能力的技术取舍
  • 创建或审查架构决策记录(ADR)
  • 从头搭建新项目或主要子系统

输入: 如果存在 plan.md(由 project-planner 生成),请阅读以了解功能范围和受影响模块的背景。否则,直接根据用户请求开展工作。

输出: 将架构决策写入 architecture.md,并在 docs/adr/ADR-NNN-<title>.md 中创建 ADR。告知用户:“架构已写入 architecture.md。运行 /api-design-patterns 编写 API 合约,或运行 /task-decomposition 制定实现任务。”

请勿将此技能用于:

  • 编写实现代码(使用 python-backend-expert 或 react-frontend-expert)
  • 设计 API 合约或端点规范(使用 api-design-patterns)
  • 制定测试模式或策略(使用 pytest-patterns 或 react-testing-patterns)
  • 做出部署或基础设施决策(使用 docker-best-practices 或 deployment-pipeline)

说明

项目分层架构

标准的 Python/React 全栈架构遵循分层模式,并严格遵守依赖方向。

后端分层(FastAPI)
HTTP Request
    ↓
┌─────────────────────┐
│   Routers (routes/)  │  ← HTTP concerns: request parsing, response formatting, status codes
│                      │     Uses: Depends() for injection, Pydantic schemas for validation
├─────────────────────┤
│   Services           │  ← Business logic: orchestration, validation rules, domain operations
│   (services/)        │     No HTTP awareness. Raises domain exceptions, not HTTPException.
├─────────────────────┤
│   Repositories       │  ← Data access: queries, CRUD operations, database interactions
│   (repositories/)    │     No business logic. Returns model instances or None.
├─────────────────────┤
│   Models (models/)   │  ← SQLAlchemy ORM models: table definitions, relationships, indexes
│   Schemas (schemas/) │  ← Pydantic v2 models: request/response contracts, validation
└─────────────────────┘
    ↓
Database

依赖方向规则:

  • 路由器依赖服务(绝不直接依赖仓储)
  • 服务依赖仓储(绝不依赖路由器)
  • 仓储依赖模型(绝不依赖服务)
  • 架构各层共享 Schema,但 Schema 本身不定义任何依赖
  • 绝不跳过层级:路由中不得直接访问数据库

依赖注入模式:

# Router depends on Service via Depends()
@router.post("/users", response_model=UserResponse)
async def create_user(
    data: UserCreate,
    service: UserService = Depends(get_user_service),
) -> UserResponse:
    return await service.create_user(data)

# Service depends on Repository via constructor injection
class UserService:
    def __init__(self, repo: UserRepository) -> None:
        self.repo = repo

# Repository depends on AsyncSession via Depends()
class UserRepository:
    def __init__(self, session: AsyncSession) -> None:
        self.session = session
前端分层(React/TypeScript)
┌─────────────────────┐
│   Pages (pages/)     │  ← Route-level components: data fetching, layout composition
├─────────────────────┤
│   Layouts            │  ← Page structure: navigation, sidebars, content areas
│   (layouts/)         │
├─────────────────────┤
│   Features           │  ← Domain-specific: UserProfile, OrderList, ChatPanel
│   (features/)        │     Composed from shared components + hooks
├─────────────────────┤
│   Shared Components  │  ← Reusable UI: Button, Modal, Table, Form, Input
│   (components/)      │     No business logic. Configurable via props.
├─────────────────────┤
│   Hooks (hooks/)     │  ← Custom hooks: useAuth, usePagination, useDebounce
│   API (api/)         │  ← API client functions, TanStack Query configurations
├─────────────────────┤
│   Types (types/)     │  ← Shared TypeScript interfaces and type definitions
└─────────────────────┘

组件依赖方向:

  • 页面导入功能模块和布局
  • 功能模块导入共享组件和 Hooks
  • 共享组件只能导入其他共享组件和类型
  • Hooks 导入 API 函数和类型
  • API 函数只能导入类型
决策框架

遇到架构决策时,请遵循以下结构化流程:

第 1 步:明确问题
  • 需要什么能力?
  • 有哪些非功能性需求?(性能、可扩展性、可维护性)
  • 存在哪些限制?(团队规模、时间安排、现有基础设施)
第 2 步:确定选项
  • 列出 2–3 个可行的架构方案
  • 对于每个方案,记录:
    • 工作方式(简要的技术说明)
    • 优势
    • 劣势
    • 风险
第 3 步:根据标准评估
标准权重说明
可维护性高团队能否轻松理解、修改和调试?
可测试性高能否单独测试每个组件?
性能中是否满足延迟和吞吐量要求?
团队熟悉度中团队是否有使用此方案的经验?
运维成本低基础设施和维护成本是多少?
未来灵活性低随着需求变化,此方案能否轻松演进?
第 4 步:做出决定并记录
  • 选择最符合加权标准的方案
  • 在 ADR 中记录决策(参见 references/architecture-decision-record-template.md)
  • 记录未选择的方案及原因——这些背景信息对未来决策很有价值
第 5 步:沟通
  • 与团队分享 ADR
  • 确定所需的迁移或发布步骤
  • 标注可逆性:这是单向门还是双向门?
数据库架构设计
设计原则
  1. 从规范化开始(3NF)——只有确认存在性能瓶颈时才进行反规范化,切勿凭空猜测
  2. 每项逻辑变更对应一个迁移——每个 Alembic 迁移都应代表一项独立、完整的架构修改
  3. 始终包含降级操作——每个迁移都必须有可正常运行的 downgrade() 函数
  4. 有策略地创建索引:
    • 主键(自动创建)
    • 外键(始终创建)
    • 常用查询的 WHERE 子句中涉及的列
    • 多列查询使用复合索引
    • 筛选查询使用部分索引(例如 WHERE is_active = true)
SQLAlchemy 2.0 异步模式
# Model definition with Mapped types (SQLAlchemy 2.0 style)
class User(Base):
    __tablename__ = "users"

    id: Mapped[int] = mapped_column(primary_key=True)
    email: Mapped[str] = mapped_column(String(255), unique=True, index=True)
    is_active: Mapped[bool] = mapped_column(default=True)
    created_at: Mapped[datetime] = mapped_column(server_default=func.now())

    # Relationships: ALWAYS use eager loading with async
    posts: Mapped[list["Post"]] = relationship(
        back_populates="author",
        lazy="selectin",  # or "joined" — NEVER "lazy" with async
    )

异步会话规则:

  • 每个请求使用一个 AsyncSession——绝不在并发任务之间共享
  • 使用 async with 上下文管理器自动清理
  • 让会话边界与事务边界保持一致
  • 使用 selectin 或 joined 加载——延迟加载与 asyncio 不兼容
  • 仅在处理遗留代码时,才将 run_sync() 作为最后手段
迁移规划
  1. 架构变更 → 生成迁移:alembic revision --autogenerate -m "description"
  2. 检查生成的迁移——验证列类型、索引和约束
  3. 测试升级:alembic upgrade head
  4. 测试降级:alembic downgrade -1
  5. 测试数据保留:确保现有数据在往返操作后仍然保留
前端架构
状态管理决策树
Is the data from the server?
├── YES → Use TanStack Query (useQuery, useMutation)
│         Configure staleTime, gcTime, query keys
│
└── NO → Is it needed across multiple components?
         ├── YES → Is it complex with actions/reducers?
         │         ├── YES → Use Zustand store
         │         └── NO  → Use React Context
         │
         └── NO → Use useState / useReducer locally

TanStack Query 约定:

  • 查询键:[resource, ...identifiers](例如 ["users", userId]、["posts", { page, limit }])
  • 使用 queryOptions() 工厂集中定义键和函数,避免复制粘贴导致的键错误
  • 根据数据新鲜度需求设置 staleTime(默认值 0 对大多数情况来说过于激进)
  • 变更后使用 invalidateQueries() 使缓存失效——不要手动调用 refetch()
  • 处理所有状态:isPending、isError、data

组件设计规则:

  • 使用 props 配置组件,使用 hooks 获取数据
  • 仅在必要时向上提升状态——不要过早创建 context
  • 组件保持在 200 行以内——超出时提取子组件或自定义 hooks
  • 优先使用 children 和组合,而非深层 props 传递
路由结构

组织路由,使其与 URL 结构保持一致:

src/
├── pages/
│   ├── HomePage.tsx           → /
│   ├── LoginPage.tsx          → /login
│   ├── users/
│   │   ├── UserListPage.tsx   → /users
│   │   └── UserDetailPage.tsx → /users/:id
│   └── settings/
│       └── SettingsPage.tsx   → /settings
横切关注点
身份验证流程
Login Request
    ↓
Backend: Validate credentials → Generate JWT (access + refresh tokens)
    ↓
Frontend: Store access token in memory, refresh token in httpOnly cookie
    ↓
API Calls: Attach access token via Authorization header
    ↓
Token Expired: Use refresh token to obtain new access token
    ↓
Refresh Failed: Redirect to login

身份验证的架构决策:

  • 访问令牌:有效期较短(15-30 分钟),存储在内存中(而非 localStorage)
  • 刷新令牌:有效期较长(7-30 天),存储在 httpOnly cookie 中
  • 后端:使用 FastAPI Depends() 链进行令牌验证 → 提取用户信息 → 检查权限
  • 前端:Auth context 提供 user、login()、logout()、isAuthenticated
错误处理策略

应在适当的层级处理错误:

层级错误类型操作
路由器HTTPException返回带状态码的 HTTP 错误响应
服务领域异常抛出自定义异常(例如 UserNotFoundError)
存储库数据库异常捕获并重新抛出为领域异常,或直接向上传播
前端API 错误显示用户易于理解的消息,并在适当时重试

后端异常层级结构:

class AppError(Exception):
    """Base application error."""

class NotFoundError(AppError):
    """Resource not found."""

class ConflictError(AppError):
    """Resource conflict (duplicate, version mismatch)."""

class ValidationError(AppError):
    """Business rule violation."""

路由器级异常处理程序会将领域异常映射为 HTTP 响应:

@app.exception_handler(NotFoundError)
async def not_found_handler(request: Request, exc: NotFoundError):
    return JSONResponse(status_code=404, content={"detail": str(exc)})
日志架构

后端(structlog):

  • 在生产环境中输出结构化 JSON 日志
  • 在开发环境中输出便于阅读的控制台日志
  • 在中间件层绑定请求上下文(request_id、user_id)
  • 在服务层记录日志(业务事件),而非在存储库层记录(过于嘈杂)
  • 使用日志级别:DEBUG(仅开发环境)、INFO(业务事件)、WARNING(可恢复的问题)、ERROR(需要关注的故障)

前端:

  • 在开发环境中使用 console.*
  • 在生产环境中向后端或 Sentry 发送结构化错误报告
  • 记录用户操作以便调试,而非用于分析
配置管理

后端(pydantic-settings):

class Settings(BaseSettings):
    model_config = SettingsConfigDict(env_file=".env")

    database_url: str
    redis_url: str = "redis://localhost:6379"
    jwt_secret: str
    debug: bool = False

前端(环境变量):

  • 使用 VITE_API_URL 设置 API 基础 URL
  • 通过 Vite 的 import.meta.env 在构建时注入
  • 前端环境变量中不存放密钥
输出文件
architecture.md

在项目根目录下将架构文档写入 architecture.md:

# Architecture: [Feature/System Name]

## Overview
[1-2 sentence summary of the architectural approach]

## Layer Structure
[Backend and frontend layer descriptions from this skill's patterns]

## Key Decisions
[Summary of decisions made, with links to ADRs]

## Database Schema
[Entity descriptions, relationships, key indexes]

## Cross-Cutting Concerns
[Auth, error handling, logging approach]

## Next Steps
- Run `/api-design-patterns` to define API contracts
- Run `/task-decomposition` to create implementation tasks
ADR

对于每个重要决策,在 docs/adr/ 中创建一份 ADR:

# ADR-NNN: [Decision Title]

## Status
Accepted | Proposed | Superseded

## Context
[Why this decision is needed]

## Decision
[What we decided]

## Consequences
[Positive and negative outcomes]

按顺序为 ADR 编号(ADR-001、ADR-002 等)。

示例

架构决策:实时通知

问题: 应用需要为用户提供实时通知(新消息、状态更新)。

评估的选项:

选项优点缺点
WebSocket真正的双向通信、延迟低连接管理复杂、扩展更困难
Server-Sent Events (SSE)简单、基于 HTTP、自动重连单向通信(仅服务器→客户端)、浏览器连接数有限
Polling实现最简单、到处都能运行延迟较高、造成不必要的服务器负载

决策: 在此场景中使用 WebSocket。

理由: 通知需要低延迟,而且系统最终需要双向通信(输入状态指示、在线状态)。仅针对通知而言,SSE 可以胜任,但未来需要双向通信时还得采用另一套方案。轮询会导致实时用户体验无法接受的延迟。

架构:

  • 后端:FastAPI WebSocket 端点,使用 ConnectionManager 类
  • 前端:自定义 useWebSocket hook,支持自动重连
  • 扩展:使用 Redis pub/sub 分发多实例消息
  • 持久化:将通知存储在数据库中,以供离线用户查看
  • 回退方案:使用 REST 端点提供通知历史和初始加载

完整的 ADR 格式请参阅 references/architecture-decision-record-template.md。

边缘情况

单体架构与微服务

对于开发人员少于 10 人的团队,默认采用模块化单体架构。模块化单体架构具备以下优点:

  • 模块边界清晰,且没有网络开销
  • 共用数据库,同时使用模块专属的架构
  • 易于重构和浏览代码
  • 部署和调试简单

仅在以下情况下考虑微服务:

  • 特定组件需要独立扩展
  • 不同模块需要使用不同的技术栈
  • 团队规模超过 10 人,且所有权边界清晰
  • 业务要求部署独立

迁移路径: 在单体架构中设计模块边界时,应将模块视作服务(不直接跨模块访问数据库,而是通过服务接口通信)。这样在有需要时,就能轻松拆分为微服务。

何时打破分层模式

对于标准 CRUD 操作,应遵循严格的 Router → Service → Repository 模式。可接受的例外包括:

  • 后台任务: 可以直接调用服务,无需经过路由器
  • 事件处理器: 领域事件监听器可以在任何上下文中调用服务
  • CLI 命令: 管理脚本可以直接访问服务或仓库
  • 迁移: 数据迁移可以直接访问模型(无需服务层或仓库层)
  • 健康检查: 可以直接访问数据库,进行简单的连通性验证

在所有情况下,业务逻辑仍应放在服务层中——这些例外涉及的是入口点,而不是绕过业务规则。

演进架构

需要更改架构时:

  1. 编写 ADR,记录更改的动机和提议
  2. 确定所有受影响的模块及其依赖项
  3. 规划渐进式迁移——绝不进行大爆炸式重写
  4. 在过渡期间保持向后兼容(绞杀者无花果模式)
  5. 设定完成迁移并移除旧代码的期限

评论

支持 Markdown