# Phase 6 Execution Plan: Modular Communication Extraction


# Islamic Sunday School Alignment Update

Phase 6 communication now treats the extension as **Islamic Sunday School**.

`SchoolCore\Communication` owns recipient preview, recipient resolution, dedupe, preferences, sending, logs, delivery status, retries, templates, and audit.

`IslamicSundaySchool\Communication` may add recipient resolvers and templates for:

```text
Qur'an class guardians
Arabic class guardians
Islamic studies class guardians
halaqa groups
volunteer teams
masjid family/community groups
Sunday program attendees
special program reminders
```

No bulk send may bypass preview just because the audience is familiar. Familiar audiences are how people accidentally message the entire masjid about one student's missing notebook. Technology remains undefeated at embarrassment.

---
## 1. Purpose

Phase 6 extracts communication behavior into a reusable `SchoolCore` module that can support any school system while allowing Islamic Sunday School-specific communication behavior through recipient resolvers, policies, templates, and extension services.

The communication module must own the invariant parts of school communication:

- message composition
- message templates
- recipient resolution
- recipient preview
- recipient deduplication
- channel selection
- email delivery
- SMS/WhatsApp adapter boundaries
- notification delivery
- communication preferences
- send logs
- delivery status
- retry behavior
- idempotency
- audit logging
- authorization boundaries
- cross-school isolation

Islamic Sunday School may customize:

- ministry recipient groups
- masjid-family/community recipient groups
- Islamic Sunday School class rosters
- volunteer/team messaging
- religious/community announcement templates
- service/event reminders
- curriculum reminders
- family/masjid/community labels

Islamic Sunday School must not own the global communication engine. It plugs into it. Otherwise one day every school using the platform will discover its “global” notification system thinks every recipient belongs to a volunteer team, because apparently hardcoding is a lifestyle.

---

## 2. Required Dependency Direction

Communication must follow the modular platform boundary:

```text
App\Domain\IslamicIslamicSundaySchool\Communication
        ↓ depends on
App\Domain\SchoolCore\Communication
        ↓ depends on
App\Domain\SchoolCore\Shared
```

Forbidden dependencies:

```text
SchoolCore\Communication -> IslamicSundaySchool\*
SchoolCore\Communication -> Http\Request
SchoolCore\Communication -> auth()
SchoolCore\Communication -> controller classes
SchoolCore\Communication -> Islamic Sunday School vocabulary
SchoolCore\Communication -> direct unscoped school queries
```

Allowed dependencies:

```text
IslamicSundaySchool\Communication -> SchoolCore\Communication contracts
Http\Controllers -> communication contracts
Jobs -> communication contracts
Communication services -> SchoolContext
Communication services -> shared audit/transaction contracts
Communication services -> queue/mail/SMS/WhatsApp adapters
```

---

## 3. Target Namespace Structure

Create the communication module under `SchoolCore`:

```text
app/
  Domain/
    SchoolCore/
      Communication/
        Contracts/
          CommunicationServiceContract.php
          MessageTemplateServiceContract.php
          RecipientResolverContract.php
          RecipientPreviewServiceContract.php
          RecipientDedupeServiceContract.php
          CommunicationPreferencePolicyContract.php
          ChannelRouterContract.php
          EmailChannelContract.php
          SmsChannelContract.php
          WhatsAppChannelContract.php
          NotificationChannelContract.php
          DeliveryStatusServiceContract.php
          CommunicationAuditLoggerContract.php
          CommunicationIdempotencyServiceContract.php
        DTO/
          ComposeMessageData.php
          SendMessageData.php
          BulkSendMessageData.php
          MessageTemplateData.php
          RecipientQueryData.php
          RecipientPreviewData.php
          RecipientData.php
          ChannelMessageData.php
          CommunicationPreferenceData.php
          DeliveryReceiptData.php
          CommunicationAuditData.php
        Enums/
          CommunicationChannel.php
          CommunicationStatus.php
          RecipientType.php
          MessagePriority.php
          MessageAudienceType.php
          CommunicationAuditAction.php
          DeliveryFailureReason.php
        Exceptions/
          CommunicationException.php
          RecipientResolutionException.php
          RecipientPreviewRequiredException.php
          UnauthorizedCommunicationAccessException.php
          MissingCommunicationPreferenceException.php
          ChannelDeliveryException.php
          DuplicateSendException.php
        Services/
          CommunicationService.php
          MessageTemplateService.php
          RecipientPreviewService.php
          RecipientDedupeService.php
          ChannelRouter.php
          DeliveryStatusService.php
          CommunicationAuditLogger.php
          CommunicationIdempotencyService.php
        Resolvers/
          StudentRecipientResolver.php
          GuardianRecipientResolver.php
          StaffRecipientResolver.php
          ClassRecipientResolver.php
          SchoolWideRecipientResolver.php
        Channels/
          EmailChannel.php
          SmsChannel.php
          WhatsAppChannel.php
          NotificationChannel.php
        Policies/
          DefaultCommunicationPreferencePolicy.php
          DefaultRecipientAuthorizationPolicy.php
        Repositories/
          MessageTemplateRepository.php
          CommunicationLogRepository.php
          RecipientReadRepository.php
        Support/
          CommunicationTransactionRunner.php
          RecipientSet.php
          RecipientFingerprint.php
          TemplateRenderer.php
          MessageSanitizer.php
          DeliveryRetryPolicy.php
```

