Refactors on TicketFlow. No solutions.md before submitting.
Exercise 1 — The Reservation aggregate's repository
- Define the Protocol
ReservationRepositorywithget,saveandexiste_reserva_activa(event_id, user_id). ImplementORMReservationRepositorywith lesson 10'sselect_for_updatequery. - Write
InMemoryReservationRepositoryfor tests: an in-memory dict, same contract. Move the duplicate-reservation test (10) to this fake. - Written decision: for
VenueandSeat(simple CRUD), do you keep the direct manager or a repository? Justify in 3 lines.
Exercise 2 — Application service with outbox
- Create the
OutboxEventtable (aggregate_type, aggregate_id, event_type, payload JSONB, created_at, nullable publicado_at) with a partial index overpublicado_at IS NULL. - Modify
reservar()to writeReservationConfirmedinto the outbox INSIDE the transaction. Verify: if the transaction fails (seat taken), there is no outbox row. - Write the poller: a
management commandthat reads up to 50 pending events ordered by id, "publishes" them (for now, print/log) and markspublicado_at. Idempotent when relaunched.
Exercise 3 — The output DTO
- Implement
ReservationSummary(frozen dataclass) and theresumen()function. Change the reservation detail view to serialize from the DTO, not from the Model. - Break the coupling all the way: what happens if tomorrow you rename a Model field? How many places does it touch if you serialize from Model vs from DTO?
- Bonus: add
expires_in_secondscomputed in the DTO (with an injected Clock), not in the serializer — why is that computation domain?
Exercise 4 — Domain events, minimum viable
- List 5 TicketFlow domain events (
ReservationConfirmed,ReservationExpired,PaymentSucceeded,RefundIssued,EventPublished) and for each: who emits it, who consumes it, minimum payload. - Add
PaymentFailedto the outbox from the payments service. Write the test: rejected payment → transaction commit + outbox row withevent_type="PaymentFailed"and a payload withreason.
Exercise 5 — Consumer deduplication
- In the events consumer (the "publishing" poller), store
event:{event_id}in Redis with a 24h TTL when processing; if it already exists, skip. Write the test that publishes the same event twice and checks the effect (log/email fake) happens ONCE. - Why does deduplication belong in the consumer and not in the poller? Write the answer in 2 lines.
Submit
Paste the repository interface, the outbox migration, the poller and the DTO. Next: Lesson 26 — Centralized error handling.