feat: alignment improvements — DDD building blocks, testing package, and example extensions#17
Merged
Merged
Conversation
- Add `make pre-commit` to run all pre-commit hooks against all files - Add `make all` as the full validation gate (check + pre-commit) - Simplify devcontainer postCreateCommand to use `make install` - Fix CHANGELOG.md consecutive blank lines that broke markdownlint (MD012) - Document new targets in CLAUDE.md Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…te() hook - Entity and AggregateRoot are now abstract classes; direct instantiation is prevented and validate() is declared abstract, forcing subclasses to explicitly define their invariants - ValueObject is abstract with a no-op validate() default, since VOs with no invariants beyond their field types are legitimate - validate() is called from __post_init__ in both base classes, removing the need for subclasses to call super().__post_init__() - Update bank_account example: Money moves validation from __post_init__ to validate(); BankAccount implements the required validate() stub - Update test fixtures to implement validate() Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Removes account_id from event payloads — aggregate_id on the base covers identity and enables traceability without payload duplication. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…m ContextVar Adds request_context.py with the correlation_id ContextVar and documents the correlation/causation propagation pattern in coding-standards.md. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds all property and reset() so test suites can inspect and clear state without injecting extra infrastructure. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…nce checks Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ncrete classes Structural typing (pyright strict) validates compliance without inheritance. Handlers retain explicit inheritance as idiomatic intent declaration. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Verifies the full wiring: OpenAccountCommand → repository → domain event → AccountOpenedDomainEventHandler → AccountOpenedIntegrationEvent published. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Removes base_integration_event.py — all integration event contracts now live in a single module alongside IntegrationEvent, IntegrationEventPublisher, IntegrationEventPublisherSpy, and IntegrationEventHandler. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…Event Documents the canonical subclass pattern for BaseIntegrationEvent in coding-standards.md, aligned with the BaseBackgroundTask convention. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
….is_ok Aligns the factory method name with TS/PHP conventions. The ok field is renamed to is_ok to avoid the classmethod/field namespace conflict in Python dataclasses. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Aligns naming with BaseIntegrationEvent and makes the base class relationship explicit. DomainEventRecord implied persistence semantics. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Exposes is_ok/is_failed as @Property over internal _ok field, aligning with isOk()/isFailed() patterns in TS and PHP. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Create src/seedwork/testing/ with repository, task_scheduler, integration_event_publisher, and outbox modules. Remove these helpers from seedwork.infrastructure and seedwork.application to keep the production surface clean. Update all test and example imports accordingly. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add WithdrawMoneyCommand, WithdrawMoneyHandler, and handler tests covering successful withdrawal, account-not-found, and insufficient-funds. Mirrors the deposit_money use case structure. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
AccountOpenedDomainEventHandler now schedules a SendWelcomeEmailTask after publishing the integration event. composition_root wires InMemoryTaskScheduler with SendWelcomeEmailTaskHandler. Tests verify scheduling and execute_scheduled() end-to-end. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
Contributor
There was a problem hiding this comment.
Pull request overview
This PR aligns the Python seedwork with updated DDD/testing conventions, moving test doubles into seedwork.testing, renaming result/domain-event APIs, and extending the bank account example with withdraw and welcome-email task flows.
Changes:
- Introduces
BaseDomainEvent,Result.ok()/is_ok/is_failed, and a newseedwork.testingpackage for in-memory/spying utilities. - Refactors infrastructure exports to remove testing-only concrete classes and rely on structural typing.
- Extends the bank account example with withdraw handling, task scheduling, correlation/causation propagation, and related docs/tests.
Reviewed changes
Copilot reviewed 62 out of 65 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
uv.lock |
Updates package lock version to 0.3.0. |
tests/infrastructure/test_transactional_command_bus.py |
Updates assertions to Result.is_ok. |
tests/infrastructure/test_registry_command_bus.py |
Updates assertions to Result.is_ok. |
tests/infrastructure/test_outbox.py |
Moves in-memory outbox imports to seedwork.testing. |
tests/infrastructure/test_in_memory_task_scheduler.py |
Moves scheduler/spy imports to seedwork.testing. |
tests/infrastructure/test_in_memory_repository.py |
Moves repository imports and adds all/reset spy coverage. |
tests/infrastructure/test_in_memory_integration_event_publisher.py |
Moves publisher imports and adds spy protocol coverage. |
tests/infrastructure/test_domain_event_coordinator_command_bus.py |
Updates result factory/assertion API usage. |
tests/infrastructure/test_deferred_domain_event_bus.py |
Migrates domain event fixtures to BaseDomainEvent with aggregate_id. |
tests/infrastructure/test_command_bus_builder.py |
Updates result assertion API usage. |
tests/infrastructure/test_bus_stack_composition.py |
Moves repository import and updates result assertion API usage. |
tests/domain/test_entity.py |
Adds concrete validate() implementations for abstract Entity tests. |
tests/domain/test_domain_event.py |
Migrates domain event tests to BaseDomainEvent and aggregate_id. |
tests/application/test_result.py |
Updates result API tests and adds failed-state checks. |
tests/application/test_open_account_handler.py |
Moves repository import to seedwork.testing. |
tests/application/test_deposit_money_handler.py |
Moves repository import to seedwork.testing. |
src/seedwork/testing/task_scheduler.py |
Keeps task scheduler structurally typed against the spy protocol. |
src/seedwork/testing/repository.py |
Adds testing repository and RepositorySpy. |
src/seedwork/testing/outbox.py |
Adds in-memory outbox repositories and spy protocols. |
src/seedwork/testing/integration_event_publisher.py |
Adds runtime-checkable publisher spy protocol. |
src/seedwork/testing/__init__.py |
Exports testing utilities. |
src/seedwork/infrastructure/transactional_command_bus.py |
Removes explicit protocol inheritance. |
src/seedwork/infrastructure/registry_query_bus.py |
Removes explicit protocol inheritance. |
src/seedwork/infrastructure/registry_command_bus.py |
Removes explicit protocol inheritance and returns Result.ok(). |
src/seedwork/infrastructure/outbox.py |
Removes testing-only in-memory outbox implementations. |
src/seedwork/infrastructure/in_memory_repository.py |
Deletes infrastructure in-memory repository implementation. |
src/seedwork/infrastructure/domain_event_coordinator_command_bus.py |
Uses result.is_ok. |
src/seedwork/infrastructure/__init__.py |
Removes testing-only exports from infrastructure. |
src/seedwork/domain/value_object.py |
Adds validate() hook via __post_init__. |
src/seedwork/domain/entity.py |
Makes entities abstract with required validate(). |
src/seedwork/domain/domain_event.py |
Replaces DomainEventRecord with BaseDomainEvent including aggregate_id. |
src/seedwork/domain/__init__.py |
Updates domain exports. |
src/seedwork/application/integration_events.py |
Consolidates BaseIntegrationEvent into integration events module. |
src/seedwork/application/commands.py |
Renames result state API. |
src/seedwork/application/base_integration_event.py |
Deletes old base integration event module. |
src/seedwork/application/__init__.py |
Updates application exports. |
src/seedwork/__init__.py |
Updates package root exports. |
README.md |
Removes best-practices guide link. |
Makefile |
Adds pre-commit and all targets. |
docs/README.md |
Removes best-practices guide link. |
docs/getting-started.md |
Removes best-practices guide link. |
docs/examples/bank_account/tests/test_withdraw_money_handler.py |
Adds withdraw handler tests. |
docs/examples/bank_account/tests/test_send_welcome_email_task_handler.py |
Adds task scheduling/execution tests. |
docs/examples/bank_account/tests/test_composition_root.py |
Adds composition-root integration event test. |
docs/examples/bank_account/infrastructure/in_memory_bank_account_repository.py |
Moves repository base import to seedwork.testing. |
docs/examples/bank_account/domain/money.py |
Migrates validation to ValueObject.validate(). |
docs/examples/bank_account/domain/events/account_opened.py |
Migrates event to BaseDomainEvent. |
docs/examples/bank_account/domain/events/account_debited.py |
Migrates event to BaseDomainEvent. |
docs/examples/bank_account/domain/events/account_credited.py |
Migrates event to BaseDomainEvent. |
docs/examples/bank_account/domain/bank_account.py |
Adds aggregate_id, validate(), and debit event updates. |
docs/examples/bank_account/composition_root.py |
Wires task scheduler and welcome-email task handling. |
docs/examples/bank_account/application/withdraw_money/withdraw_money_handler.py |
Adds withdraw command handler. |
docs/examples/bank_account/application/withdraw_money/withdraw_money_command.py |
Adds withdraw command DTO. |
docs/examples/bank_account/application/withdraw_money/__init__.py |
Adds withdraw package marker. |
docs/examples/bank_account/application/send_welcome_email/send_welcome_email_task.py |
Adds welcome-email background task. |
docs/examples/bank_account/application/send_welcome_email/send_welcome_email_task_handler.py |
Adds welcome-email task handler. |
docs/examples/bank_account/application/send_welcome_email/__init__.py |
Adds welcome-email package marker. |
docs/examples/bank_account/application/request_context.py |
Adds request-scoped correlation ID context variable. |
docs/examples/bank_account/application/account_opened_integration_event.py |
Updates integration event metadata and causation/correlation propagation. |
docs/examples/bank_account/application/account_opened_domain_event_handler.py |
Schedules welcome-email task after publishing integration event. |
docs/coding-standards.md |
Documents correlation ID and integration event conventions. |
docs/best-practices.md |
Deletes the best-practices guide. |
CLAUDE.md |
Documents new validation commands. |
CHANGELOG.md |
Cleans up spacing. |
.devcontainer/devcontainer.json |
Uses make install for setup. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Register WithdrawMoneyHandler in build_command_bus so compose() can dispatch WithdrawMoneyCommand without KeyError. Add composition-level tests for deposit and withdraw paths. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add docs/examples/bank_account/tests to testpaths so uv run pytest and CI collect the example tests automatically without extra flags. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Prevents make from skipping these targets if a file or directory with the same name exists in the working tree. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
A batch of non-breaking enhancements and breaking changes to align the library with the TypeScript seedwork counterpart and internal design decisions.
Non-breaking (B-series)
aggregate_idadded toDomainEventprotocol andBaseDomainEventAccountOpenedIntegrationEvent:causation_idnow correctly set toevent.id;correlation_idread fromContextVarInMemoryRepositorygainsRepositorySpyprotocol withreset()andallaccessorIntegrationEventPublisherSpymarked@runtime_checkableProtocolexplicitlyBankAccountRepositoryredundantProtocolbase reverted (structural typing preserved)BaseIntegrationEventconsolidated intointegration_events.py;base_integration_event.pydeletedAccountOpenedIntegrationEventdeclaresTYPE/VERSIONasClassVar[str]Breaking (A-series / vNext)
Result.succeeded()→Result.ok()DomainEventRecord→BaseDomainEventResult.ok: boolfield →is_ok/is_failedpropertiessrc/seedwork/testing/package (InMemoryRepository,RepositorySpy,InMemoryTaskScheduler,TaskSchedulerSpy,InMemoryIntegrationEventPublisher,IntegrationEventPublisherSpy, outbox in-memory helpers); removed fromseedwork.infrastructureandseedwork.applicationExample extensions (E-series)
withdraw_moneyuse case (WithdrawMoneyCommand,WithdrawMoneyHandler, tests); wired intocomposition_root.pySendWelcomeEmailTaskbackground task:AccountOpenedDomainEventHandlernow schedules a task;composition_rootwiresInMemoryTaskScheduler; tests cover scheduling andexecute_scheduled()Fixes
WithdrawMoneyCommandwas missing frombuild_command_bus(); addedWithdrawMoneyHandlerregistration and composition-level tests for deposit and withdraw pathsdocs/examples/bank_account/testsadded totestpathsinpyproject.tomlso example tests are collected byuv run pytestand CI automatically (156 tests total, up from 132)checkandtest-no-covadded to.PHONYinMakefilesomake allalways runs the intended commands regardless of filesystem stateTest plan
make checkpasses (lint + typecheck + 156 tests at 100% coverage)Result.ok,BaseDomainEvent,seedwork.testingimports🤖 Generated with Claude Code