Cvičení 10 · RiskAssessmentCompleted/Rejected, MortgageApproved/Rejected, eventual consistency

Risk a schvalování

  • Risk Service
  • Approval
  • eventual consistency
  • read model

Princip

Risk Service reaguje na MortgageApplicationSubmitted a vydá RiskAssessmentCompleted nebo RiskAssessmentRejected. Approval Service z toho vydá MortgageApproved nebo MortgageRejected.

Služby spolu nemluví přímo, každá zpracuje událost a vydá další. Čtecí model (projekce) se aktualizuje až poté, proto může být chvíli pozadu: eventual consistency.

Neodstraníš ji, navrhneš ji: UI ukáže „zpracovává se“, zdroj pravdy vs. čtecí model a po zápisu nečte starý pohled.

Co sledovat

  • Stav ve čtecím modelu zaostává za událostmi v event store.
  • Varianty zamítnutí: LTV 95 % (Risk) a úvěr 11 M (Approval).

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

Bez řešení

Spustit schválení s pomalou projekcí

Projekce má latenci 3,5 s. Klient ve čtecím modelu vidí starý stav, i když je žádost už schválená.

Spustit v simulátoru bez řešení

S řešením

Spustit s rychlou projekcí a upozorněním

Zpoždění zmizet nemůže, ale UI ho ukazuje (odznak „Čtecí model je pozadu“) a po zápisu zná verzi, kterou čeká. Rychlejší projekce zkracuje okno nekonzistence.

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

Co udělat: Klikni na „Spustit schválení s pomalou projekcí“. Na co se dívat: Čtecí model je chvíli pozadu za skutečným stavem žádosti. 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.

Přidat asynchronní řetěz Risk → Approval nad integračními událostmi a navrhnout UI pro eventual consistency.

Jazyk
Varianta
# Úkol pro coding agenta: Risk a schvalování

Stack: Java. Režim: s vedením.
Cíl: Přidat asynchronní řetěz Risk → Approval nad integračními událostmi a navrhnout UI pro eventual consistency.

## 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).
Předpoklad: projekt má broker a integrační událost `MortgageApplicationSubmitted`. Pokud ne, nejdřív založ minimální broker v paměti a publikaci této události při odeslání žádosti.

Nejdřív čti, nic neměň. Najdi a stručně shrň:
- Kde dnes probíhá výpočet rizika a schvalování (synchronní volání?) a podle jakých pravidel.
- Jak UI zjišťuje stav žádosti (polling, push).
- Které z těchto částí už v projektu existují a které chybí. Než napíšeš vlastní infrastrukturu (broker klient, outbox, retry), ověř, jestli ji projekt nebo organizace nemá jako hotovou knihovnu, a použij ji.

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

Risk a Approval spolu nemluví přímo, každý zpracuje událost a vydá další. Čtecí model se aktualizuje až potom, proto je chvíli pozadu; UI ukazuje „zpracovává se“ a po zápisu nečte starý pohled. Příklad zamítnutí: LTV 95 % zamítne Risk, úvěr 11 M zamítne Approval.

## Konkrétní úkol

Technická specifika (Java): Konzumenti přes existující messaging (Spring Cloud Stream/Kafka listener), čtecí model v samostatné tabulce.

Postupuj po krocích. Po bodu 1 (plán) napiš, co zjistíš a co navrhuješ, a počkej na potvrzení:
1. Plán: seznam událostí a kdo je vydává/odebírá (tabulka producent → událost → konzument).
2. Risk handler: MortgageApplicationSubmitted → RiskAssessmentCompleted | RiskAssessmentRejected. Chybí-li pravidlo zamítnutí, zaveď ho a uveď v závěru.
3. Approval handler: RiskAssessmentCompleted → MortgageApproved | MortgageRejected; RiskAssessmentRejected přeskoč. Výstup obou handlerů: `eventId` odvozené ze vstupu, `correlationId` beze změny, `causationId` = `eventId` vstupu.
4. Čtecí model stavu žádosti s verzí (krok toku: 1 odeslání, 2 riziko, 3 schválení) a příznakem konečného stavu; starší verzi ignoruje.
5. UI: stav „zpracovává se“, dokud čtecí model nemá verzi z odeslání nebo stav není konečný.

