Cvičení 12 · MortgageAccountOpeningRequested → MortgageAccountOpened, Inbox

Mortgage Account: duplicity a idempotence

  • at-least-once
  • duplicity
  • idempotence
  • Inbox

Princip

Broker garantuje „aspoň jednou“, ne „právě jednou“. Stejná zpráva může dorazit dvakrát (ztracené potvrzení, redelivery, retry).

Bez idempotence služba otevře druhý účet. Idempotentní příjemce si pamatuje zpracovaná eventId (Inbox) a pro stejnou žádost nevytvoří nový účinek, ale vrátí původní výsledek.

Inbox se zapisuje ve stejné transakci jako účinek, jinak se opět otevře okno pro duplicitu.

Co sledovat

  • Počet účtů v lokální databázi služby.
  • Stopa „duplicate-ignored“ v timeline brokeru.

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

Bez řešení

Spustit s duplicitním doručením

Broker doručí každý požadavek na otevření účtu 2×. Služba nemá Inbox.

Spustit v simulátoru bez řešení

S řešením

Spustit s Inboxem

Služba druhé doručení pozná podle eventId a ignoruje ho. Vznikne jediný účet.

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

Co udělat: Klikni na „Spustit s duplicitním doručením“. Na co se dívat: Mortgage Account otevře dva účty pro jednu hypotéku. 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.

Udělat konzumenta MortgageAccountOpeningRequested idempotentním přes Inbox tabulku v téže transakci jako účinek.

Jazyk
Varianta
# Úkol pro coding agenta: Mortgage Account: duplicity a idempotence

Stack: Java. Režim: s vedením.
Cíl: Udělat konzumenta MortgageAccountOpeningRequested idempotentním přes Inbox tabulku v téže transakci jako účinek.

## 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 zprávu `MortgageAccountOpeningRequested` (`applicationId`, `identityCheckId`) od Customer Identity po ověření totožnosti. Pokud ne, nejdřív založ minimálního producenta a konzumenta.

Nejdřív čti, nic neměň. Najdi a stručně shrň:
- Handler, který otevírá účet, a transakční hranici.
- Zda už existuje inbox/deduplikace v messaging knihovně (např. inbox v MassTransit/Wolverine).
- Přirozený obchodní klíč (applicationId).
- 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í

Broker doručuje „aspoň jednou“: stejná zpráva může dorazit dvakrát a bez idempotence vznikne druhý účet. Idempotentní příjemce zapíše `eventId` do Inboxu v téže transakci jako účet a druhé doručení ignoruje. Příklad: duplicita dostane původní účet (úspěch, ne 409) a odpověď `MortgageAccountOpened` se stejným `eventId`.

## Konkrétní úkol

Technická specifika (Java): `@Transactional` handler, unikátní index na `message_id` a `application_id`.

Postupuj po krocích. Po bodu 1 (plán) napiš, co zjistíš a co navrhuješ, a počkej na potvrzení:
1. Plán: kde je klíč deduplikace (eventId) a kde obchodní klíč (applicationId).
2. Tabulka Inbox (messageId unikátní) v databázi služby účtu, zapisovaná ve stejné transakci jako vytvoření účtu. Po síti posílej `eventId` jako idempotency key.
3. Duplicita vrací původní výsledek a znovu publikuje odpovědní událost (příklad výše).
4. Unikátní omezení na obchodní klíč jako druhá vrstva obrany. Nesnese-li ho stávající tabulka, dej ho do nové tabulky ve stejné transakci.
5. Test: stejná zpráva 2× → jeden účet; dva různé požadavky na stejnou žádost → jeden účet; souběh, který bez unikátního klíče selže (dvě spojení k databázi, nebo dvojník se starým čtením).

Na co si dát pozor:
- Deduplikace „if exists“ bez unikátního omezení má závod.
- Inbox roste: plán čištění po retenci; ta musí přečkat retry, DLQ i ruční redrive.

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

- Test duplicity i souběžného doručení.
- Inbox a účinek jsou v jedné transakci (test: selhání zápisu do inboxu nenechá účet).
- Existující knihovna použita, pokud je k dispozici.
- 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: Mortgage Account: duplicity a idempotence

Stack: Java. Režim: challenge.
Cíl: Udělat konzumenta MortgageAccountOpeningRequested idempotentním přes Inbox tabulku v téže transakci jako účinek.

## 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 zprávu `MortgageAccountOpeningRequested` (`applicationId`, `identityCheckId`) od Customer Identity po ověření totožnosti. Pokud ne, nejdřív založ minimálního producenta a konzumenta.

Nejdřív čti, nic neměň. Najdi a stručně shrň:
- Handler, který otevírá účet, a transakční hranici.
- Zda už existuje inbox/deduplikace v messaging knihovně (např. inbox v MassTransit/Wolverine).
- Přirozený obchodní klíč (applicationId).
- 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í

