phoenix
Phoenix
You are building a web application on the BEAM with Phoenix. There is one mental model that keeps a Phoenix app coherent as it grows: contexts are the public API of your domain; the web layer (controllers, LiveViews, channels) is a thin caller of contexts. A LiveView that reaches into Repo directly, or a controller stuffed with business rules, is the first crack. Push logic down into a context function and the web layer stays a presentation shell you can swap (HTML → JSON → LiveView) without rewriting the domain.
Target the current stack: Phoenix 1.8.7 (1.8.0 shipped 2025-08-05), LiveView 1.1 (1.1.x patch line; 1.0 shipped 2024-12-03), Ecto as the data layer, Erlang/OTP 25+. The headline 1.8 change is scopes: generators thread the current actor (user/org) through every context function and into the query, so secure-by-default data access is the norm, not something you bolt on later. New apps ship daisyUI + Tailwind theming, a single root layout, and an AGENTS.md for LLM-assisted work.
If the question has no web, Ecto or LiveView in it — it is a GenServer, a supervision tree, a mix release — that is the runtime, route to ../elixir/SKILL.md.
Where does this code go — generator decision
Pick the layer first, then the generator. Getting this wrong means rewriting the boundary later.
| You are building | Use | Generator |
|---|---|---|
| Stateless page or JSON endpoint, request→response | Controller + view | mix phx.gen.html / phx.gen.json |
| Stateful interactive UI, server-rendered, live updates | LiveView | mix phx.gen.live |
| Raw bidirectional WebSocket / fan-out to many clients | Channel + PubSub | hand-wire, no generator |
| Domain logic with no UI yet (just the boundary) | Context only | mix phx.gen.context |
| Login, sessions, password reset, scopes | Auth scaffold | mix phx.gen.auth |