SDD Algorithms
Overview
This document contains algorithm descriptions, process flows, and rule execution logic extracted from the System Design Specifications.
Running Rules Architecture
Running rules
Currently each rules is able to call SQL directly to determine applicability and collect metadata needed for the execution thereof. This is potentially causing bottlenecks and an alternative approach is proposed below.
image copy of diagram

Run Import Process
Run Import
The process of importing a run file into PCR.AI.
A run file typically contains data generated from laboratory instruments during a specific run. Importing this file into a PCR.AI system allows for efficient storage, organization, and management of the data within the PCR.AI system. This helps store and organize the data so that scientists can easily find and analyze it. It also allows them to connect the data to specific samples and make reports based on the information.
In the diagram above, the "Run File" represents the file containing data from a lab experiment that needs to be imported into the PCR.AI system. The arrows show the process of importing the run file into the system, where the data will be stored and managed.
High Level Use Case Diagram

Use Case Action Explanations
Verify format (.sds, .pcrd, etc.)
Validate Run file
Run file validation will be handled by the Client Application
Allowed user types
Any user can upload run files except for CLIENT_ADMIN and MANAGER types of users
Allowed File types
- .sds
- .ixo
- .pcrd
- .eds
Only the types mentioned above are allowed.
Mechanism behind the validation
The validation mechanism checks each file to determine if it belongs to the allowed file types. It then separates the files into two categories: valid files and invalid files.
Error Handling
- If uploaded by CLIENT_ADMIN or MANAGER
- Notify user with error message
- Stop executing further
- If there are no valid files,
Notify user with error message
- If some files are invalid and some are valid,
Notify user with warning message
Proceed after validation
The valid files will be passed to another module in the client application for uploading via vapor.
Parse Run File using Parser API
The server application's module will take care of this task, which involves several steps.
Steps
1. Gathering all files
- If use multiple site feature is disabled, then the system will move all files from the root directory into the toPcrai folder in default site.
If If use multiple site feature is enable, then system will use toPcrai folder in related site - Then it takes all files within toPcrai folder of all sites.
- The system will assign a unique name to each file and then move that file into the parsing folder. Then change the import progress state to CONVERTING.
- Finally, the system will call the module that is responsible for handing over each file to the Parser.
2. Module which handovers files to parser
- This module will search for the first converting file. If no file is found, it will stop the execution.
- That file will be handed over to the Parser module.
- After the Parser completes its task with the given file, this module will recursively invoke itself.
3. Parse runfile
-
Firstly, the parser will verify if the given file has already been imported. If it has, the file will be moved to a * problemfiles * folder, and the import state will be changed to DUPLICATE Following this, the execution will be halted.
-
If no duplication is detected, the file will be sent to an external API. The API's response will be an object containing the raw data of the given runfile. In the event that the external API encounters an error with the runfile, the file will be moved to the * problemfiles * folder and the import state will be changed to PARSE_ERROR. Following this, the execution will be halted.
-
If everything proceeds smoothly without any interruptions, the Parser will commence the conversion of the response object into a serialized .json file.

Curve Alignment Algorithm
Overview
Curve alignment is a baseline normalization technique for real-time PCR (qPCR) fluorescence curves. It standardizes curves for comparison across multiple samples or controls.
Scientific Purpose
- Eliminates Background Noise: Early PCR cycles (3-5) represent background fluorescence from instrument baseline, reagent fluorescence, non-specific binding, and environmental factors.
- Standardizes Comparison: Aligned curves enable meaningful comparison of amplification efficiency, CT values, and curve shapes.
- Enables Quality Analysis: Baseline normalization is crucial for accurate CT determination in comparative analysis.
Baseline Calculation Formula
The system calculates normalized fluorescence using a 3-cycle baseline average:
baseline_average = (reading[3] + reading[4] + reading[5]) / 3
normalized_reading[i] = reading[i] - baseline_average
Implementation:
getAverageSeries(readings) {
let average = (readings[3] + readings[4] + readings[5]) / 3
return readings.map(reading => reading - average)
}
Alignment Activation Rules
Alignment is automatically disabled when only one series is shown:
| Condition | Alignment State | Y-Axis Label |
|---|---|---|
| Single curve displayed | Disabled (grayed out) | "Fluorescence" |
| Multiple curves displayed | Available | "Normalized fluorescence" (when enabled) |
Component Implementation
| Component | Alignment Behavior |
|---|---|
ObservationModal.vue | Multiple curve options: curveCurrent (disabled), curveControls, curvesWell, curvesTarget |
RunPlateMapObservationModal.vue | Enabled when multiple wells selected |
WellObservationsModal.vue | Enabled when multiple target observations exist |
| Print views | Always disabled - shows raw fluorescence for lab records |
Data Flow
User toggles checkbox
│
▼
shouldDisableAlignCurves() check
│
▼
[If enabled] getAverageSeries() transformation
│
▼
Chart renders with normalized data
Y-axis label updated to "Normalized fluorescence"
Design Notes
- Baseline cycles (3, 4, 5) are currently hardcoded
- Single curve analysis uses raw fluorescence (no benefit from normalization)
- Print views always show raw fluorescence for consistency with lab records
- User receives tooltip feedback when alignment is unavailable
Run Analysis
Run Analysis
In PCR.AI system, "run file analysis" typically refers to the process of analyzing the data generated from a specific run. It involves processing and interpreting the raw data obtained from instruments conducted in the laboratory. This analysis step helps extract meaningful insights and information from the collected data, such as identifying patterns, calculating metrics, generating reports, or comparing results against established standards and rules. The results of the analysis are often used for quality control, decision-making, and reporting purposes in a laboratory
High Level Use Case Diagram

Configuration Upload Algorithm
Configuration Upload
The configuration import process in a PCR.AI system allows for the seamless integration of data from an Excel file. This process plays a crucial role in ensuring that the PCR.AI system aligns with the specific requirements of the client.
When initiating the configuration import, the PCR.AI system accesses the Excel file, which serves as a repository for the client's configuration data. This data includes various parameters, settings, and rules that dictate how the PCR.AI system functions for the client's specific needs.
How Kit configuration upload and works
Validate Configuration File
While uploading, the file system will validate the Excel file with following conditions:
- The system first checks the file format to ensure compatibility and prevent processing errors. It verifies that the file adheres to the expected formats (.xls, .xlsx.)
- Once the file format is validated, the system verifies the sheet name(s) within the file. This step ensures that the required sheet(s) are present and correctly named, preventing any discrepancies during data processing.
- The system examines the data types within each sheet, verifying that they match the expected format. This validation prevents any potential data inconsistencies or errors caused by incorrect data types, such as using text instead of numbers or vice versa, Data must match according to requirements.
- During the import process, each row or group of rows is checked for validation. If the validation fails, the system will mark them with an "Ignored" status. However, if the validation is successful, the system will assign an "Imported" state to the Excel file
- As a result of this process, the database will be updated
High Level Work Flow Diagram