Broker doručuje „aspoň jednou“: stejná zpráva může dorazit dvakrát a bez idempotence vznikne druhý účet. Idempotentní příjemce zapíše `eventId` do Inboxu v téže transakci jako účet a druhé doručení ignoruje. Příklad: duplicita dostane původní účet (úspěch, ne 409) a odpověď `MortgageAccountOpened` se stejným `eventId`.

## Zadání (Challenge)

Zaruč, že opakované doručení MortgageAccountOpeningRequested nikdy nevytvoří druhý účet, ani při souběžném doručení.

Technická specifika (Java): `@Transactional` handler, unikátní index na `message_id` a `application_id`.

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ž

- Test duplicity i souběžného doručení.
- Inbox a účinek jsou v jedné transakci (test: selhání zápisu do inboxu nenechá účet).
- Existující knihovna použita, pokud je k dispozici.
- 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: Mortgage Account: duplicity a idempotence

Stack: C#. Režim: s vedením.
Cíl: Udělat konzumenta MortgageAccountOpeningRequested idempotentním přes Inbox tabulku v téže transakci jako účinek.

## 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 zprávu `MortgageAccountOpeningRequested` (`applicationId`, `identityCheckId`) od Customer Identity po ověření totožnosti. Pokud ne, nejdřív založ minimálního producenta a konzumenta.

Nejdřív čti, nic neměň. Najdi a stručně shrň:
- Handler, který otevírá účet, a transakční hranici.
- Zda už existuje inbox/deduplikace v messaging knihovně (např. inbox v MassTransit/Wolverine).
- Přirozený obchodní klíč (applicationId).
- 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í

Broker doručuje „aspoň jednou“: stejná zpráva může dorazit dvakrát a bez idempotence vznikne druhý účet. Idempotentní příjemce zapíše `eventId` do Inboxu v téže transakci jako účet a druhé doručení ignoruje. Příklad: duplicita dostane původní účet (úspěch, ne 409) a odpověď `MortgageAccountOpened` se stejným `eventId`.

## Konkrétní úkol

