အသုံးပြုသူ လက်စွဲစာအုပ်

Medaius ဆေးခန်းစနစ်အတွက် လမ်းညွှန်ချက်များနှင့် အကူအညီများ

Notification & Activity Domain - Workflow Narrative

A conversational guide to understanding event tracking and notifications


What is the Notification & Activity Domain?

This domain is the nervous system of the EMR. When things happen in the system - a patient is registered, an appointment is booked, a lab result arrives - events are created and potentially trigger notifications.

It serves two purposes. First, it provides an activity feed where users can see what's been happening. Second, it delivers real-time notifications via push to keep users informed of important updates.


Activity Events

What is an Activity Event?

An activity event is a record of something that happened. Think of it as a log entry with rich metadata. Each event captures:

  • event_type - What happened (PATIENT_CREATED, APPOINTMENT_SCHEDULED, etc.)
  • priority - How important (low, normal, high, urgent)
  • title - Human-readable summary
  • description - Additional details
  • actor_user_id - Who performed the action
  • organization_id - Which organization
  • patient_id - Which patient (if applicable)
  • resource_type - Type of affected resource
  • resource_id - ID of affected resource
  • encounter_id - Which encounter (if applicable)
  • notify - Should this trigger notifications?

Event Types

The system defines many event types, organized by domain:

Patient events: PATIENT_CREATED, PATIENT_UPDATED Encounter events: ENCOUNTER_CREATED, ENCOUNTER_SIGNED Appointment events: APPOINTMENT_SCHEDULED, APPOINTMENT_CANCELLED Clinical events: MEDICATION_PRESCRIBED, LAB_RESULT_RECEIVED Administrative events: USER_INVITED, ROLE_ASSIGNED

Each event type has a default priority and visibility setting.


Creating Activity Events

The Creation Pattern

Throughout the codebase, you'll see services creating activity events after significant operations. The pattern looks like this:

self._create_activity_event_async(
    event_type=EventType.ENCOUNTER_CREATED,
    priority=EventPriority.NORMAL,
    patient_id=patient_id,
    organization_id=organization_id,
    actor_user_id=created_by_user,
    title=f"New encounter created for {patient_name}",
    description="Progress note - Follow-up visit",
    resource_id=encounter.id,
    notify=True
)

Background Thread Execution

Notice "async" in the method name. Activity events are created in background threads so they don't slow down the main API response. The patient creation returns immediately while the event gets recorded asynchronously.

Separate Database Session

The background event creation uses its own database session. This prevents issues if the main transaction rolls back but the event was already committed (or vice versa).


The Activity Feed

What Users See

The activity feed is a timeline of what's happened. Users see events relevant to their role and accessible patients.

When a practitioner opens their dashboard, they might see:

  • "New patient registered: John Smith" (5 minutes ago)
  • "Appointment scheduled for Jane Doe" (1 hour ago)
  • "Lab results received for Mike Johnson" (2 hours ago)

Role-Based Filtering

Not everyone sees everything. Events have visibility rules based on roles:

  • Some events are visible to all organization members
  • Some are visible only to clinical staff
  • Some are visible only to the actor and supervisors

The ActivityEventService.get_activity_feed() method takes user_roles and filters appropriately.

Patient-Specific Timeline

When viewing a specific patient, get_patient_timeline() returns only events for that patient. This is useful on patient charts showing their interaction history.


Notification Flow

From Event to Push Notification

Not all events become notifications. The notify flag determines this. When an event is created with notify=True, it enters the notification pipeline.

The NotificationRulesService takes over:

  1. Get Pending Events - Find events where notify=True but notification_sent_at is null
  2. Determine Recipients - Who should be notified?
  3. Check Preferences - Does each recipient want this notification type?
  4. Check Quiet Hours - Is it an appropriate time to notify?
  5. Send Push - Deliver via Firebase Cloud Messaging
  6. Mark Sent - Update the event with notification_sent_at

Who Gets Notified?

The recipient logic varies by event type:

Practitioner-only events (appointments): Only the assigned practitioner is notified. If Dr. Smith has a new appointment, only Dr. Smith gets the push.

Care team events (clinical changes): All active care team members for the patient are notified. If a lab result arrives, everyone caring for that patient might need to know.

