# Session Consolidation Plan ## Centralizing All Sessions in appointments.Session **Date:** 2025-11-11 **Status:** Planning Phase **Goal:** ONE centralized place for all sessions (appointments.Session) --- ## Current State Analysis ### Session Models Found Across System: 1. **appointments.Session** (NEW - Just Implemented) - Purpose: Scheduling, capacity management, billing - Features: Group sessions (1-20 patients), individual sessions - Status: ✅ Complete implementation 2. **psychology.PsychologySession** (EXISTING) - Purpose: Clinical therapy notes - Links to: `appointments.Appointment` (FK) - Fields: Therapy modality, interventions, progress notes 3. **ot.OTSession** (EXISTING) - Purpose: OT session notes & progress tracking - Links to: `appointments.Appointment` (FK) - Fields: Cooperative level, target skills, activities 4. **aba.ABASession** (EXISTING) - Purpose: ABA session documentation - Links to: `appointments.Appointment` (FK) - Fields: Behavior data, interventions, progress ### Apps WITHOUT Session Models: - SLP - No session model - Medical - No session model - Nursing - No session model --- ## The Problem **Scattered Session Management:** - 4 different "Session" models across apps - Confusion about what "Session" means - No unified scheduling/capacity management - Difficult to implement group sessions consistently **Violates Principle:** ONE centralized place for sessions --- ## Solution: Consolidation Strategy ### Core Principle ``` appointments.Session = Scheduling + Capacity + Billing *SessionNote models = Clinical Documentation ``` ### Architecture ``` ┌──────────────────────────────────────────────┐ │ appointments.Session (SINGLE SOURCE) │ │ ├─ Scheduling (date, time, room, provider) │ │ ├─ Capacity (1-20 patients, group support) │ │ ├─ Billing (appointment numbers) │ │ └─ Status (scheduled, in progress, etc.) │ └────────────┬─────────────────────────────────┘ │ ├─→ psychology.PsychologySessionNote ├─→ ot.OTSessionNote ├─→ aba.ABASessionNote └─→ (future clinical notes) ``` --- ## Implementation Plan ### Phase 1: Add Session Links (Non-Breaking) ✅ RECOMMENDED START **Goal:** Add new FKs without breaking existing functionality #### 1.1 Update Psychology Model ```python # psychology/models.py class PsychologySession(models.Model): # Will rename later """Clinical notes for psychology session""" # EXISTING - Keep for backward compatibility appointment = models.ForeignKey( 'appointments.Appointment', on_delete=models.SET_NULL, null=True, blank=True, related_name='psychology_sessions' ) # NEW - Link to centralized session session = models.ForeignKey( 'appointments.Session', on_delete=models.CASCADE, null=True, # Nullable during migration blank=True, related_name='psychology_notes', help_text="Link to centralized session (for scheduling)" ) # NEW - Link to specific participant (for group sessions) session_participant = models.ForeignKey( 'appointments.SessionParticipant', on_delete=models.CASCADE, null=True, blank=True, related_name='psychology_notes', help_text="For group sessions: which participant these notes are for" ) # All existing fields remain unchanged... ``` #### 1.2 Update OT Model ```python # ot/models.py class OTSession(models.Model): # Will rename later """Clinical notes for OT session""" # EXISTING appointment = models.ForeignKey( 'appointments.Appointment', on_delete=models.SET_NULL, null=True, blank=True ) # NEW session = models.ForeignKey( 'appointments.Session', on_delete=models.CASCADE, null=True, blank=True, related_name='ot_notes' ) session_participant = models.ForeignKey( 'appointments.SessionParticipant', on_delete=models.CASCADE, null=True, blank=True, related_name='ot_notes' ) # All existing fields... ``` #### 1.3 Update ABA Model ```python # aba/models.py class ABASession(models.Model): # Will rename later """Clinical notes for ABA session""" # EXISTING appointment = models.ForeignKey( 'appointments.Appointment', on_delete=models.SET_NULL, null=True, blank=True ) # NEW session = models.ForeignKey( 'appointments.Session', on_delete=models.CASCADE, null=True, blank=True, related_name='aba_notes' ) session_participant = models.ForeignKey( 'appointments.SessionParticipant', on_delete=models.CASCADE, null=True, blank=True, related_name='aba_notes' ) # All existing fields... ``` #### 1.4 Create Migrations ```bash # Generate migrations for each app python manage.py makemigrations psychology python manage.py makemigrations ot python manage.py makemigrations aba # Review migrations before applying python manage.py sqlmigrate psychology XXXX python manage.py sqlmigrate ot XXXX python manage.py sqlmigrate aba XXXX # Apply migrations python manage.py migrate ``` **Result:** ✅ New fields added, existing functionality unchanged --- ### Phase 2: Data Migration (Backward Compatible) **Goal:** Create appointments.Session for existing clinical sessions #### 2.1 Migration Strategy For each existing clinical session: 1. Check if linked appointment exists 2. Create corresponding `appointments.Session` 3. Link clinical note to new session 4. Preserve appointment link (don't break anything) #### 2.2 Example Migration Script ```python # psychology/migrations/XXXX_migrate_to_centralized_sessions.py from django.db import migrations from datetime import time def migrate_psychology_sessions(apps, schema_editor): """Create appointments.Session for existing PsychologySession records""" PsychologySession = apps.get_model('psychology', 'PsychologySession') Session = apps.get_model('appointments', 'Session') for psych_session in PsychologySession.objects.filter(session__isnull=True): if psych_session.appointment: # Create centralized session from appointment session = Session.objects.create( tenant=psych_session.tenant, session_type='INDIVIDUAL', max_capacity=1, provider=psych_session.appointment.provider, clinic=psych_session.appointment.clinic, room=psych_session.appointment.room, service_type=psych_session.appointment.service_type or 'psychology_therapy', scheduled_date=psych_session.session_date, scheduled_time=psych_session.appointment.scheduled_time or time(9, 0), duration=psych_session.duration_minutes or 60, status='COMPLETED' if psych_session.is_signed else 'SCHEDULED' ) # Link psychology session to centralized session psych_session.session = session psych_session.save() class Migration(migrations.Migration): dependencies = [ ('psychology', 'XXXX_add_session_fields'), ('appointments', '0004_add_session_models'), ] operations = [ migrations.RunPython(migrate_psychology_sessions), ] ``` **Repeat for OT and ABA apps** --- ### Phase 3: Rename Models (Breaking Change) **Goal:** Rename to clarify purpose (Session → SessionNote) #### 3.1 Model Renaming ```python # psychology/models.py class PsychologySession(models.Model): # OLD NAME ↓ class PsychologySessionNote(models.Model): # NEW NAME # ot/models.py class OTSession(models.Model): # OLD NAME ↓ class OTSessionNote(models.Model): # NEW NAME # aba/models.py class ABASession(models.Model): # OLD NAME ↓ class ABASessionNote(models.Model): # NEW NAME ``` #### 3.2 Database Table Renaming ```python # psychology/migrations/XXXX_rename_to_session_note.py from django.db import migrations class Migration(migrations.Migration): dependencies = [ ('psychology', 'XXXX_migrate_to_centralized_sessions'), ] operations = [ migrations.RenameModel( old_name='PsychologySession', new_name='PsychologySessionNote', ), ] ``` #### 3.3 Update All References **Files to Update:** - Models: Import statements - Views: All view classes - Forms: Form classes - Templates: Template references - Admin: Admin classes - Serializers: API serializers - URLs: URL patterns - Tests: Test cases **Example:** ```python # Before from psychology.models import PsychologySession # After from psychology.models import PsychologySessionNote ``` --- ### Phase 4: Update Views & Forms **Goal:** Support both individual and group sessions #### 4.1 Update Session Creation Views ```python # psychology/views.py class PsychologySessionNoteCreateView(CreateView): """Create clinical notes for a session""" model = PsychologySessionNote def form_valid(self, form): # Get session from URL or form session = get_object_or_404(Session, pk=self.kwargs['session_pk']) # For group sessions, get participant if session.session_type == 'GROUP': participant = get_object_or_404( SessionParticipant, pk=self.kwargs['participant_pk'] ) form.instance.session_participant = participant form.instance.session = session form.instance.patient = session.patient # or participant.patient form.instance.provider = self.request.user return super().form_valid(form) ``` #### 4.2 Update Forms ```python # psychology/forms.py class PsychologySessionNoteForm(forms.ModelForm): class Meta: model = PsychologySessionNote fields = [ 'presenting_issues', 'interventions_used', 'client_response', 'progress_toward_goals', # ... all clinical fields ] # Exclude: session, session_participant (set in view) ``` --- ### Phase 5: Cleanup (Optional) **Goal:** Remove deprecated fields #### 5.1 Make session FK Required ```python # After all data migrated class PsychologySessionNote(models.Model): session = models.ForeignKey( 'appointments.Session', on_delete=models.CASCADE, null=False, # Changed from True blank=False, # Changed from True related_name='psychology_notes' ) ``` #### 5.2 Remove appointment FK (Optional) ```python # Can keep for historical reference or remove # If removing: class Migration(migrations.Migration): operations = [ migrations.RemoveField( model_name='psychologysessionnote', name='appointment', ), ] ``` --- ## Benefits of This Approach ### ✅ Advantages 1. **ONE Session Model** - `appointments.Session` is single source of truth 2. **Clear Naming** - `*SessionNote` clearly indicates clinical documentation 3. **No Confusion** - "Session" always means scheduling/capacity 4. **Backward Compatible** - Can migrate gradually without breaking 5. **Group Session Ready** - All apps can support group sessions 6. **Scalable** - Easy pattern for future apps (SLP, Medical, etc.) 7. **Maintains History** - Can keep appointment FK for historical data ### 📊 Impact Analysis **Models:** 3 files (psychology, ot, aba) **Views:** ~15-20 view classes **Forms:** ~10 form classes **Templates:** ~15-20 templates **Admin:** 3 admin classes **Migrations:** 3-4 per app (9-12 total) **Estimated Effort:** 2-3 days for complete migration --- ## Testing Strategy ### Test Cases 1. **Existing Individual Sessions** - Verify old sessions still work - Verify clinical notes accessible - Verify no data loss 2. **New Individual Sessions** - Create via appointments.Session - Add clinical notes - Verify linking works 3. **New Group Sessions** - Create group session (capacity > 1) - Add multiple patients - Add clinical notes per participant - Verify each patient has separate notes 4. **Migration Verification** - Count records before/after - Verify all links correct - Check for orphaned records --- ## Rollback Plan ### If Issues Arise **Phase 1 Rollback:** - New fields are nullable - Simply don't use them - No data loss **Phase 2 Rollback:** - Keep appointment FK - Can revert to using appointment - Session data can be deleted if needed **Phase 3 Rollback:** - Rename back to original names - Update imports - More complex but possible --- ## Next Steps ### Immediate Actions 1. ✅ **Review this plan** - Get stakeholder approval 2. ⏳ **Phase 1 Implementation** - Add session FKs (non-breaking) 3. ⏳ **Test Phase 1** - Verify no regressions 4. ⏳ **Phase 2 Implementation** - Data migration 5. ⏳ **Test Phase 2** - Verify data integrity 6. ⏳ **Phase 3 Implementation** - Rename models 7. ⏳ **Update all references** - Views, forms, templates 8. ⏳ **Final testing** - End-to-end verification ### Timeline - **Week 1:** Phase 1 + Testing - **Week 2:** Phase 2 + Testing - **Week 3:** Phase 3 + Updates - **Week 4:** Final testing + Documentation --- ## Conclusion This consolidation plan achieves the goal of **ONE centralized place for sessions** while: - Maintaining backward compatibility - Preserving existing data - Enabling group session support across all clinical apps - Following clear naming conventions - Providing a scalable pattern for future apps **Key Decision:** Rename clinical "Session" models to "SessionNote" to eliminate confusion and make `appointments.Session` the single source of truth.