Islamic Sunday School-specific communication behavior goes here:

```text
app/
  Domain/
    IslamicSundaySchool/
      Communication/
        Resolvers/
          SundayClassRecipientResolver.php
          VolunteerTeamRecipientResolver.php
          MasjidFamilyRecipientResolver.php
          VolunteerRecipientResolver.php
          IslamicSundaySchoolProgramRecipientResolver.php
        Policies/
          IslamicSundaySchoolCommunicationPreferencePolicy.php
          IslamicSundaySchoolRecipientAuthorizationPolicy.php
        Templates/
          IslamicSundaySchoolTemplateCatalog.php
        Providers/
          IslamicSundaySchoolCommunicationServiceProvider.php
```

---

## 4. Core Design Rules

### 4.1 Communication services must require `SchoolContext`

Every public communication method must receive `SchoolContext`.

Example:

```php
public function previewRecipients(
    SchoolContext $context,
    RecipientQueryData $query
): RecipientPreviewResult;
```

A message without `SchoolContext` is invalid. A bulk message without it is basically a confetti cannon pointed at privacy law.

### 4.2 Bulk sends must require preview

No bulk communication may send directly from raw filters.

Required flow:

```text
1. Resolve recipient query.
2. Generate recipient preview.
3. Deduplicate recipients.
4. Apply communication preferences.
5. Store preview snapshot.
6. Confirm/send using preview snapshot ID.
7. Send through channel router.
8. Log every recipient delivery attempt.
```

Forbidden flow:

```text
Controller receives filters -> loops users -> sends emails
```

That flow looks productive until it sends 400 duplicate reminders to one guardian and misses everyone else.

### 4.3 Recipient resolution must be modular

Core recipient types:

```text
students
guardians
staff
teachers
classes/groups
school-wide audience
custom uploaded recipients, if allowed
```

Islamic Sunday School recipient types:

```text
Islamic Sunday School classes
volunteer teams
masjid/community families
volunteers
program attendees
curriculum groups
```

Islamic Sunday School recipient resolvers register through the resolver registry. Core must not know their names.

### 4.4 Communication preferences must be enforced

Every send must check:

```text
channel opt-in/opt-out
recipient contact availability
student/guardian relationship visibility
emergency override rules
quiet hours, if configured
language preference, if configured
legal/sensitive category restrictions
```

Emergency messages may override some preferences only if policy allows it and audit logs record it.

### 4.5 Controllers must not send directly

Controllers may:

```text
- validate request
- authorize route
- build DTO
- call communication contract
- return resource
```

Controllers may not:

```text
- call Mail directly
- call WhatsApp/SMS clients directly
- loop over recipients
- resolve recipient queries directly
- deduplicate recipients directly
- apply preferences directly
- build final templates directly
```

---

## 5. Core Contracts

### 5.1 `CommunicationServiceContract`

```php
namespace App\Domain\SchoolCore\Communication\Contracts;

use App\Domain\SchoolCore\Shared\Context\SchoolContext;
use App\Domain\SchoolCore\Communication\DTO\SendMessageData;
use App\Domain\SchoolCore\Communication\DTO\BulkSendMessageData;

interface CommunicationServiceContract
{
    public function sendMessage(SchoolContext $context, SendMessageData $data): SendResult;

    public function sendBulkMessage(SchoolContext $context, BulkSendMessageData $data): BulkSendResult;

    public function scheduleBulkMessage(SchoolContext $context, BulkSendMessageData $data): ScheduledMessageResult;
}
```

### 5.2 `RecipientPreviewServiceContract`

```php
namespace App\Domain\SchoolCore\Communication\Contracts;

use App\Domain\SchoolCore\Shared\Context\SchoolContext;
use App\Domain\SchoolCore\Communication\DTO\RecipientQueryData;

interface RecipientPreviewServiceContract
{
    public function preview(SchoolContext $context, RecipientQueryData $query): RecipientPreviewResult;

    public function getPreview(SchoolContext $context, string $previewId): RecipientPreviewResult;
}
```

### 5.3 `RecipientResolverContract`

```php
namespace App\Domain\SchoolCore\Communication\Contracts;

use App\Domain\SchoolCore\Shared\Context\SchoolContext;
use App\Domain\SchoolCore\Communication\DTO\RecipientQueryData;

interface RecipientResolverContract
{
    public function supports(RecipientQueryData $query): bool;

    public function resolve(SchoolContext $context, RecipientQueryData $query): RecipientSet;
}
```

### 5.4 `RecipientDedupeServiceContract`

```php
namespace App\Domain\SchoolCore\Communication\Contracts;

interface RecipientDedupeServiceContract
{
    public function dedupe(RecipientSet $recipients): RecipientSet;
}
```

### 5.5 `CommunicationPreferencePolicyContract`

