Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/diegolozadev/DataMed/llms.txt

Use this file to discover all available pages before exploring further.

Overview

The DataMed dashboard provides a centralized view of program health with real-time statistics, patient engagement alerts, and capita cycle distribution analytics. It serves as the command center for clinical operations.
The dashboard focuses exclusively on active patients (estado=‘ACTIVO’) to provide actionable insights for current operations.

Accessing the Dashboard

1

Login

Navigate to the DataMed application and log in with your credentials
2

Dashboard Landing

The dashboard is typically the default landing page after login, or access it via HomeDashboard in the navigation
3

Real-Time Data

All dashboard statistics are calculated in real-time on page load, ensuring current information

Key Statistics

The dashboard displays three primary metrics at the top:

Total Active Patients

Count of patients with ACTIVO admission statusUpdated in real-time from database query

Most Recent Admission

Latest patient to join the programShows name and admission date

Patients Needing Follow-Up

Count of patients without contact in 15+ daysCritical attention indicator

Statistics Calculation

# From dashboard/views.py:11-24
@login_required
def dashboard(request):
    hoy = timezone.now().date()
    limite = hoy - timezone.timedelta(days=15)
    
    # 1. Total active patients
    patients = Patient.objects.filter(
        ingresos__estado='ACTIVO'
    ).distinct().count()
    
    # 2. Most recent admission
    last_enter = Patient.objects.filter(
        ingresos__estado='ACTIVO'
    ).select_related().order_by(
        '-ingresos__fecha_inicio'
    ).first()
    
    # 3. Patients without recent follow-up
    total_sin_seguimiento = pacientes_queryset.count()
The distinct() call is critical because:
  • A patient might theoretically have multiple ACTIVO admissions (edge case/data error)
  • The query joins through the ingresos relationship
  • Without distinct(), the same patient could be counted multiple times
  • Ensures accurate patient count, not admission count

Follow-Up Alert System

The dashboard’s most critical feature is the follow-up alert list:

Alert Logic

1

Calculate 15-Day Threshold

hoy = timezone.now().date()
limite = hoy - timezone.timedelta(days=15)
Patients without contact for 15+ days trigger an alert
2

Query Patients Needing Attention

# From dashboard/views.py:26-36
pacientes_queryset = Patient.objects.filter(
    ingresos__estado='ACTIVO'
).annotate(
    fecha_del_ingreso=Max('ingresos__fecha_inicio'),
    ultima_atencion=Max('ingresos__seguimientos__fecha_atencion')
).filter(
    Q(ultima_atencion__lt=limite) |  # Last contact > 15 days ago
    Q(ultima_atencion__isnull=True, fecha_del_ingreso__lt=limite)  # No contact and admitted > 15 days ago
).distinct().order_by('ultima_atencion', 'fecha_del_ingreso')
3

Display Alert List

The query returns patients in two scenarios:
  • Lapsed Follow-Up: Had contact before, but > 15 days ago
  • No Initial Follow-Up: Admitted > 15 days ago, never contacted
Sorted by urgency (oldest contact first)
Scenario A: New Patient, No Follow-Up
  • Patient admitted: February 1, 2026
  • Today: February 20, 2026
  • No Seguimiento records
  • Alert Status: YES (19 days since admission)
Scenario B: Recent Follow-Up
  • Patient admitted: January 1, 2026
  • Last follow-up: February 28, 2026
  • Today: March 5, 2026
  • Alert Status: NO (only 5 days since contact)
Scenario C: Overdue Follow-Up
  • Patient admitted: December 1, 2025
  • Last follow-up: January 15, 2026
  • Today: March 5, 2026
  • Alert Status: YES (49 days since contact)
The alert list is action-oriented - it should be reviewed daily and used to prioritize outreach efforts.

Capita Cycle Distribution

The dashboard includes a visual chart showing patient distribution across the 18-month capita cycle:

Data Collection

# From dashboard/views.py:41-56
# 1. Get all active admissions
ingresos_activos = Ingreso.objects.filter(estado='ACTIVO')

# 2. Group by capita month manually (can't use DB aggregation on property)
conteos = {}
for ing in ingresos_activos:
    mes = ing.mes_capita  # Uses the @property mes_capita
    if mes:
        conteos[mes] = conteos.get(mes, 0) + 1

# 3. Sort for chart display
meses_ordenados = sorted(conteos.keys())
labels_grafica = [f"Capita {m}" for m in meses_ordenados]
datos_grafica = [conteos[m] for m in meses_ordenados]
The capita month (mes_capita) is a computed property, not a database field:
@property
def mes_capita(self):
    hoy = date.today()
    meses = (hoy.year - self.fecha_inicio.year) * 12 + \
            (hoy.month - self.fecha_inicio.month) + 1
    if meses < 1: return 1
    if meses > 18: return 18
    return meses
