Технички post-mortem за миграција на специјализиран систем за молекуларна генетика и кариотипирање. CA-Clipper 5.2 / dBASE III+ › Tauri 2 + Rust + React + PostgreSQL 16.
Проектот е правен за клиент од USA, документиран секој чекор. Детали, демо и слики од самиот софтвер нема да споделам поради NDA.
Стар јазик: CA-Clipper 5.2 | Стара база: dBASE III+ .dbf | Траење: 6 месеци | Мигрирани варијанти: ~290 000
1. Контекст и проблем
Лабораторијата работеше на две паралелни насоки: цитогенетика (кариотипирање) и молекуларна генетика (детекција на точкести мутации, мали инсерции и делеции). Стариот Clipper систем беше напишан во 1991 година, прво само за кариотипирање. Со текот на годините, молекуларните анализи беа додавани преку нови .dbf датотеки без централна архитектура. До 2025, системот имаше 17 неповрзани .dbf датотеки и ниту еден foreign key.
| ROOT CAUSE При concurrent write од две машини, последниот кој ја затворал .dbf датотеката ги презапишувал промените на другиот позадиснки, без грешка. |
ОРИГИНАЛНА СТРУКТУРА НА .DBF ДАТОТЕКИТЕ
| Датотека | Намена | Записи | Критичен проблем |
| PATIENT.DBF | Демографија + фамилија | 31 240 | Pedigree само како слободен текст |
| KARIOTYPЕ.DBF | ISCN нотација на кариотип | 28 900 | Без валидација на ISCN синтакса |
| MUTATIONS.DBF | Детектирани мутации | 189 400 | HGVS нотација рачно внесена, без стандард |
| GENES.DBF | Листа на гени | 847 | Без поврзување со OMIM/HGNC |
| PANELS.DBF | Генски панели | 94 | Без верзионирање на панели |
| REAGENTS.DBF | PCR реагенси и primers | 3 120 | Без lot-tracking по анализа |
| PATOL.DBF | Клинички фенотипови | 12 600 | Слободен текст наместо HPO термини |
| ГЛАВЕН ТЕХНИЧКИ ПРОБЛЕМ Нема ниту еден unique constraint, ниту еден foreign key, ниту валидација на HGVS нотација. Истата мутација беше запишана на 6 различни начини: c.5266dupC, 5266dupC, c.5266insC, BRCA1 ins 5266 итн. |
2. Нова архитектура: PostgreSQL schema
Дизајнот на новата база беше раководен со два стандарди: HGVS нотација за сите варијанти и HPO термини за клиничките фенотипови. Без тоа, никаква интеграција со ClinVar или OMIM не е возможна.
ГЛАВНИ ТАБЕЛИ
| patient | Тип | Белешка |
| id | uuid PK | |
| ssn | varchar(13) UNIQUE | Единствен матичен број |
| sex | char(1) | M / F |
| dob | date | |
| proband_id | uuid NULLABLE FK(self) | За фамилијарно групирање |
| ethnic_group | text | За внатрешна AF калибрација |
| variant | Тип | Белешка |
| id | uuid PK | |
| gen_id | uuid FK | |
| hgvs_c | text NOT NULL | Нормализирана HGVS нотација |
| hgvs_p | text NULLABLE | Протеинска нотација |
| rsid | varchar(20) | dbSNP идентификатор |
| acmg_class | acmg_enum | PATHOGENIC / VUS / BENIGN… |
| clinvar_id | bigint NULLABLE | |
| gnomad_af | numeric(10,8) | Алелска фреквенција |
| patient_variant | Тип | Белешка |
| id | uuid PK | |
| patient_id | uuid FK | |
| variant_id | uuid FK | |
| zygosity | zygosity_enum | HET / HOM / HEMIZYGOUS |
| heredity | heredity_tip | DE_NOVO / MAT / PAT |
| detection_method | text | NGS / SANGER / MLPA |
| reagent_lot_id | uuid FK | За трасабилност |
| reference_values | Тип | Белешка |
| id | uuid PK | |
| analysis_id | uuid FK | |
| sex | char(1) NULLABLE | NULL = важи за сите |
| age_from | int NULLABLE | |
| age_to | int NULLABLE | |
| min_val | numeric(10,3) | |
| max_val | numeric(10,3) |
PostgreSQL DDL Enum типови и партиционирање