```php
namespace App\Domain\SchoolCore\Communication\Contracts;

use App\Domain\SchoolCore\Shared\Context\SchoolContext;

interface CommunicationPreferencePolicyContract
{
    public function filterAllowedRecipients(
        SchoolContext $context,
        RecipientSet $recipients,
        CommunicationChannel $channel,
        MessageCategory $category
    ): RecipientSet;

    public function canOverridePreferences(
        SchoolContext $context,
        MessageCategory $category
    ): bool;
}
```

### 5.6 `ChannelRouterContract`

```php
namespace App\Domain\SchoolCore\Communication\Contracts;

use App\Domain\SchoolCore\Shared\Context\SchoolContext;

interface ChannelRouterContract
{
    public function route(SchoolContext $context, ChannelMessageData $message): DeliveryResult;
}
```

### 5.7 Channel contracts

```php
interface EmailChannelContract
{
    public function send(SchoolContext $context, ChannelMessageData $message): DeliveryResult;
}

interface SmsChannelContract
{
    public function send(SchoolContext $context, ChannelMessageData $message): DeliveryResult;
}

interface WhatsAppChannelContract
{
    public function send(SchoolContext $context, ChannelMessageData $message): DeliveryResult;
}

interface NotificationChannelContract
{
    public function send(SchoolContext $context, ChannelMessageData $message): DeliveryResult;
}
```

---

## 6. DTO Requirements

Do not pass raw request arrays into communication services.

### 6.1 `RecipientQueryData`

Fields:

```text
audience_type
audience_filters
channel
message_category
include_inactive, default false
include_archived, default false
include_guardians, default true
include_students, default false
include_staff, default false
language, nullable
metadata, nullable
```

### 6.2 `RecipientData`

Fields:

```text
recipient_type
recipient_id
display_name
email, nullable
phone, nullable
preferred_language, nullable
guardian_student_ids, nullable array
staff_id, nullable
student_id, nullable
school_id
delivery_channels
preference_flags
metadata, nullable
```

### 6.3 `ComposeMessageData`

Fields:

```text
template_id, nullable
subject, nullable
body
variables, nullable
message_category
priority
language, nullable
attachments, nullable array
metadata, nullable
```

### 6.4 `BulkSendMessageData`

Fields:

```text
preview_id
channel
subject, nullable
body
template_id, nullable
variables, nullable
message_category
priority
scheduled_at, nullable
idempotency_key, nullable
confirmation_token
metadata, nullable
```

### 6.5 `DeliveryReceiptData`

Fields:

```text
message_id
recipient_id
channel
provider_message_id, nullable
status
failure_reason, nullable
raw_provider_payload, nullable
delivered_at, nullable
failed_at, nullable
```

---

## 7. Recipient Preview Model

### 7.1 Required preview behavior

Preview must show:

```text
total resolved recipients
total after dedupe
total blocked by preference
total missing contact method
total unauthorized/excluded
sample recipients
recipient groups included
recipient groups excluded
estimated channel cost, if available
warning flags
preview expires_at
```

### 7.2 Preview snapshot fields

Suggested table:

```text
communication_recipient_previews
```

Fields:

```text
id
school_id
actor_user_id
audience_type
audience_filters_json
channel
message_category
recipient_count
deduped_count
blocked_count
missing_contact_count
snapshot_json
confirmation_token_hash
expires_at
created_at
```

The send step must use the preview snapshot, not rerun a mutable query without warning. Otherwise “previewed 38 recipients” becomes “sent to 417 recipients” because someone changed a class assignment mid-click. Lovely.

### 7.3 Preview confirmation

Bulk send requires:

```text
preview_id
confirmation_token
idempotency_key
```

The confirmation token proves the user is sending the set they previewed.

---

## 8. Recipient Resolution Strategy

### 8.1 Resolver registry

Create a registry that holds all resolvers.

Resolution flow:

```text
1. Receive RecipientQueryData.
2. Find resolver that supports audience_type/filter.
3. Resolve raw recipient set.
4. Scope to SchoolContext.
5. Apply authorization filters.
6. Dedupe.
7. Apply communication preferences.
8. Return preview.
```

### 8.2 Core resolvers

Core should include:

```text
StudentRecipientResolver
GuardianRecipientResolver
StaffRecipientResolver
ClassRecipientResolver
SchoolWideRecipientResolver
```

### 8.3 Islamic Sunday School resolvers

Islamic Sunday School may register:

```text
SundayClassRecipientResolver
VolunteerTeamRecipientResolver
MasjidFamilyRecipientResolver
VolunteerRecipientResolver
IslamicSundaySchoolProgramRecipientResolver
```

These must implement `RecipientResolverContract`.

---

## 9. Deduplication Rules

Recipient dedupe must handle:

```text
same guardian linked to multiple students
same email used by multiple contacts
same phone used by multiple contacts
staff member also guardian
recipient selected through multiple groups
```

Default dedupe priority:

```text
1. explicit recipient ID
2. verified email
3. verified phone
4. normalized name + contact fallback
```

Dedupe result must preserve reason metadata:

```text
recipient selected by class A
recipient selected by class B
deduped into one delivery
```

This matters because people will ask why they received a message, usually right after the message was unnecessary.

---

## 10. Communication Preferences

### 10.1 Preference dimensions

Preferences may include:

```text
channel
message category
language
quiet hours
emergency override
student-specific guardian communication rules
staff communication rules
unsubscribe status
```

Message categories:

