6 KiB
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
MedicineMongoDB schema and full CRUD API- Full-text search with filters
- Barcode lookup (future: integration with drug database APIs)
- Bulk import (CSV/JSON)
- 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 payloadUpdateMedicineSchema— partial, validates update payloadMedicineQuerySchema— validates query params
1.2 — Mongoose Schema & Repository
packages/api/src/modules/medicines/medicines.repository.tsMedicinesRepositorywith:findByHousehold(householdId, query)— supports text search, filters, cursor paginationfindByBarcode(householdId, barcode)findById(id, householdId)create(data)update(id, householdId, data)softDelete(id, householdId)bulkCreate(items[])
1.3 — Service & Routes
MedicinesServicewith business logic (dedup check on create, validation)MedicinesRouteswith 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/importaccepts 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
/medicinespage:- 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.