Skip to main content
Version: 3.0.0

Analytics Domain Design

Document Type: Domain Design (Tier 2) Domain: ANALYTICS, ANALYZER, PROGRESS Domain Character: Stateful SRS References: analytics.md, analyzer.md, progress.md Status: Draft Last Updated: 2026-01-25


1. Overview

1.1 Purpose

The Analytics domain encompasses the core analysis engine that processes PCR run data by executing configured rules against wells. This domain manages:

  • Rule execution pipeline - Executes rules in precedence order, respecting error well handling and LIMS preventability
  • Accession validation - Configurable validation of patient well data during import
  • Progress tracking - Real-time progress feedback for long-running analysis operations with multi-user visibility

This is a stateful domain because analysis jobs progress through discrete lifecycle states (queued, running, completed, failed) and progress state is persisted across user sessions via cache.

1.2 Requirements Covered

REQ IDTitlePriority
REQ-ANALYTICS-001Execute Rules on Error WellsMust
REQ-ANALYTICS-002Control Rule Execution Based on LIMS PreventabilityMust
REQ-ANALYZER-001Configure Accession Validation EnforcementMust
REQ-PROGRESS-001Display Progress for Long-Running ProcessesMust
REQ-PROGRESS-002Persist Progress Tracking Across NavigationMust
REQ-PROGRESS-003Support Multiple Concurrent Progress IndicatorsMust
REQ-PROGRESS-004Display Progress to All Users Viewing Affected ResourcesMust

1.3 Constraints

Tier 2 Constraint: This document describes ownership, patterns, and design rationale. It links to reference docs for full schemas and API specifications. Rule-specific logic is documented in the rules/ subdirectory.

1.4 Dependencies

DirectionDomain/ComponentPurpose
ConsumesRun ModelRun context for analysis
Well ModelWells to analyze
Observation ModelPer-target well observations
Rule ConfigurationConfigured rules with precedence
LimsStatus ModelLIMS outcome configuration
ClientConfigurationAccession validation settings
Provides toRUNRPTAnalysis results for display
NOTIFWell status updates for notifications
REANALYZERe-analysis triggers for combined outcomes

2. Component Architecture

2.1 Component Diagram

2.2 Component Responsibilities

ComponentLayerResponsibilityREQ Trace
RunAnalyseJobQueueQueues analysis for async processing; prevents overlappingREQ-PROGRESS-001
UpdateRunActionActionOrchestrates full analysis pipeline: normalize, analyze, summarize, persistAll
AnalyzerCoreExecutes rules in precedence order against wellsREQ-ANALYTICS-001, 002
WellCoreAbstract well state; tracks error codes, LIMS status, resolutionsREQ-ANALYTICS-001, 002
ObservationCorePer-target observation data; checks LIMS preventabilityREQ-ANALYTICS-002
PatientValidatorValidationValidates patient wells during normalizationREQ-ANALYZER-001
HasValidAccessionValidationChecks accession format against allowed charactersREQ-ANALYZER-001
RunAnalyseProgressProgressCache-based progress tracking per runREQ-PROGRESS-001, 002, 003
RunAnalyseProgressUpdatedEventBroadcasts progress to all connected clientsREQ-PROGRESS-004

3. Data Design

3.1 Entities

This domain does not own persistent entities. It consumes and transforms data from RUNRPT, ERRORCODES, and CLIENTCFG domains.

EntityOwnerUsage in ANALYTICS
runsRUNRPTRead run context, update analysis timestamp
wellsRUNRPTRead/update well state (error_code, lims_status, resolution_codes)
observationsRUNRPTRead/update observation classifications and CT values
rulesRULESRead rule configuration (precedence, allow_error_wells)
lims_statusesLIMSRead LIMS outcome configuration (does_prevent_analyse)
client_configurationsCLIENTCFGRead bypass_accession_validation setting

See Database Reference for full schema.

3.2 Data Structures

Analysis Pipeline Data Flow

// Input to analysis
interface AnalysisInput {
run: Run;
wells: Well[];
observations: Observation[];
runTargets: RunTarget[];
}

// Normalized data after validation
interface NormalizedData {
wells: WellCollection;
run_mixes: RunMix[];
run_targets: RunTarget[];
}

// Analyzed data after rule execution
interface AnalyzedData {
wells: WellCollection;
all_wells: WellCollection; // Includes exported wells for summary
run_mixes: RunMix[];
run_targets: RunTarget[];
}

Progress State

// Cache structure: 'run_analyse_progreses' -> Collection
interface ProgressCache {
[runId: string]: number; // Percentage 0-100
}

3.3 State Transitions

