agdar/SESSION_CONSOLIDATION_PLAN.md
Marwan Alwali 2f1681b18c update
2025-11-11 13:44:48 +03:00

538 lines
14 KiB
Markdown

# 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.