# Domain Boundaries

## Ownership Matrix

| Module | Owns | Must Call Outward Through |
| --- | --- | --- |
| Courses | Catalog metadata and public course presentation | Course queries and read models |
| Scheduling | Cohorts, attendance sessions, rooms, generated schedules | Scheduling actions and schedule queries |
| Enrollments | Registration lifecycle, enrollment state, seat reservation | Enrollment actions and enrollment events |
| Finance | Payments, receipts, allocations, transactions | Finance actions and financial policies |
| Attendance | Attendance records, summaries, no-show state | Attendance actions and attendance events |
| Messaging | Templates, outbox, provider dispatch, logs | Messaging contracts and provider adapters |
| WhatsApp | Contacts, conversations, webhook processing, journey state | Enrollment, Finance, and Messaging actions |
| Corporate | Organizations, B2B leads, proposals, agreements, corporate delivery | Corporate actions and Finance actions |
| CRM | CRM leads, tasks, stage history, assignment, operational follow-up state | CRM actions, CRM queries, lifecycle listeners |
| Tracking/SEO | Attribution, metadata, analytics events | Tracking contracts only |

## Allowed Dependencies

- UI layers may authorize, validate UI state, call Actions, and render Query results.
- WhatsApp may call Enrollment, Finance, and Messaging public Actions; it must not write their workflow state directly.
- Corporate may call Finance Actions for allocations and finance summaries.
- CRM may react to safe lifecycle events and update only CRM-owned state.
- Portal and dashboards should prefer tenant-safe Query classes over inline list queries.
- Listeners may call Actions when a state change is required.

## Forbidden Dependencies

- Livewire must not orchestrate multi-model finance or conversion workflows directly.
- Tracking and SEO code must not mutate business workflow state.
- Messaging providers must not bypass enrollment or payment ownership.
- CRM must not approve payments, confirm enrollments, mutate attendance records, or update WhatsApp workflow state directly.
- New work must not depend on `companies`, `users.company_id`, or `agreement_path`.
- Sensitive downloads stay behind controllers and policies, not public storage links.

## Action Pattern

Actions are the public write API for important domain operations:

1. Accept a DTO or explicit domain models.
2. Open `DB::transaction()` when multiple writes, audit records, or state transitions are involved.
3. Return the updated aggregate or result object.
4. Dispatch stable domain events after the write transaction completes.

The first extracted Phase 2 actions are:

- `ConvertB2bLeadToOrganizationAction`
- `CreateB2bLeadFromConversationAction`
- `SendWhatsAppReplyAction`
- `CreateAttendanceSessionAction`
- `UpdateAttendanceSessionAction`
- `CancelAttendanceSessionAction`
- `ReopenAttendanceSessionAction`

## DTO Rules

- Do not pass raw Livewire state arrays across a module boundary.
- DTOs keep typed inputs explicit, especially actor identity and tenant context.
- Keep display-only formatting in UI or presenter code; keep workflow facts in DTOs.

## Query Rules

- Query classes own reusable list scoping and dashboard read filters.
- Tenant-bound lists must accept tenant context explicitly.
- Queries do not mutate state.

The first query entry points are:

- `OrganizationInvoicesQuery`
- `CorporateReceivablesQuery`
- `EnrollmentPaymentsQuery`
- `InstructorScheduleQuery`
- `WhatsAppConversationListQuery`
- `CrmDashboardQuery`
- `CrmLeadListQuery`

## Event Rules

- Events describe business facts, not UI gestures.
- Event payloads must avoid secrets and transient Livewire arrays.
- Listeners should be idempotent and call Actions when they need writes.
- Phase 3 promotes lifecycle events to readonly scalar contracts and requires after-commit dispatch for transactional workflow facts.
- Current wiring stays intentionally narrow: extracted Actions emit first, older sensitive workflows remain documented planned emitters until regression coverage makes the seam safe.
- See `docs/event_catalog.md` for the emitter inventory and `docs/event_driven_architecture.md` for listener, idempotency, and retry rules.

## Architecture Check

Run:

```bash
php artisan app:architecture-check
```

Baseline mode reports debt without blocking local work. Use strict mode in guarded change sets:

```bash
php artisan app:architecture-check --strict
```

Current checks cover forbidden legacy references, direct WhatsApp cross-module writes, direct CRM cross-module writes, hardcoded Corporate admin navigation URLs, Livewire/provider side effects, direct UI tracking side effects, non-WhatsApp Action provider calls, and listener cross-module Enrollment/Payment writes. Route and sensitive-download checks remain part of the security roadmap until the route inventory is normalized further.
