F5.09 · part 3 of 3
What ships in F6
F6 brings Phoenix. The temptation is to treat that as a rewrite, but the whole point of the boundary
is that it is not. F6 replaces one thing — the thin web layer — with Phoenix and
LiveView, and adds the Phoenix endpoint to the same supervision tree. Everything else is kept:
the Portal facade is called unchanged, the closed %Portal.Error{}
contract is the render surface, the engine and store behind the port are untouched, and the F5.07 tests carry
over because they were written against the facade, not the web. The handoff is small on purpose: a stable
boundary means the next chapter inherits a working engine and only has to dress it.
Three things F6 builds on. Select one to see what F6 does with it.
What F6 inherits
Three pieces cross the chapter boundary intact. The facade is the API F6 calls; the error contract is the closed set F6 renders; the supervision tree is the structure F6 extends with its endpoint. None of them is rewritten. Select one.
What F6 builds on · select one
F6 builds on: the facade
what F6 does: F6 calls it unchanged
A good handoff is measured by how little moves. If the next chapter can call what you built without reading how you built it, the boundary held.
Kept and replaced
Only the web layer is replaced. The thin Plug router served by
Bandit (F5.01) becomes Phoenix with LiveView; everything below the facade stays as it
is. The picture is lopsided on purpose — that imbalance is the dividend of building a boundary.
At the F5 → F6 boundary
One box moves; four stay. The boundary drawn in F5.08 is what makes the column on the right immune to the change on the left.
The endpoint joins the tree
Concretely, the only change to the assembly is one more child. F6 adds PortalWeb.Endpoint
to the supervision tree from F5.09.1; the engine and store entries are unchanged, and the same
:one_for_one strategy now supervises the web too.
# F6: Phoenix adds its endpoint to the SAME tree — engine and store are untouched def start(_type, _args) do children = [ Portal.EventStore.adapter(), # kept from F5.09.1 {Portal.Engine, []}, # kept from F5.09.1 PortalWeb.Endpoint # NEW in F6: the Phoenix endpoint, supervised alongside ] Supervisor.start_link(children, strategy: :one_for_one, name: Portal.Supervisor) end
The LiveView from F5.09.2 stops being a sketch and becomes the real thing, mounted by this endpoint — still calling only the facade.
The chapter is done
F5 set out to build the Portal engine the pragmatic way, and it is finished when each of these holds: the app
runs from mix run and answers a real request; a command is checked by a contract and
recorded as an event; state is a fold of the log held in a supervised process that replays on restart; the
suite covers the pure core, properties, and the contract; the boundary is a port, a facade, and a closed error
contract; and the whole thing is assembled, mounted behind a LiveView sketch, and described by a spec with
build prompts. Each module left the Portal runnable, so the finale is an assembly, not a reckoning.
F5 · the engine
A thin server grew into a supervised, contract-checked engine behind a stable facade.
F6 · Phoenix
Replace the web layer, call the same facade, render the same error contract.
That closes F5 · Pragmatic Programming. The Portal began as a thin server and ends as a supervised engine behind a stable facade, mounted under a LiveView sketch, with a spec and prompts to rebuild it from nothing. F6 picks it up. Back to the lab or the F5 overview.
References
Primary sources for this lesson, and where it connects in the course.
Sources
- Phoenix — Phoenix.LiveView — server-rendered, stateful UI over the engine.
- Phoenix — Phoenix.Component (HEEx) — function components and the HEEx template.
- Elixir — Supervisor — the engine runs under a supervision tree.