agdar/IMPLEMENTATION_PLAN.md
2025-11-02 14:35:35 +03:00

21 KiB

Tenhal Multidisciplinary Healthcare Platform - Detailed Implementation Plan

Project Status

Current Phase: Phase 1 - Models Implementation (In Progress)

Completed:

  • Phase 0: Project Foundation & Configuration
    • Environment configuration (.env.example)
    • Dependencies (pyproject.toml with all required packages)
    • Django settings (PostgreSQL, i18n, DRF, Celery, integrations)
    • All 11 Django apps created
    • Base model mixins (UUID, TimeStamped, TenantOwned, ClinicallySignable, SoftDelete)
    • Core app models complete

Next Steps:

  • Continue with remaining app models (appointments, finance, notifications, nursing, medical, aba, ot, slp, referrals, integrations)

Phase 1: Models Implementation (Current Phase)

1.1 Core App COMPLETE

Models Created:

  • Tenant - Multi-tenancy support
  • User - Custom user with roles (ADMIN, DOCTOR, NURSE, OT, SLP, ABA, FRONT_DESK, FINANCE)
  • Patient - Demographics, bilingual names, caregiver info
  • Clinic - Specialties (MEDICAL, NURSING, ABA, OT, SLP)
  • File - Main patient file
  • SubFile - Per-clinic sub-files
  • Consent - E-signature support with multiple types
  • Attachment - Generic file attachments
  • AuditLog - Action tracking

Base Mixins Created:

  • UUIDPrimaryKeyMixin - UUID primary keys
  • TimeStampedMixin - created_at, updated_at
  • TenantOwnedMixin - tenant FK
  • ClinicallySignableMixin - signed_by, signed_at
  • SoftDeleteMixin - soft delete support

1.2 Appointments App - TO DO

Models to Create:

# appointments/models.py

class Provider(UUIDPrimaryKeyMixin, TimeStampedMixin, TenantOwnedMixin):
    """Provider (doctor/therapist) with specialties"""
    user = OneToOneField(User)
    specialties = ManyToManyField(Clinic)
    is_available = BooleanField
    max_daily_appointments = PositiveIntegerField

class Room(UUIDPrimaryKeyMixin, TimeStampedMixin, TenantOwnedMixin):
    """Clinic rooms"""
    name, room_number, clinic FK, is_available

class Schedule(UUIDPrimaryKeyMixin, TimeStampedMixin):
    """Provider availability schedule"""
    provider FK, day_of_week, start_time, end_time, slot_duration, is_active

class Appointment(UUIDPrimaryKeyMixin, TimeStampedMixin, TenantOwnedMixin):
    """Main appointment model with state machine"""
    appointment_number (auto-generated)
    patient FK, clinic FK, provider FK, room FK
    service_type, scheduled_date, scheduled_time, duration
    status: BOOKED, CONFIRMED, RESCHEDULED, CANCELLED, NO_SHOW, ARRIVED, IN_PROGRESS, COMPLETED
    confirmation_sent_at, confirmation_method
    arrival_at, start_at, end_at
    reschedule_reason, reschedule_count
    cancel_reason, cancelled_by FK
    notes, finance_cleared, consent_verified
    history = HistoricalRecords()

class AppointmentReminder(UUIDPrimaryKeyMixin, TimeStampedMixin):
    """Scheduled reminders"""
    appointment FK, reminder_type (SMS/WHATSAPP/EMAIL)
    scheduled_for, sent_at, status, message_id FK

1.3 Finance App - TO DO

Models to Create:

# finance/models.py

class Service(UUIDPrimaryKeyMixin, TimeStampedMixin, TenantOwnedMixin):
    """Billable services"""
    code, name_en, name_ar, clinic FK
    base_price (MoneyField), duration_minutes, is_active

class Package(UUIDPrimaryKeyMixin, TimeStampedMixin, TenantOwnedMixin):
    """Service packages (e.g., 10 SLP sessions)"""
    name_en, name_ar, services M2M
    total_sessions, price (MoneyField), validity_days, is_active