3. Фаза 1: HGVS нормализација пред миграција
Пред да се пренесе ниту еден запис, беше неопходно да се нормализираат 189 000 мутациски записи. Истата варијанта постоеше во 6 до 12 различни текстуални форми. Без нормализација, базата би наследила хаос.
Python 3.12 HGVS нормализација преку Biocommons hgvs библиотека

КЛУЧЕН НАОД: По нормализацијата, беа идентификувани 34 пациенти чии варијанти беа класифицирани поинаку поради inconsistent HGVS нотација. Тоа се 34 случаи каде стариот систем потенцијално носел погрешна клиничка информација.
4. Фаза 2: VCF парсирање во Rust
Новата лабораторија добива резултати во VCF формат директно од NGS секвенцерот. Стариот систем нема концепт за тоа. Новиот Tauri backend имплементира VCF pipeline директно во Rust преку noodles crate.
Rust + noodles src-tauri/src/commands/vcf.rs

5. ACMG класификација на варијанти
Ова е централната нова функционалност. ACMG (American College of Medical Genetics) дефинира 28 критериуми за класификација на секоја варијанта. Стариот Clipper систем немаше никакво знаење за тоа.
Rust src-tauri/src/acmg.rs – AcmgScore::classify()

6. Фамилијарен pedigree: de novo детекција
Стариот систем го чуваше фамилијарниот контекст само во текстуалното поле HISTORY (ANAMNEZA). Новата структура ги поврзува пациентите во фамилијарен граф преку self-referencing табела. Варијанта е de novo ако не постои ниту кај мајката ниту кај таткото.
PostgreSQL De novo детекција преку recursive CTE

ПЕРФОРМАНСИ Query за de novo детекција на 31 000 пациенти преку recursive CTE: 340ms на PostgreSQL 16 со composite индекс. На истите податоци во .dbf формат, истиот резултат траеше повеќе од 4 минути преку Clipper SEEK loop.
7. Tauri архитектура: логика и IPC
Tauri апликацијата е два одвоени runtime-а кои комуницираат преку строго дефиниран IPC канал. Core процесот е Rust бинарен со целосен OS пристап. WebView процесот е системски браузер кој ги рендерира React компонентите. WebView не може директно да допре до filesystem или мрежа без Rust да одобри.
APPSTATE И DEPENDENCY INJECTION
Rust src-tauri/src/state.rs

EVENT SYSTEM: RUST EMIT, REACT LISTEN
VCF импортот може да трае минута-две. Наместо блокирање, Rust емитира прогрес-настани, React ги слуша и ажурира UI во реално време. Нема polling, нема websocket, нема Redux middleware.
TypeScript + React src/components/VcfImport.tsx

ТИПИЗИРАНИ ГРЕШКИ НИЗ ЦЕЛИОТ STACK
Rust src-tauri/src/errors.rs

ISCN PARSER: RUST + NOM
Секоја кариотипска анализа мора да биде во ISCN 2020 формат. Стариот Clipper систем немаше никаква валидација. Новиот имплементира Rust parser со nom комбинатор библиотека. Записот не може да се зачува додека нотацијата не е валидна.
Rust + nom src-tauri/src/kariotyp/iscn_parser.rs

CAPABILITY SECURITY МОДЕЛ
Tauri 2 воведе capability систем. Секоја capability е JSON фајл кој дефинира точно кои пермисии се дозволени. За LIMS: дозволен е пристап само до конкретни директориуми.
JSON src-tauri/capabilities/lims.json

