Guidelines for AI agents contributing to or working with the Ecotone framework codebase.
Ecotone is a PHP framework for message-driven architecture with DDD, CQRS, and Event Sourcing. Works with Symfony, Laravel, or standalone (Ecotone Lite).
- Core package:
packages/Ecotone- foundation for all other packages - Each package under
packages/*is a separate Composer package - Packages are split to read-only repos during release
- Template for new packages:
_PackageTemplate/
- No comments - prefer meaningful private methods that describe intent
- Use PHP 8.1+ features (attributes, enums, named arguments)
- All public APIs need
@param/@returnPHPDoc - Follow existing patterns in the codebase
- Messages first - Commands, Events, Queries are first-class citizens
- Declarative configuration - use PHP attributes, not YAML/XML
- ServiceActivatorBuilder - for registering message handlers
- InterfaceToCall - for reflection and method metadata
- MessageHeaders - for message metadata propagation
- Modules - self-register via
ModulePackageList
- Write high-level tests from end-user perspective
- Tests use EcotoneLite to bootstrap isolated Ecotone instances
- Prefer inline anonymous classes in tests over separate fixture files
- Run tests for the specific package you modified
# Enter development container
docker compose exec -u root app /bin/bash
# Run package tests
cd packages/PackageName
composer tests:ci
# Run specific test
vendor/bin/phpunit --filter testMethodName tests/Path/To/TestFile.php# MySQL for PdoEventSourcing
DATABASE_DSN=mysql://ecotone:secret@database-mysql:3306/ecotone?serverVersion=8.0 \
vendor/bin/phpunit packages/PdoEventSourcing/tests/
# PostgreSQL (default in container)
vendor/bin/phpunit packages/PdoEventSourcing/tests/composer tests:phpunit- Unit/integration testscomposer tests:behat- BDD feature testscomposer tests:phpstan- Static analysiscomposer tests:ci- All tests for CI
#[CommandHandler]
public function handle(PlaceOrder $command): void
{
// Business logic
}#[EventHandler]
public function when(OrderPlaced $event): void
{
// React to event
}#[Asynchronous('orders')]
#[EventHandler]
public function whenAsync(OrderPlaced $event): void
{
// Processed asynchronously
}#[Aggregate]
class Order
{
#[Identifier]
private string $orderId;
#[CommandHandler]
public static function place(PlaceOrder $command): self
{
return new self($command->orderId);
}
}# Start all containers
docker compose up -d
# Enter dev container (use root for full access)
docker compose exec -u root app /bin/bash
# Verify lowest/highest dependencies
composer update --prefer-lowest && vendor/bin/phpunit
composer update --prefer-stable && vendor/bin/phpunit