Configuration Export Algorithm
Configuration Export
The configuration export process in a PCR.AI system allows for the extraction of configuration data from the system into an Excel file. This process plays a crucial role in capturing and documenting the current configuration settings and parameters of the PCR.AI system.
When initiating the configuration export, the PCR.AI system collects the relevant configuration data, which includes various components and settings that have been customized within the system.
How Kit configuration export and works
Collecting Configuration Selections
- The system will gather the configurations the user has selected for export, along with predefined configurations (Dyes, Roles, Rules, WestgardEvents, and Specimens).
- This ensures that essential configurations are included in the export, regardless of user selections.
Generating the Configuration File
- The system will send a request to the API to generate the configuration file.
- The API will retrieve the required data for each configuration category from the database.
- The raw data will be processed and converted into a readable format for inclusion in the export file.
Setting the File Name and Format
- The generated file will be named 'kit-configurations-<logged_in_site_name>.xlsx', where "<logged_in_site_name>" represents the name of the logged-in site.
- The file format will be .xlsx (Microsoft Excel format).
Selecting the File Save Location
- A file browsing dialog will appear, allowing the user to choose the location where they want to save the exported file.
- Browse through your computer's files and folders to select the desired location.
- Once the user has chosen the location, click the "Save" button to save the file.
High Level Flow Chart Diagram

Combined Outcomes Algorithm
Combined Outcomes Configurations
Usage of Combined Outcomes
The user has the ability to determine the outcome based on the combination of mixes and how well these combinations align with the targets. Depending on the results of these combinations, the user can assign different outcome
How Combine outcomes works
When the run file is uploaded, the system will execute the COMBINED_OUTCOME rule to compare well results with each Combined Outcome and determine the appropriate Outcome for the well.
Combimed Outcomes Create Outcomes from CLS results
The different configured targets' CLS combinations should give the specific outcomes

Import, open the run file with different CLS combinations

The COMBINED OUTCOMES rule is triggered. The outcomes are based on the configured CLS combination.
Error Code Generation System
The error code system categorizes and assigns error codes during run analysis to enable auditing, debugging, and quality control workflows.
Error Code Architecture
Error codes are configurable database entities managed through Kit Configuration (REQ-KITCFG-005). The system distinguishes between:
| Category | Description | Examples |
|---|---|---|
| Seed Codes | Must exist in configuration - rule implementations are hardcoded to output them | WG12S_HIGH_WELL, FAILED_POS_TARGET, UNKNOWN_MIX |
| Custom Codes | Added by clients for Combined Outcomes and Resolutions | Client-specific codes for custom workflows |
Error Code Entity Properties (per REQ-KITCFG-005):
code: Unique identifier (e.g., "WG12S_HIGH_WELL")message: Human-readable descriptiontype: Categorization for filtering/reportingaffects: Assignment level (well or target)prevents_analyse: Whether error blocks further processinglims_export: Whether included in LIMS exportcontrol_error,westgard_error,is_inhibited: Classification flags
Error Code Taxonomy
Error codes are categorized by three dimensions:
| Dimension | Values | Description |
|---|---|---|
| Scope Level | WELL, TARGET, MIX | Granularity at which the error applies |
| Category | Analytical, Blocking | Whether error is QC violation or prevents processing |
| Direction | HIGH, LOW, (none) | For directional violations (e.g., CT too high) |
Naming Convention: {CONDITION}_{DIRECTION}_{LEVEL}
- Example:
WG12S_HIGH_WELL= Westgard 1:2s rule, high direction, well level
Blocking vs Analytical Errors
Blocking Errors halt processing at specific stages:
| Stage | Example Errors | Behavior |
|---|---|---|
| Parsing | INVALID_PASSIVE_READINGS, THERMOCYCLER_UNKNOWN, INVALID_FILENAME | File rejected, no wells created |
| Analysis | SAMPLE_LABEL_IS_BAD, UNKNOWN_MIX, INVALID_EXTRACTION_DATE | Well marked as errored, no further analysis |
Analytical Errors flag QC violations but allow processing to continue:
- Westgard rule violations (WG12S, WG13S, WG22S, WG7T)
- Control validation failures (BCC, BNC, BPEC)
- Inhibition detection (INH, IC_FAILED)
Error Code Generation by Rule Category
| Rule Category | Generated Codes | Trigger Condition |
|---|---|---|
| WG12S (1:2s) | WG12S_HIGH_WELL, WG12S_HIGH_TARGET, WG12S_LOW_WELL, WG12S_LOW_TARGET | CT > 2 SD from mean |
| WG13S (1:3s) | WG13S_HIGH_, WG13S_LOW_ | CT > 3 SD from mean |
| WG22S (2:2s) | WG22S_HIGH_, WG22S_LOW_ | 2 consecutive CTs > 2 SD same direction |
| WG7T (7T) | WG7T_HIGH_, WG7T_LOW_ | 7 consecutive CTs trending same direction |
| BCC | FAILED_POS_WELL, FAILED_POS_TARGET, CONTROL_OUT_OF_RANGE_* | Control CT outside configured limits |
| INH | INH_WELL, IC_FAILED | Internal control indicates inhibition |
Sample Label Validation
Sample labels must match pattern: |{tag}:{value}|
| Valid Tags | Description |
|---|---|
| A, C, D, E, T, R, N, X, Y, W | Application-defined tag codes |
Invalid labels generate SAMPLE_LABEL_IS_BAD blocking error.
Error Propagation
Errors propagate based on scope:
- Well-level errors: Affect entire well
- Target-level errors: Affect specific target within well
- Mix-level errors: Affect specific mix within target
Error codes are stored in the errors table and linked to their respective scope (well_id, target_id, or mix_id).
Error Resolution Workflow
Error codes integrate with the Error Resolution system (REQ-KITCFG-006) to enable user-driven resolution of QC errors:
1. ERROR GENERATED
Rule outputs error code → assigned to well/target/mix
│
▼
2. ERROR DISPLAYED
Run File Report shows error code and message
User reviews affected wells
│
▼
3. RESOLUTION APPLIED (optional)
User selects configured resolution action
System applies: outcome change, rule skips, affected wells
│
▼
4. RE-ANALYSIS (if configured)
System re-runs rules, skipping those specified in resolution
Example: "RPT" outcome skips most rules since repeat testing required
Resolution Configuration (per REQ-KITCFG-006):
resolution_message: Text describing the action takenaffected_wells: Which wells receive resolution (by LIMS status, error code, or "All")rules_skipped: Rules to exclude during re-analysisoutcome_on_resolution: LIMS status to apply after resolutionresolution_level: Scope - Well, All Observations, or Discrepant Observations only
Processing Control Flow
The prevents_analyse flag on each error code determines analysis flow (REQ-RULES-ENGINE-003):
Rule executes → outputs error code
│
┌─────────┴─────────┐
│ │
prevents_analyse=true prevents_analyse=false
│ │
Analysis HALTS Continue to next rule
Return error code Accumulate warnings
Wells with blocking errors cannot:
- Have subsequent rules executed
- Be included in Westgard history calculations
- Be exported to LIMS
Related SRS Requirements:
- REQ-ERRORCODES-001 through REQ-ERRORCODES-011 (error code generation)
- REQ-KITCFG-005 (error code configuration)
- REQ-KITCFG-006 (error resolutions)
- REQ-RULES-ENGINE-003 (error/warning flow control)
See: sdd-configuration.md for error code and resolution configuration schemas.
Run Status Calculation
Run Status is the aggregate readiness state displayed on the Runfile List, calculated from the collective state of all patient wells within a run.
Status Determination Logic
INPUT: All wells in run where role = PATIENT
│
▼
┌───────────────────────────────────────┐
│ Count wells by state: │
│ - total_patient_wells │
│ - wells_with_errors │
│ - wells_exportable (no errors) │
│ - wells_exported │
└───────────────┬───────────────────────┘
│
┌───────┴───────┐
▼ ▼
[All exported?] [Any errors?]
│ │
┌───┴───┐ ┌───┴───┐
YES NO YES NO
│ │ │ │
▼ │ ▼ ▼
"All wells │ [Any "All wells
exported" │ exportable?] ready for
│ │ export"
│ ┌───┴───┐
│ YES NO
│ │ │
│ ▼ ▼
│ "Some "No export -
│ wells errors to
│ ready resolve"
│ for
│ export
│ with
│ errors
│ to
│ resolve"
│
└──[Check Westgard]
│
▼
[Westgard error
unresolved?]
│
┌───┴───┐
YES NO
│ │
▼ │
"Reanalysis │
required" │
│
└──→ (use status
from above)
Status Values
| Status | Condition | Export Allowed |
|---|---|---|
| All wells ready for export | All patient wells have no errors | Yes (all) |
| Some wells ready for export with errors to resolve | ≥1 error AND ≥1 exportable | Yes (partial) |
| No export - errors to resolve | ≥1 error AND 0 exportable | No |
| All wells exported | All patient wells have been exported | N/A (complete) |
| Reanalysis required | Unresolved Westgard error affects run | No |
Calculation Rules
- Scope: Only patient wells are counted; control wells are excluded from status calculation
- Error definition: Well has ≥1 error code where
prevents_analyse = trueORlims_export = false - Exportable definition: Well has no blocking errors AND has not been exported
- Westgard override: Unresolved Westgard errors on controls propagate to run status regardless of patient well states
Status Transitions
[New Run Imported]
│
▼
"All wells ready for export" ←───────────────┐
│ │
├──[error detected]──→ "Some/No │
│ export..." │
│ │ │
│ [resolve error]──┘
│
├──[export wells]──→ "Some wells ready..."
│ │
│ [export remaining]
│ │
└──[export all]────→ "All wells exported"
Implementation Notes
- Status is recalculated on: run import, error resolution, well export, reanalysis
- Status is cached in
runs.statuscolumn for list display performance - Westgard status check queries control wells for the same mix/target within configurable history window
Related SRS Requirements:
- REQ-RUNFILE-008 (Display Run Status)
See: Error Code Generation System (above) for error code definitions affecting status.
Complex Functionality - Rules Engine
Complex functionality
Running Rules.
Rules Introduction
Rules in PCR.AI are typically defined by laboratory personnel or system administrators. These rules establish specific conditions, constraints, or requirements that the data must meet. Rules can be created based on regulatory guidelines, internal quality control procedures, or specific protocols.
Rule application
Once defined, the rules are applied to the relevant data within the PCR.AI system. This can include data imported from instruments (from run files), The PCR.AI system evaluates the data against the defined rules to determine if the data meets the specified criteria.
Data validation
The application of rules involves data validation. The PCR.AI system checks whether the data satisfies the defined rules or if any exceptions or violations are present.
Error detection and notification
If any data fails to meet the defined rules, the PCR.AI system identifies the errors or inconsistencies. Notifications or alerts can be generated to inform laboratory personnel about the issues.These notifications will be sent to responsible users for data review or correction.
Action and resolution
Upon receiving the error notifications, laboratory personnel can take appropriate actions to address the identified issues. This may involve Re-extract this well, Re-amplify this sample, Mark as TNP, or Exclude this well from being exported and etc.
Reporting and compliance
Rules in PCR.AI help ensure compliance with regulatory requirements and internal quality control standards. By enforcing rules, the PCR.AI system generates accurate and reliable data, which can be utilized for reporting purposes, audits, or other compliance-related activities.
Flow Chart Diagram

Westgard Rules
Rule Example : Westgard Rules
Simple Westgard rules
These rules look at the CT (or quantity) of the control being measured and check that it is within certain ranges. The following rules are available in PCR.AI:
1:2S rule
This is triggered when a control is more than two SDs from the mean. For example, say you have mean of 30 and SD of 1. Any control having a CT of less than 28 (M-2SD = 30-(21) = 28) or more than 32 (M+2SD = 30 + (21) = 32) will trigger this rule.
(all images: Wikipedia)
1:3S rule
This is triggered when a control is more than three SDs from the mean. For example, say you have mean of 30 and SD of 1. Any control having a CT of less than 27 or more than 33 will trigger this rule.
Westgard rules looking at history
These rules look not only at the current control's CT (quantity) but also at recent controls' results to check that there is not an indication of something unexpected occurring.
2:2S rule
This rule is triggered if both the current control has triggered 1:2S and the previous control has triggered 1:2S or 1:3S etc (either both having high CT/quantity or both having low).
Example: Mean is 30, SD is 1.
Current control SD is 32.1 and previous was 33.2 (ie both were more than +2SD from mean): triggers
- Current control SD is 27.1 and previous was 26 (ie both were more than -2SD from mean): triggers
- Current control SD is 32.1 and previous was 26 – does not trigger
7T rule (from westgard.com )
When seven consecutive control measurements trend in the same direction, i.e., get progressively higher or progressively lower.

Westgard in error
If a Westgard error has been triggered (note some labs do not trigger errors for all of the above eg most will give warning on 1:2S or perhaps not report at all) it means that the testing process itself needs a check by the lab. Therefore any runs that are uploaded having the same mix and control type as a prior control that has received an error (that has not been 'resolved' by the user using manage results) will 'inherit' an error and results will not export.
This is important to avoid user error and especially in cases where the lab is automatically importing runs to PCR.AI and automatically receiving export reports.
In some cases, the laboratory may opt for this to be a warning and not an error.
Rule Mapping Architecture
Understanding How Codes Work and Architecture
The Magic Behind Rule Mapping Execution
- Client Configuration - Rule Mapping
- Decide Whether an Observation [Should / Should Not] Execute Through a Rule
- Map Configured Rule Name with a Php Class
1. Client Configuration for Rule Mapping
Rule Mapping is exposed to the User to Configure through the application. User can define which Rule should trigger for which Target + Role + Specimen Combination of Observations.
Properties of Rule:
- Programmatic Rule Name
- Precedence Order
- Type
- Is Allowed Error Wells
Properties of Rule Mappings:
- Rule
- Role
- Target
- Specimen (optional)
2. Decide Whether an Observation [Should / Should Not] Execute Through a Rule
An Observation has following properties which is used to map against rule
- Role
- Target
- Specimen
Main Condition:
The most basic condition is used to trigger the execution of a rule against an observation is matching the above mentioned properties of an Observation and a Rule.
Example 1
Given
Observation A
Target: Target A
Role: Role A
Specimen: Specimen A
Observation B
Target: Target B
Role: Role B
Specimen: Specimen B
Rule A
Target: Target A
Role: Role A
Specimen: Specimen A
Rule B
Target: Target B
Role: Role B
Specimen: Specimen B
Then
Observation A will trigger Rule A but not Rule B
Observation B will trigger Rule B but not Rule A
Additional Conditions:
- Well which has errors does not trigger any rules, unless
- The Error, does not prevent analyze
- The Rule, accepts error wells
- The Well has 'SKIP' resolution code, does not trigger any rules, unless
- The Rule type is 'Reanalysis'
3. Map Configured Rule Name with a Php Class
Once the decision is made that the observation should executed through a particular rule, the application find the related Php class that represent the rule. then the observation and the other required properties are passed to the rule class and execute.
How the Related Php class is identified for a particular Rule:
- A Rule configured through the Kit Configuration has a property called programmatic_rule_name.
- A list of so called Programmatic Rules as Php classes are Written under the namespace of App\Analyzer\Rules (inside the folder structure of app/Analyzer/Rules/)
The analyzer convert the rule programmatic_rule_name to Upper Camel Case and prefix with the rule namespace, and suffix with 'Rule', and try to find a matching class in the Programmatic Rules List for the fully qualified class name.
$analyzerRuleName = 'App\Analyzer\Rules\'.Str::studly(Str::title($this->programmatic_rule_name)).'Rule';
Conversion Example
| Configuration Rule - Programmatic Rule Name | Fully Qualified Php Class Name |
|---|---|
| THRESHOLD | App\Analyzer\Rules\ThresholdRule |
| WFINALCLS | App\Analyzer\Rules\WfinalclsRule |
| WG14S | App\Analyzer\Rules\Wg14SRule |
| PICQUAL_SERUM | App\Analyzer\Rules\PicqualSerumRule |
| AMB | App\Analyzer\Rules\AmbRule |
Convert to standard JSON format
After the external Parser API returns the raw data object, the system converts it to a standardized JSON structure for internal processing.
Target JSON Schema:
{
"run_metadata": {
"filename": "string",
"import_id": "uuid",
"thermocycler_model": "string",
"thermocycler_instrument": "string",
"run_date": "datetime",
"operator": "string",
"protocol": "string"
},
"wells": [
{
"position": "A1",
"sample_label": "string",
"sample_id": "string",
"observations": [
{
"target": "string",
"dye": "string",
"ct": "number|null",
"quantity": "number|null",
"fluorescence_curve": [/* array of RFU values per cycle */],
"baseline_start": "number",
"baseline_end": "number",
"threshold": "number"
}
]
}
]
}
Conversion Steps:
- Map Parser API response fields to internal schema
- Normalize well positions to standard format (A1-H12 for 96-well)
- Parse fluorescence curve data into numeric arrays
- Extract thermocycler metadata from file headers
- Generate unique import ID for tracking
- Serialize to JSON file in processing folder
Related Requirement: REQ-FILEIMPORT-002
Analyse Run File
After JSON conversion, the system performs analysis through the DXAI Calibrator API and internal rules engine.
Analysis Pipeline:
-
Mix Matching
- Match well targets/dyes to configured mixes
- Create "Unknown" mix entries for unmatched combinations
- Assign role based on Control Labels configuration
-
DXAI Calibrator Integration
- Send observation fluorescence curves to DXAI Calibrator API
- Receive classification parameters (DF, RFU analysis)
- Store calibrator response for each observation
-
Rules Execution
- Execute rules in precedence order by type
- For each observation, evaluate rule mappings (role + target + mix + specimen)
- Skip wells with preventing errors unless rule allows error wells
- Accumulate errors, warnings, and outcomes
-
Outcome Determination
- Apply Combined Outcomes rules based on CLS combinations
- Determine final well status (Valid, Error, Warning)
- Calculate quantities using QIR settings where applicable
-
Westgard Evaluation
- For control wells, evaluate against Westgard limits
- Check historical controls for trend rules (2:2S, 7T)
- Propagate Westgard errors to subsequent runs if unresolved
State Transitions:
CONVERTING→ANALYSING→COMPLETE(success)CONVERTING→ANALYSING→ANALYSIS_ERROR(failure)
Related Requirements:
Store Run File
After successful analysis, run data is persisted to the database and file storage.
Database Storage (Aurora MySQL):
| Entity | Storage Location | Key Data |
|---|---|---|
| Run | runs table | Metadata, status, timestamps, thermocycler info |
| Well | wells table | Position, sample info, role, final status |
| Observation | observations table | Target, CT, quantity, CLS, errors |
| Curve Data | fluorescence_curves table | Raw RFU values per cycle |
| Audit Log | audit_logs table | Import events, state changes |
File Storage (S3):
| Content | S3 Path | Purpose |
|---|---|---|
| Original runfile | {site}/archived/{run_id}/{original_filename} | Audit trail, re-import |
| Parsed JSON | {site}/processed/{run_id}/parsed.json | Debugging, reprocessing |
| Problem files | {site}/problem_files/{filename} | Failed imports for review |
Storage Workflow:
- Begin database transaction
- Insert run record with
STORINGstatus - Insert wells and observations
- Store fluorescence curve data
- Upload original file to S3 archived folder
- Update run status to
COMPLETE - Commit transaction
- Remove file from processing folder
Error Handling:
- Transaction rollback on any storage failure
- File moved to
problem_fileswithSTORAGE_ERRORstatus - Notification sent to configured alert recipients
Related Requirement: REQ-FILEIMPORT-010
API functionality
The system exposes and consumes several APIs for internal processing and external integrations.
Internal APIs (Laravel/Vapor):
| Endpoint Category | Purpose | Auth |
|---|---|---|
/api/runs | Run CRUD, status queries, reanalysis triggers | Cognito JWT |
/api/wells | Well data, observations, error management | Cognito JWT |
/api/kit-config/* | Configuration CRUD (mixes, rules, controls, etc.) | Cognito JWT + Super Admin |
/api/reports | Report generation, export triggers | Cognito JWT |
/api/import | Manual upload handling, import status | Cognito JWT |
/api/export | LIMS export, configuration export | Cognito JWT |
External API Integrations:
| Service | Purpose | Protocol |
|---|---|---|
| Parser API | Convert thermocycler files (.sds, .pcrd, .eds, .ixo) to raw data | REST, API key auth |
| DXAI Calibrator API | Curve classification, DF calculation, observation parameters | REST, API key auth |
| Pusher | Real-time notifications (import progress, analysis status) | WebSocket |
| SendGrid | Email notifications (alerts, reports) | REST, API key |
| Sentry | Error tracking and session replay | SDK integration |
API Authentication:
- User-facing APIs: AWS Cognito JWT tokens (regular + Super Admin pools)
- External service APIs: API keys stored in Vapor secrets
- Inter-service: IAM roles for AWS service-to-service calls
Related Requirements:
- REQ-FILEIMPORT-002 - Parser API integration
- REQ-FILEIMPORT-003 - DXAI Calibrator API integration
Dependencies
Runtime Dependencies:
| Category | Technology | Version | Purpose |
|---|---|---|---|
| Framework | Laravel | 9.x+ | Application framework |
| Deployment | Laravel Vapor | Latest | Serverless deployment to AWS Lambda |
| Database | Aurora MySQL | 8.0 | Primary data store |
| Cache | DynamoDB | N/A | Session storage |
| Storage | S3 | N/A | File storage (runfiles, exports, media) |
| Auth | AWS Cognito | N/A | User authentication and SSO |
| Queue | SQS | N/A | Async job processing |
| Frontend | Vue.js | 3.x | Client-side application |
External Service Dependencies:
| Service | Criticality | Fallback |
|---|---|---|
| Parser API | Critical | Import fails, files queued in problem_files |
| DXAI Calibrator | Critical | Analysis fails, manual classification required |
| Pusher | Non-critical | Polling fallback for status updates |
| SendGrid | Non-critical | Notifications delayed, logged for retry |
| Sentry | Non-critical | Errors logged locally |
Infrastructure Dependencies:
| AWS Service | Purpose | Failure Impact |
|---|---|---|
| Lambda | Compute | Application unavailable |
| Aurora | Database | Full outage |
| S3 | Storage | Import/export unavailable |
| Cognito | Auth | Login unavailable |
| CloudFront | CDN | Degraded performance |
| Route 53 | DNS | Domain resolution failure |
| SQS | Queuing | Async jobs delayed |
Related Architecture: See sdd-architecture.md for detailed AWS service rationale.
Related SRS Requirements
The following SRS requirements are implemented by the design described in this document:
Rules Engine Framework
| Requirement | Domain | Description | Relevance |
|---|---|---|---|
| REQ-RULES-ENGINE-001 | Rules Engine | Conditional Rule Execution Based on Mapping | Implements the rule mapping architecture section - determines which rules execute based on Dye, Target Name, Mix, and Sample Type |
| REQ-RULES-ENGINE-002 | Rules Engine | Sequential Rule Execution Order | Implements the rule precedence execution described in Running Rules Architecture |
| REQ-RULES-ENGINE-003 | Rules Engine | Error/Warning Flow Control | Implements error detection, notification, and "Does prevent Analyse" logic described in Rule Application section |
Run Import Process
| Requirement | Domain | Description | Relevance |
|---|---|---|---|
| REQ-UPLOAD-001 | Upload Runs | Accept Run File Uploads | Implements the run file upload initiation shown in Run Import use case diagram |
| REQ-UPLOAD-002 | Validate Uploaded File Types | Implements file format validation (.sds, .ixo, .pcrd, .eds) described in Allowed File Types section | |
| REQ-UPLOAD-005 | Upload Runs | Display Upload Errors | Implements error handling for duplicate files and parse errors described in Run Import |
| REQ-UPLOAD-007 | Upload Runs | Handle Bulk Uploads | Implements the valid/invalid file separation mechanism described in Run Import |
| REQ-FILEIMPORT-001 | File Import | Import Run Files from Monitored Folder | Implements the monitored folder processing (toPcrai) described in Run Import |
| REQ-FILEIMPORT-002 | File Import | Parse Thermocycler Data to Database Variables | Implements the Parser API integration and JSON conversion described in Parse Run File section |
| REQ-FILEIMPORT-003 | File Import | Analyze Run Data Using DXAI Analyser | Implements the Run Analysis integration with external analyser described in Run Analysis section |
| REQ-FILEIMPORT-010 | File Import | Manage Import Folder Structure | Implements toPcrai, Processing, Problem_Files folder structure described in Run Import |
| REQ-FILEIMPORT-011 | File Import | Prevent Duplicate File Imports | Implements duplicate detection at parsing stage described in Parse Run File section |
Configuration Import/Export
| Requirement | Domain | Description | Relevance |
|---|---|---|---|
| REQ-CONFIGIO-001 | Config I/O | Generate Import Status Reports | Implements the import result status (Imported/Ignored) described in Configuration Upload |
| REQ-CONFIGIO-003 | Config I/O | Import and Export Mixes and Targets Configuration | Implements mix/target configuration import described in Configuration Upload |
| REQ-CONFIGIO-009 | Config I/O | Import and Export Rules Configuration | Implements rules precedence normalization described in Rule Mapping Architecture |
| REQ-CONFIGIO-011 | Config I/O | Validate Westgard Limits on Import | Implements SD validation described in Westgard Rules section |
Combined Outcomes
| Requirement | Domain | Description | Relevance |
|---|---|---|---|
| REQ-RULES-COMBOUT-001 | Combined Outcomes | Evaluate Well Results Against Combined Outcome Configurations | Directly implements the Combined Outcomes Algorithm section - CLS combination matching and outcome determination |
| REQ-RULES-COMBOUT-002 | Combined Outcomes | Support Multi Mix Combined Outcomes | Implements cross-mix outcome evaluation described in Combined Outcomes |
Westgard Quality Control
| Requirement | Domain | Description | Relevance |
|---|---|---|---|
| REQ-RULES-WG-004 | Westgard | Set INVALID_SD Error for Invalid Standard Deviation | Implements SD validation logic described in Westgard section |
| REQ-RULES-WG-006 | Westgard | Trigger Westgard 1:2s Rule | Directly implements 1:2S rule algorithm with formula: delta = ABS(control.ct - mean); threshold = 2 * SD |
| REQ-RULES-WG-007 | Westgard | Trigger Westgard 1:3s Rule | Directly implements 1:3S rule algorithm with formula: threshold = 3 * SD |
| REQ-RULES-WG-009 | Westgard | Trigger Westgard 2:2s Rule | Directly implements 2:2S consecutive control rule described in Westgard Rules section |
| REQ-RULES-WG-011 | Westgard | Trigger Westgard 7T Rule | Directly implements 7T trend detection rule described in Westgard Rules section |
Kit Configuration
| Requirement | Domain | Description | Relevance |
|---|---|---|---|
| REQ-KITCFG-024 | Kit Configuration | Manage Rule Mappings | Implements the Rule Mapping configuration that feeds into Rule Mapping Architecture section |
| REQ-KITCFG-025 | Kit Configuration | Manage Rule Settings | Implements "Is Allow Error Wells" and precedence configuration described in Rule Mapping |
Data Validation and Analysis
| Requirement | Domain | Description | Relevance |
|---|---|---|---|
| REQ-ANALYZER-001 | Analyzer | Configure Accession Validation Enforcement | Relates to the data validation step in Run Analysis |
| REQ-REANALYZE-003 | Reanalyze | Exclude Resolved Controls from Westgard Calculations | Implements "Westgard in error" resolution logic described in Westgard section |
| REQ-REANALYZE-008 | Reanalyze | Update Reanalysis Status for Westgard Series Changes | Implements reanalysis trigger logic related to Westgard control history |
Error Codes
| Requirement | Domain | Description | Relevance |
|---|---|---|---|
| REQ-ERRORCODES-001 | Error Codes | Generate Westgard Rule Error Codes | Implements error code generation for Westgard QC violations (WG12S, WG13S, WG22S, WG7T) |
| REQ-ERRORCODES-002 | Error Codes | Generate Control Check Error Codes | Implements BCC, BNC, BPEC error code generation for control validation |
| REQ-ERRORCODES-003 | Error Codes | Generate Inhibition Error Codes | Implements INH, IC_FAILED error code generation for inhibition detection |
| REQ-ERRORCODES-010 | Error Codes | Generate Parsing Validation Blocking Error Codes | Implements blocking errors at parsing stage (INVALID_PASSIVE_READINGS, THERMOCYCLER_UNKNOWN) |
| REQ-ERRORCODES-011 | Error Codes | Generate Analysis Validation Blocking Error Codes | Implements blocking errors at analysis stage (SAMPLE_LABEL_IS_BAD, UNKNOWN_MIX) |
Data Flow Diagrams
System Data Flow Overview
The PCR.AI system processes data through a unified pipeline from instrument files to LIMS export.
Level 0 - Context Diagram:
Level 1 - Major Processes:
Data Entry Points
| Entry Point | Data Type | Processing Destination |
|---|---|---|
| S3 toPcrai folder | Run files (.sds, .ixo, .pcrd, .eds) | Parse → Analyze pipeline |
| Browser upload | Run files | Uploaded to S3 → same pipeline |
| Configuration upload | Excel (.xlsx) | Kit Configuration import |
| API (optional) | S3 API / AWS Transfer | Direct to toPcrai folder |
Design Note: All run file data enters through the S3 toPcrai folder regardless of upload method. This unified entry point simplifies processing logic and audit tracking.
Data Exit Points
| Exit Point | Data Format | Trigger |
|---|---|---|
| LIMS Export folder | Client-configured format | Manual export or auto-export on run complete |
| Browser download | Excel/CSV | User-initiated export |
| Email notifications | HTML email with links | Alert thresholds, report ready |
| Auto reports | PDF/Excel | Scheduled trends reports |
Export Destination Configuration: Client environment setting determines whether LIMS exports go to S3 folder (for client sync) or browser download.
Critical Data Transformation Points
| Stage | Input | Output | Component |
|---|---|---|---|
| Parse | Thermocycler file | Standardized JSON | Parser API (external) |
| Mix Match | JSON wells | Well records with mix assignment | Laravel job |
| Calibrate | Fluorescence curves | Classification parameters | DXAI Calibrator API |
| Rules | Observations | Outcomes, errors, warnings | Rules Engine |
| Westgard | Control observations | QC violations | Westgard rules |
| Status | Well states | Run status | Status calculator |
Control Flow Diagram
Lambda/Queue Orchestration
PCR.AI uses Laravel Vapor's standard patterns for serverless deployment. There is no custom Lambda orchestration; all asynchronous processing uses Laravel's queue system.
Invocation Patterns:
| Pattern | Mechanism | Use Cases |
|---|---|---|
| Synchronous | API Gateway → Web Lambda | User requests, form submissions, data queries |
| Asynchronous | SQS → Queue Lambda | File parsing, analysis, exports, notifications |
| Scheduled | CloudWatch → Queue Lambda | Alert evaluation, auto-reports |
| Chained | Job dispatches next job | Parse → Analyze pipeline |
Design Note: There is no direct Lambda-to-Lambda invocation. All inter-process communication uses Laravel's standard job dispatching to SQS.
Process Priority Table
Queue Configuration
The system uses a single SQS queue managed by Laravel Vapor with the following configuration:
| Property | Value | Description |
|---|---|---|
| Queue Type | Standard | Not FIFO; allows parallel processing |
| Visibility Timeout | 900 seconds | 15 minutes for long-running jobs |
| Concurrency | 200 | Maximum concurrent queue workers |
| Processing Order | FIFO within queue | Standard SQS ordering |
Job Priority and Processing
All jobs share the same queue. Processing priority is implicit based on dispatch order (FIFO).
| Job Type | Typical Duration | Dispatch Trigger |
|---|---|---|
| ParseRunFileJob | 10-30 seconds | S3 upload event |
| AnalyzeRunJob | 30-120 seconds | Parse completion (chained) |
| ExportToLimsJob | 5-30 seconds | User action or auto-export |
| SendNotificationJob | 1-5 seconds | Various events |
| GenerateReportJob | 10-60 seconds | User action or schedule |
Queue Configuration (from vapor.yml):
queue-timeout: 900 # 15 minutes max job duration
queue-concurrency: 200 # Max parallel workers
Design Notes:
- No priority queues implemented; all jobs processed in dispatch order
- Long-running jobs (analysis) may delay short jobs (notifications) during high load
- Concurrency of 200 provides sufficient parallelism for typical workloads
- Jobs exceeding 900 seconds timeout are failed and logged
Summary
This SDD document provides design-level detail for:
- 34 SRS requirements across 9 domains
- Core algorithmic implementations for rules execution, Westgard QC, and combined outcomes
- Error code generation system with taxonomy, blocking logic, and propagation rules
- File import pipeline from upload through analysis
- Configuration import/export validation and processing
- Data flow diagrams showing entry points, transformations, and exit points
- Control flow diagrams for Lambda/SQS orchestration
- Process priority and queue configuration
- Real-time event broadcasting via Pusher
Real-Time Event Broadcasting (Pusher)
Overview
PCRI.AI uses Pusher for real-time event broadcasting to connected clients. Events are broadcast when significant state changes occur, enabling live UI updates without polling.
Broadcast Channels
| Channel | Scope | Description |
|---|---|---|
Run.Analyse | Public | Run analysis lifecycle events |
Run.Create | Public | Run file import completion |
Run.Calibrate | Public | Assay calibration lifecycle |
run-export | Public | LIMS export events |
run-file-import | Public | File import progress |
control-label-updated | Public | Control label configuration changes |
notifications | Public | Notification read state |
App.User.{userId} | Private | User-specific events (auth, session) |
Event Classes and Triggers
Run Lifecycle Events (Run.Analyse channel)
| Event Class | Trigger | Payload |
|---|---|---|
RunAnalyzeStarted | Analysis job dispatched | runId |
RunAnalyseProgressUpdated | Analysis progress checkpoint | runId, percentage |
RunUpdated | Analysis complete | runId |
RunUpdateFailed | Analysis failed | runId, error details |
Run Import Events
| Event Class | Channel | Trigger |
|---|---|---|
RunCreateCompletedBroadcast | Run.Create | Run file successfully imported |
RunFileImportProgressBroadcast | run-file-import | Import progress update |
Export Events
| Event Class | Channel | Trigger |
|---|---|---|
RunExportBroadcast | run-export | LIMS export initiated/completed |
Calibration Events (Run.Calibrate channel)
| Event Class | Trigger |
|---|---|
AssayCalibrationStarted | Calibration job started |
AssayCalibrationCompleted | Calibration finished |
User Events (App.User.{userId} private channel)
| Event Class | Trigger |
|---|---|
UserLoggedIn | Successful authentication |
OtherDeviceLogout | Session invalidated on other device |
UserAccountDisabled | Admin disabled account |
UserAccountDeleted | Account deleted |
Configuration Events
| Event Class | Channel | Trigger |
|---|---|---|
ControlLabelUpdateBroadcast | control-label-updated | Control label config saved |
NotificationRead | notifications | User marked notification as read |
Broadcast Types
- ShouldBroadcast: Queued broadcast (runs via queue worker)
- ShouldBroadcastNow: Immediate broadcast (synchronous, used for progress updates)
Implementation
| Component | Location |
|---|---|
| Run Analysis Events | app/Events/RunAnalyze*.php, app/Events/RunUpdated.php |
| Import Events | app/Events/RunCreateCompletedBroadcast.php, app/Events/RunFileImportProgressBroadcast.php |
| Export Events | app/Events/RunExportBroadcast.php |
| User Events | app/Events/UserLoggedIn.php, app/Events/OtherDeviceLogout.php, app/Events/UserAccount*.php |
| Calibration Events | app/Events/AssayCalibration*.php |
| Channel Authorization | routes/channels.php |
Design Notes
- Progress events use
ShouldBroadcastNowfor real-time feedback (no queue delay) - User-specific events use private channels requiring authentication
- Public channels do not contain sensitive data
- Event payloads are minimal; clients fetch full data via API after receiving notification
Asynchronous Job Processing
Overview
PCRI.AI uses Laravel's queue system for asynchronous processing. Jobs handle long-running operations to maintain responsive user experience.
Queue Configuration
| Property | Value | Description |
|---|---|---|
| Default Driver | sync | Environment variable QUEUE_CONNECTION |
| Queue Table | jobs | For database driver |
| Failed Jobs Table | failed_jobs | Failed job storage |
| Retry After | 90 seconds | Database driver timeout |
Scheduled Jobs
| Command | Schedule | Purpose |
|---|---|---|
trends-report-alerts:schedule-check | Every minute | Evaluate alert thresholds |
Job Classes Inventory
| Job Class | Trigger | Purpose | Timeout | Retry |
|---|---|---|---|---|
| RunDataParseJob | DispatchNextFileToParsingAction | Parse run data from file, dispatch next file | 900s | 400 attempts |
| RunStoreJob | RunStoreRequestHandler | Create new run with wells from cached data | default | default |
| RunAnalyseJob | (Orphaned - not currently dispatched) | Update run with analyzed data | default | 3s release |
| RunUpdateJob | RunUpdateRequestHandler | Update run with analyzed well data from cache | default | default |
| ResolveRunJob | ResolveRunRequestHandler | Apply resolution codes to wells | default | default |
| ResolutionConfirmJob | ResolutionConfirmationRequestHandler | Apply confirmed resolution codes | default | default |
| RunResultExportJob | RunResultExportsController | Export run results to cloud storage | default | default |
| RunDeleteJob | DeleteRunsAction | Delete all runs for a site | default | default |
| AuditExportJob | AuditExportsController | Export audit logs to cloud storage | 900s | 1 attempt |
| ConfigDataImportJob | ConfigDataController | Import kit configuration from Excel | default | default |
| AssayCalibrationGetResultJob | AssayCalibrateableRunsController | Retrieve calibration results | default | default |
| NormalizeWithDefaultExtractionSettingsJob | UpdateClientConfigurationAction | Normalize extraction settings after config update | default | default |
| NormaliseDataForControlLabelUpdateJob | ControlLabelsController | Update control labels across site | default | default |
| UpdateDailyOutcomeTableJob | Multiple actions | Update daily outcomes table for trends reporting | default | default |
Processing Patterns
Async Threshold Decision:
- Operations with ≤100 wells or ≤50 future runs: Processed synchronously
- Larger operations: Queued for async processing
Data Persistence Strategy:
- Temporary run data stored in cache (
run_jsons_to_queue) - UUID identifiers used to reference cached data
- Jobs retrieve data via cache lookup
Event Broadcasting:
- Real-time UI updates via Laravel Broadcasting
- Events:
RunCreateCompletedBroadcast,RunExportBroadcast,ControlLabelUpdateBroadcast
Failure Handling
| Job | Failure Behavior |
|---|---|
| RunDataParseJob | Aggressive retry (400 attempts) |
| AuditExportJob | No retry; logs via failed() callback |
| Most jobs | DB transaction rollback; exception re-thrown |
Implementation
| Component | Location |
|---|---|
| Job Classes | app/Jobs/*.php |
| Queue Configuration | config/queue.php |
| Schedule Definition | app/Console/Kernel.php |
Trends Report Data Caching
Daily Outcomes Materialized Cache
The Trends Report relies on the daily_outcomes table, which stores pre-aggregated data as a materialized cache to improve query performance.
Purpose
This table serves as a materialized cache that aggregates well-level data to avoid expensive real-time queries on the large wells table when generating trends reports.
Data Population
The table is populated from well data with the following logic:
- Source Data: Aggregates data from the
wellstable - Date Handling:
- Extraction dates are converted to lab timezone and stored as date-only (time component removed)
- Non-extraction controls (e.g., NTC, PCR controls) inherit the date from their run
- This ensures all wells in a run are grouped by the same date in the lab's timezone
- Aggregation: Groups wells by date, site, thermocycler, mix, outcome type, and role alias
- Count: Stores the number of wells matching each unique combination
Table Schema
| Column | Type | Description |
|---|---|---|
date | DATE | The date of the outcome (lab timezone, date-only) |
site_id | FK | Laboratory site identifier |
thermocycler_id | FK | Thermocycler identifier |
mix_id | FK | Mix identifier |
outcome_id | FK (nullable) | Error code or LIMS status ID (NULL for "Control Passed") |
role_alias | VARCHAR | Sample type (Patient, QC, etc.) |
count | INT | Number of wells with this outcome |
is_crossover | BOOLEAN | Whether this is a crossover control |
Update Strategy
| Operation | Component | Trigger |
|---|---|---|
| Initial Population | PopulateDailyOutcomesTableAction | Migration or manual rebuild |
| Incremental Updates | UpdateDailyOutcomesTableAction | Run file processed |
| Background Job | UpdateDailyOutcomeTableJob | Dispatched after each run upload |
| Full Regeneration | Migration | Data correction required |
Performance Characteristics
- Query Speed: Trends report queries execute in milliseconds instead of seconds/minutes
- Storage Trade-off: Uses additional storage space for pre-computed aggregates
- Synchronization: Automatically synchronized with run data via job dispatching
Query Algorithm
The report query follows this algorithm:
- Join
daily_outcomeswithsites,mixes,thermocyclers, and outcome tables - Filter by selected parameters:
role_alias(Patient or QC)thermocycler_idssite_ids(when multiple sites enabled)mix_idsoutcomesdaterange
- Group by selected dimensions (site, date interval, thermocycler, mix, outcome)
- Calculate aggregates:
well_count: Sum of counts for each grouppercentage: Percentage within each partition (mix/site/thermocycler/date)
- Order results by date
Aggregation Options ("Compare By")
When aggregation is enabled, data is combined:
| Option | Effect |
|---|---|
| Mixes | Combine all selected mixes into a single trend line |
| Thermocyclers | Combine all selected thermocyclers into a single trend line |
| Outcomes | Combine all selected outcomes into a single trend line |
Multiple aggregations can be enabled simultaneously.
Trends Report Alerts
Alert Types
| Threshold Type | Trigger Condition |
|---|---|
| Count-Based | Well count exceeds configured numeric threshold |
| Percentage-Based | Outcome percentage exceeds configured percentage value |
Alert Trigger Mechanisms
| Trigger | Component | Schedule |
|---|---|---|
| Immediate | NotifyTrendAlertsAction | On each run processed |
| Periodic | NotifyPeriodicTrendAlertsAction | Via TrendsReportAlertsScheduleCheck command |
Periodic alerts support:
- Daily, weekly, and monthly schedules
- Specific day and time configuration based on site timezone
Feature Import/Cascade System
Overview
The Feature Import System provides comprehensive validation and processing capabilities for importing feature configuration data via Excel files. The system implements a robust architecture ensuring data integrity, dependency validation, and proper cascade handling.
Architecture
FeaturesImportSheet (Excel Import Orchestration)
↓
FeatureImportOrchestrator (Process Coordination)
↓
├── FeatureValidator (Validation Logic) ──┐
├── FeatureUpdateService (Business Logic) │
└── FeatureCascadeService (Cascade Logic) │
│
FeatureParentService ──────────┘
(Shared Parent Chain Logic)
↑
ToggleFeatureAction (Feature Toggle UI)
Component Responsibilities
| Component | Location | Responsibility |
|---|---|---|
| FeaturesImportSheet | app/Imports/Sheets/ | Excel import orchestration |
| FeatureImportOrchestrator | app/Imports/Sheets/Support/Features/ | Process coordination |
| FeatureUpdateService | app/Imports/Sheets/Support/Features/ | Update business logic |
| FeatureCascadeService | app/Features/ | Shared cascade dependency logic |
| FeatureParentService | app/Features/ | Shared parent chain logic |
| FeatureValidator | app/Imports/Sheets/Support/Features/Validators/ | Validation orchestration |
Validation Rules
Feature Code Validation
| Rule | Description |
|---|---|
| Required | Feature code cannot be empty |
| Type | Must be string |
| Length | Maximum 255 characters |
| Existence | Feature must exist in system |
| Restrictions | use_multiple_sites, preserve_s3_structure_for_first_site cannot be modified via import |
Feature Value Validation
| Rule | Description |
|---|---|
| Boolean only | is_enabled field must be valid boolean |
| Supported formats | true/false, 1/0, yes/no, TRUE/FALSE |
| Null handling | Null values treated as false |
| Consistency | Uses BooleanCaster for uniform handling |
Parent Dependency Validation
The system implements recursive parent chain validation to ensure dependency integrity:
- Only validates when ENABLING a feature (not when disabling)
- Checks entire parent chain recursively up to root
- Import-first logic: Checks parent status from import rows before database
Example Dependency Chain:
trends_report (root)
↓
trends_report_builder (parent)
↓
trends_report_ai_assistant (child)
Validation Scenarios:
| Scenario | Import Data | Result |
|---|---|---|
| Enable parent and child together | trends_report=true, trends_report_builder=true | ✅ Success |
| Disable any feature | trends_report_ai_assistant=false | ✅ Success (no parent check) |
| Enable child with disabled parent | trends_report=false, trends_report_ai_assistant=true | ❌ Error |
| Enable child with disabled grandparent | trends_report=false, trends_report_builder=true | ❌ Error |
Cascade Disable Pattern
The system implements a one-way cascade disable pattern:
| Action | Result |
|---|---|
| Disable Parent | Auto-disable all children (recursive) |
| Enable Parent | Children remain unchanged (manual control) |
Cascade Example:
Before: trends_report = enabled
trends_report_builder = enabled
trends_report_ai_assistant = enabled
Action: trends_report = disabled
Result: trends_report_builder = disabled (cascaded)
trends_report_ai_assistant = disabled (recursively cascaded)
Dependency Configuration
Dependencies defined in AffectedFeatures::AFFECTED_FEATURES_WHEN_UPDATING:
[
'trends_report' => [
'trends_report_aggregate',
'trends_report_alerts',
'trends_report_builder',
],
'trends_report_builder' => [
'trends_report_ai_assistant',
],
]
Import Process Flow
1. EXCEL FILE PROCESSING
Read Excel file with headers
Process in chunks of 1000 rows
Map each row to collection with status tracking
│
▼
2. VALIDATION PHASE
Feature Code Validation → Existence, restrictions, format
Feature Value Validation → Boolean format validation
Parent Dependency Validation → Recursive chain validation
│
▼
3. UPDATE PHASE
Modification Check → Only update if value changed
Feature Update → Set new is_enabled value
Cascade Processing → Handle dependent feature changes
│
▼
4. STATUS REPORTING
Success → "Feature: imported"
Validation Error → "Feature: ignored: [error details]"
Dependency Error → "Feature: ignored: Cannot enable '[child]' because parent feature '[parent]' is disabled"
Error Types
| Category | Example Message |
|---|---|
| Feature Code | "Feature code is required", "Feature does not exist in the system" |
| Feature Value | "Feature value must be a valid boolean (true/false, 1/0, yes/no)" |
| Parent Dependency | "Cannot enable '[child]' because parent feature '[parent]' is disabled" |
| Restriction | "Feature is restricted and cannot be modified through import" |
Performance Considerations
- Chunk Processing: Handles large files via 1000-row chunks
- Efficient Lookups: Uses collection methods for feature matching
- Minimal Database Queries: Loads features once per chunk
- Recursive Optimization: Cascade only when necessary (disabled features)
Role Alias to Role Workflow
Overview
The Role Alias to Role feature creates a new Role from an existing control-label alias and migrates all dependent quality-control configuration. This workflow allows laboratories to promote an alias already in use on control labels into a fully-fledged role without manually recreating every dependent mapping.
Entry Points
| Component | Location |
|---|---|
| API Route | POST /api/role-alias-to-role |
| Controller | RoleAliasToRoleController |
| Action | MapRoleAliasToNewRoleAction::execute() |
Request Parameters
| Parameter | Description |
|---|---|
role_alias | Alias shared by existing control labels |
role_name | Target name for the new role |
role_id | Identifier of currently mapped role that owns the alias |
Authentication required; executing user provides site context via getLoggedInSiteId().
Transactional Workflow
MapRoleAliasToNewRoleAction runs inside a single database transaction to ensure atomicity:
1. GATHER SOURCE DATA
Load all control labels matching alias and original role
Include source role's metadata (type, extraction flag, resolution priority)
Fetch associated rule mappings and combined outcome records scoped to user's site
│
▼
2. CREATE TARGET ROLE
Clone key fields from source role
Use authenticated user's site
Preserve type, has_extraction, resolution_priority
│
▼
3. RELINK CONTROL ECOSYSTEM
Update matched control labels → reference new role
Update wells → reference new role
Restore soft-deleted Westgard limits for alias
Reassign control range settings tied to affected targets
│
▼
4. DUPLICATE RULE CONFIGURATION
Insert copies of matching RuleMapping records with new UUIDs
Keep original created/updated timestamps
Remove original mappings once ALL aliases tied to old role migrated
│
▼
5. CLONE COMBINED OUTCOMES
Create new outcome records per original
Create new mix-result and target-result rows
Suffix names and codes with <new-role-name>-clone
Set new created_at/updated_at timestamps
│
▼
6. COMMIT OR ROLLBACK
Success → DB commit
Any exception → Transaction rollback, original config untouched
Data Dependencies
| Entity | Purpose |
|---|---|
ControlLabel | Source of alias, provides mix_id for target scoping |
Well | Updates ensure historical well data references new role |
RuleMapping / Target | Copied to retain rule behavior for mixes tied to alias |
WestgardLimit / ControlRangeSetting | QC thresholds and per-target ranges reactivated for new role |
OutcomeToLimsStatusMapping | Duplicated to maintain combined outcome logic |
Combined Outcome Duplication Details
| Property | Handling |
|---|---|
| UUID | New ordered UUID generated |
| Code | Suffixed with -<role_name>-clone |
| Name | Suffixed with -<role_name>-clone |
| Mix/Target Results | Cloned with fresh identifiers |
| Behavioral flags | Preserved from original |
| Timestamps | Set to current time during duplication |
Role Cleanup Logic
deleteOriginalRuleMappings() runs only after all control labels linked to the original role have been remapped. This prevents accidental loss of rules while aliases remain.
Implementation
| Component | Location |
|---|---|
| Controller | app/Http/Controllers/RoleAliasToRoleController.php |
| Action | app/Actions/ControlLabels/MapRoleAliasToNewRoleAction.php |
| Tests | tests/Feature/ControlLabels/RoleAliasToRoleTest.php |
Related SRS Requirements (Async Processing)
| Requirement | Domain | Description | Relevance |
|---|---|---|---|
| REQ-FILEIMPORT-001 | File Import | Import Run Files from Monitored Folder | RunDataParseJob, RunStoreJob |
| REQ-AUDIT-003 | Audit Log | Export Audit Data | AuditExportJob |
| REQ-CONFIGIO-001 | Config I/O | Generate Import Status Reports | ConfigDataImportJob |
Developer Documentation Cross-References
The following developer-focused documentation in code/docs/ provides additional implementation details beyond this SDD:
| Code Docs File | SDD Coverage | Developer Content |
|---|---|---|
features/run-analyzer-system.md | Partial | CreateRunAction 10-step workflow, UpdateRunAction details, Normalizer architecture |
features/trends-report.md | Added | Additional filter logic, API endpoints, chart visualization |
features/outcomes-report.md | Not in SDD | Well query algorithm, pagination strategy, export streaming patterns |
testing-guidelines.md | Not in SDD | Testing strategy breakdown (Unit/Feature/E2E/Integration) |
laravel-boost-guidelines.md | Not in SDD | Laravel coding standards and conventions |
Note: The code/docs layer serves as a "living developer guide" with implementation-specific details, while this SDD provides IEEE 1016-1998 compliant design specifications.