```text
academic
attendance
finance
emergency
general
event
system
religious_or_sensitive, extension-controlled
```

### 10.2 Required enforcement

Before sending:

```text
- remove opted-out recipients unless override is allowed
- remove recipients missing channel contact method
- remove guardians not authorized for selected student/category
- respect quiet hours if configured
- record every exclusion reason
```

### 10.3 Emergency behavior

Emergency messages may override preferences only if:

```text
- actor has permission
- category is emergency
- audit log records override
- message copy is preserved
```

---

## 11. Template and Rendering Rules

### 11.1 Template ownership

Core templates:

```text
attendance notice
finance notice
general announcement
event reminder
system notice
```

Islamic Sunday School templates:

```text
Islamic Sunday School class reminder
program volunteer reminder
curriculum update
masjid family/community announcement
program attendance follow-up
```

### 11.2 Rendering rules

Template rendering must:

```text
- use safe variable interpolation
- reject unknown variables unless policy allows fallback
- support language variants
- render preview before send
- log template version used
```

Forbidden:

```text
eval()
raw user HTML without sanitization
template rendering inside controller loops
```

A message template should not be a tiny remote-code-execution shrine. We have enough problems.

---

## 12. Channel Delivery Strategy

### 12.1 Channel router

The router chooses delivery channel based on:

```text
requested channel
recipient allowed channels
recipient contact availability
school provider configuration
message category
priority
fallback policy
```

### 12.2 Email channel

Must support:

```text
subject
body
attachments, if allowed
reply-to
template version
delivery status tracking, if provider supports it
```

### 12.3 SMS/WhatsApp channels

Must support:

```text
phone normalization
provider configuration by school
message length rules
template approval requirements, if provider requires it
delivery status callbacks
rate limits
```

### 12.4 Notification channel

Must support:

```text
in-app notifications
push notifications, if configured
read status
deep link target
```

---

## 13. Send Logging Requirements

Every send attempt must create a log row.

Suggested tables:

```text
communication_messages
communication_message_recipients
communication_delivery_attempts
communication_recipient_previews
communication_preferences
communication_templates
```

### 13.1 Message log fields

```text
id
school_id
academic_year_id, nullable
term_id, nullable
actor_user_id
channel
message_category
priority
subject, nullable
body_snapshot
template_id, nullable
template_version, nullable
preview_id, nullable
status
scheduled_at, nullable
sent_at, nullable
created_at
```

### 13.2 Recipient log fields

```text
id
message_id
school_id
recipient_type
recipient_id
delivery_address_hash
delivery_address_masked
status
excluded_reason, nullable
provider_message_id, nullable
sent_at, nullable
delivered_at, nullable
failed_at, nullable
created_at
```

Do not store sensitive full delivery addresses in every log table unless there is a clear policy. Store masked/hash where practical. Privacy is not a garnish.

---

## 14. Retry and Failure Handling

### 14.1 Retry policy

Retries should be handled by channel and failure type.

Retryable:

```text
provider timeout
temporary provider failure
rate limit
network error
```

Not retryable:

```text
invalid email
invalid phone
recipient opted out
unauthorized recipient
template rejected permanently
```

### 14.2 Required behavior

```text
- retry count is capped
- every retry attempt is logged
- final failure reason is stored
- provider message ID is stored where available
- bulk send result includes success/failure counts
```

---

## 15. Idempotency Requirements

Bulk sends and direct sends must support idempotency.

Minimum implementation:

```text
idempotency_key
actor_user_id
school_id
operation
payload_hash
result_entity_type
result_entity_id
created_at
expires_at
```

Behavior:

```text
- same key + same operation + same payload returns original result
- same key + same operation + different payload fails
- missing key allowed for legacy clients during transition
```

Apply first to:

```text
bulk send
single send
scheduled send
```

---

## 16. Audit Logging Requirements

Every communication action must create an audit event.

Required audit fields:

```text
school_id
academic_year_id, nullable
term_id, nullable
actor_user_id
actor_role_snapshot
action
entity_type
entity_id
before_json, nullable
after_json, nullable
reason, nullable
request_id
ip_address, nullable
user_agent, nullable
idempotency_key, nullable
created_at
```

Required actions:

```text
communication.preview.created
communication.message.created
communication.bulk_send.confirmed
communication.message.sent
communication.message.scheduled
communication.message.cancelled
communication.delivery.failed
communication.preference.updated
communication.template.created
communication.template.updated
communication.template.archived
```

---

## 17. Authorization Requirements

Minimum actions:

```text
communication.preview
communication.send.single
communication.send.bulk
communication.schedule
communication.cancel
communication.template.view
communication.template.manage
communication.preference.view
communication.preference.manage
communication.delivery.view
communication.audit.view
```

Every communication endpoint must have tests for:

```text
unauthenticated
wrong school
wrong role
wrong audience scope
wrong message category permission
authorized admin
authorized staff
authorized teacher within assigned class scope
authorized finance user for finance messages
authorized attendance user for attendance messages
```

Sensitive audience categories require stronger permission:

```text
emergency
finance
religious_or_sensitive
student discipline
medical, if ever supported
```

---

## 18. Islamic Sunday School Extension Model

