Architecture Overview
Pattern: DDD Modular Monolith
- Bounded contexts implemented as modules in a single deployable
- Modules communicate via domain events (async) or contract interfaces (sync)
- Deptrac enforces module boundaries at the code level
- Designed for future extraction to microservices if needed
Layers (per module)
- Domain — Pure PHP. Aggregates, value objects, events, repository interfaces.
- Application — Command/query handlers. Orchestrates domain + infrastructure.
- Infrastructure — Doctrine repos, external services, framework integration.
- Presentation — Controllers, DTOs. Thin HTTP layer.
- Contract — Public interfaces for cross-module access. Pure PHP.
Key Architectural Decisions
- ADR-001: Symfony 8 backend (stability, ecosystem, DDD-friendly)
- ADR-002: React Native + Expo (single codebase, OTA updates)
- ADR-003: Zitadel for auth (self-hosted OIDC, multi-tenant)
- ADR-004: PostgreSQL + ltree (hierarchy queries, JSONB flexibility)
- ADR-005: Redis + Symfony Messenger (async events, job queues)
- ADR-006: DDD + Deptrac (enforced boundaries, clean architecture)
- ADR-007: Mailgun for email (reliable, affordable)
- ADR-008: Hetzner hosting (EU data, cost-effective)
See .ai/decisions/ for full ADR documents.
Anti-patterns (never do this)
- Import another module’s Domain or Infrastructure classes
- Put business logic in controllers
- Use Doctrine annotations in the Domain layer
- Create cross-module foreign keys
- Accept tenant ID as a request parameter
- Skip domain events for cross-module communication
- Use
mixedtypes or suppress PHPStan errors
Multi-tenancy
- Tenant resolution from OIDC token (Zitadel organization)
- Every database query scoped by tenant_id
- Row-level security as defense-in-depth
- No shared data between tenants (except platform config)
Pipeline (Cross-cutting)
- Audit: logs who did what, when
- History: tracks entity changes over time
- Moderation: content review workflow
- Translation: auto-translate content (future)
- All pipeline modules consume domain events — they never modify source modules