mcpField
C
convex-ddd-architecture

convex-ddd-architecture

github.com/sebas5384开发0288 次安装21 周前更新
代码仓库

关于 convex-ddd-architecture

convex-ddd-architecture 是一项参考技能,指导团队用领域驱动设计和六边形架构组织 Convex 项目。它通过约定、模式和参考文档,帮助隔离业务规则、持久化逻辑及外部集成。

主要功能

  1. 01DDD 与六边形架构指引
  2. 02领域、仓储和适配器边界
  3. 03Convex Schema 与文件约定
  4. 04自定义函数和触发器模式
  5. 05迁移与命名参考

适用场景

  1. 01规划新的 Convex 子领域
  2. 02将旧 Convex 代码迁向 DDD
  3. 03将业务规则从处理器中分离
  4. 04统一 Convex 项目结构

安装

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

$npx skills add https://github.com/sebas5384/agentic-stuff --skill convex-ddd-architecture

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

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
adapters.md
custom-functions.md
domain-models.md
eslint-rules.md
examples.md
learnings.md
migrations.md
naming.md
repositories.md
triggers.md
value-objects.md

详细介绍

Convex DDD 架构

用于通过 DDD 和六边形架构组织 Convex 项目的参考技能。它将领域逻辑与数据库及外部 API 相关逻辑隔离开来,让变更局限于局部,演进时也更安全。

适用场景

当工作涉及以下一个或多个信号时,使用此技能:

  • 设计新的 Convex 子领域(schema、queries、mutations、domain、adapters)
  • 将旧版 Convex 代码迁移到 DDD/六边形架构边界
  • 业务规则逐渐进入处理器,而不是聚合
  • 直接访问 ctx.db 的代码扩散到仓储之外
  • 外部 API 调用需要重试、编排或转换层
  • 团队需要在 Convex 项目中统一文件布局和命名
  • 选择或重构标识符(变量、函数):导出项/模型使用领域名词;模块/函数内部若作用域已能明确含义,则使用较短名称(naming.md)

对于速度比架构边界更重要的小型原型,不要将此规范作为严格模板。

项目结构

./convex/
  _generated/                       # Auto-generated by Convex (do not edit)
  _shared/                          # Cross-domain utilities
    _libs/
      aggregate.ts                  # Base aggregate interface
      repository.ts                 # Base repository interface
  _triggers.ts                      # Central trigger registry
  customFunctions.ts                # Wrapped mutation/query exports
  schema.ts                         # Composed schema from all sub-domains
  [subDomainName]/                  # Each sub-domain folder (camelCase)
    _libs/
      stripeClient.ts               # Libs or helpers
    _tables.ts                      # Database schema tables
    _triggers.ts                    # Sub-domain trigger handlers
    _seeds.ts                       # Seeds for models
    _workflows.ts                   # Convex workflows
    queries/
      [queryName].ts                # One query per file, export default
    mutations/
      [mutationName].ts             # One mutation per file, export default
    domain/
      [modelName].model.ts          # Model schema, types, Aggregate
      [modelName].repository.ts     # Repository interface
    adapters/
      [actionName].action.ts        # External API actions
      [modelName].repository.ts     # Repository implementation

命名规则

  • 文件:使用 camelCase(contactRepository.ts、sendInvoice.action.ts)
  • 下划线前缀:用于非领域文件(_tables.ts、_triggers.ts)
  • 目录与文件:从文件开始(例如 _workflows.ts),扩展后再拆分为目录
  • 标识符:导出项、模型和 API 使用领域词汇;在函数内部,若父级名称/类型已提供上下文,则优先使用简短名词——不要在每个局部名称中重复文件名或父级名称。详情请参阅:naming.md。

快速参考

关注点规则
Convex 导入从 customFunctions.ts 导入 mutation、query、internalMutation
函数导出每个文件一个函数,并使用 export default
领域模型形状包含 _id、_creationTime,并通过 withoutSystemFields 创建不含系统字段的 New<Model>
持久化边界通过 adapters/ 中的仓储访问数据库
外部集成在操作中进行转换;业务决策留在 mutations/聚合中
_tables.ts仅包含 defineTable(NewXModel.fields) 和索引——字段定义放在领域模型文件中,绝不内联定义
Schema从各子领域导出的 _tables 组合根 schema

核心模式

1) 自定义函数边界

始终从 customFunctions.ts 导入 mutation、query、internalMutation,而不是从 _generated/server 导入。请参阅 custom-functions.md。

// ✅ Correct
import { mutation } from "../../customFunctions";

// ❌ Wrong - bypasses trigger integration
import { mutation } from "../../_generated/server";
2) API 路径约定

每个文件一个函数,使用命名定义和默认导出:

// convex/combat/mutations/createBattle.ts
import { mutation } from "../../customFunctions";
import { v } from "convex/values";

const createBattle = mutation({
  args: { heroId: v.id("heroProfiles") },
  handler: async (ctx, args) => {
    // ...
  },
});

export default createBattle;

前端使用时添加 .default 后缀:

import { api } from "@/convex/_generated/api";
useMutation(api.combat.mutations.createBattle.default);
useQuery(api.economy.queries.getHeroProfile.default);

避免使用 export const createBattle 这样的命名导出——这会产生 api.combat.mutations.createBattle.createBattle 这样的冗余路径。

3) Schema 组合

通过子领域表组合 schema:

// convex/schema.ts
import { defineSchema } from "convex/server";
import { combatTables } from "./combat/_tables";
import { economyTables } from "./economy/_tables";

export default defineSchema({
  ...combatTables,
  ...economyTables,
});
4) 领域、仓储与适配器的职责
5) 工作流与触发器安全性
  • 优先采用单向流程:UI mutation -> 定时操作/工作流 -> mutation -> 响应式查询
  • 保持触发器处理器轻量;尽可能安排异步工作
  • 将触发器代码视为对事务敏感的代码

常见错误

  • 局部变量名称过于冗长,只是重复文件或函数的上下文,而非缩小作用范围或提取更小的单元(naming.md)
  • 直接从 _generated/server 导入处理程序,绕过共享封装
  • 在操作或处理程序中编写业务规则,而非放在聚合中
  • 通过临时修改字段更新记录,而非使用聚合状态转换
  • 在需要聚合行为的场景中返回原始记录
  • 添加必填架构字段时未制定分阶段迁移策略(migrations.md)
  • 在 _tables.ts 中内联定义字段,而不是使用 defineTable(NewXModel.fields)——这会导致架构重复,并破坏模型作为事实来源的不变性
  • 开始新的子领域时,将现有(可能并非基于 DDD 的)模块用作参考——务必从 examples.md 中借鉴模式,而不要参考可能早于这些指南的相邻代码

参考资料

配套文档位于 references/ 目录中。

编写任何新的子领域代码前请先阅读:

  • examples.md — 完整的实践示例(发票领域、RPG 游戏),展示完整技术栈:模型 → _tables.ts → 仓储接口 → 适配器 → 变更。从这里开始。
  • learnings.md — 从迁移中总结出的重要规则;涵盖 _tables.ts 的陷阱、DTO 的放置位置以及渐进式重构策略。

任务涉及以下特定主题时请阅读:

评论

支持 Markdown