Airmid — Evidence-Based Phytotherapy and Botanical Intelligence Platform
This document specifies what is actually implemented in the Airmid domain.
Airmid is a pure library domain: 19 TypeScript libraries under
libs/airmid/, with no applications and no standalone services. Every type,
schema, enum, event, endpoint definition, and database table described below is
traceable to source under libs/airmid/.
The document is organized to mirror how the code layers. It starts with the
shared foundation (@airmid/core) — the types, entities, errors, events, and
constants that every other library builds on — then covers the database schema,
the API layer, and finally a summary surface for each scientific library.
Reading this document alongside features.md gives a complete picture:
features.md explains what each module does and why; this document specifies
the exact types, enum values, table names, and function signatures involved.
The canonical planning backlog is Phase 35 of TODOS.md (35.1–35.20).
1. Library Inventory#
All 19 libraries are private workspace packages (version: 0.1.0,
type: module, source entry ./src/index.ts). Every package depends on zod
(catalog). @airmid/database additionally depends on knex and (dev) uuid.
@airmid/ml additionally depends on @airmid/api (workspace:*). All packages
carry vitest as a dev dependency.
| Package | Path | Purpose |
|---|---|---|
@airmid/core |
libs/airmid/core |
Foundation types, branded IDs, enums, entities, errors, events |
@airmid/ethno |
libs/airmid/ethno |
Ethnobotanical knowledge — TCM, Ayurveda, Unani, Indigenous systems |
@airmid/phytochem |
libs/airmid/phytochem |
Computational phytochemistry — properties, drug-likeness, ADMET |
@airmid/evidence |
libs/airmid/evidence |
Trial integration, systematic review, GRADE grading, evidence search |
@airmid/interactions |
libs/airmid/interactions |
Herb-drug interaction clinical decision support |
@airmid/docking |
libs/airmid/docking |
Molecular docking, virtual screening, QSAR, molecular dynamics |
@airmid/network |
libs/airmid/network |
Network pharmacology — targets, PPI, pathway/GO enrichment |
@airmid/formulation |
libs/airmid/formulation |
Synergy analysis, extraction, stability, bioavailability |
@airmid/microbiome |
libs/airmid/microbiome |
Microbiome pharmacology — prebiotics, metabolites, dysbiosis |
@airmid/precision |
libs/airmid/precision |
Pharmacogenomics, genotype-response, biomarker integration |
@airmid/quality |
libs/airmid/quality |
DNA barcoding, spectroscopy, chromatography, chemometrics |
@airmid/safety |
libs/airmid/safety |
Adverse events, hepatotoxicity, nephrotoxicity, special populations |
@airmid/regulatory |
libs/airmid/regulatory |
Pharmacopoeia compliance, EMA/HMPC, FDA, global status, labeling |
@airmid/sustainability |
libs/airmid/sustainability |
Conservation status, sourcing, environmental impact, substitution |
@airmid/ml |
libs/airmid/ml |
Biomedical NLP, GNN, transformers, generative models |
@airmid/vision |
libs/airmid/vision |
Plant identification — leaf, flower, bark, multi-organ matching |
@airmid/clinical |
libs/airmid/clinical |
FHIR, CDS Hooks, interaction alerts, patient education |
@airmid/api |
libs/airmid/api |
External DB connectors, ETL, OpenAPI spec, export/reporting |
@airmid/database |
libs/airmid/database |
PostgreSQL schema (Knex migrations + Zod schemas) |
Every Nx project carries the tags scope:airmid, layer:domain, type:lib.
2. Core Foundation Types (@airmid/core)#
Defined in libs/airmid/core/src/types.ts. All branded ID types use a
Brand<T, B> nominal-typing helper and are validated against a UUID v4 pattern.
Branded types catch a common class of bug where a CompoundId is accidentally
passed where a SpeciesId is expected — the TypeScript compiler rejects such
assignments even though both are strings at runtime.
2.1 Branded ID Types#
The following ID types are used as foreign keys throughout all domain entities and events:
| Type | Brand | Zod schema | Validation |
|---|---|---|---|
SpeciesId |
Brand<string,…> |
SpeciesIdSchema |
UUID v4 |
CompoundId |
Brand<string,…> |
CompoundIdSchema |
UUID v4 |
TrialId |
Brand<string,…> |
TrialIdSchema |
UUID v4 |
InteractionId |
Brand<string,…> |
InteractionIdSchema |
UUID v4 |
MonographId |
Brand<string,…> |
MonographIdSchema |
UUID v4 |
PathwayId |
Brand<string,…> |
PathwayIdSchema |
UUID v4 |
AdverseEventId |
Brand<string,…> |
AdverseEventIdSchema |
UUID v4 |
2.2 Chemical Identifier Types#
Chemical identity management requires strict format validation — a corrupted CAS number or InChIKey breaks cross-database linking. These types enforce the official format rules for each identifier:
| Type | Definition | Pattern / Notes |
|---|---|---|
CASNumber |
branded string |
CAS_NUMBER_PATTERN = /^\d{2,7}-\d{2}-\d$/ |
SMILES |
string alias |
Line notation of molecular structure |
InChIKey |
string alias |
INCHI_KEY_PATTERN = /^[A-Z]{14}-[A-Z]{10}-[A-Z]$/ |
MolecularFormula |
string alias |
Hill-system notation |
AdministrationRoute |
union | 'oral' | 'sublingual' | 'topical' | 'inhalation' | 'rectal' |
2.3 Enumerations#
All enumerations are TypeScript enums with string values. They are used as
column types in the database schema (§8) and as discriminants in entity computed
properties throughout the domain. The full set of enums:
TaxonomicRank—Kingdom,Phylum,Class,Order,Family,Genus,Species,Subspecies,Variety,Cultivar.CompoundClass—Alkaloid,Flavonoid,Terpene,Terpenoid,Phenol,Polyphenol,Tannin,Saponin,Glycoside,Coumarin,Lignin,Steroid,EssentialOil,FattyAcid,Amino,Carbohydrate,Vitamin,Mineral,Other(19 members).GRADEQuality—High,Moderate,Low,VeryLow.OxfordLevel—Level1a,Level1b,Level2a,Level2b,Level3a,Level3b,Level4,Level5(Oxford CEBM, March 2009).StudyDesign—SystematicReview,MetaAnalysis,RCT,CohortStudy,CaseControl,CaseSeries,CaseReport,CrossSectional,InVitro,InVivo,ExVivo,Computational.EvidenceStrength—Strong,Moderate,Limited,Insufficient,Conflicting.InteractionSeverity—Contraindicated,Major,Moderate,Minor,Theoretical.InteractionMechanism—CYP450Inhibition,CYP450Induction,PGPInhibition,ProteinBindingDisplacement,PharmacodynamicSynergy,PharmacodynamicAntagonism,GIAbsorptionAlteration,RenalClearanceChange,Other.AdverseReactionType—Allergic,Hepatotoxic,Nephrotoxic,Neurotoxic,Dermatologic,GI,Cardiovascular,Respiratory,Hematologic,Endocrine,Other.CausalityAssessment—Certain,Probable,Possible,Unlikely,Conditional,Unassessable(WHO-UMC categories).DosageForm—Tincture,Decoction,Infusion,Capsule,Tablet,Extract,EssentialOil,Poultice,Salve,Syrup,Powder,Tea,Cream,Oil(14 members).DosageUnit—mg,g,mL,drops,cups,tablespoons,teaspoons.PreparationType—Aqueous,Ethanolic,Hydroethanolic,Supercritical,ColdPressed,SteamDistilled,Macerated,Fermented.IUCNStatus—NotEvaluated,DataDeficient,LeastConcern,NearThreatened,Vulnerable,Endangered,CriticallyEndangered,ExtinctInWild,Extinct.CITESAppendix—None,AppendixI,AppendixII,AppendixIII.Pharmacopoeia—USP,EP,BP,JP,CP,IP,WHO,ESCOP,CommissionE,HMPC.RegulatoryStatus—Approved,MonographPublished,TraditionalUse,DietarySupplement,Restricted,Banned,UnderReview.
2.4 Plain Interfaces#
The following plain interfaces are used as the raw-data input to entity class constructors (§3). Each has a corresponding Zod schema that validates the data at the boundary.
TaxonomicClassification#
Represents a complete Linnaean classification from kingdom down to species, with
optional infraspecific ranks. All required string fields enforce .min(1).
| Field | Type | Req. | Meaning |
|---|---|---|---|
kingdom |
string |
✓ | e.g. "Plantae" |
phylum |
string |
✓ | e.g. "Tracheophyta" |
class |
string |
✓ | e.g. "Magnoliopsida" |
order |
string |
✓ | e.g. "Malpighiales" |
family |
string |
✓ | e.g. "Hypericaceae" |
genus |
string |
✓ | e.g. "Hypericum" |
species |
string |
✓ | Specific epithet, e.g. "perforatum" |
subspecies |
string |
Infraspecific rank (trinomial nomenclature) | |
variety |
string |
Infraspecific variety rank | |
cultivar |
string |
Cultivar name | |
authority |
string |
✓ | Taxonomic authority (e.g. "L." for Linnaeus) |
Validated by TaxonomicClassificationSchema (Zod).
BotanicalName#
Captures both the formal binomial name (enforced by regex to require
Genus species capitalization format) and the human-facing vernacular names and
synonyms used across databases:
| Field | Type | Req. | Meaning |
|---|---|---|---|
binomial |
string |
✓ | "Genus species" format |
authority |
string |
✓ | Taxonomic authority |
commonNames |
string[] |
✓ | Vernacular names |
synonyms |
string[] |
✓ | Other accepted scientific names |
Validated by BotanicalNameSchema. binomial must match
/^[A-Z][a-z]+ [a-z]+$/.
DosageGuideline#
Structured dosage data with range bounds and frequency, enabling comparison across traditional, clinical, and pharmacopoeial dose recommendations:
| Field | Type | Req. | Meaning |
|---|---|---|---|
form |
DosageForm |
✓ | Pharmaceutical form |
preparationType |
PreparationType |
✓ | Extraction/preparation method |
minDose |
number |
✓ | Minimum single dose (positive) |
maxDose |
number |
✓ | Maximum single dose (positive) |
unit |
DosageUnit |
✓ | Unit of measurement |
frequency |
number |
✓ | Times per day (integer, 1–12) |
duration |
number |
✓ | Duration in days (integer ≥ 0) |
specialInstructions |
string |
e.g. "Take with food" |
Validated by DosageGuidelineSchema.
CompoundProperties#
Captures the physicochemical descriptors used by drug-likeness filters and ADMET prediction. The Lipinski Ro5 fields are all required; TPSA and rotatable bonds are optional because they may not be available for all natural product structures:
| Field | Type | Req. | Meaning |
|---|---|---|---|
molecularWeight |
number |
✓ | Daltons (positive) |
logP |
number |
✓ | Octanol-water partition coefficient |
hydrogenBondDonors |
number |
✓ | NH/OH groups (integer ≥ 0) |
hydrogenBondAcceptors |
number |
✓ | N/O atoms (integer ≥ 0) |
topologicalPolarSurfaceArea |
number |
TPSA in Ų (positive) | |
rotatableBonds |
number |
Integer ≥ 0 | |
compoundClass |
CompoundClass |
✓ | Classification |
Validated by CompoundPropertiesSchema.
StudyMetadata#
Fields: design (StudyDesign), sampleSize (number), blinding
('none' \| 'single' \| 'double'), allocation
('random' \| 'quasi-random' \| 'non-random'), optional
allocationConcealment, intentionToTreat, attritionRate, effectSize,
confidenceInterval ([number, number]), pValue.
InteractionRecord#
Fields: herb (string), drug (string), mechanism
(InteractionMechanism), severity (InteractionSeverity), evidenceLevel
(EvidenceStrength), description (string), optional cyp450Enzymes
(string[]). This is the shape used by the COMMON_HERB_DRUG_INTERACTIONS
constant and the core interaction helper functions.
3. Core Domain Entities (@airmid/core)#
Defined in libs/airmid/core/src/entities.ts. Each entity is a class wrapping a
Readonly<…Data> raw-data interface, with constructor validation (throws plain
Error on invalid input), computed getters, and a toJSON() serializer. There
are 15 entity classes, each with a matching …Data interface. The computed
getters are where domain logic lives — for example,
ClinicalTrial.evidenceLevel derives an Oxford evidence level from the study
design, blinding, and allocation fields.
3.1 BotanicalSpecies#
Constructed from BotanicalSpeciesData: id (SpeciesId), taxonomy
(TaxonomicClassification), botanicalName (BotanicalName), description,
nativeRegion (string[]), habitat, growthForm, plantPartsUsed
(string[]), iucnStatus (IUCNStatus), citesAppendix (CITESAppendix),
imageUrls (string[]).
Computed: binomialName, fullName, family, isEndangered, isCITESListed,
taxonomicPath, plantPartsUsed. Methods: belongsToFamily(family),
hasMedicinalUse().
3.2 PhytochemicalCompound#
Constructed from PhytochemicalCompoundData: id (CompoundId), name,
iupacName, casNumber, smiles, inchiKey, molecularFormula,
molecularWeight, logP, compoundClass, hydrogenBondDonors,
hydrogenBondAcceptors, rotatableBonds, polarSurfaceArea.
Computed: molecularWeight, isLipinskiCompliant, drugLikenessScore (0–5,
Lipinski Ro5 + Veber rotatable-bond extension), compoundClassDescription,
hasValidCAS, hasValidSMILES, logPCategory. Method: isNaturalProduct().
3.3 ClinicalTrial#
Constructed from ClinicalTrialData: id (TrialId), title, registryId,
studyDesign, phase, population, sampleSize, duration, intervention,
control, primaryOutcome, results, conclusion, blinding, allocation,
attritionRate, effectSize, pValue, confidenceInterval, journal,
publicationDate, doi, speciesId.
Computed: isRCT, evidenceLevel (Oxford level from study design + blinding +
allocation), sampleSizeCategory, hasStatisticalSignificance, qualityScore
(composite 0–100), isBlinded, isRandomized, yearPublished. Method:
meetsInclusionCriteria(minSampleSize, maxPValue).
3.4 EvidenceRecord#
Constructed from EvidenceRecordData: id, speciesId, condition,
indication, gradeQuality, oxfordLevel, evidenceStrength, studyCount,
supportingTrialIds (TrialId[]), summary, recommendation,
lastReviewDate.
Computed: isHighQuality, recommendationStrength, needsMoreResearch,
isOutdated (no review in > 5 years), studyCountCategory. Method:
summarize().
3.5 DrugHerbInteraction#
Constructed from DrugHerbInteractionData: id (InteractionId), speciesId,
drugName, drugClass, severity, mechanism, description,
clinicalEvidence (EvidenceStrength), monitoringRequired,
monitoringParameters (string[]), managementGuideline.
Computed: isContraindicated, requiresMonitoring, affectsCYP450,
clinicalSignificance, safetyMargin. Method: generateClinicalWarning().
3.6 AdverseEvent#
Constructed from AdverseEventData: id (AdverseEventId), speciesId,
reactionType, description, severity
('mild' \| 'moderate' \| 'severe' \| 'fatal'), causalityAssessment,
patientAge, patientSex ('male' \| 'female' \| 'other'), dose,
duration, outcome, concomitantMedications (string[]), reportSource,
reportDate.
Computed: isSeriousEvent, causalityStrength, isExpectedReaction,
requiresReporting, outcomeCategory.
3.7 TraditionalUse#
Constructed from TraditionalUseData: id, speciesId, tradition,
indication, preparation, dosage, plantPart, region,
historicalPeriod, culturalContext, referenceSource.
Computed: tradition, hasScientificValidation (always false — callers must
cross-reference EvidenceRecord), geographicOrigin, historicalDepth,
preparationComplexity.
3.8 PharmacognosyMonograph#
Constructed from MonographData: id (MonographId), speciesId,
pharmacopoeia, monographId, title, qualityMarkers
(QualityMarkerEntry[] — marker, minValue, maxValue, unit),
identityTests (string[]), purityTests (string[]), assayMethod,
storageConditions, shelfLifeMonths, lastRevisionDate.
Computed: pharmacopoeia, qualityMarkerCount, hasAssayMethod,
isCurrentEdition (revised within 10 years), shelfLifeMonths. Method:
meetsQualityStandard(marker, value).
3.9 ProteinTarget#
Constructed from ProteinTargetData: id, uniprotId, name, geneName,
organism, function, subcellularLocation, molecularWeight,
aminoAcidLength, bindingSites (BindingSiteEntry[] — name, residues,
type: 'active_site' \| 'allosteric' \| 'cofactor' \| 'other'),
associatedPathways (string[]), associatedDiseases (string[]),
compoundIds (CompoundId[]), pdbIds (string[]).
Computed: hasValidUniprotId, hasStructuralData, bindingSiteCount,
hasActiveSite, isDrugTarget, sizeCategory, diseaseAssociationCount,
hasAllostericSite.
3.10 BiologicalPathway#
Constructed from BiologicalPathwayData: id (PathwayId), name, keggId,
category, description, organismSpecific, nodeCount, edgeCount,
keyEnzymes (string[]), substrates, products, regulators,
associatedCompoundIds (CompoundId[]), associatedDiseases (string[]).
Computed: hasValidKeggId, complexityCategory, averageConnectivity,
hasCompoundInteractions, isDiseaseAssociated, isOrganismSpecific,
enzymeCount.
3.11 QualityMarker#
Constructed from QualityMarkerData: id, speciesId, compoundId,
markerName, markerType
('active_constituent' \| 'indicator' \| 'adulterant' \| 'contaminant'),
minConcentration, maxConcentration, unit, analyticalMethod,
pharmacopoeiaReference, acceptanceCriteria.
Computed: isActiveConstituent, isAdulterantMarker, isContaminantMarker,
concentrationRange, targetConcentration. Methods:
isWithinSpec(measuredValue), deviationFromTarget(measuredValue).
3.12 DNABarcode#
Constructed from DNABarcodeData: id, speciesId, locus, sequence,
sequenceLength, gcContent (0–1), accessionNumber, primerForward,
primerReverse, referenceDatabase, similarityThreshold (0–1),
authenticates (boolean).
Computed: isStandardLocus (ITS, ITS2, rbcL, matK, trnH-psbA),
gcContentCategory, isValidForAuthentication, sequenceLengthCategory,
hasAccessionNumber. Method: isAboveThreshold(querySimilarity).
3.13 SpectroscopicFingerprint#
Constructed from SpectroscopicFingerprintData: id, speciesId, technique
('HPLC' \| 'HPTLC' \| 'GC-MS' \| 'LC-MS' \| 'NMR' \| 'IR' \| 'UV-Vis' \| 'Raman'),
samplePreparation, instrumentParameters, peakCount, majorPeaks
(SpectroscopicPeak[] — position, intensity, assignment),
referenceStandard, similarityScore (0–1), isAuthentic, rawDataUrl.
Computed: isChromatographic, isSpectroscopic, complexityCategory,
passesAuthentication (similarity ≥ 0.9 and isAuthentic), dominantPeak,
hasRawData.
3.14 FormulationRecipe#
Constructed from FormulationRecipeData: id, name, description, form,
preparationType, ingredients (FormulationIngredient[] — optional
speciesId, name, amount, unit, optional plantPart, role:
'primary' \| 'adjuvant' \| 'corrective' \| 'vehicle' \| 'preservative'),
instructions (string[]), totalVolume, totalVolumeUnit, shelfLifeDays,
storageConditions, indications (string[]), contraindications
(string[]).
Computed: ingredientCount, primaryIngredientCount, isSimple,
hasContraindications, shelfLifeCategory, primaryIngredients,
adjuvantIngredients, complexityCategory, stepCount.
3.15 ConservationStatus#
Constructed from ConservationStatusData: id, speciesId, iucnStatus,
citesAppendix, populationTrend
('increasing' \| 'stable' \| 'decreasing' \| 'unknown'), estimatedPopulation
(number | null), threatFactors (string[]), conservationActions
(string[]), assessmentDate, assessmentAuthority, range (string[]),
protectedAreaCoverage (0–100), sustainableHarvestingPossible (boolean).
Computed: isThreatened, isExtinct, isCITESListed, isPopulationDeclining,
urgencyLevel, canBeSustainablyHarvested, threatCount,
conservationActionCount, hasAdequateProtection.
4. Core Errors (@airmid/core)#
Defined in libs/airmid/core/src/errors.ts. Airmid errors carry structured
metadata beyond a simple message string — severity, a domain-specific error
code, and a freeform details record. This allows callers to handle errors
programmatically (e.g., escalating Fatal severity interactions differently
from Warning severity taxonomy errors).
4.1 AirmidErrorSeverity#
Enum: Info, Warning, Critical, Fatal.
4.2 AirmidErrorCode#
A template-literal union: AIRMID_TAXONOMY_${string},
AIRMID_COMPOUND_${string}, AIRMID_INTERACTION_${string},
AIRMID_EVIDENCE_${string}, AIRMID_DOSAGE_${string},
AIRMID_CONTRAINDICATION_${string}, AIRMID_QUALITY_${string},
AIRMID_REGULATORY_${string}.
4.3 Error Classes#
AirmidError is the base class (Error subclass) carrying code, severity,
details (Record<string, unknown>), timestamp, and a toJSON() returning
SerializedAirmidError. The eight domain-specific subclasses map to the most
clinically significant error categories. Note that ContraindicationError and
DosageExceedanceError default to the highest severities — these represent
patient-safety critical conditions.
| Class | Default code | Default severity |
|---|---|---|
InvalidTaxonomyError |
AIRMID_TAXONOMY_INVALID |
Warning |
CompoundNotFoundError |
AIRMID_COMPOUND_NOT_FOUND |
Warning |
InteractionWarningError |
AIRMID_INTERACTION_WARNING |
Critical/Warning (by interaction severity) |
EvidenceConflictError |
AIRMID_EVIDENCE_CONFLICT |
Info |
DosageExceedanceError |
AIRMID_DOSAGE_EXCEEDED |
Critical |
ContraindicationError |
AIRMID_CONTRAINDICATION_DETECTED |
Fatal |
QualityControlError |
AIRMID_QUALITY_FAILURE |
Critical |
RegulatoryComplianceError |
AIRMID_REGULATORY_VIOLATION |
Critical |
Utilities: isAirmidError(error) (type guard), formatAirmidError(error)
(human-readable string with severity badge).
5. Core Domain Events (@airmid/core)#
Defined in libs/airmid/core/src/events.ts. The AirmidEventType constant
object provides 13 event type strings. There is no event bus in the domain;
createAirmidEvent builds typed event objects and resetEventCounter resets
the in-process ID counter. When the planned Oshun event bus integration is wired
in, these events will flow to other domains without any changes to the event
payloads.
Every event object (AirmidEvent<T>) carries type, payload, timestamp
(ISO 8601), eventId, and source (defaults to 'airmid-core').
| Event constant | Event string | Payload type |
|---|---|---|
SpeciesRegistered |
airmid.species.registered |
SpeciesRegisteredPayload |
SpeciesUpdated |
airmid.species.updated |
SpeciesUpdatedPayload |
CompoundDiscovered |
airmid.compound.discovered |
CompoundDiscoveredPayload |
CompoundLinked |
airmid.compound.linked |
CompoundLinkedPayload |
InteractionIdentified |
airmid.interaction.identified |
InteractionIdentifiedPayload |
InteractionSeverityChanged |
airmid.interaction.severity_changed |
InteractionSeverityChangedPayload |
AdverseEventReported |
airmid.adverse_event.reported |
AdverseEventReportedPayload |
AdverseEventAssessed |
airmid.adverse_event.assessed |
AdverseEventAssessedPayload |
EvidenceAdded |
airmid.evidence.added |
EvidenceAddedPayload |
EvidenceGradeChanged |
airmid.evidence.grade_changed |
EvidenceGradeChangedPayload |
QualityControlFailed |
airmid.quality_control.failed |
QualityControlFailedPayload |
RegulatoryStatusChanged |
airmid.regulatory.status_changed |
RegulatoryStatusChangedPayload |
ConservationStatusChanged |
airmid.conservation.status_changed |
ConservationStatusChangedPayload |
5.1 Payload Shapes#
Each payload carries the minimum fields needed by downstream consumers to act on
the event without querying the database — for example,
InteractionIdentifiedPayload includes both herb and drug names so a
notification service can generate an alert without a separate lookup.
| Payload | Fields |
|---|---|
SpeciesRegisteredPayload |
speciesId, binomial, family, commonNames |
SpeciesUpdatedPayload |
speciesId, binomial, updatedFields |
CompoundDiscoveredPayload |
compoundId, name, compoundClass, optional molecularFormula |
CompoundLinkedPayload |
compoundId, speciesId, plantPart, optional concentrationRange |
InteractionIdentifiedPayload |
interactionId, herb, drug, mechanism, severity |
InteractionSeverityChangedPayload |
interactionId, herb, drug, previousSeverity, newSeverity, reason |
AdverseEventReportedPayload |
adverseEventId, substance, reactionType, description, optional patientAge, patientSex |
AdverseEventAssessedPayload |
adverseEventId, substance, causality, assessedBy |
EvidenceAddedPayload |
trialId, studyDesign, herb, indication, sampleSize, outcome ('positive' | 'negative' | 'neutral') |
EvidenceGradeChangedPayload |
herb, indication, previousGrade, newGrade, previousStrength, newStrength, reason |
QualityControlFailedPayload |
product, testType, issue, optional batchNumber, contaminant |
RegulatoryStatusChangedPayload |
substance, jurisdiction, previousStatus, newStatus, effectiveDate |
ConservationStatusChangedPayload |
speciesId, binomial, previousStatus, newStatus, assessmentYear |
6. Core Constants and Reference Data (@airmid/core)#
Defined in libs/airmid/core/src/constants.ts. These constants are the
hard-coded scientific reference data that does not change frequently and does
not belong in the database — enzyme identifiers, curated short interaction
lists, WHO-recognized herb lists, and pharmacological parameters.
CYP450_ENZYMES— 12 major cytochrome P450 enzyme identifiers (CYP3A4,CYP2D6,CYP2C9,CYP2C19,CYP1A2,CYP2E1,CYP2B6,CYP2A6,CYP2C8,CYP3A5,CYP3A7,CYP2J2).COMMON_HERB_DRUG_INTERACTIONS— curatedInteractionRecord[]covering St. John's Wort, Ginkgo, Panax ginseng, Kava, Valerian, Garlic, Echinacea, Milk thistle, Grapefruit, and Goldenseal.WHO_ESSENTIAL_MEDICINES_HERBS— 25 WHO-recognized medicinal plants, each{ binomial, commonName, primaryUse }.GRADE_QUALITY_FACTORS— five downgrade factors (risk of bias, inconsistency, indirectness, imprecision, publication bias) and three upgrade factors (large effect, plausible confounding, dose-response), each with amaxReduction/maxIncrease.THERAPEUTIC_CATEGORIES— 20 categories (Adaptogen, Analgesic, etc.), each{ category, description, examples }.ELEMENT_SYMBOLS— all 118 periodic-table element symbols, used for molecular-formula validation.BIOAVAILABILITY_ROUTES— five administration routes with typical bioavailability fractions.MEDICINAL_PLANT_FAMILIES— 10 major medicinal plant families with characteristic compounds and example genera.CYP450_COMPOUND_CLASS_PROFILES— maps 11 compound classes to the CYP enzymes each inhibits or induces.
7. Core Validation and Pharmacology Functions#
The following utility modules in @airmid/core provide standalone functions
used throughout the domain. They operate on the plain interfaces and enums from
§2 rather than on entity class instances.
7.1 Validation (libs/airmid/core/src/validation.ts)#
validateCASNumber (check-digit validation), validateTaxonomy,
getRequiredRanksForLevel, validateDosage, validateSMILES,
validateMolecularFormula, validateEvidenceGrade.
7.2 Pharmacology (libs/airmid/core/src/pharmacology.ts)#
calculateBioavailability, estimateHalfLife, classifyDrugLikeness (returns
LipinskiResult), calculateTherapeuticIndex, assessCYP450Risk (returns
CYP450RiskAssessment), calculateDoseEquivalence.
7.3 Taxonomy (libs/airmid/core/src/taxonomy.ts)#
formatBinomial, parseBotanicalName (returns ParsedBotanicalName),
getPlantFamily, validateBinomialNomenclature, buildTaxonomicPath,
getCommonFamilies.
7.4 Evidence (libs/airmid/core/src/evidence.ts)#
gradeEvidence, classifyStudyQuality, calculateEffectSize,
assessPublicationBias, generateEvidenceSummary, isRCTQuality.
7.5 Interactions (libs/airmid/core/src/interactions.ts)#
assessInteractionRisk, getCYP450Profile, checkContraindications,
formatInteractionWarning, rankInteractionsBySeverity,
getMonitoringRecommendation.
8. Database Schema (@airmid/database)#
Located at libs/airmid/database/src. The library exports Zod schema modules
(schema/) and Knex migration functions (migrations/). It does not open
database connections — it provides schema definitions and migration runners that
a consuming application wires to a PostgreSQL connection.
The schema was designed with several production concerns in mind: uuid-ossp
for UUID generation, pg_trgm for full-text trigram search, an
airmid_update_timestamp() trigger for automatic updated_at maintenance,
soft-delete support via deleted_at columns, and 5 materialized views for
commonly aggregated queries that would otherwise require expensive joins.
8.1 Migrations#
Six ordered migration files (timestamp-prefixed 20260318100001–…6). They
must be applied in order — later migrations reference tables and enum types
created by earlier ones.
initial_setup— enables PostgreSQL extensionsuuid-osspandpg_trgm, creates theairmid_update_timestamp()trigger function, and creates 35 custom enum types (growth_form,plant_part,iucn_status,cites_appendix,compound_class,solubility_class,extraction_method,study_design,trial_phase,blinding_type,allocation_type,grade_quality,oxford_level,evidence_strength,interaction_severity,interaction_mechanism,clinical_evidence_level,adverse_reaction_type,adverse_event_severity,causality_assessment,adverse_event_outcome,patient_sex,medical_tradition,pharmacopoeia_source,regulatory_jurisdiction,regulatory_status_value,regulatory_category,marker_region,reference_database,spectroscopic_technique,activity_type,population_trend,harvest_sustainability,cultivation_status,airmid_audit_action).core_tables—botanical_species,phytochemical_compounds,plant_compound_associations,clinical_trials,evidence_records.safety_tables—drug_herb_interactions,adverse_event_reports,traditional_use_records,pharmacopoeia_monographs,regulatory_statuses.genomics_targets—dna_barcodes,spectroscopic_fingerprints,protein_targets,compound_target_associations,biological_pathways,conservation_records,airmid_audit_logs.materialized_views— five materialized views (mv_species_compound_evidence,mv_species_interaction_summary,mv_top_studied_species,mv_evidence_by_condition,mv_compound_activity_summary), each with a unique index, refreshed withREFRESH MATERIALIZED VIEW CONCURRENTLY.soft_delete— addsdeleted_atcolumns, partial indexes, cascade triggers, andsoft_delete/restore/purgehelper functions.
Total: 17 base tables plus 5 materialized views.
8.2 Tables (createTable calls)#
The 17 tables are distributed across three migration files according to their domain grouping:
| Table | Migration |
|---|---|
botanical_species |
core_tables |
phytochemical_compounds |
core_tables |
plant_compound_associations |
core_tables |
clinical_trials |
core_tables |
evidence_records |
core_tables |
drug_herb_interactions |
safety_tables |
adverse_event_reports |
safety_tables |
traditional_use_records |
safety_tables |
pharmacopoeia_monographs |
safety_tables |
regulatory_statuses |
safety_tables |
dna_barcodes |
genomics_targets |
spectroscopic_fingerprints |
genomics_targets |
protein_targets |
genomics_targets |
compound_target_associations |
genomics_targets |
biological_pathways |
genomics_targets |
conservation_records |
genomics_targets |
airmid_audit_logs |
genomics_targets |
8.3 Zod Schema Modules#
schema/index.ts re-exports 15 modules: common, botanical-species,
phytochemicals, plant-compounds, clinical-trials, evidence-records,
drug-interactions, adverse-events, traditional-use, pharmacopoeia,
regulatory, genomics, targets-pathways, conservation, audit.
The common.ts module provides shared building blocks used across all other
schema modules: UuidSchema (UUID v4), TimestampSchema (ISO datetime, with or
without offset), UrlSchema, DoiSchema, CasNumberSchema, InChIKeySchema,
PaginationSchema, SortDirectionSchema, SortSchema,
DateRangeFilterSchema, NumericRangeFilterSchema, JsonValueSchema,
JsonObjectSchema, StringArrayJsonSchema.
Each entity module exports a row schema plus matching …CreateInputSchema
(omits id, createdAt, updatedAt) and …UpdateInputSchema (partial).
Example: BotanicalSpeciesSchema has fields id, binomialName (regex
/^[A-Z][a-z]+ [a-z]+$/), genus, species, subspecies?, authority,
family, commonNames (JSON array), synonyms (JSON array), description,
nativeRegion, habitat, growthForm, plantPartUsed (≥ 1), iucnStatus,
citesAppendix, isEndemic, imageUrls, createdAt, updatedAt.
Note a field naming divergence between the two layers: the database schema uses
singular plantPartUsed and adds isEndemic, while the core
BotanicalSpeciesData entity uses plural plantPartsUsed without isEndemic.
Consuming code must account for this mapping at the persistence boundary.
9. API Layer (@airmid/api)#
Located at libs/airmid/api/src. @airmid/api does not run an HTTP server.
It provides: external bioinformatics database connectors, an ETL pipeline
framework, an OpenAPI 3.1 endpoint specification (as data and a generator),
SMILES/SMARTS cheminformatics utilities, and data-export/reporting functions.
9.1 External Database Connectors#
EXTERNAL_DATABASE_CONFIGS defines 10 external bioinformatics databases,
each with name and baseUrl. The following table shows each database and its
base URL as configured in the library:
| Database | Base URL |
|---|---|
| PubMed/NCBI E-utilities | https://eutils.ncbi.nlm.nih.gov/entrez/eutils/ |
| PubChem PUG REST | https://pubchem.ncbi.nlm.nih.gov/rest/pug/ |
| ChEMBL | https://www.ebi.ac.uk/chembl/api/data/ |
| UniProt | https://rest.uniprot.org/uniprotkb/ |
| STRING | https://string-db.org/api/ |
| KEGG REST | https://rest.kegg.jp/ |
| DrugBank | https://go.drugbank.com/ws/ |
| ClinicalTrials.gov | https://clinicaltrials.gov/api/v2/ |
| WHO VigiBase | https://api.who-umc.org/vigibase/ |
| Natural Medicines Database | https://api.naturalmedicines.therapeuticresearch.com/v1/ |
URL builders cover each database (e.g. buildPubMedSearchURL,
buildPubMedFetchURL, buildPubChemPropertyURL, buildPubChemNameSearchURL,
buildPubChemSMILESSearchURL, buildChEMBLMoleculeURL,
buildChEMBLActivityURL, buildUniProtSearchURL, buildUniProtEntryURL,
buildSTRINGNetworkURL, buildSTRINGPartnersURL, buildSTRINGEnrichmentURL,
buildKEGGFindURL, buildKEGGListURL, buildKEGGLinkURL,
buildKEGGPathwayURL, buildClinicalTrialsSearchURL). Response parsers
(parseNCBIResponse, parsePubMedArticleXML, parsePubChemResponse,
parseChEMBLResponse, parseChEMBLActivities, parseUniProtResponse,
parseSTRINGResponse, parseKEGGResponse, parseKEGGCompoundList) map raw
responses to typed objects. Retry support: calculateExponentialBackoff,
DEFAULT_RETRY_CONFIG, isRetryable, isRateLimitError,
getEffectiveRateLimit (3/s NCBI without key, 10/s with key), plus
validateDatabaseURL and getDatabaseConfig.
9.2 ETL Pipeline Framework#
PIPELINE_DEFINITIONS defines 8 scheduled pipelines (PubMed weekly, PubChem
monthly, ChEMBL monthly, ClinicalTrials.gov weekly, UniProt quarterly, STRING
quarterly, KEGG quarterly, VigiBase monthly). TRANSFORMATION_RULES defines
18 transformation rules (CAS check-digit validation, InChIKey format
validation, SMILES canonicalization, species-name resolution with 40+ mappings,
unit harmonization, cross-reference mapping, deduplication, confidence scoring).
Pipeline functions: createPipeline, runETLExtraction,
runETLTransformation, runETLLoad, updatePipelineStatus,
calculateNextRun, getTransformationRulesForPipeline. Data-integrity helpers:
computeSHA256Hex, trackProvenance, verifyProvenanceChecksum. Normalizers:
normalizeCASNumber, normalizeAuthorName, normalizeOrganism,
resolveSpeciesName, canonicalizeSMILES, convertUnit,
convertToMicromolar, convertToDaltons, validateCASCheckDigit,
validateInChIKey.
9.3 Cheminformatics Utilities#
Two cheminformatics modules handle SMILES and SMARTS processing in TypeScript, without external chemistry tool dependencies:
smiles-canonical.ts exports parseSmiles, canonicalSmiles,
emitCanonicalSmiles, morganCanonicalRanks (plus Atom, Bond, Molecule
types). smarts.ts exports parseSmarts, matchSmarts, smartsMatchesSmiles,
findAllSmartsMatches, countSmartsMatches (plus SmartsAtomQuery,
SmartsBondQuery, SmartsPattern types).
9.4 OpenAPI 3.1 Endpoint Specification#
AIRMID_API_ENDPOINTS is a typed array of 44 OpenAPI 3.1 endpoint
definitions across 12 resource tags. generateOpenAPISpec() assembles a
complete OpenAPI 3.1 document (info, servers, bearerAuth security scheme,
ProblemDetail schema, tags). This is a published specification used by a
consuming application; the library itself does not serve these routes.
Authentication is a JWT Bearer token (bearerAuth security scheme) for all
secured endpoints. All errors follow RFC 7807 (application/problem+json);
standard responses for 400, 401, 403, 404, 429, and 500 are attached to every
secured endpoint.
| Method | Path | operationId | Tags | Auth | Rate-limit tier |
|---|---|---|---|---|---|
GET |
/api/v1/species |
listSpecies |
Species | ✓ | basic |
GET |
/api/v1/species/{id} |
getSpeciesById |
Species | ✓ | basic |
GET |
/api/v1/species/{id}/compounds |
getSpeciesCompounds |
Species,Compounds | ✓ | basic |
GET |
/api/v1/species/{id}/interactions |
getSpeciesInteractions |
Species,Interactions | ✓ | basic |
GET |
/api/v1/species/{id}/evidence |
getSpeciesEvidence |
Species,Evidence | ✓ | basic |
GET |
/api/v1/species/{id}/safety |
getSpeciesSafety |
Species,Safety | ✓ | basic |
GET |
/api/v1/species/search |
searchSpecies |
Species | ✓ | basic |
GET |
/api/v1/compounds |
listCompounds |
Compounds | ✓ | basic |
GET |
/api/v1/compounds/{id} |
getCompoundById |
Compounds | ✓ | basic |
GET |
/api/v1/compounds/{id}/targets |
getCompoundTargets |
Compounds,Targets | ✓ | basic |
GET |
/api/v1/compounds/{id}/admet |
getCompoundADMET |
Compounds | ✓ | pro |
GET |
/api/v1/compounds/search |
searchCompoundsByName |
Compounds | ✓ | basic |
POST |
/api/v1/compounds/structure-search |
searchCompoundsByStructure |
Compounds | ✓ | pro |
POST |
/api/v1/interactions/check |
checkInteractions |
Interactions | ✓ | basic |
GET |
/api/v1/interactions/{id} |
getInteractionById |
Interactions | ✓ | basic |
GET |
/api/v1/interactions |
listInteractions |
Interactions | ✓ | basic |
GET |
/api/v1/evidence |
listEvidence |
Evidence | ✓ | basic |
GET |
/api/v1/evidence/{id} |
getEvidenceById |
Evidence | ✓ | basic |
GET |
/api/v1/evidence/search |
searchEvidence |
Evidence | ✓ | basic |
POST |
/api/v1/safety/assess |
assessSafety |
Safety | ✓ | pro |
GET |
/api/v1/safety/pregnancy/{species} |
getPregnancySafety |
Safety | ✓ | basic |
GET |
/api/v1/safety/contraindications/{species} |
getContraindications |
Safety | ✓ | basic |
GET |
/api/v1/safety/adverse-events |
getAdverseEvents |
Safety | ✓ | pro |
POST |
/api/v1/clinical/cds-hooks |
cdshooksRequest |
Clinical | ✓ | enterprise |
POST |
/api/v1/clinical/interaction-check |
clinicalInteractionCheck |
Clinical | ✓ | pro |
GET |
/api/v1/clinical/patient-education/{species} |
getPatientEducation |
Clinical | ✓ | basic |
GET |
/api/v1/targets |
listTargets |
Targets | ✓ | basic |
GET |
/api/v1/targets/{id} |
getTargetById |
Targets | ✓ | basic |
GET |
/api/v1/targets/{id}/network |
getTargetNetwork |
Targets | ✓ | pro |
GET |
/api/v1/pathways |
listPathways |
Pathways | ✓ | basic |
GET |
/api/v1/pathways/{id} |
getPathwayById |
Pathways | ✓ | basic |
POST |
/api/v1/pathways/enrichment |
analyzePathwayEnrichment |
Pathways | ✓ | pro |
POST |
/api/v1/reports/generate |
generateReport |
Reports | ✓ | pro |
GET |
/api/v1/reports/templates |
listReportTemplates |
Reports | ✓ | basic |
GET |
/api/v1/reports/{id} |
getReportById |
Reports | ✓ | basic |
POST |
/api/v1/export/species |
exportSpecies |
Export | ✓ | pro |
POST |
/api/v1/export/compounds |
exportCompounds |
Export | ✓ | pro |
GET |
/api/v1/export/fair-assessment |
getFAIRAssessment |
Export | ✓ | basic |
POST |
/api/v1/webhooks |
createWebhook |
Webhooks | ✓ | pro |
GET |
/api/v1/webhooks |
listWebhooks |
Webhooks | ✓ | pro |
DELETE |
/api/v1/webhooks/{id} |
deleteWebhook |
Webhooks | ✓ | pro |
GET |
/api/v1/status |
getAPIStatus |
Admin | — | free |
GET |
/api/v1/stats |
getDataStats |
Admin | ✓ | basic |
GET |
/api/v1/rate-limit |
getRateLimitStatus |
Admin | ✓ | free |
9.5 Rate-Limit Tiers#
RATE_LIMIT_TIERS defines 4 tiers. The CDS Hooks endpoint requires
enterprise tier because it is called synchronously from within an EHR workflow
and needs to handle high-frequency clinical traffic.
| Tier | Requests/day | Requests/minute | Burst |
|---|---|---|---|
free |
100 | 10 | 5 |
basic |
1,000 | 60 | 20 |
pro |
10,000 | 300 | 50 |
enterprise |
Number.MAX_SAFE_INTEGER (effectively unlimited) |
1,000 | 200 |
Rate-limit functions: checkRateLimit, getRateLimitTier. Request validation:
validateRequest. RFC 7807 helpers: createProblemDetail,
createValidationError. Cursor pagination (base64-encoded position):
generateCursorPagination, encodeCursor, decodeCursor.
9.6 Webhooks and API Documentation#
api-documentation.ts exports WEBHOOK_SPECIFICATIONS (12 webhook event types
— species.updated, species.created, compound.added, compound.updated,
interaction.discovered, interaction.updated, evidence.published,
evidence.retracted, safety.alert, pipeline.completed, pipeline.failed,
report.generated), getWebhookSpec, generateWebhookPayload,
verifyWebhookSignature (HMAC-SHA256), computeHMACSHA256, plus
generateTypeScriptClient, generateCodeExample, generateAllCodeExamples.
9.7 Data Export and Reporting#
data-export.ts exports exportToJSON, exportToCSV (RFC 4180),
exportToXML, exportToRDFTurtle (linked data), exportToSDF (cheminformatics
Structure-Data File), escapeCSVField, escapeXML. Reporting:
REPORT_TEMPLATES (6 templates), listReportTemplates, generateReport.
Open-data assessment: assessFAIRCompliance (Findable, Accessible,
Interoperable, Reusable scoring).
10. Scientific Library Surface#
The remaining scientific libraries each expose a typed module surface through
src/index.ts. Rather than duplicating all field-level detail here (consult the
library source for exhaustive types), this section documents the headline data
magnitudes and key function names that define each library's public contract.
| Library | Headline implemented surface |
|---|---|
@airmid/phytochem |
NATURAL_PRODUCTS_DATABASE — 55 curated compound entries; molecular property calculation (logP, TPSA, QED, Fsp3); drug-likeness (Lipinski, Veber, Ghose, Egan, Muegge); ADMET prediction; toxicity prediction (Ames, hERG, hepatotoxicity, LD50, GHS); 3D structure; metabolite prediction |
@airmid/evidence |
Trial integration, createSystematicReview/performMetaAnalysis, ROB2_DOMAINS (Cochrane RoB 2.0), GRADE grading (computeGRADECertainty, GRADE_FACTORS), forest plot data, publication-quality scoring, evidence search |
@airmid/interactions |
HERB_DRUG_INTERACTION_DATABASE — 80+ herb-drug interaction entries; CYP450 profiling; transporter interactions; pharmacodynamic interaction analysis; checkInteractions, predictInhibitionMagnitude, generatePatientCounseling |
@airmid/safety |
WHO-UMC causality, Naranjo ADR, RUCAM hepatotoxicity, Hy's Law, DILI pattern; nephrotoxicity; special-population safety (pregnancy 40+, pediatric 20+, geriatric 15+ herbs); 30+ toxic compounds; contamination assessment |
@airmid/precision |
CPIC CYP450 allele databases (9 genes); Activity Score; GENOTYPE_RESPONSE_DATABASE — 48 herb-gene-phenotype entries; 30 microbiome-herb interaction entries; 30+ biomarkers; personalized recommendation engine |
@airmid/docking |
AutoDock Vina scoring, protein preparation, binding-site detection, virtual screening, PAINS filtering, QSAR, inverse docking, molecular dynamics specification and trajectory analysis |
@airmid/network |
Target identification, PPI networks (STRING), network topology metrics, KEGG pathway enrichment, GO analysis, multi-layer network integration, synergy/disease-module mapping |
@airmid/formulation |
Synergy analysis (Chou-Talalay, Bliss, Loewe, HSA), antagonism detection, extraction optimization, stability/shelf-life prediction, bioavailability enhancement |
@airmid/microbiome |
Prebiotic-effect database, microbial metabolite production, dysbiosis-correction protocols, herb-metabolism modeling, clinical integration |
@airmid/quality |
DNA barcoding (dna-barcoding-data reference set), spectroscopic fingerprinting, chromatographic profiling, chemometrics, marker-compound quantification, adulteration detection |
@airmid/regulatory |
Pharmacopoeia compliance (USP, EP, BP, JP, CP, IP), EMA/HMPC monograph system, FDA/DSHEA, global jurisdiction status, labeling and claims classification |
@airmid/sustainability |
IUCN conservation status, sustainable sourcing, cultivation alternatives, environmental impact (LCA-style), at-risk species substitution engine |
@airmid/ml |
Biomedical NLP, ADMET filtering, graph neural networks, molecular transformers, generative models, fragment database, molecular editor, explainable AI, advanced learning |
@airmid/vision |
Leaf analysis, flower analysis, bark analysis, climate model, geographic filter, multi-organ species matcher |
@airmid/clinical |
FHIR integration, interaction alerts, evidence summaries, patient education, audit/compliance |
@airmid/ethno |
Traditional medicine databases, indigenous knowledge, preparation methods, formulation principles, scientific validation |
Each library's types.ts defines its own domain types, unions, and Zod schemas;
those types are not duplicated here — consult the library source for exhaustive
field-level detail.
11. Configuration#
Airmid libraries are configured through their callers. There is no .env file
or environment-variable loader inside libs/airmid/. Configuration that is
expressed in code:
- External database base URLs and rate limits —
EXTERNAL_DATABASE_CONFIGSin@airmid/api(the NCBI E-utilities client distinguishes a 3/s unkeyed rate limit from a 10/s keyed rate limit viagetEffectiveRateLimit). - ETL pipeline schedules —
PIPELINE_DEFINITIONSin@airmid/api. - API rate-limit tiers —
RATE_LIMIT_TIERSin@airmid/api. - OpenAPI servers —
generateOpenAPISpec()lists production, staging, and local-development server URLs. - Database connection —
@airmid/databaseprovides Knex migrations and Zod schemas only; the connection string is supplied by the migration runner / consuming application.
12. Technology Stack and Build#
| Layer | Technology |
|---|---|
| Language | TypeScript (Node.js, ESM — type: module) |
| Validation | Zod (catalog dependency in every package) |
| Database | PostgreSQL via Knex.js (@airmid/database) |
| UUIDs | uuid (dev dependency of @airmid/database) |
| Build | Nx @nx/js:tsc |
| Test | Vitest (@nx/vite:test) |
| Tags | scope:airmid, layer:domain, type:lib |
Cheminformatics algorithms (SMILES canonicalization, SMARTS substructure matching, AutoDock Vina scoring, Needleman-Wunsch alignment, molecular property formulas) are implemented in TypeScript; there is no Python subprocess or RDKit dependency in the current code.
When Nx is unavailable (for example, due to duplicate project detection from worktrees), use these direct invocations:
# Type check a library
cd libs/airmid/<library> && npx tsc --noEmit
# Run a library's tests
cd libs/airmid/<library> && npx vitest run
# Run all airmid tests
npx vitest run libs/airmid/
13. Acceptance Criteria#
The following criteria must all pass. They are phrased as observable test outcomes rather than code assertions, so they can be evaluated against any test runner output.
- All 19 libraries type-check (
npx tsc --noEmit) and pass their Vitest suites. - Branded ID schemas reject non-UUID strings;
CAS_NUMBER_PATTERNandINCHI_KEY_PATTERNreject malformed identifiers. - Entity constructors throw on missing required fields and on out-of-range
numeric inputs (e.g.
pValueoutside 0–1,gcContentoutside 0–1). - Domain-correctness tests assert known literature values (e.g. compound molecular weights, established herb-drug interaction severities) rather than shape-only assertions.
- Contraindicated interactions are never downgraded by clinical-decision logic.
- The 6 database migrations apply in order and create the 17 base tables, 5 materialized views, and 35 enum types described in §8.
generateOpenAPISpec()produces a valid OpenAPI 3.1 document covering all 44 endpoints in §9.4.