Skip to content

Add Contact Center module - #501

Open
MikeAlhayek wants to merge 277 commits into
mainfrom
ma/add-contact-center
Open

Add Contact Center module#501
MikeAlhayek wants to merge 277 commits into
mainfrom
ma/add-contact-center

Conversation

@MikeAlhayek

Copy link
Copy Markdown
Member

No description provided.

Comment thread src/Core/CrestApps.OrchardCore.ContactCenter.Core/Services/IInteractionStore.cs Outdated
Comment thread src/Core/CrestApps.OrchardCore.ContactCenter.Core/Services/InteractionManager.cs Outdated
Comment thread src/Core/CrestApps.OrchardCore.ContactCenter.Core/Services/InteractionStore.cs Outdated
Comment thread src/Modules/CrestApps.OrchardCore.ContactCenter/Manifest.cs Outdated
@github-actions

github-actions Bot commented Jul 1, 2026

Copy link
Copy Markdown

This pull request has merge conflicts. Please resolve those before requesting a review.

MikeAlhayek and others added 2 commits July 1, 2026 10:43
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
AI-Model: gpt-5.5
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
AI-Model: gpt-5.5
MikeAlhayek and others added 7 commits July 1, 2026 11:46
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
AI-Model: gpt-5.5
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions

github-actions Bot commented Jul 6, 2026

Copy link
Copy Markdown

This pull request has merge conflicts. Please resolve those before requesting a review.

MikeAlhayek and others added 2 commits July 6, 2026 15:55
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
MikeAlhayek and others added 7 commits July 31, 2026 19:41
- Subject Flows list: drop disposition tag, show direction plus automated
  interaction type and channel using consistent ta-badge styling
- OmnichannelSubjectPart settings: show the AI configuration only for
  inbound automated subjects, group it in a card, and gate voice/SMS
  settings by channel
- Move the require-disposition hint inline after the label
- Update docs and changelog

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…el endpoint

- Remove the separate AI settings card and its per-batch speech overrides
  for Automatic inventory loads
- Render the AI profile selector inside the Inventory load settings card
  directly under the campaign field, keeping the AI dependency optional so
  the base management feature still does not require IAIProfileManager
- Show the Channel endpoint field only for the Automatic source
- Update docs, changelog, and public API baseline

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ing a profile

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add an indexed CreatedUtc column to the activity batch index and a
dedicated catalog that orders paged results by newest first, so a
newly created inventory load appears at the top of the list. Wire the
Load Inventory admin view to the shared list-management script, render
the pager, and enable the header select-all checkbox.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The admin list header derived the 'in total' count and the visible item
range from the current page's item count, so a paged list reported, for
example, '10 items / 10 items in total' even when more pages existed.
Read the total from the pager shape (TotalItemCount) and compute a
page-aware start/end range across every affected CrestApps admin list.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Replace the ineffective OmnichannelActivityBatchCatalog.PagingAsync override
(which is bypassed by ICatalogManager.PageAsync) with a direct ISession query
ordered by CreatedUtc descending in the Index action, matching the
CallSessionStore ordering pattern. Removes the now-dead custom catalog class
and its registration.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions

Copy link
Copy Markdown

This pull request has merge conflicts. Please resolve those before requesting a review.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
MikeAlhayek and others added 19 commits August 1, 2026 02:38
Consolidate PLAN.md, PLAN-2, PLAN-3, and R0-BASELINE into a single
right-sized, cross-reviewed plan with a checklist tracker. De-scopes
over-engineered/reinvented work in favour of extending Orchard Core
(Deployment/Recipes, IHealthCheck, outbox, retention background task,
RemovingAsync tenant teardown). Reviewed to GO by GPT-5.6 and Opus-5.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Delete the 213-line KnownDevelopmentValues static register (SHA-256 digest
table + generic placeholder-word lists) and its test. Replace it with small,
explicit inline checks at the two call sites that actually enforce the
control:

- DefaultAsteriskOptionsValidator: fails options validation in Production
  when Password / TurnSharedSecret / UserName / PjsipRealtimeConnectionString
  are checked-in development credentials (crestapps-dev*) or unsubstituted
  bracket placeholders.