Islamic Sunday School communication extends core through resolvers, templates, and policies.

### 18.1 Islamic Sunday School allowed customizations

```text
- Islamic Sunday School class recipient resolver
- volunteer team recipient resolver
- masjid family/community recipient resolver
- volunteer recipient resolver
- Sunday program attendance follow-up resolver
- masjid/family announcement templates
- volunteer/program reminder templates
- religious/sensitive category policy
```

### 18.2 Islamic Sunday School forbidden customizations

```text
- bypassing recipient preview
- bypassing dedupe
- bypassing preferences
- bypassing audit logs
- sending directly from controllers
- hardcoding ministry/masjid/community vocabulary into SchoolCore contracts
- querying recipients without SchoolContext
```

### 18.3 Binding example

```php
$this->app->tag([
    SundayClassRecipientResolver::class,
    VolunteerTeamRecipientResolver::class,
    MasjidFamilyRecipientResolver::class,
    VolunteerRecipientResolver::class,
], 'communication.recipient_resolvers');

$this->app->bind(
    CommunicationPreferencePolicyContract::class,
    IslamicSundaySchoolCommunicationPreferencePolicy::class
);
```

---

## 19. Migration Strategy

### 19.1 Use vertical slices

Recommended order:

```text
1. Recipient preview service
2. Recipient resolver registry
3. Recipient dedupe service
4. Communication preference policy
5. Email channel extraction
6. Bulk send flow
7. WhatsApp/SMS adapter boundaries
8. Template service
9. Delivery status/retries
10. Islamic Sunday School recipient extensions
```

Why this order:

```text
- preview prevents accidental mass sends
- resolver/dedupe creates stable recipient set
- preferences prevent unauthorized/unwanted sends
- email is usually easiest to stabilize first
- SMS/WhatsApp provider behavior needs adapter boundaries
- templates and delivery status build on stable sends
```

### 19.2 Compatibility layer

Existing controllers may remain temporarily, but must delegate to new contracts.

Example:

```text
BroadcastController
  -> BulkSendMessageRequest
  -> SchoolContext
  -> RecipientPreviewServiceContract::preview()
  -> CommunicationServiceContract::sendBulkMessage()
  -> MessageResource
```

Legacy direct-send methods should become wrappers or be deprecated.

### 19.3 Deprecation rule

Every legacy communication method must be labeled as one of:

```text
canonical
adapter
deprecated
remove
```

No unlabeled duplicate send loops.

---

## 20. First Implementation Slice: Recipient Preview

### Objective

Introduce preview-before-send for all bulk communication.

### Tasks

```text
COM-001. Create Communication module scaffold.
COM-002. Create RecipientPreviewServiceContract.
COM-003. Create RecipientQueryData.
COM-004. Create preview snapshot table/model.
COM-005. Implement basic preview for existing audience filters.
COM-006. Add confirmation token.
COM-007. Update bulk send endpoints to require preview_id.
```

### Required tests

```text
- preview returns recipient count
- preview is school-scoped
- preview excludes unauthorized audience
- preview stores snapshot
- expired preview cannot be used
- send without preview fails for bulk messages
```

### Done when

```text
- no active bulk send path can bypass preview
- preview snapshot is used for send confirmation
```

---

## 21. Second Implementation Slice: Resolver Registry

### Objective

Centralize recipient resolution through pluggable resolvers.

### Tasks

```text
COM-008. Create RecipientResolverContract.
COM-009. Create resolver registry.
COM-010. Add core student/guardian/staff/class resolvers.
COM-011. Scope all resolver queries by school_id.
COM-012. Add resolver tests.
```

### Required tests

```text
- resolves guardians for class
- resolves staff group
- resolves school-wide audience
- rejects unsupported audience type
- does not include another school's users
```

### Done when

```text
- recipient queries do not live in controllers
- Islamic Sunday School can register custom resolvers
```

---

## 22. Third Implementation Slice: Dedupe and Preferences

### Objective

Prevent duplicate and unauthorized recipient delivery.

### Tasks

```text
COM-013. Create RecipientDedupeServiceContract.
COM-014. Implement dedupe rules.
COM-015. Create CommunicationPreferencePolicyContract.
COM-016. Implement default preference policy.
COM-017. Add exclusion reason tracking.
```

### Required tests

```text
- same guardian selected twice receives one message
- same email selected through two students dedupes correctly
- opted-out recipient is excluded
- missing email/phone is excluded for relevant channel
- emergency override follows policy
```

### Done when

```text
- bulk preview shows deduped and excluded counts
- send uses deduped/preference-filtered recipient set
```

---

## 23. Fourth Implementation Slice: Email Channel Extraction

### Objective

Move email sending behind a reusable channel contract.

### Tasks

```text
COM-018. Create ChannelRouterContract.
COM-019. Create EmailChannelContract.
COM-020. Implement EmailChannel.
COM-021. Create message and recipient logs.
COM-022. Add communication.message.sent audit event.
COM-023. Update email send endpoints to delegate.
```

### Required tests

```text
- sends single email
- sends bulk email from preview
- logs each recipient attempt
- blocks cross-school recipient
- respects preferences
- idempotency prevents duplicate send
```

### Done when

```text
- controllers do not call Mail directly
- email sends are logged and auditable
```

