# 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 ```typescript // 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 ```javascript // 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 ```typescript interface PaginatedResponse { 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.