diff --git a/docs/architecture/data-flow-explainer.html b/docs/architecture/data-flow-explainer.html index 44757c9..75e8f63 100644 --- a/docs/architecture/data-flow-explainer.html +++ b/docs/architecture/data-flow-explainer.html @@ -1529,14 +1529,15 @@ footer .colophon {
§ 04

Mocks, contracts & factories.

-

Three things in every feature live near tests but play different roles. The mock repository is a real implementation of the repository interface — it's also the default DI binding. The contract is a portable test suite that runs against any implementation. The factory is a builder for valid entity values. The mock isn't only a test thing; that's the part that surprises people.

+

Three artifacts that sit near tests, at different distances from runtime. The mock repository is a real implementation of the interface — runtime code (DI, dev mode, storybook) reaches it. The contract is a test suite that runs against any implementation of the repo interface, mock or real. The factory builds valid entity values. The relationship between them is the interesting bit.

-
three roles · one test surface
-

Where each lives, and why.

-

The mock is the surprising one. People assume it lives in __mocks__/ because tests use it — but the DI container needs it as the default binding at runtime, and reaching into __mocks__/ from production code crosses a boundary. So the mock lives next to the real implementation, in infrastructure/repositories/. They're siblings.

+
where the boundaries are
+

Same neighborhood, different reach.

+

The mock is a test artifact, but it's also more than that — it's a real implementation of the repository interface, and runtime code reaches it directly. DI binds it as the default; dev mode runs against it when Payload isn't booted; storybook stories that need data resolve to it. The contract and factory are only reached from test files. That difference in reach is what determines where each lives.

+

So the mock sits in infrastructure/repositories/ next to the real impl — they're sibling implementations of the same interface, both legitimate citizens of the runtime layer. The contract and factory live under __-prefixed directories that nothing outside *.test.ts ever imports from.

@@ -1577,16 +1578,16 @@ footer .colophon {
-

The mock has two jobs.

+

The mock is reached from two directions. Both are legitimate, neither is "the test version":

    -
  1. Default DI binding. BlogModule binds IArticlesRepository to MockArticlesRepository at module-load time. Anything resolving that symbol — use cases, controllers, the whole chain — gets the mock until bindProductionBlog(config) swaps it for the real Payload-backed one. See §03.
  2. -
  3. Test fake (direct injection). Unit tests skip the container entirely. They construct the mock with new MockArticlesRepository() and pass it directly into the use-case factory function. No DI involved — just a closure with a fake repo.
  4. +
  5. By the DI container at runtime. BlogModule binds IArticlesRepository to MockArticlesRepository at module-load time. Anything resolving that symbol — use cases, controllers, tRPC procedures, the dev server — gets the mock until bindProductionBlog(config) swaps it for the real Payload-backed one. See §03.
  6. +
  7. By tests, via direct construction. Unit tests skip the container entirely. They construct the mock with new MockArticlesRepository() and pass it directly into the use-case factory function. Same class, different consumer — just a closure with a fake repo.
-

The contract and factory are pure test ergonomics — they only show up in *.test.ts files. Both live under __-prefixed directories that signal "test territory; not part of the public surface; not imported by runtime code." Their roles:

+

The contract and factory are reached from one direction only — tests. They never appear in runtime imports. Their roles: