packages/. Each package owns a specific business domain and communicates with others through contracts (PHP interfaces). This page shows you the full picture.
The Package Map
What Each Package Owns (One-Liner)
How Packages Communicate: Contracts
Packages never import each other’s classes directly. Instead, they depend on interfaces (contracts): Each package exposes an interface in itssrc/Contracts/ directory. Other packages depend on the interface, not the implementation. Laravel’s service container binds the real class at runtime.
Example: When the Order package needs to create an accounting entry after a sale, it does not import LedgerService directly. It uses LedgerInterface:
The Request Journey: What Happens When Sena Makes a Sale
Let us tracePOST /v1/order/orders from HTTP request to database writes, showing which packages are involved at each step.
Packages involved in a single sale:
This is why understanding the package map matters — even a “simple” sale touches 4 out of 8 packages.
Dependency Rules
These rules keep the codebase maintainable:- Shared has no dependencies — it is the foundation layer
- IAM depends only on Shared — authentication is a foundational concern
- Team depends on IAM + Shared — organizational structure needs identity
- Catalog, Order, Customer depend on IAM + Team + Shared — business logic needs both identity and company context
- Ledger depends on IAM + Team + Shared — accounting needs identity and company context
- Order depends on Catalog — orders reference products and manage stock
- Order and Customer depend on Ledger — financial events create accounting entries
- Notification depends on Shared — handles email sending (invitations, onboarding, verification, password reset)
- No circular dependencies — if A depends on B, B must not depend on A
Common Mistakes
Importing a class from another package directly — Always use the contract interface. If you need something from the Ledger package, injectLedgerInterface, not LedgerService.
Creating circular dependencies — If Package A depends on Package B, then Package B must not depend on Package A. If you need two-way communication, use events or a shared interface in the Shared package.
Forgetting that Catalog is organization-scoped — Products, categories, and vendors are shared across all companies. If you add a company-specific filter to a catalog query, you will break multi-branch visibility.
Forgetting that Stock is company-scoped — Stock levels are per company, not per organization. If you aggregate stock without grouping by company, the numbers will be wrong.
Where to Go Next
Previous: Permissions Explained | Next: Open your shop