Analysis Job Lifecycle

State Descriptions:

StateEntry ActionProgress %
QueuedJob added to queue0
RunningRunAnalyzeStarted event fired1
NormalizingLoading wells, observations, run targets1-25
AnalyzingExecuting rules in precedence order25-75
SummarizingAggregating results per mix/target75-90
PersistingBatch updating database90-100
CompletedRunUpdated event, progress deleted-
FailedRunUpdateFailed event, progress deleted-

4. Interface Design

4.1 APIs Consumed

EndpointMethodPurposeResponse Fields Used
Internal-Configuration repositoryRules, LIMS statuses, client config

4.2 APIs Provided

This domain does not expose external APIs. Analysis is triggered via job dispatch.

4.3 Events

EventDirectionPayloadPurpose
RunAnalyzeStartedBackend → Frontend{ runId }Notify clients analysis started
RunAnalyseProgressUpdatedBackend → Frontend (Pusher){ runId, percentage }Real-time progress updates
RunUpdatedBackend → Frontend{ runId, username }Analysis completed successfully
RunUpdateFailedBackend → Frontend{ runId, message }Analysis failed with error

Broadcasting Channel: Run.Analyse


5. Behavioral Design

5.1 Rule Execution Pipeline

Algorithm: Execute Rules

Inputs:
- run: Run - The run being analyzed
- wells: WellCollection - Wells to analyze
- runMixes: Collection - Mix configurations
- runTargets: Collection - Target configurations

Outputs:
- analyzedWells: WellCollection - Wells with updated state

Assumptions:
- Rules are loaded from configuration repository sorted by precedence
- Wells have been normalized and validated

Steps:
1. Get rules sorted by precedence for well role/target/specimen combinations
2. Count total rules for progress calculation
3. For each rule in precedence order:
a. Update progress: (ruleIndex / rulesCount * 50) + 25
b. For each well:
i. If well.hasExportDate(): skip (already exported)
ii. If well.limsStatusIsExcluded(): skip (EXCLUDE status)
iii. Check error well handling (§5.2)
iv. Check LIMS preventability (§5.3)
v. If allowed: rule.execute(well, context)
4. Return wells with updated state

Notes:
- Progress range during rule execution is 25-75%
- Rules are idempotent; re-execution produces same result

5.2 Error Well Handling

Algorithm: Check Error Well Processing

Inputs:
- well: Well - The well to check
- rule: Rule - The rule being executed

Outputs:
- shouldExecute: boolean - Whether to execute rule on this well

Steps:
1. If well.hasErrorWhichPreventAnalyse():
a. If rule.is_allow_error_wells == true:
Return true (execute rule)
b. Else:
Return false (skip rule)
2. Else:
Return true (no error, execute rule)

Notes:
- Rules with allow_error_well=true can "recover" error wells
- Error recovery enables downstream rules to resolve upstream errors

5.3 LIMS Preventability Check

Algorithm: Check LIMS Preventability

Inputs:
- well: Well - The well to check
- rule: Rule - The rule being executed

Outputs:
- shouldExecute: boolean - Whether to execute rule on this well

Steps:
1. If well.hasAnalysePreventableLimsStatus():
a. Get LIMS status configuration
b. If limsStatus.does_prevent_analyse == true:
Return false (skip subsequent rules)
2. Return true (continue rule chain)

Notes:
- Preventable LIMS outcomes represent "final" statuses
- Non-preventable outcomes allow subsequent rules to override
- Example: DETECTED (non-preventable) can become INHERITED_CONTROL_FAILURE

5.4 Progress Tracking

5.5 Accession Validation

Algorithm: Validate Accession

Inputs:
- well: PatientWell - The patient well being validated
- config: ClientConfiguration - Client settings

Outputs:
- errors: MessageBag - Validation errors (empty if valid or bypassed)

Steps:
1. If config.bypass_accession_validation == true:
Return empty errors (bypass validation)
2. Get accession value from well
3. Check against allowed character pattern
4. If invalid characters found:
Add validation error
5. Return errors

Notes:
- Bypass is client-level configuration
- Only affects patient wells, not control wells
- Invalid wells are imported but flagged for review

6. Error Handling

ConditionDetectionResponseUser Impact
Rule execution errorException in rule.execute()Log error, set run to failed stateAnalysis aborted, error notification
Database timeoutPDOExceptionRetry with backoff, then failMay see stale data briefly
Overlapping analysisWithoutOverlapping middlewareRelease job after 3 secondsSlight delay in processing
Missing configurationConfig lookup returns nullUse defaults, log warningAnalysis proceeds with defaults
Pusher disconnectConnection lostUI reconnects, refetches stateProgress may be stale briefly

