Community Orchestration
Assignment workflows for Issues and Discussions with real-time notification dispatch to Malet staff via the Alerts service.
Architecture Overview
Community Orchestration bridges two services: the community subgraph owns the assignment state machine and GraphQL API, while the alerts subgraph handles notification fan-out with preference-aware, multi-channel delivery.
| Component | Service | Transport | Purpose |
|---|---|---|---|
| Assignment Mutations | community |
GraphQL | Assign, unassign, state-change |
| Event Dispatch | community โ alerts |
TCP (NestJS Microservices) | Fire-and-forget event emission |
| Notification Delivery | alerts |
Email + Push | Preference-based routing |
Event Flow
โโโโโโโโโโโโโโโโโโโโโโโ TCP emit โโโโโโโโโโโโโโโโโโโโโโโ
โ Community Service โ โโโโโโโโโโโโโโโบ โ Alerts Service โ
โ โ โ โ
โ AssignmentService โ issue_assigned โ CommunityAlerts- โ
โ AssignmentResolver โ issue_created โ Controller โ
โ AlertsClient โ state_changed โ โ
โ โ disc_assigned โ โ NodesClient โ
โ โ disc_created โ โ AlertDelivery โ
โโโโโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโโโโ
โ
โโโโโโโโโโโผโโโโโโโโโโ
โผ โผ โผ
Email Push (In-App)
GraphQL Mutations
Issue Assignment
Assign a Malet staff member to triage an Issue. Only Malet Owners and authorized members should execute assignment mutations.
mutation AssignIssue($input: AssignIssueInput!) {
assignIssue(input: $input) {
id
issueID
title
assignedTo
assignedAt
state
}
}
Variables:
{
"input": {
"issueId": "680abcdef1234567890abcde",
"assigneeId": "user-staff-member"
}
}
Unassign Issue
Remove the current assignee from an Issue, returning it to the unassigned queue.
mutation UnassignIssue($issueId: ID!) {
unassignIssue(issueId: $issueId) {
id
assignedTo
}
}
Change Issue State
Transition an Issue through the state machine: OPEN โ IN_PROGRESS โ RESOLVED โ CLOSED.
mutation ChangeIssueState($issueId: ID!, $state: IssueState!) {
changeIssueState(issueId: $issueId, state: $state) {
id
issueID
state
}
}
Valid states: OPEN, IN_PROGRESS, RESOLVED, CLOSED
When an Issue transitions to CLOSED, the system automatically records a resolvedAt timestamp for SLA compliance tracking.
Discussion Assignment
Discussions follow the same assignment pattern as Issues, allowing Malet staff to take ownership.
mutation AssignDiscussion($input: AssignDiscussionInput!) {
assignDiscussion(input: $input) {
id
discussionID
name
assignedTo
assignedAt
}
}
mutation UnassignDiscussion($discussionId: ID!) {
unassignDiscussion(discussionId: $discussionId) {
id
assignedTo
}
}
Event Types
Every assignment and state-change mutation emits a TCP event to the Alerts service. These are fire-and-forget โ the community service does not wait for delivery confirmation.
| Event | Trigger | Notification |
|---|---|---|
issue_created |
New Issue submitted by a Visitor | Email to Malet staff |
issue_assigned |
Issue assigned to a staff member | Email + Push to assignee |
issue_unassigned |
Assignee removed from Issue | โ |
issue_state_changed |
Issue state transition | Email to Malet staff |
discussion_created |
New Discussion started | Email to Malet staff |
discussion_assigned |
Discussion assigned to staff | Email + Push to assignee |
discussion_unassigned |
Assignee removed from Discussion | โ |
Event Payload Example
// issue_assigned event payload
interface IssueAssignedEvent {
issueId: string; // MongoDB document ID
issueID: string; // Human-readable ID (e.g. "I-a8f3b2")
title: string; // Issue title
subjectId: string; // Malet, Product, or Service ID
subjectType: string; // "MALET" | "PRODUCT" | "SERVICE" | "ORDER"
assignedTo: string; // User ID of the assignee
assignedBy: string; // User ID of the actor who assigned
}
Notification Delivery
The CommunityAlertsController in the Alerts service consumes events and applies preference-aware routing before dispatching.
Delivery Logic
- Profile Resolution โ Fetch assignee profile via
NodesClientServiceto obtain email, push tokens, and notification preferences. - Quiet Hours Check โ If the user has configured quiet hours (e.g.
22:00โ08:00), notifications are suppressed during that window. - Channel Dispatch โ Based on the user's saved preferences:
- Email: Always sent for
assignedandstate_changedevents (unless quiet hours apply). - Push: Sent for
assignedevents and URGENT priorityissue_createdevents.
- Email: Always sent for
- Priority Escalation โ Issues with
URGENTpriority override normal rules and trigger immediate push notifications on creation, ensuring critical customer issues surface instantly.
Preference Integration
Notification preferences are managed via the existing Account Settings โ Notifications panel. The community events respect the same email/sms/push toggles used by Murchase and Workroom notifications.
// Preferences checked per delivery
type Channel = 'email' | 'sms' | 'push';
type Category = 'murchases' | 'workroom' | 'promotions' | 'security' | 'community';
Entity Schema
Issue Fields (Added)
| Field | Type | Description |
|---|---|---|
assignedTo |
String? |
User ID of the assigned Malet staff member |
assignedAt |
DateTime? |
Timestamp when the assignment was made |
Discussion Fields (Added)
| Field | Type | Description |
|---|---|---|
assignedTo |
String? |
User ID of the assigned Malet staff member |
assignedAt |
DateTime? |
Timestamp when the assignment was made |
Environment Configuration
The community service requires TCP connectivity to the alerts service for event dispatch.
# Community service (.env)
COMMUNITY_SERVICE_PORT=3007
ALERTS_SERVICE_HOST=localhost # Alerts TCP hostname
ALERTS_SERVICE_PORT_TCP=3012 # Alerts TCP port
No configuration changes are needed on the alerts service โ it already listens on the configured TCP port.
Module Structure
apps/community/src/
โโโ assignment/
โ โโโ assignment.module.ts # Module wiring
โ โโโ assignment.service.ts # Core assignment logic
โ โโโ assignment.resolver.ts # GraphQL mutations
โ โโโ assignment.service.spec.ts # 14 unit tests
โ โโโ assignment.resolver.spec.ts # 6 unit tests
โ โโโ dto/
โ โโโ assign-issue.input.ts
โ โโโ assign-discussion.input.ts
โโโ external/
โโโ alerts.client.ts # TCP event emitter
โโโ events.ts # 7 event payload interfaces
โโโ external.module.ts # ClientsModule registration
apps/alerts/src/
โโโ community-alerts/
โโโ community-alerts.controller.ts # @EventPattern handlers
โโโ community-alerts.controller.spec.ts # 8 unit tests
โโโ community-alerts.module.ts
โโโ dto/
โโโ index.ts # Payload DTOs
Testing
| Suite | Tests | Coverage |
|---|---|---|
assignment.service.spec.ts |
14 | Assign/unassign/state-change for Issues & Discussions |
assignment.resolver.spec.ts |
6 | Mutation delegation to service layer |
community-alerts.controller.spec.ts |
8 | Event handlers, quiet hours, profile resolution |
community.e2e-spec.ts |
14 | Full workflow: create โ assign โ unassign โ state-change |
Running Tests
# Unit tests (community + alerts)
make test-pattern PATTERN=community
make test-pattern PATTERN=alerts
# E2E tests
make test-e2e-pattern PATTERN=community
Note: E2E tests override
AlertsClientwith a mock since the Alerts service isn't running during test execution. This follows the same pattern used by the Murchases E2E suite.
Related
- Community Features โ Base community system โ reviews, Q&A, ratings, and moderation that Orchestration extends
- Alerts Resilience & Delivery Tracking โ DLQ retry and multi-channel delivery for the notifications dispatched by Orchestration
- Alerts & Notifications โ Frontend toast system and notification monitoring
- Organizations & Permissions โ Permission infrastructure used to gate assignment mutations