Since it’s calculated in Python (not SQL), we can’t use database aggregation functions like GROUP BY or COUNT(). The code must:
  1. Fetch all active admissions
  2. Calculate mes_capita for each in Python
  3. Manually count occurrences in a dictionary

Chart Interpretation

Ideal Pattern:
  • Relatively even spread across months 1-18
  • Slight decline toward month 18 (natural attrition)
  • No dramatic spikes or valleys
Example:
Capita 1:  12 patients
Capita 2:  11 patients
Capita 3:  10 patients
...
Capita 18: 8 patients
Indicates steady enrollment and consistent cycle progression

Dashboard Layout

The dashboard typically displays information in this structure:
┌─────────────────────────────────────────────────────────┐
│  Key Statistics Row                                     │
│  [Active Patients] [Latest Admission] [Need Follow-Up] │
└─────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────┐
│  Capita Distribution Chart                              │
│  Bar chart showing patient count by capita month        │
└─────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────┐
│  Patients Needing Follow-Up (Detailed List)             │
│  ┌───────────────────────────────────────────────────┐  │
│  │ Patient 1 - Last contact: 23 days ago   [Contact]│  │
│  │ Patient 2 - Last contact: 19 days ago   [Contact]│  │
│  │ Patient 3 - No contact since admission  [Contact]│  │
│  │ ...                                               │  │
│  └───────────────────────────────────────────────────┘  │
│  [Page 1] [2] [3] [Next]                                │
└─────────────────────────────────────────────────────────┘

Real-Time Updates

All dashboard data is calculated on each page load:

No Caching

Statistics reflect current database stateRefresh page to see latest data

Performance Considerations

For large patient databases (>1000 patients), consider:
  • Caching capita distribution (recalculate hourly)
  • Indexing estado and fecha_inicio fields
  • Optimizing follow-up query with database indexes
For production deployments at scale:
# Add database indexes
class Ingreso(models.Model):
    estado = models.CharField(
        max_length=20,
        choices=ESTADO_CHOICES,
        default='ACTIVO',
        db_index=True  # Index for faster filtering
    )
    fecha_inicio = models.DateField(db_index=True)

# Cache capita distribution for 1 hour
from django.core.cache import cache

def get_capita_distribution():
    cached = cache.get('capita_distribution')
    if cached:
        return cached
    
    # Calculate distribution...
    distribution = {'labels': labels_grafica, 'data': datos_grafica}
    cache.set('capita_distribution', distribution, 3600)  # 1 hour
    return distribution

Dashboard Context Data

The view passes this context to the template:
# From dashboard/views.py:64-72
return render(request, 'dashboard/dashboard.html', {
    'patients': patients,  # Total active count
    'last_enter': last_enter,  # Most recent patient object
    'page_obj': page_obj,  # Paginated alert list
    'total_sin_seguimiento': total_sin_seguimiento,  # Alert count
    'hoy': hoy,  # Today's date
    'labels_grafica': labels_grafica,  # Chart x-axis labels
    'datos_grafica': datos_grafica,  # Chart y-axis data
})

User Workflows

1

Morning Check-In

Daily Routine:
  1. Log in to DataMed
  2. Review dashboard statistics
  3. Check “Patients Needing Follow-Up” count
  4. Click through alert list pages
2

Triage Alerts

For each patient in alert list:
  • Check capita month (prioritize early months)
  • Review days since last contact
  • Click patient name to access full record
3

Take Action

From patient record:
  • Call patient to schedule follow-up
  • Register new appointment/exam
  • Document contact in clinical notes
  • Patient automatically clears from alert list
4

Capacity Planning

Weekly Review:
  • Analyze capita distribution chart
  • Identify upcoming workload spikes
  • Plan staff scheduling accordingly

Best Practices

Make the dashboard your first task each day:
  • Identify urgent patient needs
  • Track program growth trends
  • Monitor alert list size
Goal: Zero patients in alert list (or minimal count)
When a patient appears in the alert list:
  • Contact within 24 hours of alert appearance
  • Don’t let patients exceed 20 days without contact
  • Document all contact attempts (even if unsuccessful)
Dashboard metrics support:
  • Monthly reports to administration
  • Payer audits (total active patients, engagement)
  • Quality improvement initiatives
  • Staff workload assessment

Mobile Responsiveness

The dashboard is optimized for desktop use, but pagination ensures mobile usability. Statistics cards stack vertically on small screens.

Future Enhancements

Potential dashboard improvements:

Adherence Metrics

Average CPAP usage hours across active patients

Exam Completion Rates

Percentage of patients with required exams by capita month

Outcomes Tracking

Average IAH reduction, patient-reported outcomes

Financial Dashboard

Capita revenue, cost per patient, profit margins

Next Steps

Follow-Up System

Deep dive into follow-up tracking and state management

Patient Management

Learn about patient lifecycle and capita cycles