class Invoice(UUIDPrimaryKeyMixin, TimeStampedMixin, TenantOwnedMixin):
    """Patient invoices"""
    invoice_number (auto-generated)
    patient FK, appointment FK (nullable)
    issue_date, due_date
    subtotal, tax, discount, total
    status: DRAFT, ISSUED, PAID, PARTIALLY_PAID, CANCELLED
    notes
    history = HistoricalRecords()

class InvoiceLineItem(UUIDPrimaryKeyMixin):
    """Invoice line items"""
    invoice FK, service FK (nullable), package FK (nullable)
    description, quantity, unit_price, total

class Payment(UUIDPrimaryKeyMixin, TimeStampedMixin, TenantOwnedMixin):
    """Payment records"""
    invoice FK, payment_date, amount
    method: CASH, CARD, BANK_TRANSFER, INSURANCE
    transaction_id, reference, status
    processed_by FK

class Payer(UUIDPrimaryKeyMixin, TimeStampedMixin, TenantOwnedMixin):
    """Insurance/payer information"""
    name, type: SELF, INSURANCE, GOVERNMENT
    policy_number, coverage_percentage
    patient FK, is_active

1.4 Notifications App - TO DO

Models to Create:

# notifications/models.py

class MessageTemplate(UUIDPrimaryKeyMixin, TimeStampedMixin, TenantOwnedMixin):
    """Message templates"""
    code (unique), name
    channel: SMS, WHATSAPP, EMAIL
    subject (for email), body_en, body_ar
    variables (JSONField), is_active

class Message(UUIDPrimaryKeyMixin, TimeStampedMixin, TenantOwnedMixin):
    """Outbound messages"""
    template FK, channel, recipient
    subject, body, variables_used (JSONField)
    status: QUEUED, SENT, DELIVERED, FAILED, BOUNCED
    sent_at, delivered_at
    provider_message_id, provider_response (JSONField)
    error_message, retry_count

class NotificationPreference(UUIDPrimaryKeyMixin, TimeStampedMixin):
    """Patient notification preferences"""
    patient FK
    sms_enabled, whatsapp_enabled, email_enabled
    appointment_reminders, appointment_confirmations, results_notifications

1.5 Nursing App - TO DO

Models to Create (Based on MD-N-F-1 form):

# nursing/models.py

class NursingEncounter(UUIDPrimaryKeyMixin, TimeStampedMixin, TenantOwnedMixin, ClinicallySignableMixin):
    """Nursing vitals and assessment"""
    patient FK, appointment FK (nullable)
    encounter_date, filled_by FK
    
    # Anthropometrics
    height_cm, weight_kg, head_circumference_cm
    bmi (calculated property)
    
    # Vitals
    hr_bpm, bp_systolic, bp_diastolic
    respiratory_rate, spo2, temperature
    crt: LESS_THAN_2S, MORE_THAN_2S
    pain_score (0-10)
    
    # Allergies
    allergy_present, allergy_details
    
    # Observations
    observations (TextField)
    
    history = HistoricalRecords()

class GrowthChart(UUIDPrimaryKeyMixin):
    """Growth chart data points"""
    patient FK, measurement_date
    height_cm, weight_kg, head_circ_cm
    age_months
    percentile_height, percentile_weight

1.6 Medical App - TO DO

Models to Create (Based on MD-F-1 and MD-F-2 forms):

# medical/models.py

class MedicalConsultation(UUIDPrimaryKeyMixin, TimeStampedMixin, TenantOwnedMixin, ClinicallySignableMixin):
    """Medical consultation (MD-F-1)"""
    patient FK, appointment FK, consultation_date, provider FK
    
    # History sections
    chief_complaint, present_illness_history
    past_medical_history, vaccination_status
    family_history, social_history
    pregnancy_history, neonatal_history
    
    # Developmental milestones
    developmental_motor_milestones
    developmental_language_milestones
    developmental_social_milestones
    developmental_cognitive_milestones
    
    # Behavioral symptoms (JSONField checklist)
    behavioral_symptoms
    
    # Physical exam (JSONField structured)
    physical_exam
    
    # Assessment & Plan
    clinical_summary, recommendations
    referrals_needed
    lab_orders (JSONField), radiology_orders (JSONField)
    
    history = HistoricalRecords()