Organization-wide events (urgent announcements): All active users in the organization receive the notification.

Actor exclusion: The person who caused the event typically doesn't get notified. You don't need a push telling you about the appointment you just scheduled.


User Notification Preferences

Preference Settings

Each user can configure their notification preferences:

  • push_enabled - Master switch for push notifications
  • email_enabled - Whether to receive email notifications
  • enabled_types - List of event types they want notifications for
  • quiet_hours_start/end - When to suppress notifications

The Defaults

New users get sensible defaults:

  • Push enabled for high/urgent priority events
  • Common clinical event types enabled
  • Quiet hours disabled

Preference Updates

The update_preferences() method allows users to customize. They might disable appointment notifications if they prefer to check their schedule manually.


Quiet Hours

What They Are

Quiet hours are a courtesy feature. Healthcare workers are often on-call but don't want non-urgent notifications at 2 AM.

When quiet hours are configured (say, 10 PM to 7 AM), low and normal priority notifications are held until quiet hours end. High and urgent notifications still come through immediately.

Time Zone Consideration

Currently, quiet hours are specified in UTC. The system checks the current UTC time against the configured window. Future enhancement might add user-specific timezone support.


Push Notification Delivery

Firebase Cloud Messaging

The actual notification delivery uses Firebase Cloud Messaging (FCM). The FCMService handles:

  • Formatting the notification payload
  • Sending to registered device tokens
  • Handling delivery failures

Device Tokens

Users register their devices by providing FCM tokens. Each device (phone, browser) gets its own token. A single user might have multiple tokens for different devices.

Token Management

Tokens can become stale. The system handles:

  • Refreshing tokens when devices re-register
  • Removing tokens that consistently fail
  • Preferring the most recently used token to avoid duplicates

User Notifications (Persistence)

Beyond Push

Push notifications are immediate but ephemeral. If you miss the push, it's gone. The system also persists notifications to a UserNotification table.

This powers the notification bell in the UI. Users can see their recent notifications, mark them as read, and take action on them.

Notification Properties

  • user_id - Who this notification is for
  • event_id - Link to the source activity event
  • is_read - Has the user seen it?
  • read_at - When was it marked read?
  • resource_type/id - What to navigate to when clicked

Unread Count

The notification bell shows an unread count. This is a simple query: count notifications where user_id matches and is_read is false.


Sending Notifications for Events

The Complete Flow

Here's the full flow when an appointment is created:

  1. AppointmentService.create_appointment() creates the appointment
  2. It calls _create_activity_event_async() with notify=True
  3. Background thread creates the ActivityEvent in the database
  4. Notification processor picks up events with notify=True
  5. NotificationRulesService.get_users_to_notify() finds the practitioner
  6. should_notify_user() checks if they want appointment notifications
  7. FCMService.send_notification() delivers the push
  8. mark_notification_sent() updates the event
  9. UserNotification record is created for in-app history

Processing Pending Notifications

A background job runs periodically to process notifications. process_pending_notifications() handles events that have notify=True but haven't been sent yet.

This ensures notifications aren't lost even if the background thread failed initially.


Urgent Announcements

Special Case: Organization Broadcasts

Urgent announcements bypass normal targeting. When an admin posts an urgent announcement, everyone in the organization gets notified immediately regardless of their normal preferences.

The event type ANNOUNCEMENT_URGENT has special handling in the notification rules. It targets all organization users and respects only the master push_enabled switch.


Performance Considerations

Event Feed Queries

Activity feeds can grow large. The system uses:

  • Pagination (skip/limit parameters)
  • Index on organization_id and created_at
  • Optional date filters to limit scope

Notification Processing

The notification processor handles events in batches to avoid overwhelming FCM. It also tracks failures to prevent infinite retry loops.


Key Takeaways

  1. Events are the source - activity events record what happened

  2. notify flag triggers delivery - not all events become notifications

  3. Recipients vary by event type - practitioner, care team, or org-wide

  4. Preferences give control - users configure what they receive

  5. Quiet hours suppress non-urgent - respect for off-hours

  6. FCM delivers push - Firebase handles the actual delivery

  7. Persistence enables history - notifications are also stored in database


Next: Read about the AI Domain to understand clinical intelligence features