14 KiB
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:
-
appointments.Session (NEW - Just Implemented)
- Purpose: Scheduling, capacity management, billing
- Features: Group sessions (1-20 patients), individual sessions
- Status: ✅ Complete implementation
-
psychology.PsychologySession (EXISTING)
- Purpose: Clinical therapy notes
- Links to:
appointments.Appointment(FK) - Fields: Therapy modality, interventions, progress notes
-
ot.OTSession (EXISTING)
- Purpose: OT session notes & progress tracking
- Links to:
appointments.Appointment(FK) - Fields: Cooperative level, target skills, activities
-
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
# 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
# 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
# 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
# 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:
- Check if linked appointment exists
- Create corresponding
appointments.Session - Link clinical note to new session
- Preserve appointment link (don't break anything)
2.2 Example Migration Script
# 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
# 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
# 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:
# 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
# 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
# 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
# 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)
# 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
- ONE Session Model -
appointments.Sessionis single source of truth - Clear Naming -
*SessionNoteclearly indicates clinical documentation - No Confusion - "Session" always means scheduling/capacity
- Backward Compatible - Can migrate gradually without breaking
- Group Session Ready - All apps can support group sessions
- Scalable - Easy pattern for future apps (SLP, Medical, etc.)
- 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
-
Existing Individual Sessions
- Verify old sessions still work
- Verify clinical notes accessible
- Verify no data loss
-
New Individual Sessions
- Create via appointments.Session
- Add clinical notes
- Verify linking works
-
New Group Sessions
- Create group session (capacity > 1)
- Add multiple patients
- Add clinical notes per participant
- Verify each patient has separate notes
-
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
- ✅ Review this plan - Get stakeholder approval
- ⏳ Phase 1 Implementation - Add session FKs (non-breaking)
- ⏳ Test Phase 1 - Verify no regressions
- ⏳ Phase 2 Implementation - Data migration
- ⏳ Test Phase 2 - Verify data integrity
- ⏳ Phase 3 Implementation - Rename models
- ⏳ Update all references - Views, forms, templates
- ⏳ 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.