class MedicationPlan(UUIDPrimaryKeyMixin):
    """Medication details"""
    consultation FK
    drug_name, dose
    frequency: DAILY, BID, TID, QID, PRN, OTHER
    frequency_other
    compliance: GOOD, PARTIAL, BAD
    gains, side_effects
    target_behavior, improved

class MedicalFollowUp(UUIDPrimaryKeyMixin, TimeStampedMixin, TenantOwnedMixin, ClinicallySignableMixin):
    """Medical follow-up (MD-F-2)"""
    patient FK, appointment FK
    previous_consultation FK
    followup_date, provider FK
    
    # Previous complaints status (JSONField: complaint → RESOLVED/STATIC/WORSE)
    previous_complaints_status
    new_complaints
    
    # Links
    nursing_vitals FK (to NursingEncounter)
    
    # Assessment
    assessment, recommendations
    family_satisfaction: ZERO, FIFTY, HUNDRED
    medication_snapshot (JSONField)
    
    history = HistoricalRecords()

1.7 ABA App - TO DO

Models to Create (Based on ABA-F-1 form):

# aba/models.py

class ABAConsult(UUIDPrimaryKeyMixin, TimeStampedMixin, TenantOwnedMixin, ClinicallySignableMixin):
    """ABA consultation"""
    patient FK, appointment FK, consultation_date, provider FK
    
    reason_of_referral: (TextChoices with options from form)
    parental_concern, school_concern
    respondents, interviewer
    diagnosed_condition
    interaction_hours_per_day
    
    # Factors (JSONField with booleans)
    physiological_factors
    medical_factors
    
    recommendations
    
    history = HistoricalRecords()

class ABABehavior(UUIDPrimaryKeyMixin):
    """Behavior details"""
    consult FK
    behavior_description
    frequency: HOURLY, DAILY, WEEKLY, LESS_THAN_WEEKLY
    duration
    intensity: MILD, MODERATE, SEVERE
    antecedents_likely, antecedents_least_likely
    consequences
    order (for sorting)

1.8 OT App - TO DO

Models to Create (Based on OT-F-1 and OT-F-3 forms):

# ot/models.py

class OTConsult(UUIDPrimaryKeyMixin, TimeStampedMixin, TenantOwnedMixin, ClinicallySignableMixin):
    """OT consultation (OT-F-1)"""
    patient FK, appointment FK, consultation_date, provider FK
    
    reasons (ArrayField or M2M with choices)
    top_difficulty_areas (JSONField: 3 text fields)
    
    # Developmental & skills (JSONField matrices)
    developmental_motor_milestones
    self_help_skills
    feeding_participation
    
    # Behavior descriptors (JSONField)
    infant_behavior_descriptors
    current_behavior_descriptors
    
    recommendation: CONTINUE, DISCHARGE, REFER_TO_OTHER
    recommendation_notes
    
    history = HistoricalRecords()

class OTSession(UUIDPrimaryKeyMixin, TimeStampedMixin, TenantOwnedMixin, ClinicallySignableMixin):
    """OT session notes (OT-F-3)"""
    patient FK, appointment FK (nullable), session_date, provider FK
    
    session_type: CONSULT, INDIVIDUAL, GROUP, PARENT_TRAINING
    cooperative_level (1-4)
    distraction_tolerance (1-4)
    
    activities_checklist (JSONField: "Today we work on...")
    observations, activities_performed
    recommendations
    
    history = HistoricalRecords()

