Cvičení 02 · Eventy jako zdroj pravdy, stav = fold(events)

Event Sourcing kalkulačky

  • event stream
  • aggregate
  • current state

Princip

Místo přepsání řádku zapíšeme fakta v minulém čase: CalculationCreated, IncomeChanged, PropertyPriceChanged, RateChanged, TermChanged, CalculationCompleted.

Aktuální stav (agregát) není uložený, vzniká přehráním událostí od začátku streamu: stav = fold(events). Příkaz se nejdřív ověří proti stavu (invariant: splátka max. 45 % příjmu) a teprve pak vznikne událost.

Event store je jen přidávání na konec. Událost se nemění a nemaže.

Co sledovat

  • Každá změna přidá událost se správnou verzí streamu.
  • Aktuální stav vpravo se vždy rovná přehrání celého streamu.
  • Dokončení výpočtu s příliš vysokou splátkou agregát odmítne.

Bez řešení / S řešením

Bez řešení

Spustit CRUD verzi

Stejná sekvence změn v CRUD modelu: na konci zbude jen poslední stav a otázka „kolikrát se měnil příjem a z čeho“ nemá odpověď.

Spustit v simulátoru bez řešení

S řešením

Spustit Event Sourcing

Stejné změny jako události. Historii lze přehrát, dotázat („příjem se měnil 2ד) i vysvětlit. Nový pohled nemusíme znát předem, musíme jen zachovat fakta.

Spustit v simulátoru s řešením

Co udělat: Klikni na „Spustit CRUD verzi“. Na co se dívat: Po čtyřech změnách zbyde jen poslední stav a nevíme, kolikrát se příjem měnil. Simulátor potřebuje JavaScript a běží jako samostatná aplikace.

Zkus to ve svém projektu

Zkopíruj prompt do svého coding agenta (Claude Code, Copilot, Codex…) a spusť ho v repozitáři svého projektu.

Zavést append-only event stream pro agregát kalkulačky a odvodit z něj aktuální stav.

Jazyk
Varianta
# Úkol pro coding agenta: Event Sourcing kalkulačky

Stack: Java. Režim: s vedením.
Cíl: Zavést append-only event stream pro agregát kalkulačky a odvodit z něj aktuální stav.

## Kontext existujícího kódu

Pracuješ v existujícím projektu (Java backend (typicky Java 21, Spring Boot, JPA nebo JDBC). Použij build nástroj a styl, který projekt už má (Maven/Gradle, JUnit 5).).
Doména: hypoteční kalkulačka, která se postupně mění v event-driven systém (kalkulačka, rizika, schvalování, identita, účet, dokumenty, výplata).

Nejdřív čti, nic neměň. Najdi a stručně shrň:
- Entitu/model kalkulačky a všechna místa, která ji mění.
- Pravidla (invarianty), která se dnes kontrolují při uložení.
- Existující tabulku/kolekci kalkulací, kterou nechceš rozbít.
- Které z těchto částí už v projektu existují a které chybí. Než napíšeš vlastní infrastrukturu (event store), ověř, jestli ji projekt nebo organizace nemá jako hotovou knihovnu, a použij ji.

## Očekávané chování

Místo přepsání řádku se zapisují fakta v minulém čase; aktuální stav (agregát) vzniká přehráním streamu: stav = fold(events). Příkaz se nejdřív ověří proti stavu, teprve pak vznikne událost s další verzí streamu; událost se nemění ani nemaže. Příklad: příjem 80 000 → 90 000 → 100 000 Kč dá dvě události `IncomeChanged` a historii jde přehrát i dotázat („příjem se měnil 2ד). Dokončení výpočtu se splátkou nad 45 % příjmu agregát odmítne a nic nezapíše.

## Konkrétní úkol

Technická specifika (Java): Immutable `record` pro události, agregát jako čistá třída; event store přes JdbcTemplate nebo JPA s unikátním indexem.

