Add Contact Center module - #501
Open
MikeAlhayek wants to merge 277 commits into
Open
Conversation
MikeAlhayek
commented
Jun 29, 2026
MikeAlhayek
commented
Jun 29, 2026
MikeAlhayek
commented
Jun 29, 2026
MikeAlhayek
commented
Jun 29, 2026
|
This pull request has merge conflicts. Please resolve those before requesting a review. |
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
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>
|
This pull request has merge conflicts. Please resolve those before requesting a review. |
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- 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>
|
This pull request has merge conflicts. Please resolve those before requesting a review. |
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.