- AsteriskSoftPhoneRegistrationConfigContributor: runtime TURN-secret guard
  that degrades to STUN-only ICE in Production for tenant-configured values
  that IValidateOptions never sees.

Narrow, honest scope per the production-readiness plan: reject only the
credentials this repo actually ships, no shared static register, no digest
rescan test. Focused tests cover both crestapps-dev credentials and the
template placeholder at the validator site.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Adds three DependencyTag health probes for the production Redis topology,
without introducing any bespoke aggregate health plumbing or a hard
dependency on OrchardCore.HealthChecks:

- ContactCenterDistributedLockHealthCheck (Core): acquires and releases a
  dedicated probe lock via IDistributedLock.
- ContactCenterRedisConnectivityHealthCheck: bounded ConnectAsync + PingAsync
  against the shared Redis connection.
- ContactCenterBackplaneHealthCheck: bounded publish/subscribe round-trip on
  an invocation-unique, tenant-qualified channel to prove the SignalR backplane.

All three resolve IRedisService optionally and report Healthy when Redis is
absent, leaving the topology validator to decide whether Redis is required.
Probes are DependencyTag only, so node readiness stays local. The backplane
check is allowlisted in the architecture guard for its legitimate ISubscriber
use. Adds 10 focused tests including a Moq timeout-cleanup regression test,
and documents the new probes.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…x A2 Redis probes

Remove three classes of dead or dishonest surface and reconcile the A2 health
checks with the pinned no-optional-dependency invariant.

A3 - delete the never-implemented generic provider-webhook ingress
(IProviderVoiceWebhookAdapter, HmacProviderVoiceWebhookAdapterBase,
ProviderVoiceWebhookProcessor, its endpoint and models, and two test fakes).
Both shipping PBXs ingest through IProviderVoiceEventService, so the adapter's
ProcessAsync returned UnknownProvider for every request.

A4 - delete the advertised-but-unimplemented supervisor take-over surface
(MonitorMode.TakeOver, the TakeOver capability bit, its monitoring-service entry
and ResolveCapability arm, and the supervisor-dashboard control). Add
ContactCenterVoiceProviderCapabilityCoverageTests asserting every capability bit
is provider-declared or explicitly reserved.

A5 - delete the entire bespoke Maintenance feature (preview export/reset). Config
export/import now flows through Orchard Deployment steps and Recipes; operational
recovery is database backup/restore. Removes the public maintenance abstractions,
the ManagePreviewData permission, the manifest Feature block, and its tests.

A2 correctness - the earlier A2 commit left four architecture-governance tests red
because the Redis probes took an optional IRedisService, the exact pattern
ContactCenterOptionalDependencyTests forbids. Make IRedisService mandatory on the
Redis-connectivity and backplane probes, move all three distributed-dependency
probes into AddContactCenterRedisHealthChecks registered by a
[RequireFeatures("OrchardCore.Redis")] startup, and guard that registration with
services.Any(IRedisService) exactly as OrchardCore's own Redis sub-features do so
the probes never register when Redis is enabled without a valid connection string.

Regenerate the ContactCenter.Abstractions and .Core public-API baselines, apply a
minimal governance-ledger patch (full release-ledger removal is deferred to T1),
and clean all stale docs references.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Introduce an IAsteriskRealtimeVoiceListener seam so the listener-start
decision in AsteriskRealtimeVoiceTenantEvents is unit-testable without
opening a real WebSocket. The tenant events already gated listener start
on provider-local validation (HasRequiredConfiguration) and ARI-application
ownership (IAsteriskAriApplicationGate.TryAcquire); this adds a test proving
the WebSocket opens only after both pass, and that the gate is not even
consulted when provider-local validation fails.

Contact Center admission remains gated on the topology verdict via
IContactCenterFeatureWorkManager.TryEnter -> ContactCenterTopologyState
.IsAdmissible (fail-closed), already covered by existing lifecycle tests.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add TelephonyCommandNotAdmittedException thrown by the command executor
when the host is already stopping, so a refused command is reported as a
definite non-application rather than an indeterminate outcome. It derives
from OperationCanceledException so existing monitoring/transfer catches
degrade safely to Unknown.