Postupuj po krocích. Po bodu 1 (plán) napiš, co zjistíš a co navrhuješ, a počkej na potvrzení:
1. Plán: navrhni stream id a payloady šesti událostí. Výchozí návrh: `CalculationCreated`, `IncomeChanged`, `PropertyPriceChanged` (cena, akontace), `RateChanged`, `TermChanged`, `CalculationCompleted` (výpočet uzavřen pro odeslání).
2. Přidej tabulku/kolekci event store (streamId, version, type, schemaVersion, payload, timestamp) s unikátním (streamId, version) a globálním pořadím zápisu `position`.
3. Implementuj agregát: `decide(state, command) -> events` a `apply(state, event) -> state`, bez I/O.
4. Implementuj `load(streamId)` jako fold událostí (vrací stav i verzi) a `append(streamId, expectedVersion, events)`.
5. Napiš testy ve stylu given-events / when-command / then-events, včetně odmítnutí nad limit splátky (např. `CompleteCalculation` nad 45 % příjmu). Kontroluje-li aplikace limit až při odeslání, dej pravidlo do příkazu, který výpočet uzavírá; chování starého endpointu neměň.
6. Zapoj nový agregát vedle starého CRUD endpointu (např. `/api/v2/calculations`). Starý endpoint, tabulku i frontend nech beze změny; existující výpočty nepřeváděj.

Na co si dát pozor:
- `apply` nesmí rozhodovat ani volat I/O.
- Události pojmenuj v minulém čase a dej jim jen fakta, ne vypočtené hodnoty pro UI. Ani `CalculationCompleted` nenese splátku; tu později pokryje verze algoritmu výpočtu.
- Unikátní index (streamId, version) je základ kontroly souběhu (optimistic concurrency).

## Co nesmíš měnit

- Stávající veřejné API a chování endpointů kalkulačky, které teď funguje.
- Databázové schéma stávajících tabulek (nové tabulky/migrace jsou v pořádku, přejmenování a mazání ne).
- Cizí testy, seed data a existující hodnoty. Když je změna nutná, dej ji do samostatného commitu a uveď ji. Pokud změna tvaru události nebo nový konzument nutně mění existující test, uprav ho v samostatném commitu a v závěru uveď proč.
- Veřejné kontrakty (API, schémata událostí) bez zpětné kompatibility.

## Hotovo, když

- Stav agregátu vznikne jen z událostí.
- Testy given/when/then pokrývají úspěch i odmítnutý příkaz.
- Starý endpoint funguje beze změny.
- JUnit 5 testy ve stávající struktuře `src/test/java` projdou build nástrojem projektu.
- V závěru uveď: co jsi změnil, co jsi předpokládal, co zbývá.
# Úkol pro coding agenta: Event Sourcing kalkulačky

Stack: Java. Režim: challenge.
Cíl: Zavést append-only event stream pro agregát kalkulačky a odvodit z něj aktuální stav.

## Kontext existujícího kódu

Pracuješ v existujícím projektu (Java backend (typicky Java 21, Spring Boot, JPA nebo JDBC). Použij build nástroj a styl, který projekt už má (Maven/Gradle, JUnit 5).).
Doména: hypoteční kalkulačka, která se postupně mění v event-driven systém (kalkulačka, rizika, schvalování, identita, účet, dokumenty, výplata).

Nejdřív čti, nic neměň. Najdi a stručně shrň:
- Entitu/model kalkulačky a všechna místa, která ji mění.
- Pravidla (invarianty), která se dnes kontrolují při uložení.
- Existující tabulku/kolekci kalkulací, kterou nechceš rozbít.
- Které z těchto částí už v projektu existují a které chybí. Než napíšeš vlastní infrastrukturu (event store), ověř, jestli ji projekt nebo organizace nemá jako hotovou knihovnu, a použij ji.

## Očekávané chování

Místo přepsání řádku se zapisují fakta v minulém čase; aktuální stav (agregát) vzniká přehráním streamu: stav = fold(events). Příkaz se nejdřív ověří proti stavu, teprve pak vznikne událost s další verzí streamu; událost se nemění ani nemaže. Příklad: příjem 80 000 → 90 000 → 100 000 Kč dá dvě události `IncomeChanged` a historii jde přehrát i dotázat („příjem se měnil 2ד). Dokončení výpočtu se splátkou nad 45 % příjmu agregát odmítne a nic nezapíše.

## Zadání (Challenge)

Přidej vedle stávajícího CRUD ukládání event-sourced agregát kalkulačky se šesti událostmi, invariantem splátky a testy given/when/then.

Technická specifika (Java): Immutable `record` pro události, agregát jako čistá třída; event store přes JdbcTemplate nebo JPA s unikátním indexem.

Postup si zvol sám. Pasti v tomto tématu nejsou vypsané: najdi je (souběh, opakované doručení, pořadí, selhání uprostřed) a ke každé napiš test, který by ji odhalil. Na konci vypiš, jaké pasti jsi našel a které jsi vědomě nechal otevřené.