---

## 24. Fifth Implementation Slice: Bulk Send Flow

### Objective

Standardize bulk send orchestration.

### Tasks

```text
COM-024. Create CommunicationServiceContract.
COM-025. Create BulkSendMessageData.
COM-026. Implement sendBulkMessage().
COM-027. Require preview_id and confirmation_token.
COM-028. Add idempotency support.
COM-029. Add summary result counts.
```

### Required tests

```text
- bulk send requires preview
- invalid confirmation token fails
- expired preview fails
- repeated idempotency key returns same result
- same key with different payload fails
- bulk result includes sent/excluded/failed counts
```

### Done when

```text
- bulk send has one orchestration path
- direct loops are deprecated
```

---

## 25. Sixth Implementation Slice: SMS/WhatsApp Boundaries

### Objective

Move SMS and WhatsApp delivery behind channel contracts.

### Tasks

```text
COM-030. Create SmsChannelContract.
COM-031. Create WhatsAppChannelContract.
COM-032. Implement provider adapter wrappers.
COM-033. Add phone normalization.
COM-034. Add provider failure mapping.
COM-035. Add delivery attempt logs.
```

### Required tests

```text
- invalid phone is excluded
- provider timeout is retryable
- opt-out blocks SMS/WhatsApp
- WhatsApp provider failure is logged
- school-specific provider configuration is respected
```

### Done when

```text
- controllers/services do not call provider SDKs directly
- channel failures are normalized
```

---

## 26. Seventh Implementation Slice: Template Service

### Objective

Centralize templates and rendering.

### Tasks

```text
COM-036. Create MessageTemplateServiceContract.
COM-037. Create TemplateRenderer.
COM-038. Add template versioning.
COM-039. Add variable validation.
COM-040. Add template audit logs.
```

### Required tests

```text
- renders valid template
- rejects unknown required variable
- stores template version used
- supports language variant
- unsafe HTML is sanitized or rejected by policy
```

### Done when

```text
- templates are reusable and versioned
- send logs preserve rendered message snapshot
```

---

## 27. Eighth Implementation Slice: Delivery Status and Retries

### Objective

Track delivery status and retry transient failures.

### Tasks

```text
COM-041. Create DeliveryStatusServiceContract.
COM-042. Create DeliveryRetryPolicy.
COM-043. Add delivery receipt endpoint/handler where provider supports it.
COM-044. Add retry job.
COM-045. Add final failure handling.
```

### Required tests

```text
- delivered receipt updates status
- failed receipt updates status
- retryable failure schedules retry
- non-retryable failure does not retry
- retry limit is enforced
```

### Done when

```text
- delivery status is not guessed
- retry behavior is deterministic
```

---

## 28. Ninth Implementation Slice: Islamic Sunday School Recipient Extensions

### Objective

Add Islamic Sunday School recipient behavior through resolvers and policies.

### Tasks

```text
COM-046. Create SundayClassRecipientResolver.
COM-047. Create VolunteerTeamRecipientResolver.
COM-048. Create MasjidFamilyRecipientResolver.
COM-049. Create IslamicSundaySchoolCommunicationPreferencePolicy.
COM-050. Register resolvers through provider tags.
COM-051. Add Islamic Sunday School-specific templates.
```

### Required tests

```text
- resolves Islamic Sunday School class guardians
- resolves volunteer team members
- resolves masjid family/community group
- Islamic Sunday School resolver cannot return another school's recipients
- SchoolCore does not import IslamicSundaySchool resolver classes
```

### Done when

```text
- Islamic Sunday School communication behavior is extension-driven
- core communication remains school-neutral
```

---

## 29. Database and Schema Requirements

### 29.1 Required indexes

Add or verify:

```text
communication_messages.school_id indexed
communication_messages.actor_user_id indexed
communication_messages.channel indexed
communication_messages.message_category indexed
communication_messages.status indexed
communication_messages.created_at indexed

communication_message_recipients.school_id indexed
communication_message_recipients.message_id indexed
communication_message_recipients.recipient_type/recipient_id indexed
communication_message_recipients.status indexed

communication_delivery_attempts.message_recipient_id indexed
communication_delivery_attempts.provider_message_id indexed, nullable
communication_delivery_attempts.status indexed
communication_delivery_attempts.created_at indexed

communication_recipient_previews.school_id indexed
communication_recipient_previews.actor_user_id indexed
communication_recipient_previews.expires_at indexed

communication_preferences.school_id indexed
communication_preferences.recipient_type/recipient_id indexed
communication_preferences.channel indexed

communication_templates.school_id indexed, nullable
communication_templates.template_key indexed
communication_templates.status indexed
```

### 29.2 Recommended unique constraints

```text
unique(school_id, idempotency_key, operation) where idempotency_key is not null
unique(school_id, template_key, version)
unique(message_id, recipient_type, recipient_id, channel) if one delivery per channel is required
```

---

## 30. FormRequest Requirements

Create or update:

```text
RecipientPreviewRequest
BulkSendMessageRequest
SendMessageRequest
ScheduleMessageRequest
CancelScheduledMessageRequest
CreateMessageTemplateRequest
UpdateMessageTemplateRequest
UpdateCommunicationPreferenceRequest
DeliveryReceiptRequest
```

