"This shouldn't be a frontend concern"
The last decode is about layering: logic belongs where the domain says it does, not where it’s convenient to type. This is Module 5’s concept (dependencies point inward, each layer has a job), caught across a few reviewers and PRs.
The sharpest one was Nisha on #491. You’d handled a slow backend call by retrying on the browser. Her comment:
Mustafa, same theme, blunter: “The UI shouldn’t be doing the retries, it should all be in the backend.”
A retry is a resilience concern, and resilience is a backend responsibility. Putting it in the browser inverts the layering, the client shouldn’t own retry policy, and it can make things worse: browser retries pile onto a cold-start timeout, hammering a backend that’s already struggling. The failure was in the backend; the fix belonged in the backend. It ended up on the frontend because the frontend was the layer that happened to be under the cursor.
Nick made the same point from the other direction on #355, about a business default. A request could omit a date, meaning “use today,” and you’d defaulted it with ?? today deep in the query store:
Your fix, from the dossier: “Execute now takes a non-null DateOnly, and the endpoint resolves the default before calling, so the operational day is decided at the boundary rather than threaded down as a nullable.” Deciding what “no date” means is a product decision, so it’s resolved at the boundary (the endpoint), which then passes a definite value inward. A nullable threaded down through the layers hides where the decision actually gets made, and lets the persistence layer make a business call it has no business making.
That connects to the last piece, Nick on #397: clean data before the domain.
This is anti-corruption at the boundary. Garbage from the outside world (a Databricks row with a missing key, a malformed request body) gets rejected or cleaned at the boundary, so by the time data reaches the domain, it’s already valid. The aggregate never has to defensively re-check, its invariants are guaranteed by the fact that nothing invalid can reach it. Mustafa’s null-vs-empty comment on #508 is the subtle version: string? plus ?? "" conflates a malformed null with a deliberate empty string (a clear), so model the two states you actually mean ([Required(AllowEmptyStrings = true)]) rather than erasing the distinction.
That’s the full decode. Six concepts, the real comments that taught you each, and the design-time instinct that would have pre-empted the review. The pattern across all of them, and the note the dossier ends on: your replies were already strong DDD reasoning. What this module adds is the vocabulary and the up-front instinct, so you arrive at these designs before the review rather than during it. The final module turns the highest-frequency versions into a pre-push checklist you can run on your own diff.
Try it yourself
Why the retry was in the wrong layer
The layering principle, from Nisha's comment.
You'd put a retry on the browser side. Why did Nisha and Mustafa say that was an anti-pattern, and where did it belong?
Reveal answer
A retry is a resilience concern, and resilience is a backend responsibility. Surfacing it to the frontend inverts the layering (a client shouldn't own retry policy) and can make the underlying problem worse (browser retries pile onto a cold-start timeout). It belonged in the backend, where the actual failure and the actual fix live. The unifying rule: push a decision to the layer that owns it; don't relocate it to whatever layer was convenient to edit.
Where a default belongs
A request may omit a date, meaning "use today." Where should that default be resolved?
Show answer
Correct answer: B — At the boundary (the endpoint), before calling the use case with a non-null date
The default is a business decision (what 'no date' means), so it's resolved at the boundary: the endpoint fills in today and calls the use case with a non-null date. Burying ?? today in the query store makes the persistence layer make a product decision and hides where the decision actually happens. Decide at the edge, then thread a definite value inward.
Clean data before the domain
Nick's boundary-validation rule.
Why did Nick want rows without a valid flight key dropped at the query store, and how does that make the aggregate simpler?
Reveal answer
Because data should be cleaned and valid before it reaches the domain (anti-corruption at the boundary). The query store drops and logs rows missing a unique_flight_key, so the aggregate receives a guaranteed-present, valid id and never has to defensively re-check. Invariants are guaranteed by the fact that nothing invalid can reach the domain, so the aggregate stays focused on rules, not on re-validating its inputs.