## Co nesmíš měnit

- Stávající veřejné API a chování endpointů kalkulačky, které teď funguje.
- Databázové schéma stávajících tabulek (nové tabulky/migrace jsou v pořádku, přejmenování a mazání ne).
- Cizí testy, seed data a existující hodnoty. Když je změna nutná, dej ji do samostatného commitu a uveď ji. Pokud změna tvaru události nebo nový konzument nutně mění existující test, uprav ho v samostatném commitu a v závěru uveď proč.
- Veřejné kontrakty (API, schémata událostí) bez zpětné kompatibility.

## Hotovo, když

- Stav agregátu vznikne jen z událostí.
- Testy given/when/then pokrývají úspěch i odmítnutý příkaz.
- Starý endpoint funguje beze změny.
- JUnit 5 testy ve stávající struktuře `src/test/java` projdou build nástrojem projektu.
- V závěru uveď: co jsi změnil, co jsi předpokládal, co zbývá.
# Úkol pro coding agenta: Event Sourcing kalkulačky

Stack: C#. Režim: s vedením.
Cíl: Zavést append-only event stream pro agregát kalkulačky a odvodit z něj aktuální stav.

## Kontext existujícího kódu

Pracuješ v existujícím projektu (C# backend (.NET, ASP.NET Core, EF Core nebo Dapper). Použij solution, styl a DI konvence, které projekt už má (xUnit/NUnit).).
Doména: hypoteční kalkulačka, která se postupně mění v event-driven systém (kalkulačka, rizika, schvalování, identita, účet, dokumenty, výplata).

Nejdřív čti, nic neměň. Najdi a stručně shrň:
- Entitu/model kalkulačky a všechna místa, která ji mění.
- Pravidla (invarianty), která se dnes kontrolují při uložení.
- Existující tabulku/kolekci kalkulací, kterou nechceš rozbít.
- Které z těchto částí už v projektu existují a které chybí. Než napíšeš vlastní infrastrukturu (event store), ověř, jestli ji projekt nebo organizace nemá jako hotovou knihovnu, a použij ji.

## Očekávané chování

Místo přepsání řádku se zapisují fakta v minulém čase; aktuální stav (agregát) vzniká přehráním streamu: stav = fold(events). Příkaz se nejdřív ověří proti stavu, teprve pak vznikne událost s další verzí streamu; událost se nemění ani nemaže. Příklad: příjem 80 000 → 90 000 → 100 000 Kč dá dvě události `IncomeChanged` a historii jde přehrát i dotázat („příjem se měnil 2ד). Dokončení výpočtu se splátkou nad 45 % příjmu agregát odmítne a nic nezapíše.

## Konkrétní úkol

Technická specifika (C#): Událostí jsou `record` typy, agregát čistá třída s `Decide`/`Apply`; event store přes EF Core/Dapper s unikátním indexem.

Postupuj po krocích. Po bodu 1 (plán) napiš, co zjistíš a co navrhuješ, a počkej na potvrzení:
1. Plán: navrhni stream id a payloady šesti událostí. Výchozí návrh: `CalculationCreated`, `IncomeChanged`, `PropertyPriceChanged` (cena, akontace), `RateChanged`, `TermChanged`, `CalculationCompleted` (výpočet uzavřen pro odeslání).
2. Přidej tabulku/kolekci event store (streamId, version, type, schemaVersion, payload, timestamp) s unikátním (streamId, version) a globálním pořadím zápisu `position`.
3. Implementuj agregát: `decide(state, command) -> events` a `apply(state, event) -> state`, bez I/O.
4. Implementuj `load(streamId)` jako fold událostí (vrací stav i verzi) a `append(streamId, expectedVersion, events)`.
5. Napiš testy ve stylu given-events / when-command / then-events, včetně odmítnutí nad limit splátky (např. `CompleteCalculation` nad 45 % příjmu). Kontroluje-li aplikace limit až při odeslání, dej pravidlo do příkazu, který výpočet uzavírá; chování starého endpointu neměň.
6. Zapoj nový agregát vedle starého CRUD endpointu (např. `/api/v2/calculations`). Starý endpoint, tabulku i frontend nech beze změny; existující výpočty nepřeváděj.

Na co si dát pozor:
- `apply` nesmí rozhodovat ani volat I/O.
- Události pojmenuj v minulém čase a dej jim jen fakta, ne vypočtené hodnoty pro UI. Ani `CalculationCompleted` nenese splátku; tu později pokryje verze algoritmu výpočtu.
- Unikátní index (streamId, version) je základ kontroly souběhu (optimistic concurrency).

## Co nesmíš měnit

- Stávající veřejné API a chování endpointů kalkulačky, které teď funguje.
- Databázové schéma stávajících tabulek (nové tabulky/migrace jsou v pořádku, přejmenování a mazání ne).
- Cizí testy, seed data a existující hodnoty. Když je změna nutná, dej ji do samostatného commitu a uveď ji. Pokud změna tvaru události nebo nový konzument nutně mění existující test, uprav ho v samostatném commitu a v závěru uveď proč.
- Veřejné kontrakty (API, schémata událostí) bez zpětné kompatibility.

## Hotovo, když

- Stav agregátu vznikne jen z událostí.
- Testy given/when/then pokrývají úspěch i odmítnutý příkaz.
- Starý endpoint funguje beze změny.
- Testy ve stávajícím testovacím projektu projdou (`dotnet test`).
- V závěru uveď: co jsi změnil, co jsi předpokládal, co zbývá.
# Úkol pro coding agenta: Event Sourcing kalkulačky

Stack: C#. Režim: challenge.
Cíl: Zavést append-only event stream pro agregát kalkulačky a odvodit z něj aktuální stav.

## Kontext existujícího kódu

Pracuješ v existujícím projektu (C# backend (.NET, ASP.NET Core, EF Core nebo Dapper). Použij solution, styl a DI konvence, které projekt už má (xUnit/NUnit).).
Doména: hypoteční kalkulačka, která se postupně mění v event-driven systém (kalkulačka, rizika, schvalování, identita, účet, dokumenty, výplata).

Nejdřív čti, nic neměň. Najdi a stručně shrň:
- Entitu/model kalkulačky a všechna místa, která ji mění.
- Pravidla (invarianty), která se dnes kontrolují při uložení.
- Existující tabulku/kolekci kalkulací, kterou nechceš rozbít.
- Které z těchto částí už v projektu existují a které chybí. Než napíšeš vlastní infrastrukturu (event store), ověř, jestli ji projekt nebo organizace nemá jako hotovou knihovnu, a použij ji.

## Očekávané chování

Místo přepsání řádku se zapisují fakta v minulém čase; aktuální stav (agregát) vzniká přehráním streamu: stav = fold(events). Příkaz se nejdřív ověří proti stavu, teprve pak vznikne událost s další verzí streamu; událost se nemění ani nemaže. Příklad: příjem 80 000 → 90 000 → 100 000 Kč dá dvě události `IncomeChanged` a historii jde přehrát i dotázat („příjem se měnil 2ד). Dokončení výpočtu se splátkou nad 45 % příjmu agregát odmítne a nic nezapíše.

## Zadání (Challenge)

Přidej vedle stávajícího CRUD ukládání event-sourced agregát kalkulačky se šesti událostmi, invariantem splátky a testy given/when/then.

Technická specifika (C#): Událostí jsou `record` typy, agregát čistá třída s `Decide`/`Apply`; event store přes EF Core/Dapper s unikátním indexem.

Postup si zvol sám. Pasti v tomto tématu nejsou vypsané: najdi je (souběh, opakované doručení, pořadí, selhání uprostřed) a ke každé napiš test, který by ji odhalil. Na konci vypiš, jaké pasti jsi našel a které jsi vědomě nechal otevřené.

## Co nesmíš měnit

- Stávající veřejné API a chování endpointů kalkulačky, které teď funguje.
- Databázové schéma stávajících tabulek (nové tabulky/migrace jsou v pořádku, přejmenování a mazání ne).
- Cizí testy, seed data a existující hodnoty. Když je změna nutná, dej ji do samostatného commitu a uveď ji. Pokud změna tvaru události nebo nový konzument nutně mění existující test, uprav ho v samostatném commitu a v závěru uveď proč.
- Veřejné kontrakty (API, schémata událostí) bez zpětné kompatibility.

## Hotovo, když

- Stav agregátu vznikne jen z událostí.
- Testy given/when/then pokrývají úspěch i odmítnutý příkaz.
- Starý endpoint funguje beze změny.
- Testy ve stávajícím testovacím projektu projdou (`dotnet test`).
- V závěru uveď: co jsi změnil, co jsi předpokládal, co zbývá.
# Úkol pro coding agenta: Event Sourcing kalkulačky

Stack: Web (HTML/JS nebo stack aplikace). Režim: s vedením.
Cíl: Zavést append-only event stream pro agregát kalkulačky a odvodit z něj aktuální stav.

## Kontext existujícího kódu

Pracuješ v existujícím projektu (webová aplikace: frontend v prohlížeči, případně s vlastním backendem. Když má projekt backend, patří event store, broker a služby na backend a body o endpointech a tabulkách se týkají jeho. Když backend nemá, použij IndexedDB v prohlížeči a v testech `fake-indexeddb`. Framework a test runner projektu zachovej; nové závislosti přidávej jen s odůvodněním.).
Doména: hypoteční kalkulačka, která se postupně mění v event-driven systém (kalkulačka, rizika, schvalování, identita, účet, dokumenty, výplata).

Nejdřív čti, nic neměň. Najdi a stručně shrň:
- Entitu/model kalkulačky a všechna místa, která ji mění.
- Pravidla (invarianty), která se dnes kontrolují při uložení.
- Existující tabulku/kolekci kalkulací, kterou nechceš rozbít.
- Které z těchto částí už v projektu existují a které chybí. Než napíšeš vlastní infrastrukturu (event store), ověř, jestli ji projekt nebo organizace nemá jako hotovou knihovnu, a použij ji.

## Očekávané chování

Místo přepsání řádku se zapisují fakta v minulém čase; aktuální stav (agregát) vzniká přehráním streamu: stav = fold(events). Příkaz se nejdřív ověří proti stavu, teprve pak vznikne událost s další verzí streamu; událost se nemění ani nemaže. Příklad: příjem 80 000 → 90 000 → 100 000 Kč dá dvě události `IncomeChanged` a historii jde přehrát i dotázat („příjem se měnil 2ד). Dokončení výpočtu se splátkou nad 45 % příjmu agregát odmítne a nic nezapíše.

## Konkrétní úkol

Technická specifika (Web (HTML/JS nebo stack aplikace)): Události jako objekty s `type` a `payload`, `apply` jako čistá reducer funkce; event store vedle persistence výpočtů (na backendu tabulka, bez backendu IndexedDB object store) s klíčem [streamId, version].

Postupuj po krocích. Po bodu 1 (plán) napiš, co zjistíš a co navrhuješ, a počkej na potvrzení:
1. Plán: navrhni stream id a payloady šesti událostí. Výchozí návrh: `CalculationCreated`, `IncomeChanged`, `PropertyPriceChanged` (cena, akontace), `RateChanged`, `TermChanged`, `CalculationCompleted` (výpočet uzavřen pro odeslání).
2. Přidej tabulku/kolekci event store (streamId, version, type, schemaVersion, payload, timestamp) s unikátním (streamId, version) a globálním pořadím zápisu `position`.
3. Implementuj agregát: `decide(state, command) -> events` a `apply(state, event) -> state`, bez I/O.
4. Implementuj `load(streamId)` jako fold událostí (vrací stav i verzi) a `append(streamId, expectedVersion, events)`.
5. Napiš testy ve stylu given-events / when-command / then-events, včetně odmítnutí nad limit splátky (např. `CompleteCalculation` nad 45 % příjmu). Kontroluje-li aplikace limit až při odeslání, dej pravidlo do příkazu, který výpočet uzavírá; chování starého endpointu neměň.
6. Zapoj nový agregát vedle starého CRUD endpointu (např. `/api/v2/calculations`). Starý endpoint, tabulku i frontend nech beze změny; existující výpočty nepřeváděj.

Na co si dát pozor:
- `apply` nesmí rozhodovat ani volat I/O.
- Události pojmenuj v minulém čase a dej jim jen fakta, ne vypočtené hodnoty pro UI. Ani `CalculationCompleted` nenese splátku; tu později pokryje verze algoritmu výpočtu.
- Unikátní index (streamId, version) je základ kontroly souběhu (optimistic concurrency).

## Co nesmíš měnit

- Stávající veřejné API a chování endpointů kalkulačky, které teď funguje.
- Databázové schéma stávajících tabulek (nové tabulky/migrace jsou v pořádku, přejmenování a mazání ne).
- Cizí testy, seed data a existující hodnoty. Když je změna nutná, dej ji do samostatného commitu a uveď ji. Pokud změna tvaru události nebo nový konzument nutně mění existující test, uprav ho v samostatném commitu a v závěru uveď proč.
- Veřejné kontrakty (API, schémata událostí) bez zpětné kompatibility.

## Hotovo, když

- Stav agregátu vznikne jen z událostí.
- Testy given/when/then pokrývají úspěch i odmítnutý příkaz.
- Starý endpoint funguje beze změny.
- Testy projdou stávajícím test runnerem; lint a build projdou, pokud je projekt má.
- V závěru uveď: co jsi změnil, co jsi předpokládal, co zbývá.
# Úkol pro coding agenta: Event Sourcing kalkulačky

Stack: Web (HTML/JS nebo stack aplikace). Režim: challenge.
Cíl: Zavést append-only event stream pro agregát kalkulačky a odvodit z něj aktuální stav.

## Kontext existujícího kódu

Pracuješ v existujícím projektu (webová aplikace: frontend v prohlížeči, případně s vlastním backendem. Když má projekt backend, patří event store, broker a služby na backend a body o endpointech a tabulkách se týkají jeho. Když backend nemá, použij IndexedDB v prohlížeči a v testech `fake-indexeddb`. Framework a test runner projektu zachovej; nové závislosti přidávej jen s odůvodněním.).
Doména: hypoteční kalkulačka, která se postupně mění v event-driven systém (kalkulačka, rizika, schvalování, identita, účet, dokumenty, výplata).

Nejdřív čti, nic neměň. Najdi a stručně shrň:
- Entitu/model kalkulačky a všechna místa, která ji mění.
- Pravidla (invarianty), která se dnes kontrolují při uložení.
- Existující tabulku/kolekci kalkulací, kterou nechceš rozbít.
- Které z těchto částí už v projektu existují a které chybí. Než napíšeš vlastní infrastrukturu (event store), ověř, jestli ji projekt nebo organizace nemá jako hotovou knihovnu, a použij ji.

## Očekávané chování

Místo přepsání řádku se zapisují fakta v minulém čase; aktuální stav (agregát) vzniká přehráním streamu: stav = fold(events). Příkaz se nejdřív ověří proti stavu, teprve pak vznikne událost s další verzí streamu; událost se nemění ani nemaže. Příklad: příjem 80 000 → 90 000 → 100 000 Kč dá dvě události `IncomeChanged` a historii jde přehrát i dotázat („příjem se měnil 2ד). Dokončení výpočtu se splátkou nad 45 % příjmu agregát odmítne a nic nezapíše.

## Zadání (Challenge)

Přidej vedle stávajícího CRUD ukládání event-sourced agregát kalkulačky se šesti událostmi, invariantem splátky a testy given/when/then.

Technická specifika (Web (HTML/JS nebo stack aplikace)): Události jako objekty s `type` a `payload`, `apply` jako čistá reducer funkce; event store vedle persistence výpočtů (na backendu tabulka, bez backendu IndexedDB object store) s klíčem [streamId, version].

Postup si zvol sám. Pasti v tomto tématu nejsou vypsané: najdi je (souběh, opakované doručení, pořadí, selhání uprostřed) a ke každé napiš test, který by ji odhalil. Na konci vypiš, jaké pasti jsi našel a které jsi vědomě nechal otevřené.

## Co nesmíš měnit

- Stávající veřejné API a chování endpointů kalkulačky, které teď funguje.
- Databázové schéma stávajících tabulek (nové tabulky/migrace jsou v pořádku, přejmenování a mazání ne).
- Cizí testy, seed data a existující hodnoty. Když je změna nutná, dej ji do samostatného commitu a uveď ji. Pokud změna tvaru události nebo nový konzument nutně mění existující test, uprav ho v samostatném commitu a v závěru uveď proč.
- Veřejné kontrakty (API, schémata událostí) bez zpětné kompatibility.

## Hotovo, když

- Stav agregátu vznikne jen z událostí.
- Testy given/when/then pokrývají úspěch i odmítnutý příkaz.
- Starý endpoint funguje beze změny.
- Testy projdou stávajícím test runnerem; lint a build projdou, pokud je projekt má.
- V závěru uveď: co jsi změnil, co jsi předpokládal, co zbývá.

Školení pro váš tým

Chcete školení pro svůj tým?

Školení vedeme na vašem kódu a vašem doménovém problému. Domluvíme rozsah, termín a formu.

Probrat školení