-- ============================================================ -- 🖥️ 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. -- ============================================================