Healthcare scheduling and medication reminder system
npm install @aleonnet/healthcare-schedulerProduction-ready healthcare scheduling library for medication reminders, appointments, and health-related notifications with OS-level integration.
onConflict: 'user_id,id'docs/SUPABASE_MIGRATION_MULTI_TENANT.sqlSUPABASE_TEST=1 npm run test:supabase- ๐
Flexible Scheduling: 6 schedule types (TIMES, WEEKLY, INTERVAL, CYCLIC, DAYS_INTERVAL, PARTS_OF_DAY)
- ๐ OS Notifications: Native notification scheduling with automatic reconciliation
- ๐พ Offline-First: SQLite local storage
- ๐ Adherence Tracking: Materialized daily adherence metrics
- ๐ฎ Gamification: Streak calculation and level progression
- ๐ Extensible: Event-driven plugin system
- ๐งช Test Coverage: Comprehensive validation suite
``bash`
npm install @healthcare-schedulerPeer dependency (if using React Native)
npm install expo-sqlite
`typescript
import { HealthcareScheduler, MockAdapter, MockNotificationAdapter } from '@healthcare-scheduler';
const scheduler = new HealthcareScheduler({
storage: new MockAdapter(), // or SQLiteAdapter for production
notificationDriver: new MockNotificationAdapter(), // or NotifeeAdapter (see below)
windowDays: 14,
maxPendingNotifications: 45,
enableGrouping: false
});
await scheduler.bootstrap();
// Create medication plan
const planId = await scheduler.createPlan({
item: {
type: 'MED',
name: 'Losartana 50mg',
meta: { concentration: '50mg' }
},
schedule: {
kind: 'TIMES',
times: ['08:00', '20:00']
},
startsAt: new Date().toISOString()
});
// Get today's medication schedule
const today = await scheduler.getTodayOccurrences();
// Record medication taken
await scheduler.recordEvent(occurrenceId, 'TAKEN', { source: 'user' });
`
typescript
{ kind: 'TIMES', times: ['08:00', '14:00', '20:00'] }
`$3
`typescript
{
kind: 'WEEKLY',
lines: [
{ id: '1', daysOfWeek: [1,2,3,4,5], time: '08:00', qty: 1 }
]
}
`$3
`typescript
{
kind: 'INTERVAL',
intervalH: 8,
firstDoseAt: '2025-01-01T08:00:00.000Z'
}
`$3
`typescript
{
kind: 'CYCLIC',
takeDays: 21,
pauseDays: 7,
times: ['21:00'],
cycleAnchorISO: '2025-01-01T00:00:00.000Z'
}
`$3
`typescript
{
kind: 'DAYS_INTERVAL',
daysInterval: 7,
times: ['09:00'],
anchorDateISO: '2025-01-01T00:00:00.000Z'
}
`$3
`typescript
{
kind: 'PARTS_OF_DAY',
parts: [
{ code: 'morning', label: 'Manhรฃ', time: '08:00', qty: 1 },
{ code: 'night', label: 'Noite', time: '21:00', qty: 1 }
]
}
`Gamification Plugin
`typescript
import { GamificationPlugin } from '@healthcare-scheduler';const config = {
levels: [
{ id: 'novice', name: 'Novato', range: [0, 6], tolerance: 0 },
{ id: 'bronze', name: 'Bronze', range: [7, 13], tolerance: 1 },
{ id: 'silver', name: 'Prata', range: [14, 29], tolerance: 2 },
{ id: 'gold', name: 'Ouro', range: [30, 59], tolerance: 3 },
{ id: 'diamond', name: 'Diamante',range: [60, 9999], tolerance: 4 },
],
rules: [],
streakThresholdPercent: 80,
recomputeWindowDays: 30,
streakCalculationWindowDays: 90,
streakFallbackMode: 'fallback', // 'fallback' | 'reset'
};
scheduler.registerPlugin(new GamificationPlugin(config));
await scheduler.bootstrap();
// Get current level and streak
const plugin = scheduler.getPlugin('gamification');
const levels = await plugin.getCurrentLevelsState();
// => { streak: 5, levelId: 'bronze', levelName: 'Bronze', progress: 0.4, ... }
// Get daily adherence
const adherence = await plugin.getDayAdherence(new Date());
// => { date: '2025-10-11', total: 4, done: 3, pending: 1, percent: 75 }
`$3
Levels have
tolerance (grace period) for missed days:
- Within tolerance: Streak freezes, level preserved
- Exceeds tolerance (streakFallbackMode):
- 'fallback': Streak falls to min of previous level (gradual)
- 'reset': Streak falls to 0 (original behavior)Production Usage with NotifeeAdapter
For React Native production apps, use
NotifeeAdapter with Platform information:`typescript
import { Platform } from 'react-native';
import {
HealthcareScheduler,
SQLiteAdapter,
NotifeeAdapter,
GamificationPlugin
} from '@healthcare-scheduler';// Initialize storage
const storage = await SQLiteAdapter.connect({
dbName: 'healthcare.db',
autoApplySchema: true
});
// Initialize notifications with Platform info
const notificationDriver = new NotifeeAdapter({
platform: Platform // Required for Android/iOS specific behavior
});
// Create scheduler
const scheduler = new HealthcareScheduler({
storage,
notificationDriver,
windowDays: 14,
maxPendingNotifications: 45
});
// Register plugins
scheduler.registerPlugin(new GamificationPlugin());
// Bootstrap
await scheduler.bootstrap();
`Note:
NotifeeAdapter requires platform to be passed to avoid dynamic imports of react-native, ensuring compatibility with React Native's New Architecture and preventing deprecated API warnings.Handling Significant Time/Timezone Changes (DST, travel)
When the device timezone/offset changes, OS timestamp-based triggers fire at the same absolute epoch, which may shift local times. To guarantee exact local times, re-build the window and re-schedule notifications:
`typescript
// iOS: observe UIApplicationSignificantTimeChange
// Android: observe ACTION_TIMEZONE_CHANGED / ACTION_TIME_CHANGED
await scheduler.handleSignificantTimeChange({ horizonDays: 2 });
`What it does:
- Rebuilds the local window using current timezone.
- Cancels all scheduled notifications.
- Reconciles with the OS scheduling upcoming items again, including a 1-day past check to clean border cases.
References:
- Apple UIApplication.significantTimeChangeNotification โ https://developer.apple.com/documentation/uikit/uiapplication/1622943-significanttimechangenotification
- Android ACTION_TIMEZONE_CHANGED / ACTION_TIME_CHANGED โ https://developer.android.com/reference/android/content/Intent#ACTION_TIMEZONE_CHANGED
- Notifee timestamp triggers โ https://notifee.app/react-native/docs/trigger-notifications#timestamp-trigger
Architecture
`
src/
โโโ core/ # Main API, EventBus, types
โโโ database/ # Storage abstraction, repositories
โ โโโ repositories/ # ItemsRepo, PlansRepo, OccurrencesRepo, EventsRepo
โ โโโ adapters/ # MockAdapter, SQLiteAdapter (peer dep)
โโโ planning/ # Schedule expansion engine
โโโ reconciler/ # DB โ OS notification sync
โโโ notifications/ # Notification driver abstraction
โโโ plugins/ # Extensible plugin system
โ โโโ gamification/ # Adherence tracking & levels
โโโ utils/ # Queue, timezone helpers
`Events
`typescript
scheduler.on('plans:changed', ({ planIds }) => {
console.log('Plans updated:', planIds);
});scheduler.on('occurrences:changed', ({ occurrenceIds }) => {
console.log('Occurrences changed:', occurrenceIds);
});
scheduler.on('window:filled', ({ count }) => {
console.log('Notifications scheduled:', count);
});
`Note:
- Window fill and reconciliation are asynchronous and triggered by events (
plans:changed, occurrences:changed). Wait for window:filled in tests or after batch operations; there is no public updateWindow method.Development
`bash
Install
npm installRun tests
npm testRun specific test suite
npm test -- tests/validation/scenarios/scenario1_weekly.test.tsBuild
npm run buildLint
npm run lint
``The library includes comprehensive validation:
- Unit tests: Planning engine, repositories, window scheduler
- Integration tests: Full CRUD cycles
- Validation scenarios: 6 real-world medication schedules
- Plugin tests: Gamification, streak calculation
All tests run in-memory using MockAdapter (no database required).
- Implementation Plan
- Executive Summary
- Developer Guide
MIT
Alessandro Barbosa.
Built with TypeScript, tested with Jest, validated against real-world use cases.