class OTTargetSkill(UUIDPrimaryKeyMixin):
    """Target skills with 0-10 scoring"""
    session FK
    skill_name
    score (0-10)
    notes
    order

1.9 SLP App - TO DO

Models to Create (Based on SLP-F-1, F-2, F-3, F-4 forms):

# slp/models.py

class SLPConsult(UUIDPrimaryKeyMixin, TimeStampedMixin, TenantOwnedMixin, ClinicallySignableMixin):
    """SLP consultation (SLP-F-1 with variants)"""
    patient FK, appointment FK, consultation_date, provider FK
    
    consult_variant: ASD, LANGUAGE_DELAY, FLUENCY
    primary_concern
    suspected_areas (JSONField)
    type_of_service: CONSULT, EVAL, INTERVENTION, PARENT_TRAINING
    
    communication_modes (JSONField checklist)
    screen_time_hours
    
    # Variant-specific questionnaires (JSONField)
    variant_questionnaire
    
    # Skills to observe (JSONField matrix)
    skills_to_observe
    
    # Oral motor screening (JSONField)
    oral_motor_screening
    
    recommendations
    
    history = HistoricalRecords()

class SLPAssessment(UUIDPrimaryKeyMixin, TimeStampedMixin, TenantOwnedMixin, ClinicallySignableMixin):
    """SLP assessment (SLP-F-2)"""
    patient FK, appointment FK, assessment_date, provider FK
    
    diagnosis_statement, case_history
    
    # History sections
    prenatal_history, perinatal_history, postnatal_history
    developmental_history, medical_status
    
    # Speech/Language detail (JSONField)
    speech_language_detail
    
    # Test scores
    gfta3_score, jat_score, ssi_score
    
    # Oral mechanism (JSONField)
    oral_mechanism
    
    # Rossetti domains (JSONField: domain → age level)
    rossetti_domains
    
    # Joint attention skills (JSONField)
    joint_attention_skills
    
    # Summary & Plan
    clinical_summary, recommendations
    frequency_per_week, session_duration_minutes
    referral_rules (JSONField)
    
    history = HistoricalRecords()

class SLPIntervention(UUIDPrimaryKeyMixin, TimeStampedMixin, TenantOwnedMixin, ClinicallySignableMixin):
    """SLP intervention session (SLP-F-3)"""
    patient FK, appointment FK
    session_number, session_date, session_time
    provider FK
    previous_session FK (self-referential, nullable)
    
    history = HistoricalRecords()

class SLPTarget(UUIDPrimaryKeyMixin):
    """Intervention targets (SOAP format)"""
    intervention FK
    target_number (1 or 2)
    subjective, objective, assessment, plan
    prompt_strategies (JSONField)

class SLPProgressReport(UUIDPrimaryKeyMixin, TimeStampedMixin, TenantOwnedMixin, ClinicallySignableMixin):
    """SLP progress report (SLP-F-4)"""
    patient FK, report_date, provider FK
    
    sessions_scheduled, sessions_attended
    final_diagnosis
    
    # Objectives & progress (JSONField: objective → % accuracy)
    objectives_progress
    
    # Plan details (JSONField)
    plan_details
    
    overall_progress, participation_level
    attendance_rate, carryover_level
    prognosis, recommendations
    
    package_sessions_count
    reassessment_needed
    
    history = HistoricalRecords()

1.10 Referrals App - TO DO

Models to Create:

# referrals/models.py

class Referral(UUIDPrimaryKeyMixin, TimeStampedMixin, TenantOwnedMixin):
    """Inter-discipline and external referrals"""
    patient FK
    from_clinic FK, to_clinic FK (nullable)
    from_provider FK, to_provider FK (nullable)
    external_provider_name
    
    reason
    urgency: ROUTINE, URGENT, EMERGENCY
    status: PENDING, ACCEPTED, REJECTED, COMPLETED
    
    created_at, responded_at
    notes

1.11 Integrations App - TO DO

Models to Create:

# integrations/models.py