Na co si dát pozor:
- Čtení vlastního zápisu: uživatel právě odeslal žádost a vidí starý stav.
- Neposílej přes události data, která mohou zastarat (stav žádosti, kopie údajů jiné služby); pošli id a fakt rozhodnutí.

## 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ž

- Cesta schválení i obě zamítnutí mají test.
- Čtecí model nese verzi a konečný stav a UI umí stav „zpracovává se“.
- Handlery jsou čisté vůči vstupní události (stejná událost dává stejnou zprávu včetně `eventId`).
- 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: Risk a schvalování

Stack: Java. Režim: challenge.
Cíl: Přidat asynchronní řetěz Risk → Approval nad integračními událostmi a navrhnout UI pro eventual consistency.

## 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).
Předpoklad: projekt má broker a integrační událost `MortgageApplicationSubmitted`. Pokud ne, nejdřív založ minimální broker v paměti a publikaci této události při odeslání žádosti.

Nejdřív čti, nic neměň. Najdi a stručně shrň:
- Kde dnes probíhá výpočet rizika a schvalování (synchronní volání?) a podle jakých pravidel.
- Jak UI zjišťuje stav žádosti (polling, push).
- Které z těchto částí už v projektu existují a které chybí. Než napíšeš vlastní infrastrukturu (broker klient, outbox, retry), ověř, jestli ji projekt nebo organizace nemá jako hotovou knihovnu, a použij ji.

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

Risk a Approval spolu nemluví přímo, každý zpracuje událost a vydá další. Čtecí model se aktualizuje až potom, proto je chvíli pozadu; UI ukazuje „zpracovává se“ a po zápisu nečte starý pohled. Příklad zamítnutí: LTV 95 % zamítne Risk, úvěr 11 M zamítne Approval.

## Zadání (Challenge)

Napoj Risk a Approval jako asynchronní konzumenty událostí a zobraz stav žádosti tak, aby UI nelhalo během zpoždění projekce.

Technická specifika (Java): Konzumenti přes existující messaging (Spring Cloud Stream/Kafka listener), čtecí model v samostatné tabulce.

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ž

- Cesta schválení i obě zamítnutí mají test.
- Čtecí model nese verzi a konečný stav a UI umí stav „zpracovává se“.
- Handlery jsou čisté vůči vstupní události (stejná událost dává stejnou zprávu včetně `eventId`).
- 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: Risk a schvalování

Stack: C#. Režim: s vedením.
Cíl: Přidat asynchronní řetěz Risk → Approval nad integračními událostmi a navrhnout UI pro eventual consistency.

## 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).
Předpoklad: projekt má broker a integrační událost `MortgageApplicationSubmitted`. Pokud ne, nejdřív založ minimální broker v paměti a publikaci této události při odeslání žádosti.

Nejdřív čti, nic neměň. Najdi a stručně shrň:
- Kde dnes probíhá výpočet rizika a schvalování (synchronní volání?) a podle jakých pravidel.
- Jak UI zjišťuje stav žádosti (polling, push).
- Které z těchto částí už v projektu existují a které chybí. Než napíšeš vlastní infrastrukturu (broker klient, outbox, retry), ověř, jestli ji projekt nebo organizace nemá jako hotovou knihovnu, a použij ji.

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

Risk a Approval spolu nemluví přímo, každý zpracuje událost a vydá další. Čtecí model se aktualizuje až potom, proto je chvíli pozadu; UI ukazuje „zpracovává se“ a po zápisu nečte starý pohled. Příklad zamítnutí: LTV 95 % zamítne Risk, úvěr 11 M zamítne Approval.

## Konkrétní úkol