7. Configuration

SettingLocationDefaultEffect
allow_error_wellrules tablefalseWhether rule processes error wells
does_prevent_analyselims_statuses tabletrueWhether LIMS blocks subsequent rules
bypass_accession_validationclient_configurationsfalseSkip accession validation on import
long_running_threshold_secondsclient_configurations10Threshold to show progress indicator
progress_update_interval_secondsclient_configurations2Frequency of progress updates
analyzer.max_execution_timeconfig/analyzer.php90PHP max execution time for analysis

See Configuration Reference for details.


8. Implementation Mapping

8.1 Code Locations

ComponentTypePath
AnalyzerCore Classcode/app/Analyzer/Analyzer.php
WellAbstract Classcode/app/Analyzer/Well.php
ObservationClasscode/app/Analyzer/Observation.php
PatientWellClasscode/app/Analyzer/PatientWell.php
ControlWellClasscode/app/Analyzer/ControlWell.php
PatientValidatorValidatorcode/app/Analyzer/Validators/PatientValidator.php
HasValidAccessionRulecode/app/Analyzer/Validators/Rules/HasValidAccession.php
RunAnalyseJobJobcode/app/Jobs/RunAnalyseJob.php
UpdateRunActionActioncode/app/Actions/Runs/UpdateRunAction.php
RunAnalyseProgressSupportcode/app/Support/RunAnalyseProgress.php
RunAnalyseProgressUpdatedEventcode/app/Events/RunAnalyseProgressUpdated.php
RunAnalyzeStartedEventcode/app/Events/RunAnalyzeStarted.php
RunUpdatedEventcode/app/Events/RunUpdated.php
ConfigurationRepositoryContractcode/app/Analyzer/Contracts/ConfigurationRepository.php
EloquentConfigurationRepositoryRepositorycode/app/Analyzer/EloquentConfigurationRepository.php

8.2 Rules Engine Code

CategoryCountLocation
Classification rules~15code/app/Analyzer/Rules/Wdcls*.php, Wfinalcls*.php
Combined outcome rules4code/app/Analyzer/Rules/*CombinedOutcome*.php
Westgard QC rules7code/app/Analyzer/Rules/Wg*.php
Quantification rules8code/app/Analyzer/Rules/Quant*.php, Rquant*.php
Inhibition rules3code/app/Analyzer/Rules/Inh*.php, SystemicInhibition*.php
Other specialized rules~30Various

See SDS: Rules Engine for detailed rule documentation.

8.3 Requirement Traceability

REQ IDDesign SectionCode Location
REQ-ANALYTICS-001§5.1, §5.2Analyzer.php, Well.php:hasErrorWhichPreventAnalyse()
REQ-ANALYTICS-002§5.1, §5.3Observation.php:shouldSkipRule(), LimsStatus.php
REQ-ANALYZER-001§5.5PatientValidator.php, HasValidAccession.php
REQ-PROGRESS-001§5.4UpdateRunAction.php, RunAnalyseProgress.php
REQ-PROGRESS-002§3.3, §5.4RunAnalyseProgress.php (cache-based)
REQ-PROGRESS-003§3.2RunAnalyseProgress.php (per-run keys)
REQ-PROGRESS-004§4.3, §5.4RunAnalyseProgressUpdated.php (ShouldBroadcastNow)

9. Design Decisions

DecisionRationaleAlternatives Considered
Cache-based progress trackingEnables persistence across navigation without DB writesDatabase table (rejected: too many writes), Session (rejected: no multi-user visibility)
Pusher for real-time updatesExisting infrastructure, low latency, multi-user broadcastPolling (rejected: higher load), SSE (rejected: less browser support)
Job-based async analysisPrevents UI blocking on long operations; supports retriesSynchronous execution (rejected: poor UX for large runs)
Rules as separate classesEach rule is testable; easy to add new rulesSingle rule engine (rejected: monolithic, hard to maintain)
Precedence-based rule orderingDeterministic outcomes; rules can depend on prior rule resultsPriority flags (rejected: harder to reason about)
WithoutOverlapping middlewarePrevents race conditions on same runDatabase locking (rejected: more complex)

DocumentRelevant Sections
SRS: analytics.mdRule execution requirements
SRS: analyzer.mdAccession validation requirements
SRS: progress.mdProgress tracking requirements
SDS: ArchitecturePusher integration, queue architecture
SDS: Rules EngineRule framework overview
SDS: RUNRPT DomainWell/observation data owner
SDS: REANALYZE DomainRe-analysis triggers