255 lines
12 KiB
SQL
255 lines
12 KiB
SQL
-- ============================================================
|
|
-- 🖥️ CLQMS Edge Workstation - SQLite Database Schema
|
|
-- Project Pandaria: Offline-First LIS Architecture
|
|
-- ============================================================
|
|
-- This is the LOCAL database for each Smart Workstation.
|
|
-- Stack: Node.js (Electron) + SQLite
|
|
-- Role: "The Cortex" - Immediate Processing
|
|
-- ============================================================
|
|
|
|
-- 🔧 Enable foreign keys (SQLite needs this explicitly)
|
|
PRAGMA foreign_keys = ON;
|
|
|
|
-- ============================================================
|
|
-- 1. 📋 CACHED ORDERS (Hot Cache - Last 7 Days)
|
|
-- ============================================================
|
|
-- Orders downloaded from the Core Server for local processing.
|
|
-- Workstation can work 100% offline with this data.
|
|
|
|
CREATE TABLE IF NOT EXISTS orders (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
server_order_id TEXT UNIQUE NOT NULL, -- Original ID from Core Server
|
|
patient_id TEXT NOT NULL,
|
|
patient_name TEXT NOT NULL,
|
|
patient_dob DATE,
|
|
patient_gender TEXT CHECK(patient_gender IN ('M', 'F', 'O')),
|
|
order_date DATETIME NOT NULL,
|
|
priority TEXT DEFAULT 'routine' CHECK(priority IN ('stat', 'routine', 'urgent')),
|
|
status TEXT DEFAULT 'pending' CHECK(status IN ('pending', 'in_progress', 'completed', 'cancelled')),
|
|
barcode TEXT,
|
|
notes TEXT,
|
|
synced_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
CREATE INDEX idx_orders_barcode ON orders(barcode);
|
|
CREATE INDEX idx_orders_status ON orders(status);
|
|
CREATE INDEX idx_orders_patient ON orders(patient_id);
|
|
|
|
-- ============================================================
|
|
-- 2. 🔬 ORDER TESTS (What tests are requested?)
|
|
-- ============================================================
|
|
-- Each order can have multiple tests (CBC, Urinalysis, etc.)
|
|
|
|
CREATE TABLE IF NOT EXISTS order_tests (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
order_id INTEGER NOT NULL,
|
|
test_code TEXT NOT NULL, -- Standardized code (e.g., 'WBC_TOTAL')
|
|
test_name TEXT NOT NULL, -- Display name (e.g., 'White Blood Cell Count')
|
|
status TEXT DEFAULT 'pending' CHECK(status IN ('pending', 'processing', 'completed', 'failed')),
|
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
FOREIGN KEY (order_id) REFERENCES orders(id) ON DELETE CASCADE
|
|
);
|
|
|
|
CREATE INDEX idx_order_tests_order ON order_tests(order_id);
|
|
CREATE INDEX idx_order_tests_code ON order_tests(test_code);
|
|
|
|
-- ============================================================
|
|
-- 3. 📊 RESULTS (Machine Output - Normalized)
|
|
-- ============================================================
|
|
-- Results from lab machines, already translated to standard format.
|
|
|
|
CREATE TABLE IF NOT EXISTS results (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
order_test_id INTEGER,
|
|
machine_id INTEGER,
|
|
test_code TEXT NOT NULL, -- Standardized test code
|
|
value REAL NOT NULL, -- Numeric result
|
|
unit TEXT NOT NULL, -- Standardized unit
|
|
reference_low REAL,
|
|
reference_high REAL,
|
|
flag TEXT CHECK(flag IN ('L', 'N', 'H', 'LL', 'HH', 'A')), -- Low, Normal, High, Critical Low/High, Abnormal
|
|
raw_value TEXT, -- Original value from machine
|
|
raw_unit TEXT, -- Original unit from machine
|
|
raw_test_code TEXT, -- Original code from machine (before translation)
|
|
validated BOOLEAN DEFAULT 0,
|
|
validated_by TEXT,
|
|
validated_at DATETIME,
|
|
machine_timestamp DATETIME,
|
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
FOREIGN KEY (order_test_id) REFERENCES order_tests(id) ON DELETE SET NULL,
|
|
FOREIGN KEY (machine_id) REFERENCES machines(id) ON DELETE SET NULL
|
|
);
|
|
|
|
CREATE INDEX idx_results_order_test ON results(order_test_id);
|
|
CREATE INDEX idx_results_test_code ON results(test_code);
|
|
CREATE INDEX idx_results_validated ON results(validated);
|
|
|
|
-- ============================================================
|
|
-- 4. 📮 OUTBOX QUEUE (Registered Mail Pattern)
|
|
-- ============================================================
|
|
-- Data waits here until the Core Server confirms receipt (ACK).
|
|
-- Zero data loss, even if network blinks!
|
|
|
|
CREATE TABLE IF NOT EXISTS outbox_queue (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
event_type TEXT NOT NULL, -- 'result_created', 'result_validated', 'order_updated'
|
|
payload TEXT NOT NULL, -- JSON data to sync
|
|
target_entity TEXT, -- 'results', 'orders', etc.
|
|
target_id INTEGER, -- ID of the record
|
|
priority INTEGER DEFAULT 5, -- 1 = highest, 10 = lowest
|
|
retry_count INTEGER DEFAULT 0,
|
|
max_retries INTEGER DEFAULT 5,
|
|
last_error TEXT,
|
|
status TEXT DEFAULT 'pending' CHECK(status IN ('pending', 'processing', 'sent', 'acked', 'failed')),
|
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
sent_at DATETIME,
|
|
acked_at DATETIME
|
|
);
|
|
|
|
CREATE INDEX idx_outbox_status ON outbox_queue(status);
|
|
CREATE INDEX idx_outbox_priority ON outbox_queue(priority, created_at);
|
|
|
|
-- ============================================================
|
|
-- 5. 📥 INBOX QUEUE (Messages from Server)
|
|
-- ============================================================
|
|
-- Incoming messages/orders from Core Server waiting to be processed.
|
|
|
|
CREATE TABLE IF NOT EXISTS inbox_queue (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
server_message_id TEXT UNIQUE NOT NULL, -- ID from server for deduplication
|
|
event_type TEXT NOT NULL, -- 'new_order', 'order_cancelled', 'config_update'
|
|
payload TEXT NOT NULL, -- JSON data
|
|
status TEXT DEFAULT 'pending' CHECK(status IN ('pending', 'processing', 'completed', 'failed')),
|
|
error_message TEXT,
|
|
received_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
processed_at DATETIME
|
|
);
|
|
|
|
CREATE INDEX idx_inbox_status ON inbox_queue(status);
|
|
|
|
-- ============================================================
|
|
-- 6. 🔌 MACHINES (Connected Lab Equipment)
|
|
-- ============================================================
|
|
-- Registry of connected machines/analyzers.
|
|
|
|
CREATE TABLE IF NOT EXISTS machines (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
name TEXT NOT NULL, -- 'Sysmex XN-1000', 'Mindray BC-6800'
|
|
manufacturer TEXT,
|
|
model TEXT,
|
|
serial_number TEXT,
|
|
driver_file TEXT NOT NULL, -- 'driver-sysmex-xn1000.js'
|
|
connection_type TEXT CHECK(connection_type IN ('RS232', 'TCP', 'USB', 'FILE')),
|
|
connection_config TEXT, -- JSON: {"port": "COM3", "baudRate": 9600}
|
|
is_active BOOLEAN DEFAULT 1,
|
|
last_communication DATETIME,
|
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
-- ============================================================
|
|
-- 7. 📖 TEST DICTIONARY (The Translator)
|
|
-- ============================================================
|
|
-- Maps machine-specific codes to standard codes.
|
|
-- Solves the "WBC vs Leukocytes" problem!
|
|
|
|
CREATE TABLE IF NOT EXISTS test_dictionary (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
machine_id INTEGER, -- NULL = universal mapping
|
|
raw_code TEXT NOT NULL, -- What the machine sends: 'W.B.C', 'Leukocytes'
|
|
standard_code TEXT NOT NULL, -- Our standard: 'WBC_TOTAL'
|
|
standard_name TEXT NOT NULL, -- 'White Blood Cell Count'
|
|
unit_conversion_factor REAL DEFAULT 1.0, -- Multiply raw value by this (e.g., 10 for g/dL to g/L)
|
|
raw_unit TEXT, -- Unit machine sends
|
|
standard_unit TEXT, -- Our standard unit
|
|
reference_low REAL,
|
|
reference_high REAL,
|
|
is_active BOOLEAN DEFAULT 1,
|
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
FOREIGN KEY (machine_id) REFERENCES machines(id) ON DELETE CASCADE,
|
|
UNIQUE(machine_id, raw_code)
|
|
);
|
|
|
|
CREATE INDEX idx_dictionary_lookup ON test_dictionary(machine_id, raw_code);
|
|
|
|
-- ============================================================
|
|
-- 8. 📜 SYNC LOG (Audit Trail)
|
|
-- ============================================================
|
|
-- Track all sync activities for debugging & recovery.
|
|
|
|
CREATE TABLE IF NOT EXISTS sync_log (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
direction TEXT CHECK(direction IN ('push', 'pull')),
|
|
event_type TEXT NOT NULL,
|
|
entity_type TEXT,
|
|
entity_id INTEGER,
|
|
server_response_code INTEGER,
|
|
server_message TEXT,
|
|
success BOOLEAN,
|
|
duration_ms INTEGER,
|
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
CREATE INDEX idx_sync_log_created ON sync_log(created_at DESC);
|
|
|
|
-- ============================================================
|
|
-- 9. ⚙️ LOCAL CONFIG (Workstation Settings)
|
|
-- ============================================================
|
|
-- Key-value store for workstation-specific settings.
|
|
|
|
CREATE TABLE IF NOT EXISTS config (
|
|
key TEXT PRIMARY KEY,
|
|
value TEXT,
|
|
description TEXT,
|
|
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
-- ============================================================
|
|
-- 📦 SAMPLE DATA: Machines & Dictionary
|
|
-- ============================================================
|
|
|
|
-- Sample Machines
|
|
INSERT INTO machines (name, manufacturer, model, driver_file, connection_type, connection_config) VALUES
|
|
('Sysmex XN-1000', 'Sysmex', 'XN-1000', 'driver-sysmex-xn1000.js', 'RS232', '{"port": "COM3", "baudRate": 9600}'),
|
|
('Mindray BC-6800', 'Mindray', 'BC-6800', 'driver-mindray-bc6800.js', 'TCP', '{"host": "192.168.1.50", "port": 5000}');
|
|
|
|
-- Sample Test Dictionary (The Translator)
|
|
INSERT INTO test_dictionary (machine_id, raw_code, standard_code, standard_name, raw_unit, standard_unit, unit_conversion_factor, reference_low, reference_high) VALUES
|
|
-- Sysmex mappings (machine_id = 1)
|
|
(1, 'WBC', 'WBC_TOTAL', 'White Blood Cell Count', '10^3/uL', '10^3/uL', 1.0, 4.0, 11.0),
|
|
(1, 'RBC', 'RBC_TOTAL', 'Red Blood Cell Count', '10^6/uL', '10^6/uL', 1.0, 4.5, 5.5),
|
|
(1, 'HGB', 'HGB', 'Hemoglobin', 'g/dL', 'g/L', 10.0, 120, 170),
|
|
(1, 'PLT', 'PLT_TOTAL', 'Platelet Count', '10^3/uL', '10^3/uL', 1.0, 150, 400),
|
|
-- Mindray mappings (machine_id = 2) - Different naming!
|
|
(2, 'Leukocytes', 'WBC_TOTAL', 'White Blood Cell Count', 'x10^9/L', '10^3/uL', 1.0, 4.0, 11.0),
|
|
(2, 'Erythrocytes', 'RBC_TOTAL', 'Red Blood Cell Count', 'x10^12/L', '10^6/uL', 1.0, 4.5, 5.5),
|
|
(2, 'Hb', 'HGB', 'Hemoglobin', 'g/L', 'g/L', 1.0, 120, 170),
|
|
(2, 'Thrombocytes', 'PLT_TOTAL', 'Platelet Count', 'x10^9/L', '10^3/uL', 1.0, 150, 400),
|
|
-- Universal mappings (machine_id = NULL)
|
|
(NULL, 'W.B.C', 'WBC_TOTAL', 'White Blood Cell Count', NULL, '10^3/uL', 1.0, 4.0, 11.0),
|
|
(NULL, 'White_Cells', 'WBC_TOTAL', 'White Blood Cell Count', NULL, '10^3/uL', 1.0, 4.0, 11.0);
|
|
|
|
-- Sample Config
|
|
INSERT INTO config (key, value, description) VALUES
|
|
('workstation_id', 'LAB-WS-001', 'Unique identifier for this workstation'),
|
|
('workstation_name', 'Hematology Station 1', 'Human-readable name'),
|
|
('server_url', 'https://clqms-core.example.com/api', 'Core Server API endpoint'),
|
|
('cache_days', '7', 'Number of days to keep cached orders'),
|
|
('auto_validate', 'false', 'Auto-validate results within normal range'),
|
|
('last_sync', NULL, 'Timestamp of last successful sync');
|
|
|
|
-- Sample Order (for testing)
|
|
INSERT INTO orders (server_order_id, patient_id, patient_name, patient_dob, patient_gender, order_date, priority, barcode) VALUES
|
|
('ORD-2025-001234', 'PAT-00001', 'John Smith', '1980-01-15', 'M', '2025-12-19 08:00:00', 'routine', 'LAB2025001234');
|
|
|
|
INSERT INTO order_tests (order_id, test_code, test_name) VALUES
|
|
(1, 'WBC_TOTAL', 'White Blood Cell Count'),
|
|
(1, 'RBC_TOTAL', 'Red Blood Cell Count'),
|
|
(1, 'HGB', 'Hemoglobin'),
|
|
(1, 'PLT_TOTAL', 'Platelet Count');
|
|
|
|
-- ============================================================
|
|
-- ✅ DONE! Your Edge Workstation database is ready.
|
|
-- ============================================================
|