MeshiTrack/docs/phases/phase-1-medicine-library.md

6 KiB

Phase 1 — Medicine Library

Goal: A searchable catalog of medicines with dosage and form information. Medicines are the atomic building blocks for regimens, cabinet inventory, and refill tracking.

Depends on: Phase 0 (auth, households, shared types)


Deliverables

  1. Medicine MongoDB schema and full CRUD API
  2. Full-text search with filters
  3. Barcode lookup (future: integration with drug database APIs)
  4. Bulk import (CSV/JSON)
  5. Medicine library web UI (search, add, edit)

Data Model

Medicine Schema

// packages/shared/src/types/medicine.ts
export interface Medicine {
  id: string;
  householdId: string;
  name: string;
  genericName?: string;
  brand?: string;
  barcode?: string;
  form: MedicineForm;
  strength: number;
  strengthUnit: StrengthUnit;
  category: MedicineCategory;
  activeIngredient?: string;
  manufacturer?: string;
  notes?: string;
  imageUrl?: string;
  tags: string[];
  source: MedicineSource;
  createdBy: string;
  createdAt: Date;
  updatedAt: Date;
}

export enum MedicineForm {
  TABLET = 'tablet',
  CAPSULE = 'capsule',
  LIQUID = 'liquid',
  CREAM = 'cream',
  INJECTION = 'injection',
  INHALER = 'inhaler',
  PATCH = 'patch',
  DROPS = 'drops',
  POWDER = 'powder',
  SUPPOSITORY = 'suppository',
  OTHER = 'other',
}

export enum StrengthUnit {
  MG = 'mg',
  MCG = 'mcg',
  G = 'g',
  ML = 'ml',
  IU = 'IU',
  PERCENT = '%',
  OTHER = 'other',
}

export enum MedicineCategory {
  PRESCRIPTION = 'prescription',
  OTC = 'otc',
  SUPPLEMENT = 'supplement',
  VITAMIN = 'vitamin',
  HERBAL = 'herbal',
  OTHER = 'other',
}

export enum MedicineSource {
  MANUAL = 'manual',
  BARCODE_LOOKUP = 'barcode_lookup',
  IMPORT = 'import',
}

MongoDB Indexes

// Text index for search
{ name: 'text', genericName: 'text', brand: 'text', activeIngredient: 'text', tags: 'text' }

// Compound indexes
{ householdId: 1, category: 1 }
{ householdId: 1, barcode: 1 }                    // unique within household
{ householdId: 1, name: 1, strength: 1, form: 1 } // near-unique for dedup

API Endpoints

MedicinesModule

Method Path Description Auth
GET /medicines List/search medicines (paginated) member
GET /medicines/:id Get single medicine member
POST /medicines Create medicine member
PATCH /medicines/:id Update medicine member
DELETE /medicines/:id Soft-delete medicine admin
GET /medicines/barcode/:code Lookup by barcode member
POST /medicines/import Bulk import from CSV/JSON admin

Query Parameters for GET /medicines

?q=metformin                  # Full-text search
&category=prescription        # Filter by category
&form=tablet                  # Filter by form
&tags=daily,morning           # Filter by tags (AND)
&cursor=abc123                # Cursor-based pagination
&limit=20                     # Page size (max 100)
&sort=name|-updatedAt         # Sort field, prefix - for desc

Response Shape

interface PaginatedResponse<T> {
  data: T[];
  pagination: {
    cursor: string | null; // null = last page
    hasMore: boolean;
    total: number;
  };
}

Tasks

1.1 — Shared Types & Validation

  • Add all types above to packages/shared/src/types/medicine.ts
  • Add enums to packages/shared/src/enums/
  • Create Zod schemas:
    • CreateMedicineSchema — validates create payload
    • UpdateMedicineSchema — partial, validates update payload
    • MedicineQuerySchema — validates query params

1.2 — Mongoose Schema & Repository

  • packages/api/src/modules/medicines/medicines.repository.ts
  • MedicinesRepository with:
    • findByHousehold(householdId, query) — supports text search, filters, cursor pagination
    • findByBarcode(householdId, barcode)
    • findById(id, householdId)
    • create(data)
    • update(id, householdId, data)
    • softDelete(id, householdId)
    • bulkCreate(items[])

1.3 — Service & Routes

  • MedicinesService with business logic (dedup check on create, validation)
  • MedicinesRoutes with Fastify route plugin registering all endpoints
  • Register Awilix dependencies via fp() plugin

1.4 — Barcode Lookup

  • BarcodeLookupService:
    • First check local DB for matching barcode
    • Placeholder for external drug database API integration (manual entry fallback)
    • Cache results in local DB with source: 'barcode_lookup'

1.5 — Import Endpoint

  • POST /medicines/import accepts multipart CSV or JSON file
  • Validate each row against CreateMedicineSchema
  • Return summary: { imported: N, skipped: M, errors: [...] }
  • CSV column mapping: name, genericName, brand, barcode, form, strength, strengthUnit, category, activeIngredient, manufacturer

1.6 — Web UI: Medicine Library

  • /medicines page:
    • Search bar with debounced full-text search
    • Category and form filter dropdowns
    • Tag filter chips
    • Medicine grid/list view (toggle)
    • Each medicine card shows: name, strength + unit, form, brand, category badge
  • Add/Edit medicine modal:
    • Form fields for all medicine properties
    • Barcode field with "Lookup" button
  • Import dialog: file upload with preview and error display

Acceptance Criteria

  • Can create, read, update, delete medicines via API
  • Full-text search returns relevant results
  • Barcode lookup checks local DB first
  • Bulk import processes a CSV with 100+ medicines
  • Web UI allows searching, filtering, adding, and editing medicines
  • All medicine queries are scoped to householdId
  • Dedup check prevents creating duplicate medicines (same name + strength + form)

Estimated Effort

Medium. Straightforward CRUD with search, following the same patterns established in Phase 0.