Design Decisions
Key design constraints, architectural rationale, tradeoffs, and extensibility notes for Molecular.
Molecular Design Decisions
Use this page to capture why the feature was built this way, not only what the code does.
Design Intent
Molecular diagnostics requires strict linkage between genetic markers, the organisms that carry them, and the antimicrobial agents used to treat them. The feature is designed around a prerequisite-master-data model to ensure these relationships are structurally sound before any reporting happens.
The design premise:
Molecular reporting configuration must be built on explicit, mapped master catalogs (Genes, Organisms, Antibiotics) to enable automated resistance calculation and standardized reporting, rather than ad-hoc text entry.
Decision Stack
Key Design Constraints
| Constraint | Why it is real | Architectural consequence |
|---|---|---|
| Molecular targets (Genes) and targets (Organisms) share Antibiotics | Susceptibility testing uses the same catalog of antimicrobial agents regardless of the diagnostic target | A single Antibiotic master table serves both Gene and Organism relationships |
| Organisms have standard and molecular antibiograms | Some testing uses standard culture methods, while molecular methods require specific ordering and active state tracking | Two junction tables exist: OrganismAntibiotics and MolecularOrganismAntibiotics |
| Detection interpretation is inverted compared to Toxicology | In molecular testing, a value below a cut-off (e.g., lower Ct value in PCR) indicates presence | The frontend AgGrid detection logic evaluates value <= cut_off as Detected |
| Master records can be operationally disabled | Records may need to stop being selectable without losing historical report integrity | Soft-disable flags (is_disabled) are used instead of hard deletes; linked records are protected via disable-warnings |
| Master records need clear synchronization | Caching layer needs to stay consistent across related entities | Aggressive cache invalidation: saving a gene updates the organism cache; saving an organism updates the gene cache |
Architectural Rationale
1. Antibiotic Master is the shared foundation
Antibiotics form the core vocabulary for susceptibility testing. Both Genes and Organisms depend on them.
Why this was preferred
- Avoids duplicating drug definitions across molecular and standard culture modules.
- Allows a unified susceptibility reporting format.
- Provides a single point of integration for device mapping (
device_organism_mapping,device_gene_mapping).
2. Specialized Junction Tables for Organisms
The system uses OrganismAntibiotics for standard mappings, but introduces MolecularOrganismAntibiotics for molecular reports.
Why this was preferred
- Molecular reports require specific display ordering (
sequence) and the ability to toggle individual antibiotic mappings on/off (is_active) without destroying the underlying standard antibiogram. - The
MolecularOrganismAntibioticstable is managed via upsert logic during organism save to preserve sequence and active states, unlike standard mappings which use delete-and-recreate bulk operations.
3. Inverted Detection Logic in the Frontend Grid
Instead of creating a completely separate grid architecture, Molecular reuses the report entry grid but applies a specific componentType check (GENE or ORGANISM) to alter the interpretation logic.
Why this was preferred
- Allows maximum reuse of the
AgGridreport entry components. - Centralizes the logic in
helpers.tsx(renderCell,getColorForMolecular) based on the component type flag.
Tradeoff
- The
helpers.tsxfile must carefully branch logic based oncomponentType, increasing the complexity of a shared file to accommodate the inverted≤ cut_off = Detectedrule.
4. Cache Invalidation Strategy
Due to the complex interdependencies (Genes map to Antibiotics, Organisms map to Antibiotics, and API responses often serialize these nested relationships), caching must be aggressively managed.
Why this was preferred
- When a gene changes, an organism's serialized response (which might embed gene resistance data) must reflect the change. Thus,
update_organism_cache()is called from Gene'safter_save. - This bidirectional invalidation ensures that the
livehealthappread APIs always serve consistent nested mappings without requiring expensive real-time table joins on every list load.
Extensibility Notes
- If new molecular targets (e.g., specific mutations or variants) are added, consider extending the
Genemodel with new fields rather than creating a new base entity, as the resistance mapping logic is already established there. - The dual junction table approach for Organisms (
OrganismAntibioticsvsMolecularOrganismAntibiotics) should be carefully maintained. If new ordering/active-state logic is needed for standard cultures in the future, consider unifying the junction tables rather than adding a third. - Any new Molecular component types added to the report configuration must be explicitly handled in the
renderCellandprepareSummaryComponentColumnDefhelpers in the frontend grid logic.