Each FormRequest must define:

```text
authorize()
rules()
messages(), if needed
toDTO(), optional but recommended
```

Controllers should use:

```php
$data = $request->toDTO();
```

Not raw request merging.

---

## 31. Service Provider Bindings

Create:

```php
namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use App\Domain\SchoolCore\Communication\Contracts\CommunicationServiceContract;
use App\Domain\SchoolCore\Communication\Services\CommunicationService;

final class SchoolCoreCommunicationServiceProvider extends ServiceProvider
{
    public function register(): void
    {
        $this->app->bind(CommunicationServiceContract::class, CommunicationService::class);
        $this->app->bind(RecipientPreviewServiceContract::class, RecipientPreviewService::class);
        $this->app->bind(RecipientDedupeServiceContract::class, RecipientDedupeService::class);
        $this->app->bind(CommunicationPreferencePolicyContract::class, DefaultCommunicationPreferencePolicy::class);
        $this->app->bind(ChannelRouterContract::class, ChannelRouter::class);
        $this->app->bind(EmailChannelContract::class, EmailChannel::class);
        $this->app->bind(SmsChannelContract::class, SmsChannel::class);
        $this->app->bind(WhatsAppChannelContract::class, WhatsAppChannel::class);
        $this->app->bind(NotificationChannelContract::class, NotificationChannel::class);
        $this->app->bind(MessageTemplateServiceContract::class, MessageTemplateService::class);
        $this->app->bind(DeliveryStatusServiceContract::class, DeliveryStatusService::class);
        $this->app->bind(CommunicationAuditLoggerContract::class, CommunicationAuditLogger::class);
        $this->app->bind(CommunicationIdempotencyServiceContract::class, CommunicationIdempotencyService::class);

        $this->app->tag([
            StudentRecipientResolver::class,
            GuardianRecipientResolver::class,
            StaffRecipientResolver::class,
            ClassRecipientResolver::class,
            SchoolWideRecipientResolver::class,
        ], 'communication.recipient_resolvers');
    }
}
```

Islamic Sunday School may add tagged resolvers in its own provider.

---

## 32. Architecture Tests

Add tests that fail if communication boundaries are violated.

Required assertions:

```text
SchoolCore\Communication must not depend on Domain\IslamicIslamicSundaySchool
SchoolCore\Communication must not depend on Illuminate\Http\Request
SchoolCore\Communication services must not call auth()
SchoolCore\Communication services must not call request()
Controllers must not instantiate communication concrete services directly
Bulk send must go through CommunicationServiceContract
Bulk send must require RecipientPreviewServiceContract result
Controllers must not call Mail/SMS/WhatsApp providers directly
```

Optional static checks:

```text
No Sunday/masjid/community/ministry vocabulary inside SchoolCore\Communication contracts
No direct send loops in controllers
No bulk send without preview_id
No provider SDK calls outside channel adapters
No raw recipient query outside resolver classes
```

---

## 33. Rollout Plan

### Step 1: Add communication module scaffolding

```text
- create namespaces
- create contracts
- create DTOs
- create provider
- bind default implementations
```

### Step 2: Add regression tests around current sends

```text
- existing email send
- bulk send
- WhatsApp/SMS send, if present
- recipient targeting
- duplicate recipient behavior
```

Some tests may reveal the current system is doing “creative recipient math.” That is not surprising. That is why this phase exists.

### Step 3: Add preview-before-send

```text
- safest high-value boundary
- prevents accidental mass sends
```

### Step 4: Extract resolver registry

```text
- centralize recipient queries
- enable Islamic Sunday School extensions
```

### Step 5: Add dedupe/preferences

```text
- prevent duplicates
- respect opt-outs and contact rules
```

### Step 6: Extract email channel

```text
- stabilize one delivery path first
```

### Step 7: Standardize bulk send

```text
- confirmation token
- idempotency
- summary result
```

### Step 8: Extract SMS/WhatsApp adapters

```text
- normalize provider failures
- add retry handling
```

### Step 9: Add template service

```text
- version templates
- preserve rendered snapshots
```

### Step 10: Add Islamic Sunday School recipient extensions

```text
- resolvers and templates outside core
```

---

## 34. Implementation Tickets

## COM-001: Create communication module scaffold

### Description

Create the `SchoolCore\Communication` namespace and initial contracts, DTO folders, services, channels, resolvers, enums, exceptions, and provider.

### Acceptance Criteria

```text
- Namespace exists.
- Service provider is registered.
- Empty contracts compile.
- No controller behavior changes yet.
```

---

## COM-002: Add recipient preview service

### Description

Create preview-before-send behavior for bulk communication.

### Acceptance Criteria

```text
- Preview is school-scoped.
- Preview stores recipient snapshot.
- Preview has confirmation token.
- Expired preview cannot be used.
- Bulk send without preview fails.
```

---

## COM-003: Add recipient resolver registry

### Description

Centralize recipient resolution through pluggable resolvers.

### Acceptance Criteria

```text
- Core resolvers are tagged/registered.
- Unsupported audience fails safely.
- Cross-school recipients are excluded.
- Islamic Sunday School can register resolvers without core changes.
```

---

