← All seeds
lims ADL v0.3.1

NGS Laboratory (LIMS)

A next-generation-sequencing lab information system. Samples move receipt → QC → library prep → sequencing → analysis, tracked against instruments, protocols, and runs.

Resources
Project, Sample, Instrument, Protocol, Run, Analysis
Roles
admin, pi, lab_tech, authenticated
Features (8)
auditsearchexportstate_machinem2m_relationshipspermissionsrich_enumscomputed_fields

Next-generation sequencing (NGS) laboratory information management system. Tracks the complete workflow from sample receipt through quality control, library preparation, sequencing on high-throughput instruments, and bioinformatics analysis. Supports Illumina (NovaSeq 6000, NextSeq 2000, MiSeq) and Oxford Nanopore (MinION) platforms. Designed for a core facility processing 50-200 samples per week across multiple research groups.

Resources

ResourceFeatures
ProjectCRUD, audit, search. Groups related samples from a single research group or grant. Tracks PI, organism, target sample count, and timeline.
SampleCRUD, audit, search, export, state machine (7 states). Biological sample progressing through the NGS workflow. Carries QC metrics (concentration, volume, RIN/DIN, purity ratios) and library prep details.
InstrumentCRUD, audit. Sequencing instrument in the core facility. Tracks platform, serial number, operational status, maintenance schedule, and cumulative run count.
ProtocolCRUD, search. Standard operating procedures for library prep and sequencing. Specifies applicable sample types, platforms, input requirements, and expected turnaround.
RunCRUD, audit, search, export, state machine (5 states). Sequencing run on an instrument. Processes one or more samples via the RunSamples junction table. Records post-run QC metrics (total reads, Q30, yield).
AnalysisCRUD, audit, state machine (4 states with retry loop). Bioinformatics analysis of sequencing run data. Runs a specific pipeline (GATK, nf-core, QIIME2, Flye) and tracks compute resources and results.

Relationships

RelationshipTypeDescription
Project hasMany SamplehasManyA project contains multiple samples
Sample belongsTo ProjectbelongsToEach sample belongs to one project
Instrument hasMany RunhasManyAn instrument hosts multiple sequencing runs
Run belongsTo InstrumentbelongsToEach run uses one instrument
Run belongsTo ProtocolbelongsToEach run follows one protocol
Run belongsToMany SamplebelongsToManyMany-to-many via RunSamples junction table
Run hasMany AnalysishasManyA run can have multiple analyses
Analysis belongsTo RunbelongsToEach analysis is for one run

State Machines

Sample Workflow (7 states)

received --> pass_qc --> qc_passed --> begin_library_prep --> library_prep
    ^           |                                                 |
    |       fail_qc                                       begin_sequencing
    |           v                                                 v
    |       qc_failed                                         sequencing
    |           |                                                 |
    +--resubmit-+                                         begin_analysis
                                                                  v
                                                              analysis
                                                                  |
                                                              complete
                                                                  v
                                                           complete (final)

Run Workflow (5 states)

planned --> begin_loading --> loading --> start_run --> running --> complete --> completed
                                                          |
                                                         fail
                                                          v
                                                        failed

Analysis Workflow (4 states, retry loop)

queued --> start --> running --> complete --> completed
                       |
                      fail
                       v
                     failed --> retry --> queued (loop)

Enums

EnumValues
SampleTypedna (Genomic DNA), rna (Total RNA), cfDNA (Cell-free DNA), ffpe (FFPE)
SampleStatusreceived, qc_passed, qc_failed, library_prep, sequencing, analysis, complete
RunStatusplanned, loading, running, completed, failed
InstrumentStatusavailable, in_use, maintenance, offline
AnalysisStatusqueued, running, completed, failed
Organismhuman (Homo sapiens), mouse (Mus musculus), rat (Rattus norvegicus), ecoli (E. coli K-12), custom
LibraryPrepKitnextera_dna_flex, truseq_stranded_mrna, truseq_stranded_total_rna, twist_exome, nanopore_ligation
SequencingPlatformnovaseq_6000, nextseq_2000, miseq, minion

Roles and Permissions

RoleCapabilities
adminFull access to all resources. Can create/delete instruments and protocols. Manages users and roles.
piPrincipal investigator. Can create projects and submit samples. Can read all resources.
lab_techLab technician. Can create/update samples, operate instruments, create runs, run analyses, and trigger all state machine transitions.
authenticatedAny authenticated user. Read-only list and read access to all resources.

Permission Matrix

Resourcelistreadcreateupdatedelete
Projectauthenticatedauthenticatedpi, adminowner, pi, adminadmin
Sampleauthenticatedauthenticatedlab_tech, pi, adminlab_tech, adminadmin
Instrumentauthenticatedauthenticatedadminlab_tech, adminadmin
Protocolauthenticatedauthenticatedadminadminadmin
Runauthenticatedauthenticatedlab_tech, adminlab_tech, adminadmin
Analysisauthenticatedauthenticatedlab_tech, adminlab_tech, adminadmin