Technická specifika (C#): Konzumenti přes existující messaging vrstvu (MassTransit/Service Bus, co projekt používá), čtecí model v samostatné tabulce.

Postupuj po krocích. Po bodu 1 (plán) napiš, co zjistíš a co navrhuješ, a počkej na potvrzení:
1. Plán: seznam událostí a kdo je vydává/odebírá (tabulka producent → událost → konzument).
2. Risk handler: MortgageApplicationSubmitted → RiskAssessmentCompleted | RiskAssessmentRejected. Chybí-li pravidlo zamítnutí, zaveď ho a uveď v závěru.
3. Approval handler: RiskAssessmentCompleted → MortgageApproved | MortgageRejected; RiskAssessmentRejected přeskoč. Výstup obou handlerů: `eventId` odvozené ze vstupu, `correlationId` beze změny, `causationId` = `eventId` vstupu.
4. Čtecí model stavu žádosti s verzí (krok toku: 1 odeslání, 2 riziko, 3 schválení) a příznakem konečného stavu; starší verzi ignoruje.
5. UI: stav „zpracovává se“, dokud čtecí model nemá verzi z odeslání nebo stav není konečný.

Na co si dát pozor:
- Čtení vlastního zápisu: uživatel právě odeslal žádost a vidí starý stav.
- Neposílej přes události data, která mohou zastarat (stav žádosti, kopie údajů jiné služby); pošli id a fakt rozhodnutí.

## 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ž

- Cesta schválení i obě zamítnutí mají test.
- Čtecí model nese verzi a konečný stav a UI umí stav „zpracovává se“.
- Handlery jsou čisté vůči vstupní události (stejná událost dává stejnou zprávu včetně `eventId`).
- 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: Risk a schvalování

Stack: C#. Režim: challenge.
Cíl: Přidat asynchronní řetěz Risk → Approval nad integračními událostmi a navrhnout UI pro eventual consistency.

## 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).
Předpoklad: projekt má broker a integrační událost `MortgageApplicationSubmitted`. Pokud ne, nejdřív založ minimální broker v paměti a publikaci této události při odeslání žádosti.

Nejdřív čti, nic neměň. Najdi a stručně shrň:
- Kde dnes probíhá výpočet rizika a schvalování (synchronní volání?) a podle jakých pravidel.
- Jak UI zjišťuje stav žádosti (polling, push).
- Které z těchto částí už v projektu existují a které chybí. Než napíšeš vlastní infrastrukturu (broker klient, outbox, retry), ověř, jestli ji projekt nebo organizace nemá jako hotovou knihovnu, a použij ji.

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

Risk a Approval spolu nemluví přímo, každý zpracuje událost a vydá další. Čtecí model se aktualizuje až potom, proto je chvíli pozadu; UI ukazuje „zpracovává se“ a po zápisu nečte starý pohled. Příklad zamítnutí: LTV 95 % zamítne Risk, úvěr 11 M zamítne Approval.

## Zadání (Challenge)

Napoj Risk a Approval jako asynchronní konzumenty událostí a zobraz stav žádosti tak, aby UI nelhalo během zpoždění projekce.

Technická specifika (C#): Konzumenti přes existující messaging vrstvu (MassTransit/Service Bus, co projekt používá), čtecí model v samostatné tabulce.

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ž

- Cesta schválení i obě zamítnutí mají test.
- Čtecí model nese verzi a konečný stav a UI umí stav „zpracovává se“.
- Handlery jsou čisté vůči vstupní události (stejná událost dává stejnou zprávu včetně `eventId`).
- 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: Risk a schvalování

Stack: Web (HTML/JS nebo stack aplikace). Režim: s vedením.
Cíl: Přidat asynchronní řetěz Risk → Approval nad integračními událostmi a navrhnout UI pro eventual consistency.

## 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).
Předpoklad: projekt má broker a integrační událost `MortgageApplicationSubmitted`. Pokud ne, nejdřív založ minimální broker v paměti a publikaci této události při odeslání žádosti.

Nejdřív čti, nic neměň. Najdi a stručně shrň:
- Kde dnes probíhá výpočet rizika a schvalování (synchronní volání?) a podle jakých pravidel.
- Jak UI zjišťuje stav žádosti (polling, push).
- Které z těchto částí už v projektu existují a které chybí. Než napíšeš vlastní infrastrukturu (broker klient, outbox, retry), ověř, jestli ji projekt nebo organizace nemá jako hotovou knihovnu, a použij ji.

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

Risk a Approval spolu nemluví přímo, každý zpracuje událost a vydá další. Čtecí model se aktualizuje až potom, proto je chvíli pozadu; UI ukazuje „zpracovává se“ a po zápisu nečte starý pohled. Příklad zamítnutí: LTV 95 % zamítne Risk, úvěr 11 M zamítne Approval.

## Konkrétní úkol

Technická specifika (Web (HTML/JS nebo stack aplikace)): Polling nebo SSE na endpoint se stavem žádosti; zobraz `version` a stav „zpracovává se“.

Postupuj po krocích. Po bodu 1 (plán) napiš, co zjistíš a co navrhuješ, a počkej na potvrzení:
1. Plán: seznam událostí a kdo je vydává/odebírá (tabulka producent → událost → konzument).
2. Risk handler: MortgageApplicationSubmitted → RiskAssessmentCompleted | RiskAssessmentRejected. Chybí-li pravidlo zamítnutí, zaveď ho a uveď v závěru.
3. Approval handler: RiskAssessmentCompleted → MortgageApproved | MortgageRejected; RiskAssessmentRejected přeskoč. Výstup obou handlerů: `eventId` odvozené ze vstupu, `correlationId` beze změny, `causationId` = `eventId` vstupu.
4. Čtecí model stavu žádosti s verzí (krok toku: 1 odeslání, 2 riziko, 3 schválení) a příznakem konečného stavu; starší verzi ignoruje.
5. UI: stav „zpracovává se“, dokud čtecí model nemá verzi z odeslání nebo stav není konečný.

Na co si dát pozor:
- Čtení vlastního zápisu: uživatel právě odeslal žádost a vidí starý stav.
- Neposílej přes události data, která mohou zastarat (stav žádosti, kopie údajů jiné služby); pošli id a fakt rozhodnutí.

## 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ž

- Cesta schválení i obě zamítnutí mají test.
- Čtecí model nese verzi a konečný stav a UI umí stav „zpracovává se“.
- Handlery jsou čisté vůči vstupní události (stejná událost dává stejnou zprávu včetně `eventId`).
- 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: Risk a schvalování

Stack: Web (HTML/JS nebo stack aplikace). Režim: challenge.
Cíl: Přidat asynchronní řetěz Risk → Approval nad integračními událostmi a navrhnout UI pro eventual consistency.

## 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).
Předpoklad: projekt má broker a integrační událost `MortgageApplicationSubmitted`. Pokud ne, nejdřív založ minimální broker v paměti a publikaci této události při odeslání žádosti.

Nejdřív čti, nic neměň. Najdi a stručně shrň:
- Kde dnes probíhá výpočet rizika a schvalování (synchronní volání?) a podle jakých pravidel.
- Jak UI zjišťuje stav žádosti (polling, push).
- Které z těchto částí už v projektu existují a které chybí. Než napíšeš vlastní infrastrukturu (broker klient, outbox, retry), ověř, jestli ji projekt nebo organizace nemá jako hotovou knihovnu, a použij ji.

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

Risk a Approval spolu nemluví přímo, každý zpracuje událost a vydá další. Čtecí model se aktualizuje až potom, proto je chvíli pozadu; UI ukazuje „zpracovává se“ a po zápisu nečte starý pohled. Příklad zamítnutí: LTV 95 % zamítne Risk, úvěr 11 M zamítne Approval.

## Zadání (Challenge)

Napoj Risk a Approval jako asynchronní konzumenty událostí a zobraz stav žádosti tak, aby UI nelhalo během zpoždění projekce.

Technická specifika (Web (HTML/JS nebo stack aplikace)): Polling nebo SSE na endpoint se stavem žádosti; zobraz `version` a stav „zpracovává se“.

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ž

- Cesta schválení i obě zamítnutí mají test.
- Čtecí model nese verzi a konečný stav a UI umí stav „zpracovává se“.
- Handlery jsou čisté vůči vstupní události (stejná událost dává stejnou zprávu včetně `eventId`).
- 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í