## COM-004: Add recipient dedupe service and preference policy

### Description

Deduplicate recipients and enforce communication preferences.

### Acceptance Criteria

```text
- Duplicate guardian/contact receives one message.
- Opted-out recipients are excluded.
- Missing contact method is excluded.
- Exclusion reasons are visible in preview.
```

---

## COM-005: Extract email channel

### Description

Move email sending behind `EmailChannelContract`.

### Acceptance Criteria

```text
- Controllers no longer call Mail directly.
- Email sends create message and recipient logs.
- Idempotency prevents duplicate send.
- Preferences are enforced.
```

---

## COM-006: Standardize bulk send flow

### Description

Create single bulk send orchestration path using preview snapshot.

### Acceptance Criteria

```text
- Requires preview_id and confirmation_token.
- Uses preview snapshot.
- Returns sent/excluded/failed counts.
- Uses idempotency.
```

---

## COM-007: Extract SMS and WhatsApp adapters

### Description

Move SMS/WhatsApp delivery behind channel contracts.

### Acceptance Criteria

```text
- Provider SDK calls are isolated.
- Phone normalization exists.
- Provider failures are normalized.
- Delivery attempts are logged.
```

---

## COM-008: Add template service

### Description

Create reusable versioned message template service.

### Acceptance Criteria

```text
- Templates are versioned.
- Variables are validated.
- Rendered message snapshot is logged.
- Unsafe content is sanitized or rejected.
```

---

## COM-009: Add delivery status and retry handling

### Description

Track delivery status and retry transient failures.

### Acceptance Criteria

```text
- Delivery receipts update status.
- Retryable failures schedule retry.
- Non-retryable failures do not retry.
- Retry limit is enforced.
```

---

## COM-010: Add Islamic Sunday School communication extensions

### Description

Add Islamic Sunday School recipient resolvers, templates, and preference policy.

### Acceptance Criteria

```text
- Islamic Sunday School resolvers register through provider tags.
- Core does not import IslamicSundaySchool classes.
- Islamic Sunday School recipients are school-scoped.
- Islamic Sunday School templates are extension-owned.
```

---

## COM-011: Add communication architecture tests

### Description

Enforce communication module boundaries in CI.

### Acceptance Criteria

```text
- SchoolCore\Communication cannot import IslamicSundaySchool.
- Communication services cannot call auth() or request().
- Controllers cannot call provider SDKs directly.
- Bulk send cannot bypass preview.
- CI fails on boundary violation.
```

---

## 35. Definition of Done for Phase 6

Phase 6 is done when:

```text
- Communication core contracts exist.
- Bulk communication requires recipient preview.
- Recipient resolution is modular.
- Recipients are deduped.
- Communication preferences are enforced.
- Email delivery uses channel contract.
- SMS/WhatsApp delivery uses channel contracts or adapter boundaries.
- Bulk send uses preview snapshot, confirmation token, and idempotency.
- Message, recipient, and delivery attempt logs exist.
- Delivery retry behavior is deterministic.
- Templates are versioned and rendered safely.
- Islamic Sunday School recipient behavior is implemented through resolvers/policies/templates.
- Communication services require SchoolContext.
- Cross-school recipient leakage is blocked by tests.
- Architecture tests prevent SchoolCore from depending on IslamicSundaySchool.
- Legacy communication methods are labeled canonical, adapter, deprecated, or remove.
```

---

## 36. Non-Goals

Do not include in Phase 6:

```text
- full marketing campaign system
- advanced newsletter builder
- CRM replacement
- donation campaign tooling
- social media posting
- AI message generation
- complete parent portal redesign
- full emergency alert compliance program
```

Those may come later. Phase 6 is about making communication safe, reusable, previewable, and auditable.

---

## 37. Main Risks

### Risk: accidental mass send

Mitigation:

```text
- mandatory preview
- confirmation token
- recipient snapshot
- authorization tests
```

### Risk: duplicate recipients

Mitigation:

```text
- dedupe service
- recipient fingerprint
- preview counts
```

### Risk: cross-school leakage

Mitigation:

```text
- mandatory SchoolContext
- school-scoped resolvers
- architecture tests
```

### Risk: preference violations

Mitigation:

```text
- preference policy
- exclusion reasons
- emergency override audit
```

### Risk: provider chaos

Mitigation:

```text
- channel adapters
- normalized delivery results
- retry policy
- delivery logs
```

### Risk: Islamic Sunday School leakage into core

Mitigation:

```text
- extension resolvers
- template catalog outside core
- vocabulary architecture tests
```

---

## 38. Immediate Next Work Queue

Start here:

```text
1. COM-001 Create communication module scaffold
2. COM-002 Add recipient preview service
3. COM-003 Add recipient resolver registry
4. COM-004 Add recipient dedupe service and preference policy
5. COM-005 Extract email channel
6. COM-006 Standardize bulk send flow
7. COM-007 Extract SMS and WhatsApp adapters
8. COM-008 Add template service
9. COM-009 Add delivery status and retry handling
10. COM-010 Add Islamic Sunday School communication extensions
11. COM-011 Add communication architecture tests
```

Do not start by making nicer templates. A beautiful message sent to the wrong people is still a privacy incident with better typography.