Seed Data

  • 4 projects: BRCA WGS (human), Colorectal Organoid RNA-seq (human), Mouse Gut 16S (mouse), E. coli Assembly (ecoli)
  • 8 samples: 3 BRCA tumor/normal DNA, 2 RNA-seq organoid, 1 mouse 16S, 1 E. coli, 1 FFPE
  • 4 instruments: NovaSeq-1 (available), NextSeq-1 (in use), MiSeq-Bench3 (maintenance), MinION-1 (available)
  • 5 protocols: WGS 30x, RNA-seq polyA, 16S V3-V4, ONT Long-Read, Whole Exome
  • 4 runs: one per instrument, all in planned status
  • 4 analyses: one per run, all in queued status
  • 5 users: admin, dr_chen (PI), dr_patel (PI), maria (lab_tech), james (lab_tech)

ADL Features Exercised

  • Full CRUD on all 6 resources
  • Relationships: belongsTo (4), hasMany (3), belongsToMany (1 via RunSamples junction)
  • State machines: Sample (7-state), Run (5-state), Analysis (4-state with retry loop)
  • Rich enums: 8 enums with labels, descriptions, and color codes
  • Types: uuid, string, text, integer, decimal, percentage, date, datetime, email, boolean, set, url, slug
  • Shared objects via $merge (Timestamp)
  • Shared properties via $ref (slug)
  • Audit trail on Project, Sample, Instrument, Run, Analysis
  • Full-text search on Project, Sample, Protocol, Run
  • Data export on Sample, Run
  • Role-based permissions with 4 roles across all resources

Domain definition

View raw (1320 lines)
Show domain.yaml
# adl-lims.yaml
#
# Next-Generation Sequencing LIMS — ADL Domain Definition
# ADL version: 0.3.1
#
# Resources:  Project, Sample, Instrument, Protocol, Run, Analysis
# Relations:  Sample belongsTo Project
#             Project hasMany Sample
#             Run belongsTo Instrument
#             Run belongsTo Protocol
#             Run belongsToMany Sample (via RunSamples junction)
#             Analysis belongsTo Run
#             Run hasMany Analysis
#
# ADL features exercised:
#   CRUD           — Full CRUD on all 6 resources
#   Relationships  — belongsTo (4), hasMany (3), belongsToMany (1 — Run ↔ Sample)
#   State machines — Sample workflow (7-state), Run workflow (5-state),
#                    Analysis workflow (4-state with retry loop)
#   Rich enums     — SampleType (4), SampleStatus (7), RunStatus (5),
#                    InstrumentStatus (4), AnalysisStatus (4), Organism (5),
#                    LibraryPrepKit (5), SequencingPlatform (4)
#   Types          — decimal, percentage, date, datetime, integer, email, boolean,
#                    set, url, text
#   Audit trail    — Project, Sample, Run, Analysis (track workflow transitions)
#   Search         — Project, Sample, Protocol, Run (full-text)
#   Export         — Sample, Run (data export for external reporting)
#   Permissions    — Role-based: admin, pi, lab_tech, authenticated
#
# Roles referenced:
#   admin     — Full access to all resources
#   pi        — Principal investigator — creates projects, views all data
#   lab_tech  — Lab technician — processes samples, operates instruments, runs analyses
#   authenticated — Can list/read all resources
#
# State machine — Sample:
#
#   received ──pass_qc──▶ qc_passed ──begin_library_prep──▶ library_prep
#       ▲         │                                             │
#       │    fail_qc                                   begin_sequencing
#       │         ▼                                             ▼
#       │     qc_failed                                    sequencing
#       │         │                                             │
#       └─resubmit┘                                    begin_analysis
#                                                               ▼
#                                                           analysis
#                                                               │
#                                                           complete
#                                                               ▼
#                                                           complete (final)
#
# State machine — Run:
#
#   planned ──begin_loading──▶ loading ──start_run──▶ running ──complete──▶ completed
#                                                        │
#                                                       fail
#                                                        ▼
#                                                      failed
#
# State machine — Analysis:
#
#   queued ──start──▶ running ──complete──▶ completed
#                        │
#                       fail
#                        ▼
#                      failed ──retry──▶ queued (loop)

