用途:为 Phoenix 应用设计与实现上下文(有界上下文)提供参考,涉及上下文创建与拆分、Scope(1.8+)、Ecto.Multi、PubSub、路由、Plug 和控制器。Ash 项目用 Ash.Domain 替代 Phoenix 上下文做数据访问,应改用 ash-framework 技能;上下文边界与 PubSub 模式仍适用。
核心原则:上下文拥有自己的数据,不得通过 Repo 直接查询其他上下文的 schema;Phoenix 1.8+ 中每个上下文函数必须以 scope 作为第一个参数;控制器/LiveView 保持轻薄,业务逻辑留在上下文中;schema 中不产生副作用,带副作用的操作使用 Ecto.Multi。
结构:上下文目录(如 accounts/)存放 schema 与 scope.ex,上下文模块(如 accounts.ex)作为公开 API。
Scope 用法:函数接收 %Scope{} 并按调用者过滤查询,例如 list_posts(%Scope{} = scope) 中按 scope.user.id 过滤;create_post 同样以 scope 设置 user_id 并广播。
拆分判断:模块超过约 400 行、函数不共享领域语言、理论上可拆为独立微服务、可由团队成员独立负责时考虑拆分;共享词汇与领域概念、函数常一起操作同一数据、拆分会导致过多跨上下文调用时保持合并。
跨上下文引用:按 ID 引用并在边界转换,例如通过 Accounts.fetch_user(scope, user_id) 获取用户;不要 alias 其他上下文的 schema 或跨 schema 联表查询。
反模式:避免服务对象(如 UserCreationService)、包装 Repo 的仓储模式、控制器中直接调用 Repo、schema 回调中产生副作用。
版本说明:Phoenix 1.8+ 使用内置 %Scope{} 结构;1.7 需手动实现授权上下文。详细模式见 references 下的 context-patterns.md、scopes-auth.md、routing-patterns.md、plug-patterns.md、json-api-patterns.md。