Phoenix上下文设计Skill phoenix-contexts

Phoenix上下文设计技能用于在Elixir的Phoenix框架中设计和实现有界上下文、管理范围、优化模块结构。它帮助开发者组织业务逻辑、确保数据隔离、遵循最佳实践,提升后端开发效率和代码可维护性。关键词:Phoenix、上下文、范围、Elixir、后端开发、架构设计、有界上下文、模块结构、业务逻辑、数据隔离。

后端开发 0 次安装 0 次浏览 更新于 3/11/2026

名称: phoenix-contexts 描述: Phoenix上下文模式、有界上下文设计、范围以及模块结构。在设计上下文、组织业务逻辑或规划模块结构时加载。 用户可调用: 假

Phoenix上下文参考

设计和实现Phoenix上下文(有界上下文)的参考。

铁律 — 切勿违反

  1. 上下文拥有其数据 — 切勿通过Repo直接查询另一个上下文的架构
  2. 范围是强制性的(Phoenix 1.8+) — 每个上下文函数必须接受范围作为第一个参数
  3. 瘦控制器/LiveView — 控制器处理HTTP,业务逻辑保持在上下文中
  4. 架构中无副作用 — 使用Ecto.Multi处理具有副作用的事务

上下文结构

lib/my_app/
├── accounts/           # 上下文目录
│   ├── user.ex         # 架构
│   ├── scope.ex        # 范围结构体(Phoenix 1.8+)
├── accounts.ex         # 上下文模块(公共API)

Phoenix 1.8+ 范围(关键)

所有上下文函数必须接受范围作为第一个参数:

def list_posts(%Scope{} = scope) do
  from(p in Post, where: p.user_id == ^scope.user.id)
  |> Repo.all()
end

def create_post(%Scope{} = scope, attrs) do
  %Post{user_id: scope.user.id}
  |> Post.changeset(attrs)
  |> Repo.insert()
  |> broadcast(scope, :created)
end

快速决策

何时拆分上下文?

  • 模块超过约400行
  • 函数不共享领域语言
  • 理论上可以是独立的微服务
  • 团队成员可以独立拥有

何时保持在一起?

  • 资源共享词汇和领域概念
  • 函数经常一起操作相同数据
  • 拆分会产生过多的跨上下文调用

跨上下文引用

# ✅ 通过ID引用,在边界处转换
def create_order(%Scope{} = scope, user_id, product_ids) do
  with {:ok, user} <- Accounts.fetch_user(scope, user_id) do
    do_create_order(scope, user.id, product_ids)
  end
end

# ❌ 深入到其他上下文的内部
alias MyApp.Accounts.User  # 不要这样做
Repo.all(from o in Order, join: u in User, ...)  # 不要查询其他架构

反模式

错误 正确
服务对象(UserCreationService 上下文函数(Accounts.create_user/2
包裹Repo的仓储模式 Repo就是仓储
控制器中直接调用Repo 委托给上下文
具有副作用的架构回调 使用Ecto.Multi

版本说明

  • Phoenix 1.8+:使用内置的%Scope{}结构体进行授权上下文
  • Phoenix 1.7:需要手动授权上下文(见references/scopes-auth.md“预范围模式”)

参考资料

详细模式见:

  • references/context-patterns.md - 完整上下文模块、PubSub、Multi、跨边界
  • references/scopes-auth.md - 范围结构体、多租户、授权、插件
  • references/routing-patterns.md - 已验证路由、管道、API授权
  • references/plug-patterns.md - 函数/模块插件、放置、守卫
  • references/json-api-patterns.md - JSON控制器、FallbackController、API授权