Technická specifika (C#): Transakce `DbContext`, unikátní indexy; použij inbox existující messaging knihovny, pokud ho má.

Postupuj po krocích. Po bodu 1 (plán) napiš, co zjistíš a co navrhuješ, a počkej na potvrzení:
1. Plán: kde je klíč deduplikace (eventId) a kde obchodní klíč (applicationId).
2. Tabulka Inbox (messageId unikátní) v databázi služby účtu, zapisovaná ve stejné transakci jako vytvoření účtu. Po síti posílej `eventId` jako idempotency key.
3. Duplicita vrací původní výsledek a znovu publikuje odpovědní událost (příklad výše).
4. Unikátní omezení na obchodní klíč jako druhá vrstva obrany. Nesnese-li ho stávající tabulka, dej ho do nové tabulky ve stejné transakci.
5. Test: stejná zpráva 2× → jeden účet; dva různé požadavky na stejnou žádost → jeden účet; souběh, který bez unikátního klíče selže (dvě spojení k databázi, nebo dvojník se starým čtením).

Na co si dát pozor:
- Deduplikace „if exists“ bez unikátního omezení má závod.
- Inbox roste: plán čištění po retenci; ta musí přečkat retry, DLQ i ruční redrive.

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

- Test duplicity i souběžného doručení.
- Inbox a účinek jsou v jedné transakci (test: selhání zápisu do inboxu nenechá účet).
- Existující knihovna použita, pokud je k dispozici.
- 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: Mortgage Account: duplicity a idempotence

Stack: C#. Režim: challenge.
Cíl: Udělat konzumenta MortgageAccountOpeningRequested idempotentním přes Inbox tabulku v téže transakci jako účinek.

## 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 zprávu `MortgageAccountOpeningRequested` (`applicationId`, `identityCheckId`) od Customer Identity po ověření totožnosti. Pokud ne, nejdřív založ minimálního producenta a konzumenta.

Nejdřív čti, nic neměň. Najdi a stručně shrň:
- Handler, který otevírá účet, a transakční hranici.
- Zda už existuje inbox/deduplikace v messaging knihovně (např. inbox v MassTransit/Wolverine).
- Přirozený obchodní klíč (applicationId).
- 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í

Broker doručuje „aspoň jednou“: stejná zpráva může dorazit dvakrát a bez idempotence vznikne druhý účet. Idempotentní příjemce zapíše `eventId` do Inboxu v téže transakci jako účet a druhé doručení ignoruje. Příklad: duplicita dostane původní účet (úspěch, ne 409) a odpověď `MortgageAccountOpened` se stejným `eventId`.

## Zadání (Challenge)

Zaruč, že opakované doručení MortgageAccountOpeningRequested nikdy nevytvoří druhý účet, ani při souběžném doručení.

Technická specifika (C#): Transakce `DbContext`, unikátní indexy; použij inbox existující messaging knihovny, pokud ho má.

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ž

- Test duplicity i souběžného doručení.
- Inbox a účinek jsou v jedné transakci (test: selhání zápisu do inboxu nenechá účet).
- Existující knihovna použita, pokud je k dispozici.
- 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: Mortgage Account: duplicity a idempotence

Stack: Web (HTML/JS nebo stack aplikace). Režim: s vedením.
Cíl: Udělat konzumenta MortgageAccountOpeningRequested idempotentním přes Inbox tabulku v téže transakci jako účinek.

## 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 zprávu `MortgageAccountOpeningRequested` (`applicationId`, `identityCheckId`) od Customer Identity po ověření totožnosti. Pokud ne, nejdřív založ minimálního producenta a konzumenta.

Nejdřív čti, nic neměň. Najdi a stručně shrň:
- Handler, který otevírá účet, a transakční hranici.
- Zda už existuje inbox/deduplikace v messaging knihovně (např. inbox v MassTransit/Wolverine).
- Přirozený obchodní klíč (applicationId).
- 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í

Broker doručuje „aspoň jednou“: stejná zpráva může dorazit dvakrát a bez idempotence vznikne druhý účet. Idempotentní příjemce zapíše `eventId` do Inboxu v téže transakci jako účet a druhé doručení ignoruje. Příklad: duplicita dostane původní účet (úspěch, ne 409) a odpověď `MortgageAccountOpened` se stejným `eventId`.

## Konkrétní úkol

Technická specifika (Web (HTML/JS nebo stack aplikace)): S backendem jedna transakce služby účtu přes inbox i účet; bez backendu jedna IndexedDB transakce přes inbox i data.

Postupuj po krocích. Po bodu 1 (plán) napiš, co zjistíš a co navrhuješ, a počkej na potvrzení:
1. Plán: kde je klíč deduplikace (eventId) a kde obchodní klíč (applicationId).
2. Tabulka Inbox (messageId unikátní) v databázi služby účtu, zapisovaná ve stejné transakci jako vytvoření účtu. Po síti posílej `eventId` jako idempotency key.
3. Duplicita vrací původní výsledek a znovu publikuje odpovědní událost (příklad výše).
4. Unikátní omezení na obchodní klíč jako druhá vrstva obrany. Nesnese-li ho stávající tabulka, dej ho do nové tabulky ve stejné transakci.
5. Test: stejná zpráva 2× → jeden účet; dva různé požadavky na stejnou žádost → jeden účet; souběh, který bez unikátního klíče selže (dvě spojení k databázi, nebo dvojník se starým čtením).

Na co si dát pozor:
- Deduplikace „if exists“ bez unikátního omezení má závod.
- Inbox roste: plán čištění po retenci; ta musí přečkat retry, DLQ i ruční redrive.

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

- Test duplicity i souběžného doručení.
- Inbox a účinek jsou v jedné transakci (test: selhání zápisu do inboxu nenechá účet).
- Existující knihovna použita, pokud je k dispozici.
- 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: Mortgage Account: duplicity a idempotence

Stack: Web (HTML/JS nebo stack aplikace). Režim: challenge.
Cíl: Udělat konzumenta MortgageAccountOpeningRequested idempotentním přes Inbox tabulku v téže transakci jako účinek.

## 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 zprávu `MortgageAccountOpeningRequested` (`applicationId`, `identityCheckId`) od Customer Identity po ověření totožnosti. Pokud ne, nejdřív založ minimálního producenta a konzumenta.

Nejdřív čti, nic neměň. Najdi a stručně shrň:
- Handler, který otevírá účet, a transakční hranici.
- Zda už existuje inbox/deduplikace v messaging knihovně (např. inbox v MassTransit/Wolverine).
- Přirozený obchodní klíč (applicationId).
- 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í

Broker doručuje „aspoň jednou“: stejná zpráva může dorazit dvakrát a bez idempotence vznikne druhý účet. Idempotentní příjemce zapíše `eventId` do Inboxu v téže transakci jako účet a druhé doručení ignoruje. Příklad: duplicita dostane původní účet (úspěch, ne 409) a odpověď `MortgageAccountOpened` se stejným `eventId`.

## Zadání (Challenge)

Zaruč, že opakované doručení MortgageAccountOpeningRequested nikdy nevytvoří druhý účet, ani při souběžném doručení.

Technická specifika (Web (HTML/JS nebo stack aplikace)): S backendem jedna transakce služby účtu přes inbox i účet; bez backendu jedna IndexedDB transakce přes inbox i data.

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ž

- Test duplicity i souběžného doručení.
- Inbox a účinek jsou v jedné transakci (test: selhání zápisu do inboxu nenechá účet).
- Existující knihovna použita, pokud je k dispozici.
- 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í