# Lab/Radiology
class ExternalOrder(UUIDPrimaryKeyMixin, TimeStampedMixin, TenantOwnedMixin):
    """Lab and radiology orders"""
    patient FK
    order_type: LAB, RADIOLOGY
    order_details (JSONField)
    status: ORDERED, IN_PROGRESS, COMPLETED, CANCELLED
    result_url, result_data (JSONField)
    ordered_by FK, ordered_at, completed_at

# NPHIES (Insurance e-Claims)
class NphiesMessage(UUIDPrimaryKeyMixin, TimeStampedMixin, TenantOwnedMixin):
    """NPHIES FHIR messages"""
    direction: OUTBOUND, INBOUND
    resource_type: ELIGIBILITY, PRIOR_AUTH, CLAIM, PAYMENT_NOTICE, PAYMENT_RECONCILIATION
    fhir_json (JSONField)
    status: QUEUED, SENT, ACK, ERROR
    correlation_id
    response_http_status, error_code, error_message
    created_at, sent_at

class NphiesEncounterLink(UUIDPrimaryKeyMixin, TenantOwnedMixin):
    """Link appointments to NPHIES encounters"""
    patient FK, appointment FK
    encounter_id, claim_id, claim_response_id

class PayerContract(UUIDPrimaryKeyMixin, TimeStampedMixin, TenantOwnedMixin):
    """Insurance payer configurations"""
    payer_code, payer_name
    credentials (JSONField encrypted)
    endpoints (JSONField)
    supports_eligibility, supports_prior_auth, supports_claims
    is_active

# ZATCA (E-Invoicing)
class EInvoice(UUIDPrimaryKeyMixin, TimeStampedMixin, TenantOwnedMixin):
    """ZATCA e-invoices"""
    invoice FK (to finance.Invoice)
    uuid, xml_payload, qr_base64
    clearance_status: PENDING, CLEARED, REJECTED, REPORTED
    zatca_document_type
    submission_mode: CLEARANCE, REPORTING
    response_payload (JSONField)
    error_code, error_message
    submitted_at

class ZatcaCredential(UUIDPrimaryKeyMixin, TimeStampedMixin, TenantOwnedMixin):
    """ZATCA credentials (CSIDs)"""
    environment: SIMULATION, COMPLIANCE, PRODUCTION
    csid, certificate, private_key (encrypted)
    is_active, expires_at

Phase 2: Forms Implementation (4-5 days)

Forms to Create Per App

Core Forms:

  • PatientForm - Bilingual patient registration
  • ConsentForm - With signature capture
  • AttachmentForm - File upload

Appointments Forms:

  • AppointmentBookingForm
  • AppointmentConfirmForm
  • AppointmentRescheduleForm
  • AppointmentCancelForm

Nursing Forms:

  • NursingEncounterForm - Auto-calculate BMI

Medical Forms:

  • MedicalConsultationForm - Sections matching MD-F-1
  • MedicationPlanFormSet - Inline formset
  • MedicalFollowUpForm - Sections matching MD-F-2

ABA Forms:

  • ABAConsultForm
  • ABABehaviorFormSet - Inline formset

OT Forms:

  • OTConsultForm
  • OTSessionForm
  • OTTargetSkillFormSet - Inline formset

SLP Forms:

  • SLPConsultForm - Variant-specific sections
  • SLPAssessmentForm
  • SLPInterventionForm
  • SLPTargetFormSet - Inline formset
  • SLPProgressReportForm

Finance Forms:

  • InvoiceForm
  • PaymentForm

Phase 3: Views Implementation (5-7 days)

Views Structure Per App

Core Views:

  • Patient CRUD (List, Detail, Create, Update)
  • Patient Dashboard (hub with tabs)
  • Consent CRUD

Appointments Views:

  • Calendar view (weekly grid)
  • Appointment CRUD
  • HTMX partials for state transitions

Clinical Document Views (per app):

  • List, Detail, Create, Update for each document type
  • HTMX partials for dynamic forms