ЗОШТО Е ОВА ВАЖНО Ако напаѓач инјектира малициозен JavaScript преку XSS во некој VCF коментар, тој не може да чита датотеки надвор од $TEMP и lab_data. Electron нема еквивалентен механизам без значителна дополнителна конфигурација.
8. Зошто баш Tauri: образложение на одлуката
Изборот на технолошки stack за медицински софтвер не е само технички, туку и регулаторен и оперативен. Во овој дел ги објаснувам конкретните причини зошто се одлучив за Tauri 2 и PostgreSQL, кои алтернативи ги разгледував сериозно, зошто ги отфрлив, и во кои сценарија би избрал поинаку.
ФИКСНИ БАРАЊА
| Барање | Опис | Статус |
| Работи офлајн | Апликацијата мора да работи целосно без мрежа | Критично |
| Linux апарат | Вграден Linux до NGS секвенцерот, 4 GB RAM | Критично |
| ISO 15189 | Секоја промена на податок мора да биде трасабилна | Критично |
| Еден dev, долг рок | Зрела технологија, без vendor lock-in | Важно |
LINUX АПАРАТ ДО СЕКВЕНЦЕРОТ: ОДЛУЧУВАЧКИ ФАКТОР
Покрај болничките работни станици под Windows, постоеше уште едно целно опкружување кое во голема мера ја запечати одлуката. Лабораторискиот секвенцер е поврзан со вградена Linux машина со само 4 GB RAM. На неа треба да работи истата апликација за прием на VCF резултати и нивен внес во базата. Тоа беше барање кое ниту еден друг candidate не го исполни без сериозни компромиси.
На машина со 4 GB RAM, Tauri апликацијата при старт зафаќа 42 MB RAM. Секвенцерот, PostgreSQL и апликацијата работат паралелно без проблем. Истиот сценарио со Electron: 310 MB само за апликацискиот процес, пред да е отворен ниту еден пациент. При обработка на VCF со 50 000 записи, Electron го доведе системот до 3.7 GB и почна да swap-ува на диск. Таури заврши за 94 секунди, без swap.
СПОРЕДБА ПО RAM УПОТРЕБА
| Технологија | RAM при старт | RAM (VCF 50k записи) | Linux поддршка |
| Tauri 2 (избран) | 42 MB | 430 MB | WebKit2GTK, native |
| Electron | 310 MB | 3.7 GB (swap!) | Да, no bundled Chromium |
| Flutter Desktop | 168 MB | ~600 MB | Да, no runtime overhead |
| Python + PyQt6 | 120 MB | ~400 MB | Да, no GPL license |
Ова исто така ми беа единствени опции поради програмските јазици. .NET, JAVA,C++ не ми беа опција бидејќи немам доволмо познавање од нив.
CROSS-COMPILATION: ЕДЕН CI PIPELINE ЗА СИТЕ ПЛАТФОРМИ
YAML .github/workflows/release.yml

ПЕТТЕ КОНКРЕТНИ ПРИЧИНИ ЗОШТО TAURI ПОБЕДИ
[01] Rust memory safety за медицински податоци Во генетска лабораторија, data corruption не е само bug, туку потенцијално погрешна дијагноза. Rust-овиот borrow checker го прави невозможно случајното пишување надвор од граници на buffer или data race при concurrent VCF import. Компајлерот фати 14 потенцијални race condition грешки кои во Electron само ќе се манифестираа при runtime.
[02] SQLx compile-time query validation SQLx ги верификува SQL queries директно при компајлирање, против вистинска PostgreSQL инстанца. Ако табелата или колоната не постои, или типовите не се совпаѓаат, компајлот паѓа. За апликација со 60+ SQL queries, тоа е значајна сигурносна мрежа.
[03] Системски WebView без Chromium Tauri го користи WebKit2GTK на Linux, WebKit на macOS, WebView2 на Windows. Безбедносните patches доаѓаат преку системски пакет менаџер, не преку нов release на апликацијата. Electron апликациите бараат регуларни нови releases само за безбедносни Chromium апдејти.
[04] Capability security модел и IPC изолација Capability системот ми дозволи да дефинирам прецизно кои делови од OS-от ги допира апликацијата. WebView нема директен пристап до PostgreSQL или filesystem надвор од дефинираните директориуми.
[05] React ecosystem за UI без компромис React со TanStack Table, React Query и Radix UI ги решава сите UI проблеми со зрели, добро тестирани библиотеки. Dart/Flutter и Qt немаат еквивалентен UI ecosystem со иста зрелост.
КОГА НЕМА ДА ГО ИЗБЕРАМ TAURI
| Сценарио | Подобар избор | Причина |
| Тим без Rust искуство | Electron | Rust има стрмна крива на учење |
| Cloud-native / SaaS | Next.js / SvelteKit | Побрзо, поевтино, push updates |
| Сложена нативна UI | Qt | Подлабока OS интеграција |
| Мобилност | Flutter | Tauri mobile е сеуште во бета |
РЕТРОСПЕКТИВНА ОЦЕНКА ПО 6 МЕСЕЦИ: По 6 месеци развој и 6 месеци продукција, би ја донел истата одлука. Единствениот дел каде ја почувствував ограниченоста е при complex drag-and-drop за pedigree editor во WebView2. Сè останато: производство, стабилност, безбедност беше над очекувањата.
“Генетскиот запис е перманентен. Системот кој го чува, исто така треба да биде.”
Clipper кодот е архивиран во git. Новиот систем ги задоволува барањата на ISO 15189. Секоја варијанта, секоја рекласификација, секој lot-број е трасабилен.