Change IContactCenterRecordingService to return a tri-state
RecordingCommandResult (mirroring TransferResult) so recording no longer
collapses interrupted/timed-out commands to a silent false: NotAdmitted or
guard/governance failures map to Failure, timeout/in-flight cancellation and
unconfirmed provider outcomes map to Unknown, and confirmed changes map to
Success.

Add executor and recording tests for the shutdown paths and regenerate the
Telephony.Abstractions and ContactCenter.Core public API baselines.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…actor)

Add EnterpriseInteractionReportConcurrencyTests proving the only report
provider with mutable per-execution fields (EnterpriseInteractionReportProvider)
cannot leak state across requests: a scoped-lifetime registration assertion
(runs the real AnalyticsStartup.ConfigureServices and asserts every IReport is
ServiceLifetime.Scoped) closes the cross-request shape structurally, and a
real-SQLite reuse test proves RunAsync re-captures agent/capability state each
call. No production change per the plan's prove-before-refactoring directive.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
BuildIdempotencyKey hashed the raw payload bytes, so a whitespace/property-order
or numeric-token change from an Asterisk upgrade or a re-serializing proxy would
silently defeat deduplication and cause double-processing. ARI events carry no
eventId/sequence, so the key is now built from a canonical form of the payload:
object properties are ordered, arrays preserve order, and numeric tokens are
normalized (Int64/UInt64 exact, else shortest round-trippable double), then
SHA-256 hashed and prefixed with provider + event type. Re-serialized redeliveries
of one event dedupe; two genuinely distinct same-type events on one call (differing
in timestamp/varset value/sub-state) keep distinct keys and are both processed.

Adds mapper tests covering property-order re-serialization, numeric re-serialization,
two distinct same-type events on one call, and the provider:eventType key prefix.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…guard

Verification confirms the live CallSession topology is fully typed (Bridge,
ConsultCall, CallLeg, CallRelationship, MonitorSession; ConsultCall.TargetType is
the typed InteractionTransferTargetType) and MediaTopologyId is gone from all
production source. The only historical transfer strings are the audit-only
InteractionTransferHistoryEntry.TargetType/.Result fields, which no neutral
consumer parses back into typed values (reports only count them or group them for
display). Keeps the fields as string (retyping would break the persisted YesSql
JSON of existing interactions).

- Clarifies the XML docs on the two audit fields as historical text snapshots
  that are never re-parsed.
- Adds ContactCenterTransferTopologyTypingArchitectureTests pinning: live consult
  topology uses the typed enum; no live topology model exposes MediaTopologyId or
  a string TargetType; MediaTopologyId stays absent from production source.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…active-process constraint (B6)

- AsteriskAriApplicationOwnershipRegistry.TryClaim now fails closed: blank
  baseUrl/applicationName/tenantName/ownershipToken are denied and logged,
  instead of silently granting a blank claim.
- Inject ILogger into the registry; update the interface XML doc contract.
- Log the single-active-process ownership constraint at startup when the
  Asterisk real-time voice listener starts.
- Document the non-overlapping deployment requirement in the runbook.
- Update ownership/gate tests for the new constructor and deny-on-blank
  behavior.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Bound each run to a wall-clock budget (90s) enforced by both an IClock
  between-operations deadline check and a hard CancelAfter on a linked
  CancellationTokenSource, keeping the run below the 120s distributed-lock
  expiration so a slow run cannot outlive its lock and overlap the next tick.
- Participate in the Routing feature work-admission drain via TryEnter and a
  matching ContactCenterFeatureWorkLifecycleParticipant registration.
- Propagate shutdown cancellation instead of swallowing it; treat deadline
  cancellation as a graceful defer-to-next-tick.
- Observe cancellation between per-item lock acquisitions in
  ActivityReservationService.ExpireDueAsync so contended expiry cannot run
  unbounded past the task lock.
- Update feature-lifecycle contract ledger to implemented-r3 and add tests.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
ReadDateTimeOffset now parses with CultureInfo.InvariantCulture and
DateTimeStyles.AssumeUniversal | AdjustToUniversal so offset-less provider
timestamps are treated as UTC instead of the server's local time zone, and
offset-bearing values normalize to UTC. Exposed the helper as internal for
direct unit testing across cultures.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants