Skip to main content
Version: 3.0.1

Software Design Specification: Data Architecture

Document Type: System-Level (Tier 1) Status: Draft Last Updated: 2026-01-25


1. Purpose

This document describes the global data architecture of the PCR Analysis System. It defines the high-level entity model, database technology choices, multi-tenancy strategy, and cross-domain relationships.

This document does not:

  • Define domain-internal entity details (see domain design documents)
  • Provide full table schemas (see Database Reference)
  • Specify business rules for data (see SRS and domain documents)

2. Database Technology

2.1 Primary Database

PropertyValue
EngineAmazon Aurora MySQL 8.0
DeploymentAurora Serverless v2
ConnectionVia Laravel/Vapor with connection pooling
Character Setutf8mb4

Rationale: Aurora Serverless v2 provides auto-scaling for variable workloads, cost optimization during low-usage periods, and managed high availability. MySQL was selected for broad ecosystem support and Laravel compatibility.

2.2 Primary Key Strategy

All entities use UUIDs (ordered UUIDs via Laravel's HasUuid trait) as primary keys:

  • Non-sequential for security (prevents enumeration attacks)
  • Globally unique across all tables
  • 36-character string format stored as CHAR(36)

2.3 Audit Database

Audit records are stored in a separate database connection (database.audit) for isolation and compliance. This prevents audit data from being accidentally modified during application operations.


3. Multi-Tenancy Strategy

3.1 Site-Based Data Partitioning

The system implements logical multi-tenancy using site_id foreign keys:

Key characteristics:

  • Sites represent physical laboratory locations
  • Most configuration and transactional data is scoped by site_id
  • Users can have access to multiple sites via user_visible_sites junction table
  • Site deletion is soft delete (preserves audit trail)

3.2 Site-Scoped Entities

Entity TypeExamplesScoping Pattern
ConfigurationMixes, Targets, Roles, Error Codes, LIMS StatusesDirect site_id FK
TransactionalRuns, Wells, ObservationsVia parent (Run → Site)
QC DataWestgard Limits, Control Range SettingsDirect site_id FK
User AccessVisible SitesJunction table user_visible_sites

3.3 Query Filtering

Site filtering is implemented via Laravel query scopes (FilterableBySite trait):

// All site-scoped queries automatically filter by user's logged_in_site_id
Well::forSite($siteId)->where(...)

4. Global Entity Model

4.1 High-Level ER Diagram

This diagram illustrates cross-domain entity relationships. Domain-internal relationships are documented in respective domain design documents.

4.2 Domain Boundaries

DomainOwned EntitiesKey Relationships
KITCFGKit, Mix, Target, Dye, RoleKit → Mixes → Targets
RUNFILERun, Well, Observation, RunMix, RunTargetRun → Wells → Observations
CONFIGIOErrorCode, ResolutionCode, LimsStatusReferenced by Wells
USERMGMTUser, SiteUser ↔ Sites (many-to-many)
AUDITAuditLinks to User, Run, Well
QCWestgardLimit, WestgardEvent, ControlRangeSettingLinks to Target, Role, Lot

5. Key Cross-Domain Relationships

5.1 Run Processing Pipeline

Data flow:

  1. Run file imported → creates runs record
  2. Wells parsed → creates wells records linked to mixes
  3. Observations created → links wells to targets
  4. Analysis rules execute → may assign error_code_id or lims_status
  5. QC evaluation → updates westgard_limits
  6. Export → sets export_date on wells

5.2 Kit Configuration Hierarchy

Purpose: Kits bundle mixes, which contain targets (analytes). Each target uses a dye for fluorescence detection. Roles (PC, NC, Sample) map to targets for control validation.

5.3 Well State Composition

Wells do not have a single status field. State is computed from multiple indicators:

IndicatorColumnMeaning
Error stateerror_code_idNULL = no error, FK = has error
LIMS outcomelims_statusString code (DETECTED, RPT, etc.)
Export stateexport_dateNULL = not exported, datetime = exported
ExclusionexcludeBoolean flag for manual exclusion
Resolutionresolution_codesPipe-delimited applied resolution codes

Mutual exclusivity: A well has either an error_code_id OR a lims_status, never both simultaneously after analysis completes.


6. Soft Delete Patterns

The system uses Laravel's SoftDeletes trait for entities that require audit trail preservation:

EntitySoft Delete?Reason
usersYesPreserve audit trail references
sitesYesPreserve site-scoped historical data
control_labelsYesPreserve well references
westgard_limitsYesPreserve QC history
tagsYesPreserve run categorization history
runsNoNever deleted (archival instead)
wellsNoNever deleted (part of run)

Implementation: Soft-deleted records have deleted_at timestamp set. Queries exclude soft-deleted records by default via global scope.


7. Audit Trail Approach

7.1 Audit Storage

Audit records are stored in the audits table with:

  • Separate database connection - Isolates audit data from application transactions
  • Microsecond timestamps - High-precision timing for audit sequence
  • Immutable records - No UPDATE or DELETE operations permitted

7.2 Audit Record Structure

ColumnPurpose
usernameActor who performed action
areaFunctional area (Configuration, User Management, Runfile Report)
change_typeEntity type modified
actionAction performed (Created, Edit, Delete)
change_locationContext (resource identifier)
value_beforePrevious value (for edits)
value_afterNew value
site_nameSite context (nullable)

7.3 Audit Event Architecture

Audit events are captured via Laravel's event system:

  1. Domain code dispatches AuditableEvent implementations
  2. LogIntoDatabase listener persists to audit table
  3. ~71 distinct event types across all domains

See SDS: Domain Audit for detailed audit domain design.


8. Data Integrity Patterns

8.1 Referential Integrity

  • Foreign keys enforced at database level for critical relationships
  • Cascade rules vary by relationship:
    • Run → Wells: Cascade delete (wells deleted with run)
    • Well → Error Code: SET NULL on error code delete
    • Site → Runs: RESTRICT (cannot delete site with runs)

8.2 Decimal Precision

QC statistics use high-precision decimals to prevent rounding errors:

-- Westgard limits use decimal(32,10) for sd, mean
sd DECIMAL(32, 10) NOT NULL DEFAULT 0,
mean DECIMAL(32, 10) NOT NULL DEFAULT 0

8.3 Enum Storage

Enums are stored as SMALLINT with application-level mapping:

EntityFieldValues
error_codeserror_type0=Label, 1=Error, 2=Warning, 3=Info, 4=Associate
rolestype1=PC, 2=NC, 3=Sample, 4=Ignore, 5=Quant, 6=Quant&PC, 7=Crossover
lims_statusestype1=Warning, 2=Exclude, 4=Information
observationsfinal_cls0=Neg, 1=Pos, 2=Amb, 3=Neg N/A, 4=Pos N/A, 5=Amb N/A

DocumentRelationship
SDS: Architecture OverviewSystem-level architecture context
SDS: Database ReferenceFull table schemas and column definitions
SDS: Security ArchitectureData access control patterns
SRS: Site ManagementSite entity requirements
SRS: Audit LogAudit trail requirements