Reads and writes that want opposite things
The write side needs normalised tables and transactions. The dashboard needs one wide row per customer, and building it joins nine tables on every page load.
Splitting the models is the answer, but the two stores now have to be kept in step — and the thing that does that is where the whole design lives or dies.
Boundaries, outermost first: Write side: Write store (normalised), Command handler (validates) Read side: Read store (one row per view; FAILED: too slow), Query handler (no joins) Outside every boundary: an empty slot for the keeps them in step Connections: Command handler calls Write store — persist (step 1) Write store publishes to keeps them in step — change events (step 2) keeps them in step publishes to Read store — upsert view (step 3) Query handler calls Read store — single read