Date: April 7, 2026 Current Phase: Phase 8 (Testing & Bug Fixes) — Continued Previous Log: Day 10 (Weekly schedule fix, history date detail, history sync)


✅ This Session Progress

Task Description Status
FCM integration Firebase Admin SDK setup and FCM send implementation ✅ Done
Foreground push notification Receive FCM and display local notification with action buttons ✅ Done
Background push notification Background isolate handler with local notification + action buttons ✅ Done
Notification action buttons Taken ✓ / Skip ✗ buttons trigger API and update UI ✅ Done
Undo dose feature DELETE /dose/undo endpoint + frontend integration ✅ Done
Medication edit cycle fix cycleType now parsed from active schedule only ✅ Done
Inactive schedule cleanup Hard delete schedules with no dose_logs references ✅ Done
DB cleanup Removed test medications and data ✅ Done

1. FCM Integration

Firebase Admin SDK Setup

Added firebase-admin to backend and initialized with service account credentials:

if not firebase_admin._apps:
    cred = credentials.Certificate(settings.FIREBASE_CREDENTIALS_PATH)
    firebase_admin.initialize_app(cred)

Used pathlib + .env for credential path management to avoid hardcoded absolute paths.

Backend _send_fcm() Implementation

Sends data-only FCM messages so Flutter handles notification display with action buttons:

message = messaging.Message(
    data={
        'schedule_id': schedule_id,
        'log_date': datetime.now(timezone.utc).strftime('%Y-%m-%d'),
        'medication_name': medication_name,
        'type': 'medication_reminder',
    },
    android=messaging.AndroidConfig(priority='high'),
    token=token,
)

Key decision: data-only (no notification field) so Android does not auto-display a system notification, allowing Flutter to show a custom local notification with action buttons instead.


2. Foreground Push Notification

FcmService._handleForegroundMessage converts incoming FCM data into a local notification with Taken ✓ / Skip ✗ buttons:

static Future<void> _handleForegroundMessage(RemoteMessage message) async {
  await _showNotificationFromData(
    _localNotifications,
    message.data,
    message.hashCode,
  );
}

Extracted _showNotificationFromData as a shared helper used by both foreground and background handlers to avoid duplication.