domain:
  name: lims
  version: "1.0.0"
  description: >
    Next-generation sequencing laboratory information management system.
    Tracks the complete NGS workflow from sample receipt through quality
    control, library preparation, sequencing on high-throughput instruments,
    and bioinformatics analysis. Supports Illumina (NovaSeq, NextSeq, MiSeq)
    and Oxford Nanopore platforms. Designed for a core facility processing
    50-200 samples per week across multiple research groups.

  api: {}

  # ─── Shared objects ────────────────────────────────────────────
  objects:
    Timestamp:
      createdAt: { type: datetime, autoNow: create }
      updatedAt: { type: datetime, autoNow: update }

  # ─── Shared properties ─────────────────────────────────────────
  properties:
    slug:
      type: slug
      unique: true
      maxLength: 255

  # ─── Enums ─────────────────────────────────────────────────────
  enums:
    SampleType:
      values:
        dna:
          label: "Genomic DNA"
          description: "Extracted genomic DNA for whole-genome or targeted sequencing"
          color: "#3b82f6"
        rna:
          label: "Total RNA"
          description: "Extracted total RNA for RNA-seq or small RNA sequencing"
          color: "#10b981"
        cfDNA:
          label: "Cell-free DNA"
          description: "Circulating cell-free DNA from plasma for liquid biopsy"
          color: "#8b5cf6"
        ffpe:
          label: "FFPE"
          description: "Formalin-fixed paraffin-embedded tissue DNA/RNA"
          color: "#f59e0b"

    SampleStatus:
      values:
        received:
          label: "Received"
          description: "Sample received and accessioned into the system"
          color: "#94a3b8"
        qc_passed:
          label: "QC Passed"
          description: "Sample passed quality control — ready for library prep"
          color: "#3b82f6"
        qc_failed:
          label: "QC Failed"
          description: "Sample failed QC — insufficient quality or quantity"
          color: "#ef4444"
        library_prep:
          label: "Library Prep"
          description: "Library preparation in progress"
          color: "#8b5cf6"
        sequencing:
          label: "Sequencing"
          description: "On the sequencer — data generation in progress"
          color: "#f59e0b"
        analysis:
          label: "Analysis"
          description: "Bioinformatics analysis in progress"
          color: "#06b6d4"
        complete:
          label: "Complete"
          description: "All processing finished — results delivered"
          color: "#10b981"
          final: true

    RunStatus:
      values:
        planned:
          label: "Planned"
          description: "Run is scheduled but not yet started"
          color: "#94a3b8"
        loading:
          label: "Loading"
          description: "Flow cell is being loaded with libraries"
          color: "#f59e0b"
        running:
          label: "Running"
          description: "Sequencer is actively generating data"
          color: "#3b82f6"
        completed:
          label: "Completed"
          description: "Sequencing finished — data available for analysis"
          color: "#10b981"
        failed:
          label: "Failed"
          description: "Run failed — check instrument logs and flow cell"
          color: "#ef4444"

    InstrumentStatus:
      values:
        available:
          label: "Available"
          description: "Instrument is operational and ready for use"
          color: "#10b981"
        in_use:
          label: "In Use"
          description: "Currently running a sequencing experiment"
          color: "#3b82f6"
        maintenance:
          label: "Maintenance"
          description: "Scheduled or unscheduled maintenance in progress"
          color: "#f59e0b"
        offline:
          label: "Offline"
          description: "Instrument is down — repair or decommission pending"
          color: "#ef4444"

    AnalysisStatus:
      values:
        queued:
          label: "Queued"
          description: "Waiting for compute resources"
          color: "#94a3b8"
        running:
          label: "Running"
          description: "Pipeline is actively processing data"
          color: "#3b82f6"
        completed:
          label: "Completed"
          description: "Analysis finished — results available"
          color: "#10b981"
        failed:
          label: "Failed"
          description: "Pipeline failed — check error log for details"
          color: "#ef4444"

    Organism:
      values:
        human:
          label: "Human (Homo sapiens)"
          description: "GRCh38/hg38 reference genome"
          color: "#3b82f6"
        mouse:
          label: "Mouse (Mus musculus)"
          description: "GRCm39/mm39 reference genome"
          color: "#94a3b8"
        rat:
          label: "Rat (Rattus norvegicus)"
          description: "mRatBN7.2/rn7 reference genome"
          color: "#94a3b8"
        ecoli:
          label: "E. coli (K-12)"
          description: "Standard laboratory strain"
          color: "#f59e0b"
        custom:
          label: "Custom / Other"
          description: "Non-standard organism — specify in project notes"
          color: "#8b5cf6"

    LibraryPrepKit:
      values:
        nextera_dna_flex:
          label: "Nextera DNA Flex"
          description: "Illumina tagmentation-based DNA library prep (1-500ng input)"
          color: "#3b82f6"
        truseq_stranded_mrna:
          label: "TruSeq Stranded mRNA"
          description: "Illumina poly-A selection RNA-seq library prep"
          color: "#10b981"
        truseq_stranded_total_rna:
          label: "TruSeq Stranded Total RNA"
          description: "Illumina ribo-depletion total RNA library prep"
          color: "#8b5cf6"
        twist_exome:
          label: "Twist Bioscience Exome"
          description: "Twist Human Core Exome panel for whole-exome sequencing"
          color: "#f59e0b"
        nanopore_ligation:
          label: "ONT Ligation Sequencing"
          description: "Oxford Nanopore ligation-based long-read library prep"
          color: "#94a3b8"

    SequencingPlatform:
      values:
        novaseq_6000:
          label: "NovaSeq 6000"
          description: "Illumina high-throughput, up to 6 Tb per run"
          color: "#3b82f6"
        nextseq_2000:
          label: "NextSeq 2000"
          description: "Illumina mid-throughput, XLEAP chemistry"
          color: "#8b5cf6"
        miseq:
          label: "MiSeq"
          description: "Illumina benchtop, ideal for amplicon and small genome"
          color: "#10b981"
        minion:
          label: "MinION"
          description: "Oxford Nanopore portable long-read sequencer"
          color: "#f59e0b"

  # ─── Resources ─────────────────────────────────────────────────
  resources:

    # ╔══════════════════════════════════════════════════════════════╗
    # ║  Project                                                     ║
    # ╚══════════════════════════════════════════════════════════════╝
    Project:
      description: >
        A sequencing project grouping related samples from a single
        research group or grant. Projects define the organism, sequencing
        objectives, and timeline. All samples within a project share the
        same organism and are tracked toward a common delivery date.

      object:
        id:
          type: uuid
          primaryKey: true

        name:
          type: string
          required: true
          maxLength: 200

        slug:
          $ref: '#/properties/slug'
          from: name

        description:
          type: text
          maxLength: 3000
          description: "Research objectives, sample types expected, and special requirements"

        organism:
          $ref: '#/enums/Organism'
          required: true

        referenceGenome:
          type: string
          maxLength: 50
          description: "Reference genome build (e.g. GRCh38, GRCm39, custom assembly)"

        piName:
          type: string
          required: true
          maxLength: 200

        piEmail:
          type: email

        labName:
          type: string
          maxLength: 200
          description: "Research group or lab name"

        department:
          type: string
          maxLength: 200
          description: "Academic department"

        grantNumber:
          type: string
          maxLength: 50
          description: "Funding grant award number for billing"

        sequencingObjective:
          type: string
          maxLength: 200
          description: "e.g. Whole Genome 30x, RNA-seq (polyA), Exome, 16S Amplicon"

        targetSampleCount:
          type: integer
          description: "Expected number of samples"

        samplesReceived:
          type: integer
          default: 0
          description: "Number of samples received so far"

        samplesCompleted:
          type: integer
          default: 0
          description: "Number of samples fully processed"

        startDate:
          type: date

        targetDate:
          type: date
          description: "Desired completion date"

        active:
          type: boolean
          default: true

        notes:
          type: text
          maxLength: 5000
          description: "Special handling instructions, billing notes, communication log"

        $merge:
          - { $ref: '#/objects/Timestamp' }

      relationships:
        samples:
          type: hasMany
          target: Sample
          foreignKey: projectId

      indexes:
        - fields: [organism]
          description: "Filter projects by organism"
        - fields: [piName]
          description: "Filter projects by PI"
        - fields: [active]
          description: "Filter active/completed projects"

      features:
        search: true
        audit: true

      audit:
        track: [name, organism, piName, targetSampleCount, samplesReceived, samplesCompleted, active]
        exclude: [updatedAt]

      permissions:
        list:   [authenticated]
        read:   [authenticated]
        create: [pi, admin]
        update: [owner, pi, admin]
        delete: [admin]

    # ╔══════════════════════════════════════════════════════════════╗
    # ║  Sample                                                      ║
    # ╚══════════════════════════════════════════════════════════════╝
    Sample:
      description: >
        A biological sample progressing through the NGS workflow.
        Samples arrive at the core facility, undergo quality control,
        library preparation, sequencing, and bioinformatics analysis.
        Each stage is a state machine transition. Samples carry
        quantitative QC metrics (concentration, volume, quality score)
        and are linked to a project and optionally to specific library
        prep kits.

      object:
        id:
          type: uuid
          primaryKey: true

        name:
          type: string
          required: true
          maxLength: 200
          description: "Lab-assigned sample identifier"

        externalId:
          type: string
          maxLength: 100
          description: "Client's own sample ID for cross-referencing"

        sampleType:
          $ref: '#/enums/SampleType'
          required: true

        status:
          $ref: '#/enums/SampleStatus'
          default: received

        organism:
          $ref: '#/enums/Organism'
          description: "Overrides project organism if different"

        tissue:
          type: string
          maxLength: 100
          description: "Tissue or cell type (e.g. whole blood, liver, tumor, PBMC)"

        preservationMethod:
          type: string
          maxLength: 100
          description: "e.g. Fresh frozen, FFPE, RNAlater, ethanol-fixed"

        collectionDate:
          type: date
          description: "Date the sample was collected from the subject"

        receivedAt:
          type: datetime
          description: "When the sample arrived at the core facility"

        # ─── QC Metrics ───────────────────────────────────────────
        concentration:
          type: decimal
          description: "Concentration in ng/µL (measured by Qubit or NanoDrop)"

        volume:
          type: decimal
          description: "Volume in µL"

        totalAmount:
          type: decimal
          description: "Total mass in ng (concentration × volume)"

        a260_280:
          type: decimal
          description: "A260/A280 absorbance ratio — purity indicator (DNA ~1.8, RNA ~2.0)"

        a260_230:
          type: decimal
          description: "A260/A230 absorbance ratio — contaminant indicator (ideal 2.0-2.2)"

        rin:
          type: decimal
          description: "RNA Integrity Number (1-10, RNA only, measured by Bioanalyzer)"

        din:
          type: decimal
          description: "DNA Integrity Number (1-10, DNA only, measured by TapeStation)"

        fragmentSize:
          type: integer
          description: "Average fragment size in bp (from Bioanalyzer or TapeStation)"

        qcNotes:
          type: text
          maxLength: 2000
          description: "QC observations, Bioanalyzer trace notes, degradation assessment"

        qcPassedAt:
          type: datetime
          description: "When QC was completed"

        qcPerformedBy:
          type: string
          maxLength: 100
          description: "Username of the technician who performed QC"

        # ─── Library Prep ─────────────────────────────────────────
        libraryPrepKit:
          $ref: '#/enums/LibraryPrepKit'
          description: "Kit used for library preparation"

        libraryPrepDate:
          type: date

        indexSequence:
          type: string
          maxLength: 50
          description: "i7/i5 index barcode sequence for demultiplexing (e.g. ATCACG-TTAGGC)"

        libraryConcentration:
          type: decimal
          description: "Post-prep library concentration in nM"

        libraryFragmentSize:
          type: integer
          description: "Post-prep average fragment size in bp"

        libraryPrepNotes:
          type: text
          maxLength: 2000

        # ─── Project Link ─────────────────────────────────────────
        projectId:
          type: uuid
          required: true

        projectName:
          type: string
          maxLength: 200
          description: "Denormalized project name for display"

        # ─── General ──────────────────────────────────────────────
        notes:
          type: text
          maxLength: 3000
          description: "General notes, special handling, client communications"

        completedAt:
          type: datetime
          description: "When all processing was finished"

        $merge:
          - { $ref: '#/objects/Timestamp' }

      relationships:
        project:
          type: belongsTo
          target: Project
          foreignKey: projectId

      indexes:
        - fields: [projectId]
          description: "List samples by project"
        - fields: [status]
          description: "Filter by processing status"
        - fields: [sampleType]
          description: "Filter by sample type"
        - fields: [organism]
          description: "Filter by organism"
        - fields: [projectId, status]
          description: "Composite: project samples by status"
        - fields: [libraryPrepKit]
          description: "Filter by prep kit"

      features:
        audit: true
        search: true
        export: true

      audit:
        track: [name, status, concentration, volume, rin, din, qcNotes, libraryPrepKit, indexSequence]
        exclude: [updatedAt]

      # ─── State machine ──────────────────────────────────────────
      stateMachine:
        field: status
        initial: received

        states:
          received:
            description: "Sample accessioned — awaiting QC"
            transitions:
              pass_qc:
                to: qc_passed
                guards: [lab_tech, admin]
                sets:
                  qcPassedAt: now()
              fail_qc:
                to: qc_failed
                guards: [lab_tech, admin]
                sets:
                  qcPassedAt: now()

          qc_passed:
            description: "QC passed — ready for library preparation"
            transitions:
              begin_library_prep:
                to: library_prep
                guards: [lab_tech, admin]

          qc_failed:
            description: "QC failed — sample may need re-extraction or replacement"
            transitions:
              resubmit:
                to: received
                guards: [lab_tech, admin]
                sets:
                  qcPassedAt: null
                  qcNotes: null
                  concentration: null
                  volume: null
                  totalAmount: null
                  a260_280: null
                  a260_230: null
                  rin: null
                  din: null

          library_prep:
            description: "Library preparation in progress"
            transitions:
              begin_sequencing:
                to: sequencing
                guards: [lab_tech, admin]

          sequencing:
            description: "Sample is on the sequencer"
            transitions:
              begin_analysis:
                to: analysis
                guards: [lab_tech, admin]

          analysis:
            description: "Bioinformatics analysis in progress"
            transitions:
              complete:
                to: complete
                guards: [lab_tech, admin]
                sets:
                  completedAt: now()

          complete:
            description: "All processing finished — results delivered to PI"

      # ─── Permissions ─────────────────────────────────────────────
      permissions:
        list:   [authenticated]
        read:   [authenticated]
        create: [lab_tech, pi, admin]
        update: [lab_tech, admin]
        delete: [admin]

    # ╔══════════════════════════════════════════════════════════════╗
    # ║  Instrument                                                  ║
    # ╚══════════════════════════════════════════════════════════════╝
    Instrument:
      description: >
        A sequencing instrument in the core facility. Each instrument
        has a model, serial number, platform type, and operational
        status. Instruments are linked to sequencing runs. Maintenance
        schedules are tracked to minimize downtime.

      object:
        id:
          type: uuid
          primaryKey: true

        name:
          type: string
          required: true
          maxLength: 100
          description: "Friendly name (e.g. NovaSeq-1, MiSeq-Bench3)"

        platform:
          $ref: '#/enums/SequencingPlatform'
          required: true

        model:
          type: string
          required: true
          maxLength: 100
          description: "Full model name (e.g. NovaSeq 6000, NextSeq 2000, MinION Mk1C)"

        serialNumber:
          type: string
          unique: true
          maxLength: 50

        status:
          $ref: '#/enums/InstrumentStatus'
          default: available

        location:
          type: string
          maxLength: 100
          description: "Room and bench location (e.g. Sequencing Core, Room 312, Bench A)"

        ipAddress:
          type: string
          maxLength: 45
          description: "Network IP for instrument control software"

        softwareVersion:
          type: string
          maxLength: 50
          description: "Current control software version"

        purchaseDate:
          type: date

        warrantyExpires:
          type: date

        lastMaintenanceDate:
          type: date

        nextMaintenanceDate:
          type: date

        totalRuns:
          type: integer
          default: 0
          description: "Cumulative number of runs on this instrument"

        notes:
          type: text
          maxLength: 3000
          description: "Maintenance history, known issues, performance notes"

        $merge:
          - { $ref: '#/objects/Timestamp' }

      relationships:
        runs:
          type: hasMany
          target: Run
          foreignKey: instrumentId

      indexes:
        - fields: [platform]
          description: "Filter by sequencing platform"
        - fields: [status]
          description: "Filter by operational status"

      features:
        audit: true

      audit:
        track: [name, status, softwareVersion, lastMaintenanceDate, nextMaintenanceDate, totalRuns]
        exclude: [updatedAt]

      permissions:
        list:   [authenticated]
        read:   [authenticated]
        create: [admin]
        update: [lab_tech, admin]
        delete: [admin]

    # ╔══════════════════════════════════════════════════════════════╗
    # ║  Protocol                                                    ║
    # ╚══════════════════════════════════════════════════════════════╝
    Protocol:
      description: >
        Standard operating procedures for library preparation and
        sequencing. Each protocol has a name, version, and description
        of the workflow steps. Protocols specify which sample types
        they support and estimated processing time. Lab technicians
        select a protocol when setting up a sequencing run.

      object:
        id:
          type: uuid
          primaryKey: true

        name:
          type: string
          required: true
          maxLength: 200
          description: "Protocol name (e.g. WGS 30x Human, RNA-seq polyA, 16S V3-V4)"

        version:
          type: string
          required: true
          maxLength: 20
          description: "Protocol version (e.g. 3.1, 2024-Q4)"

        category:
          type: string
          maxLength: 100
          description: "e.g. Whole Genome, RNA-seq, Exome, Amplicon, Metagenomics"

        description:
          type: text
          maxLength: 5000
          description: "Detailed protocol steps, reagent list, and quality checkpoints"

        applicableSampleTypes:
          type: set
          description: "Which sample types this protocol supports (dna, rna, cfDNA, ffpe)"

        applicablePlatforms:
          type: set
          description: "Which sequencing platforms this protocol targets"

        recommendedKit:
          $ref: '#/enums/LibraryPrepKit'
          description: "Recommended library prep kit for this protocol"

        inputRequirements:
          type: text
          maxLength: 1000
          description: "Minimum input requirements (e.g. 100ng DNA, RIN >= 7, DIN >= 6)"

        estimatedDuration:
          type: string
          maxLength: 50
          description: "Estimated hands-on time (e.g. 4 hours, 2 days)"

        estimatedTurnaround:
          type: string
          maxLength: 50
          description: "Total turnaround including sequencing (e.g. 5 business days)"

        readConfiguration:
          type: string
          maxLength: 50
          description: "Default read length and type (e.g. 2×150bp PE, 1×75bp SE, 2×250bp PE)"

        targetCoverage:
          type: string
          maxLength: 50
          description: "Target coverage or read depth (e.g. 30x, 50M reads, 100k reads/sample)"

        active:
          type: boolean
          default: true
          description: "Whether this protocol is currently in use"

        author:
          type: string
          maxLength: 200
          description: "Protocol developer or responsible scientist"

        approvedDate:
          type: date
          description: "Date the protocol was approved for production use"

        $merge:
          - { $ref: '#/objects/Timestamp' }

      indexes:
        - fields: [category]
          description: "Filter by protocol category"
        - fields: [active]
          description: "Filter active protocols"

      features:
        search: true

      permissions:
        list:   [authenticated]
        read:   [authenticated]
        create: [admin]
        update: [admin]
        delete: [admin]

    # ╔══════════════════════════════════════════════════════════════╗
    # ║  Run                                                         ║
    # ╚══════════════════════════════════════════════════════════════╝
    Run:
      description: >
        A sequencing run on an instrument. Each run processes one or
        more samples (via the RunSamples junction table), follows a
        protocol, and produces raw sequencing data. Runs progress
        through a state machine: planned → loading → running →
        completed (or failed). QC metrics (total reads, pass filter
        percentage, Q30 score) are recorded after the run completes.

      object:
        id:
          type: uuid
          primaryKey: true

        name:
          type: string
          required: true
          maxLength: 200
          description: "Run identifier (e.g. NS6K-20260315-WGS-001)"

        flowCellId:
          type: string
          maxLength: 50
          description: "Flow cell barcode (e.g. HXXXXXXXX)"

        flowCellType:
          type: string
          maxLength: 50
          description: "Flow cell type (e.g. SP, S1, S2, S4 for NovaSeq)"

        status:
          $ref: '#/enums/RunStatus'
          default: planned

        instrumentId:
          type: uuid
          required: true

        instrumentName:
          type: string
          maxLength: 100
          description: "Denormalized instrument name"

        protocolId:
          type: uuid

        protocolName:
          type: string
          maxLength: 200
          description: "Denormalized protocol name"

        operatorId:
          type: string
          maxLength: 100
          description: "Username of the lab technician running the instrument"

        operatorName:
          type: string
          maxLength: 200

        readLength:
          type: string
          maxLength: 50
          description: "Actual read configuration (e.g. 2×150bp, 1×300bp)"

        indexReads:
          type: string
          maxLength: 50
          description: "Index read configuration (e.g. 8+8bp, 10+10bp)"

        loadingConcentration:
          type: decimal
          description: "Library loading concentration in pM"

        phiXPercent:
          type: percentage
          description: "Percentage of PhiX spike-in control"

        # ─── Post-run QC metrics ──────────────────────────────────
        totalReads:
          type: integer
          description: "Total clusters / reads generated (millions)"

        readsPassFilter:
          type: integer
          description: "Reads passing quality filter (millions)"

        passFilterPercent:
          type: percentage
          description: "Percentage of clusters passing filter"

        q30Percent:
          type: percentage
          description: "Percentage of bases with quality score >= Q30"

        meanQuality:
          type: decimal
          description: "Mean quality score across all bases"

        errorRate:
          type: decimal
          description: "Estimated sequencing error rate (percentage)"

        yieldGb:
          type: decimal
          description: "Total data yield in gigabases"

        clusterDensity:
          type: decimal
          description: "Cluster density (K/mm²) — Illumina only"

        # ─── Timing ───────────────────────────────────────────────
        scheduledDate:
          type: date
          description: "Planned run date"

        startedAt:
          type: datetime

        completedAt:
          type: datetime

        estimatedCompletion:
          type: datetime
          description: "Estimated completion time (calculated from run parameters)"

        # ─── General ──────────────────────────────────────────────
        outputPath:
          type: string
          maxLength: 500
          description: "Path to raw data output directory on the file server"

        notes:
          type: text
          maxLength: 3000
          description: "Run observations, issues encountered, post-run assessment"

        $merge:
          - { $ref: '#/objects/Timestamp' }

      relationships:
        instrument:
          type: belongsTo
          target: Instrument
          foreignKey: instrumentId

        protocol:
          type: belongsTo
          target: Protocol
          foreignKey: protocolId

        samples:
          type: belongsToMany
          target: Sample
          through: RunSamples
          foreignKey: runId
          otherKey: sampleId

        analyses:
          type: hasMany
          target: Analysis
          foreignKey: runId

      indexes:
        - fields: [instrumentId]
          description: "List runs by instrument"
        - fields: [status]
          description: "Filter by run status"
        - fields: [protocolId]
          description: "List runs by protocol"
        - fields: [operatorId]
          description: "List runs by operator"
        - fields: [scheduledDate]
          description: "Sort by scheduled date"
        - fields: [instrumentId, status]
          description: "Composite: instrument runs by status"

      features:
        audit: true
        search: true
        export: true

      audit:
        track: [name, status, instrumentId, totalReads, q30Percent, passFilterPercent, yieldGb]
        exclude: [updatedAt]

      # ─── State machine ──────────────────────────────────────────
      stateMachine:
        field: status
        initial: planned

        states:
          planned:
            description: "Run is scheduled — loading date set, samples selected"
            transitions:
              begin_loading:
                to: loading
                guards: [lab_tech, admin]

          loading:
            description: "Flow cell is being loaded with pooled libraries"
            transitions:
              start_run:
                to: running
                guards: [lab_tech, admin]
                sets:
                  startedAt: now()

          running:
            description: "Sequencer is actively generating data"
            transitions:
              complete:
                to: completed
                guards: [lab_tech, admin]
                sets:
                  completedAt: now()
              fail:
                to: failed
                guards: [lab_tech, admin]
                sets:
                  completedAt: now()

          completed:
            description: "Run finished successfully — data ready for analysis"

          failed:
            description: "Run failed — check instrument logs and flow cell integrity"

      # ─── Permissions ─────────────────────────────────────────────
      permissions:
        list:   [authenticated]
        read:   [authenticated]
        create: [lab_tech, admin]
        update: [lab_tech, admin]
        delete: [admin]

    # ╔══════════════════════════════════════════════════════════════╗
    # ║  Analysis                                                    ║
    # ╚══════════════════════════════════════════════════════════════╝
    Analysis:
      description: >
        A bioinformatics analysis of sequencing run data. Each analysis
        runs a specific pipeline (e.g. GATK, bcl2fastq, nf-core/rnaseq)
        on the data from a sequencing run. Analyses progress through a
        state machine: queued → running → completed (or failed with
        retry option). Failed analyses can be retried, which clears
        the error state and re-queues the job.

      object:
        id:
          type: uuid
          primaryKey: true

        name:
          type: string
          required: true
          maxLength: 200
          description: "Analysis identifier (e.g. WGS-Alignment-Run001, RNAseq-DGE-Proj42)"

        pipeline:
          type: string
          required: true
          maxLength: 100
          description: "Pipeline name (e.g. bcl2fastq, GATK-HaplotypeCaller, nf-core/rnaseq, nf-core/sarek)"

        pipelineVersion:
          type: string
          maxLength: 20
          description: "Pipeline version (e.g. 3.12.0, 2024.1)"

        referenceGenome:
          type: string
          maxLength: 50
          description: "Reference genome used (e.g. GRCh38, GRCm39)"

        status:
          $ref: '#/enums/AnalysisStatus'
          default: queued

        runId:
          type: uuid
          required: true

        runName:
          type: string
          maxLength: 200
          description: "Denormalized run name"

        submittedBy:
          type: string
          maxLength: 100
          description: "Username of the person who submitted the analysis"

        submittedByName:
          type: string
          maxLength: 200

        # ─── Compute ──────────────────────────────────────────────
        computeNode:
          type: string
          maxLength: 100
          description: "HPC node or cloud instance running the analysis"

        cpuHours:
          type: decimal
          description: "CPU hours consumed"

        peakMemoryGb:
          type: decimal
          description: "Peak memory usage in GB"

        wallTimeHours:
          type: decimal
          description: "Wall-clock time in hours"

        # ─── Timing ───────────────────────────────────────────────
        startedAt:
          type: datetime

        completedAt:
          type: datetime

        # ─── Results ──────────────────────────────────────────────
        outputPath:
          type: string
          maxLength: 500
          description: "Path to analysis output directory"

        reportUrl:
          type: url
          description: "URL to the MultiQC or analysis report"

        totalVariants:
          type: integer
          description: "Number of variants called (for variant calling pipelines)"

        alignmentRate:
          type: percentage
          description: "Percentage of reads aligned to reference"

        duplicationRate:
          type: percentage
          description: "Percentage of duplicate reads"

        meanCoverage:
          type: decimal
          description: "Mean genome coverage (for WGS/WES)"

        # ─── Error handling ───────────────────────────────────────
        errorLog:
          type: text
          maxLength: 10000
          description: "Error output from the pipeline (captured on failure)"

        retryCount:
          type: integer
          default: 0
          description: "Number of times this analysis has been retried"

        notes:
          type: text
          maxLength: 3000

        $merge:
          - { $ref: '#/objects/Timestamp' }

      relationships:
        run:
          type: belongsTo
          target: Run
          foreignKey: runId

      indexes:
        - fields: [runId]
          description: "List analyses by run"
        - fields: [status]
          description: "Filter by analysis status"
        - fields: [pipeline]
          description: "Filter by pipeline"
        - fields: [runId, status]
          description: "Composite: run analyses by status"

      features:
        audit: true

      audit:
        track: [name, status, pipeline, startedAt, completedAt, errorLog, retryCount]
        exclude: [updatedAt]

      # ─── State machine ──────────────────────────────────────────
      stateMachine:
        field: status
        initial: queued

        states:
          queued:
            description: "Waiting for compute resources on the HPC cluster"
            transitions:
              start:
                to: running
                guards: [lab_tech, admin]
                sets:
                  startedAt: now()

          running:
            description: "Pipeline is actively processing sequencing data"
            transitions:
              complete:
                to: completed
                guards: [lab_tech, admin]
                sets:
                  completedAt: now()
              fail:
                to: failed
                guards: [lab_tech, admin]
                sets:
                  completedAt: now()

          completed:
            description: "Analysis complete — results available at outputPath"

          failed:
            description: "Pipeline failed — check errorLog for diagnostics"
            transitions:
              retry:
                to: queued
                guards: [lab_tech, admin]
                sets:
                  startedAt: null
                  completedAt: null
                  errorLog: null

      # ─── Permissions ─────────────────────────────────────────────
      permissions:
        list:   [authenticated]
        read:   [authenticated]
        create: [lab_tech, admin]
        update: [lab_tech, admin]
        delete: [admin]

Download bundle