Data & Research
LOSPOR stores perioperative data for clinical documentation, audit, personal portfolio, and de-identified / pseudonymised research datasets. The dedicated lospor-api service owns the canonical PostgreSQL/API contract; web, mobile, and PWA clients map their payloads into the same field names and libraries before persistence.
What data does LOSPOR collect?
Preoperative data
-
Demographics: age, sex, height, weight, BMI, blood group, Rh factor.
-
Diagnosis: ICD-10 code with English and Bulgarian labels.
-
Planned procedure: the procedure group, and optionally the exact ICD-10-PCS operation the clinician chose within it. A procedure imported from a hospital system keeps the hospital's code (for example КСМП) and wording beside it.
-
Comorbidities: ICD-10-coded tags with English/Bulgarian labels.
-
Medication history and medication allergy rows, including
Medication.kind = CURRENTorALLERGY. -
Risk scores: ASA, RCRI, Apfel, STOP-BANG, and their component inputs.
The component inputs are three-valued: yes, no, and not asked. A criterion nobody put to the patient is stored as null, not as a negative, and does not count toward the score — so a score is a lower bound when some of its criteria were never asked. Analyses that treat a null as a "no" are counting something the register did not measure; the component inputs are exported precisely so that distinction is available to you.
Scores are stored and exported as raw counts (RCRI 0–6, Apfel 0–4, STOP-BANG 0–8, POVOC, COLDS, PAED). A band is a reading of the count by one guideline, so it is added at display time and never frozen into the data. The POVOC risk percentage and the Gupta MICA risk are derived on export from their inputs and are not stored.
-
ASA suggestion: the class the suggestion rules proposed from the coded conditions and BMI, the rules that decided it and the rule-table version, stored beside the class the clinician chose.
-
Planned anaesthesia (optional): techniques, airway devices and instruments, lines, and planned ventilation after the operation.
-
Paediatric nil by mouth: one assignment per intake, in hours before surgery, with the policy it was assigned under.
-
Preop documents: each printed consent records the version and fingerprint of its text, the print layout and, for layout C, the techniques described.
-
Airway assessment: Mallampati, mouth opening, thyromental distance, neck mobility, ULBT, Cormack-Lehane, difficult-airway history, and airway features.
-
Free-text clinical notes where needed: team notes, physical exam report, difficult-airway notes. These are character-limited. On the cloud service identifying text in them is refused when it is saved. On a hospital appliance it is stored as typed, inside the hospital, and free text is cleaned of names, dates, ЕГН, long numbers and email addresses whenever it leaves: in OMOP and research exports, in Central delivery and in what is sent to the AI advisor. Coded fields (diagnoses, procedures, drug and allergy lists) leave as they are.
-
Vitals: BP, HR, SpO2, temperature, respiratory rate, including unable-to-obtain flags where available.
-
Laboratory results: canonical lab name, value, parsed numeric value, canonical unit, LOINC code, reference range, abnormal flag, source, and timestamp where available.
Preoperative questions
Every question of the preoperative catalogue is also stored as one answer row
per case (PreopAssessmentAnswer), and these rows are what research and OMOP
read. That includes the baseline questions behind the standard controls, whose
form fields remain as a compatibility copy.
- A question that is switched on for the case has a row:
YES,NO,UNKNOWN,NOT_APPLICABLE, orNOT_ASKEDwhen it was on the form and left blank. A question that was off has no row, so "not on the form" and "left blank" stay distinguishable. - Each row records who answered it: the clinician, or an accepted suggestion from the hospital record, with the rule and the record it came from.
- An answer given before the hospital switched the question off is kept; an answer recorded while it was off is kept and marked as such.
- Rows of a finalized case cannot be changed.
Intraoperative data
- Timing: the start and end of anaesthesia as moments in time, with the case's time zone, the case month and the duration.
- Techniques, position, airway devices/tools, ventilation modes, monitoring modalities.
- Vascular access rows with site, size, unit, depth, lumens, and pre-existing flag.
- Premedication rows by phase: the day before surgery, or the morning before surgery. Each row carries the drug, its WHO ATC code, dose, unit and route; there is no clock time.
- Drug infusions record both rates: the dose rate and, where the syringe
strength is known, the pump rate in mL/h with the strength. A
target-controlled infusion records its model, site (Cp or Ce), the opioid
switch, each target, and the pump's own total when entered. The millilitres
given through infusions are stored as
infusionsMland count in the fluid balance. - Append-only event timeline: vitals, serum/peripheral glucose, bolus drugs, infusion starts/rate changes/stops, fluid starts/stops, inhalational agent starts/stops, fresh gas flow changes, and clinical events.
- Fresh gas flow over time: FGF L/min, carrier gas, FiO2, calculated FiAir, and calculated FiN2O. FiO2 is clamped to 21-100%; O2-only is FiO2 100%.
- Fluids, urine, blood products, complications, and event notes.
Postoperative data
- Aldrete score components and total.
- Recovery vitals: systolic BP, diastolic BP, heart rate, SpO2, temperature.
- Pain NRS, PONV, disposition, handover checklist, complications, and notes.
What is not stored?
The following are intentionally never uploaded or stored:
- Patient name.
- Patient national ID / EGN.
- Hospital file number or patient ID number.
- Date of birth; the age at the procedure is stored instead. (The date and time of the anaesthesia are stored, because the chart is a timeline.)
- Surgeon, anaesthesiologist, or nurse names as structured fields.
- On the cloud service, free text that triggers the server-side PII detector.
The printable protocol leaves patient identity fields blank. Clinicians fill those fields by hand after printing if needed for the local paper record.
Canonical libraries
LOSPOR uses shared backend libraries rather than app-specific hardcoded lists.
| Library | Source of truth | Used for |
|---|---|---|
| ICD-10 | Icd10Code, Icd10Synonym | diagnoses and comorbidities |
| Labs/LOINC | LabLoinc and canonical lab code | AI scan, manual labs, export |
| Drugs/ATC/INN | Atc, Drug, option-library drug rows | medication history, allergies, intraop drugs/infusions |
| App options | OptionLibrary | techniques, airway, ventilation, monitoring, position, fluids, events, disposition, handover, numeric ranges |
| Athena/OMOP vocabulary | OmopConcept, OmopVocabulary, relationships, ancestors, synonyms | local standard concept resolution |
| Concept map | ConceptMap | source code/label preservation, mapping method/confidence, review state, and OMOP concept IDs where known |
ICD-10 English and Bulgarian labels are metadata for the same ICD code. They are not duplicate clinical concepts.
Research data layers
LOSPOR keeps compatibility JSON/cache data for the apps, but research queries should use normalized rows where available.
| Clinical data | SQL table | Research columns |
|---|---|---|
| Diagnoses | PreopDiagnosis | ICD code, labels, source vocabulary/code, OMOP concept ID if mapped |
| Procedures | PreopProcedure | code, group, domain, source mapping |
| Comorbidities | Comorbidity | ICD-10 code, labels, source mapping |
| Labs | LabResult | valueNum, unitCanon, LOINC, ranges, abnormal flag, source mapping |
| Medications/allergies | Medication | kind, drugId, INN, ATC, dose, route, source mapping |
| Vascular access | VascularAccess | site, size, unit, depth, lumens, pre-existing flag |
| Premedication | PremedicationAdministration | phase, raw name, INN, ATC, dose, route |
| Complications | CaseComplication | section, label, note, timestamp, source mapping |
| Selections | CaseSelection | section, category, value, source mapping |
| Intraop timeline | CaseEvent | event type, timestamp, typed vitals/gas/drug/fluid/agent columns, provenance |
| Missingness | ClinicalFieldStatus | fieldKey, presence, source, sourceVersion |
CaseEvent is append-only. Edits supersede older rows and deletes tombstone rows, so the current chart can be projected from active rows while preserving history for audit.
Missingness and provenance
Research exports must distinguish blank data from negative data. ClinicalFieldStatus records whether key fields are:
PRESENTABSENTUNKNOWNNOT_APPLICABLENOT_DOCUMENTED
Normalized rows also carry source/provenance metadata such as user input, web/mobile source, AI scan, backfill, migration, or relational sync where available. Field-status coverage is intentionally broad so normalized rows can serve as the research/export authority while UI JSON remains a compatibility cache.
OMOP export
The OMOP export is an OMOP CDM v5.4-oriented research export. It now reads normalized rows and active event rows instead of raw legacy blobs.
The export includes:
- care site as its own table, referenced by visit occurrence through
care_site_id - person and observation period, the CDM root tables
- visit occurrence
- condition occurrence from diagnoses and comorbidities. An ICD-10 code that OMOP splits into several concepts (E11.2: type 2 diabetes, and a kidney disorder due to it) exports one row per concept with the same source value
- procedure occurrence from every planned procedure, the anaesthesia technique, vascular access, the act of placing an instrumented airway, and each blood unit's transfusion. A planned procedure carries its standard concept only when the clinician chose the exact ICD-10-PCS operation; a group alone exports concept 0 with the group in the source value
- observation rows for each answered preoperative question, from its answer
row: the question's concept from the catalogue (0 with the
LOSPOR:PREOP_<question>source value where no standard concept says what the question asks), and the answer asvalue_as_concept_idYes 4188539 or No 4188540.NOT_ASKEDexports nothing. Unintentional weight loss exports as a condition, and the planned urgency as a procedure modifier - measurement rows for preop/postop vitals, labs, intraop vitals, glucose, and gas settings,
carrying
value_source_valuefor results the laboratory reported as text andrange_low/range_highfor the reference range the result was judged against - drug exposure rows for medications, bolus drugs, premedication, agents, infusions and IV
fluids, with
drug_exposure_end_datepaired from stop events for continuous administrations. A fluid is coded as the clinical drug at the strength given, from a hand-checked table, because fluids share ATC codes (saline, Hartmann's and Plasma-Lyte are all B05BB01). Premedication is dated the day before (D-1) or the day of the operation - device exposure rows for instrumented airway devices and for each blood unit, the unit
carrying its product concept and its volume as
quantityin mL (unit_concept_id8587). Cell salvage has no product concept and exports as the autotransfusion procedure, with its volume as an observation - observations for ASA, scores, selections, complications, handover, disposition, the preoperative history and airway examination, airway devices and ventilation, drug allergies, and other app-local concepts
Clinical yes/no questions are exported for a recorded "no" as well as a "yes". No row means the question was never asked, which is a different claim about a patient than a negative finding.
An allergy is exported as an observation, never as a drug exposure. A substance a patient reacts to is not one they were given.
Dates and times are the theatre's clock.
- Dates: every
*_dateis the local calendar date in the case's time zone. - Times: every
*_datetimeis the local time with its UTC offset, for example2026-06-02T01:30:00+03:00for a case begun at 01:30 in Sofia. It is the same moment as the UTC instant, readable as the clock in theatre. - No zone: a case that never recorded its zone is in UTC.
A target-controlled infusion exports as one drug exposure:
- Dose: the amount given, which is the pump's own total when entered and otherwise the model's calculation.
- Beside it, observations: the model (
LOSPOR:TCI_MODEL), the site, the opioid switch, every target (LOSPOR:TCI_TARGET), and both the calculated and the pump total. - mL without a syringe: a pump total in mL with no syringe strength cannot
become an amount, and is kept as
LOSPOR:TCI_TOTAL_PUMP_ML.
Infusion volume. The drug-infusion millilitres export as
LOSPOR:DRUG_INFUSIONS_ML, with each infusion's pump rate and strength.
Known OMOP concept IDs are stored/exported where confidently mapped. The concept is fixed when the case is saved, so exporting a case twice gives the same file, and a finalized case is never rewritten when vocabularies change.
The research numbers LOSPOR needs ship with every release, so a site exports standard concepts without importing any terminology: the ICD-10-PCS operations, the OMOP concept ids of LOSPOR's ICD-10 codes, the LOINC codes of its laboratory tests, and the RxNorm targets of its catalogue drugs' ATC codes. For SNOMED CT only the OMOP concept numbers are bundled, never SNOMED codes or descriptions. The Bulgarian national ICD-10 extensions have no concept of their own and export as source codes; they do not borrow their parent code's concept. A filtered Athena CSV import can still enrich mappings through local OMOP vocabulary tables, and wins where it resolves a code. Otherwise LOSPOR exports source vocabulary, source code, and source labels with an explicit source-only/unmapped status. Fake OMOP IDs are not used.
Each export includes a manifest with app/schema version, concept-map version, row counts, mapping summary, de-identification notes, and quality warnings. Governed export manifest v2 also freezes the parent clinical/event/relational revisions and every section revision for each finalized case. App exports warn rather than block when source-only mappings, missing field-status rows, exact timestamps, or institution linkage are present. Downloadable research artifacts are retained for 30 days by default; their checksum, row count, source version, and audit history remain after the file expires.
An OMOP request that matches more than 5000 cases is rejected with HTTP 422
and reports the matching count, limit, and complete: false. LOSPOR never
returns the first 5000 cases as if they were the full research dataset. Narrow
the export or use the future resumable institution-to-datacentre export
workflow for larger cohorts.
De-identification / pseudonymisation
Each case receives a generated case code such as 2026-0001. This is the visible case-level pseudonym used in the UI and exports.
Internally, LOSPOR stores operational linkage needed for access control, audit, governance, and research quality: user ID, institution ID, timestamps, role/audit information, and finalisation snapshots. These are not patient identifiers, but they mean LOSPOR data should be described as de-identified / pseudonymised, not fully anonymised.
Data quality tools
The backend includes tooling for release and research checks:
scripts/seed-vocabularies.tsseeds ICD-10, ICD-10CM synonyms, ATC, and Drug rows.scripts/seed-athena-vocabularies.ts --filtered-losporimports only LOSPOR-needed local Athena/OMOP rows for vocabulary-backed mapping.scripts/seed-lab-loinc.tsseeds the canonical lab/LOINC catalogue.scripts/seed-option-library.tsseeds shared app option libraries.scripts/seed-concept-maps.tsseeds local bilingual concept maps and enriches them from Athena when available.scripts/backfill-relational.tsrebuilds normalized rows and typed event columns from existing cases.scripts/data-quality-report.tsreports relational drift, unmapped/source-only concepts, invalid ranges, impossible timestamps, and missing key research fields.scripts/wipe-dev-clinical-data.tscan wipe dev clinical data while preserving accounts, institutions, vocabularies, option libraries, and configuration.
Research access
The standalone LOSPOR Database Research Browser provides governed cohort queries, comparisons, pseudonymous case inspection, data-quality review, benchmarks, saved cohorts, and complete audited exports. It uses read-only /v1/research/* API projections and never connects to operational tables directly. See Research Browser.
Citing LOSPOR
If you use LOSPOR data in a publication, cite:
LOSPOR - Large Open Source Perioperative Register. Available at https://lospor.org. Licensed under AGPL-3.0.