Finance Views:

  • Invoice CRUD
  • Payment processing

Notifications Views:

  • Message outbox
  • Message detail

Audit Views:

  • Audit timeline
  • Version comparison

Phase 4: URLs Configuration (1-2 days)

  • Namespaced URLs for all apps
  • HTMX partial endpoints
  • DRF routers for API apps

Phase 5: Templates Implementation (5-7 days)

  • Base templates with RTL/LTR
  • Patient hub with tabs
  • Clinical form templates matching paper forms
  • Charts (OT/SLP target progress, growth charts)
  • Appointment calendar

Phase 6: DRF API Implementation (3-4 days)

APIs to Create:

  • Appointments API (CRUD + state transitions)
  • Notifications API (create, webhook receiver)
  • Referrals API (CRUD)
  • Integrations API:
    • NPHIES endpoints (eligibility, prior-auth, claims, payment)
    • ZATCA endpoints (prepare, submit, onboard)
    • Lab/Radiology stubs
    • Consent verification

Phase 7: Signals, Services & Tasks (3-4 days)

Signals:

  • Patient created → create File
  • Appointment created → create SubFile (if first for clinic)
  • Appointment status changed → enqueue notification

Services:

  • Notification service (SMS/WhatsApp/Email)
  • NPHIES FHIR client
  • ZATCA e-invoicing service
  • Lab/Radiology service

Celery Tasks:

  • Appointment reminders (T-24h, T-12h)
  • NPHIES polling
  • Payment reconciliation
  • ZATCA batch submission

Phase 8: Admin, RBAC & Auditing (2-3 days)

  • Django admin for all models
  • Permission matrix implementation
  • Audit trail views
  • Export functionality

Phase 9: Testing (4-5 days)

  • Model tests
  • Form tests
  • View tests (permissions, HTMX)
  • API tests
  • Integration tests
  • i18n tests

Phase 10: Documentation & Deployment (2-3 days)

  • README.md
  • DEPLOYMENT.md
  • API_DOCS.md
  • RBAC_MATRIX.md
  • INTEGRATION_GUIDE.md

Timeline Summary

Phase Duration Status
0: Foundation 2-3 days COMPLETE
1: Models 7-10 days 🔄 IN PROGRESS (Core complete)
2: Forms 4-5 days PENDING
3: Views 5-7 days PENDING
4: URLs 1-2 days PENDING
5: Templates 5-7 days PENDING
6: DRF APIs 3-4 days PENDING
7: Services/Tasks 3-4 days PENDING
8: Admin/RBAC 2-3 days PENDING
9: Testing 4-5 days PENDING
10: Docs/Deploy 2-3 days PENDING
TOTAL 38-53 days ~8-11 weeks

Next Immediate Steps

  1. Complete core models
  2. ⏭️ Create appointments models
  3. ⏭️ Create finance models
  4. ⏭️ Create notifications models
  5. ⏭️ Create nursing models
  6. ⏭️ Create medical models
  7. ⏭️ Create aba models
  8. ⏭️ Create ot models
  9. ⏭️ Create slp models
  10. ⏭️ Create referrals models
  11. ⏭️ Create integrations models
  12. ⏭️ Run migrations
  13. ⏭️ Create signals for auto-generation (MRN, file numbers)
  14. ⏭️ Begin Phase 2 (Forms)

Critical Notes

  • DO NOT skip phases - Each phase builds on the previous
  • Models must be complete before starting forms
  • All clinical documents must use simple_history
  • All user-facing strings must use gettext_lazy
  • UUID primary keys for all models
  • Tenant isolation must be enforced everywhere
  • RBAC must be checked in every view
  • Audit trail for all clinical document changes

Reference Documents

  • Clinical forms in project root (DOCX files)
  • Original prompt: multidisciplinary_django_prompt_1.md
  • Settings: AgdarCentre/settings.py
  • Environment: .env.example