Files
ETB/ETB-API/sla_oncall/migrations/0001_initial.py
Iliyan Angelov 6b247e5b9f Updates
2025-09-19 11:58:53 +03:00

284 lines
18 KiB
Python

# Generated by Django 5.2.6 on 2025-09-18 15:50
import datetime
import django.core.validators
import django.db.models.deletion
import uuid
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
('incident_intelligence', '0003_incident_auto_remediation_attempted_and_more'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.CreateModel(
name='BusinessHours',
fields=[
('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
('name', models.CharField(max_length=200, unique=True)),
('description', models.TextField()),
('timezone', models.CharField(default='UTC', max_length=50)),
('weekday_start', models.TimeField(default=datetime.time(9, 0))),
('weekday_end', models.TimeField(default=datetime.time(17, 0))),
('weekend_start', models.TimeField(default=datetime.time(10, 0))),
('weekend_end', models.TimeField(default=datetime.time(16, 0))),
('day_overrides', models.JSONField(default=dict, help_text='Override hours for specific dates (YYYY-MM-DD format)')),
('holiday_calendar', models.JSONField(default=list, help_text="List of holidays (YYYY-MM-DD format) when business hours don't apply")),
('is_active', models.BooleanField(default=True)),
('is_default', models.BooleanField(default=False, help_text='Default business hours for the system')),
('created_at', models.DateTimeField(auto_now_add=True)),
('updated_at', models.DateTimeField(auto_now=True)),
('created_by', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL)),
],
options={
'ordering': ['name'],
},
),
migrations.CreateModel(
name='EscalationPolicy',
fields=[
('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
('name', models.CharField(max_length=200, unique=True)),
('description', models.TextField()),
('escalation_type', models.CharField(choices=[('TIME_BASED', 'Time-based Escalation'), ('SEVERITY_BASED', 'Severity-based Escalation'), ('RESOURCE_BASED', 'Resource-based Escalation'), ('CUSTOM', 'Custom Escalation')], max_length=20)),
('trigger_condition', models.CharField(choices=[('SLA_BREACH', 'SLA Breach'), ('SLA_THRESHOLD', 'SLA Threshold Reached'), ('NO_RESPONSE', 'No Response'), ('NO_ACKNOWLEDGMENT', 'No Acknowledgment'), ('CUSTOM', 'Custom Condition')], max_length=20)),
('incident_severities', models.JSONField(default=list, help_text='List of incident severities this policy applies to')),
('incident_categories', models.JSONField(default=list, help_text='List of incident categories this policy applies to')),
('trigger_delay_minutes', models.PositiveIntegerField(default=0, help_text='Delay before escalation triggers (in minutes)')),
('escalation_steps', models.JSONField(default=list, help_text='List of escalation steps with timing and actions')),
('notification_channels', models.JSONField(default=list, help_text='Channels to notify during escalation (email, sms, slack, etc.)')),
('notification_templates', models.JSONField(default=dict, help_text='Templates for different notification channels')),
('is_active', models.BooleanField(default=True)),
('is_default', models.BooleanField(default=False)),
('created_at', models.DateTimeField(auto_now_add=True)),
('updated_at', models.DateTimeField(auto_now=True)),
('created_by', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL)),
],
options={
'ordering': ['name'],
},
),
migrations.CreateModel(
name='NotificationTemplate',
fields=[
('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
('name', models.CharField(max_length=200)),
('template_type', models.CharField(choices=[('ESCALATION', 'Escalation Notification'), ('ONCALL_HANDOFF', 'On-Call Handoff'), ('SLA_BREACH', 'SLA Breach Alert'), ('SLA_WARNING', 'SLA Warning'), ('CUSTOM', 'Custom Notification')], max_length=20)),
('channel_type', models.CharField(choices=[('EMAIL', 'Email'), ('SMS', 'SMS'), ('SLACK', 'Slack'), ('TEAMS', 'Microsoft Teams'), ('WEBHOOK', 'Webhook'), ('CUSTOM', 'Custom Channel')], max_length=20)),
('subject_template', models.CharField(help_text='Subject template with variables', max_length=500)),
('body_template', models.TextField(help_text='Body template with variables')),
('variables', models.JSONField(default=list, help_text='Available variables for this template')),
('is_active', models.BooleanField(default=True)),
('is_default', models.BooleanField(default=False)),
('created_at', models.DateTimeField(auto_now_add=True)),
('updated_at', models.DateTimeField(auto_now=True)),
('created_by', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL)),
],
options={
'ordering': ['template_type', 'channel_type', 'name'],
},
),
migrations.CreateModel(
name='OnCallRotation',
fields=[
('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
('name', models.CharField(max_length=200, unique=True)),
('description', models.TextField()),
('rotation_type', models.CharField(choices=[('WEEKLY', 'Weekly Rotation'), ('DAILY', 'Daily Rotation'), ('MONTHLY', 'Monthly Rotation'), ('CUSTOM', 'Custom Schedule')], max_length=20)),
('status', models.CharField(choices=[('ACTIVE', 'Active'), ('PAUSED', 'Paused'), ('INACTIVE', 'Inactive')], default='ACTIVE', max_length=20)),
('team_name', models.CharField(max_length=100)),
('team_description', models.TextField(blank=True, null=True)),
('schedule_config', models.JSONField(default=dict, help_text='Configuration for the rotation schedule')),
('timezone', models.CharField(default='UTC', max_length=50)),
('external_system', models.CharField(choices=[('PAGERDUTY', 'PagerDuty'), ('OPSGENIE', 'OpsGenie'), ('INTERNAL', 'Internal System'), ('CUSTOM', 'Custom Integration')], default='INTERNAL', max_length=50)),
('external_system_id', models.CharField(blank=True, help_text='ID in external system (PagerDuty schedule ID, etc.)', max_length=255, null=True)),
('integration_config', models.JSONField(default=dict, help_text='Configuration for external system integration')),
('created_at', models.DateTimeField(auto_now_add=True)),
('updated_at', models.DateTimeField(auto_now=True)),
('created_by', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL)),
],
options={
'ordering': ['name'],
},
),
migrations.CreateModel(
name='OnCallAssignment',
fields=[
('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
('start_time', models.DateTimeField()),
('end_time', models.DateTimeField()),
('status', models.CharField(choices=[('SCHEDULED', 'Scheduled'), ('ACTIVE', 'Active'), ('COMPLETED', 'Completed'), ('CANCELLED', 'Cancelled')], default='SCHEDULED', max_length=20)),
('handoff_notes', models.TextField(blank=True, null=True)),
('handoff_time', models.DateTimeField(blank=True, null=True)),
('incidents_handled', models.PositiveIntegerField(default=0)),
('response_time_avg', models.DurationField(blank=True, null=True)),
('created_at', models.DateTimeField(auto_now_add=True)),
('updated_at', models.DateTimeField(auto_now=True)),
('handed_off_from', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='handed_off_assignments', to=settings.AUTH_USER_MODEL)),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
('rotation', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='assignments', to='sla_oncall.oncallrotation')),
],
options={
'ordering': ['start_time'],
},
),
migrations.CreateModel(
name='SLADefinition',
fields=[
('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
('name', models.CharField(max_length=200)),
('description', models.TextField()),
('sla_type', models.CharField(choices=[('RESPONSE_TIME', 'Response Time'), ('RESOLUTION_TIME', 'Resolution Time'), ('ACKNOWLEDGMENT_TIME', 'Acknowledgment Time'), ('FIRST_RESPONSE', 'First Response Time')], max_length=20)),
('incident_categories', models.JSONField(default=list, help_text='List of incident categories this SLA applies to')),
('incident_severities', models.JSONField(default=list, help_text='List of incident severities this SLA applies to')),
('incident_priorities', models.JSONField(default=list, help_text='List of incident priorities this SLA applies to')),
('target_duration_minutes', models.PositiveIntegerField(help_text='SLA target in minutes')),
('business_hours_only', models.BooleanField(default=False, help_text='Whether SLA only applies during business hours')),
('escalation_enabled', models.BooleanField(default=True)),
('escalation_threshold_percent', models.FloatField(default=80.0, help_text='Escalate when X% of SLA time has passed', validators=[django.core.validators.MinValueValidator(0.0), django.core.validators.MaxValueValidator(100.0)])),
('is_active', models.BooleanField(default=True)),
('is_default', models.BooleanField(default=False)),
('created_at', models.DateTimeField(auto_now_add=True)),
('updated_at', models.DateTimeField(auto_now=True)),
('business_hours', models.ForeignKey(blank=True, help_text='Business hours configuration for this SLA', null=True, on_delete=django.db.models.deletion.SET_NULL, to='sla_oncall.businesshours')),
('created_by', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL)),
],
options={
'ordering': ['name'],
},
),
migrations.CreateModel(
name='SLAInstance',
fields=[
('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
('status', models.CharField(choices=[('ACTIVE', 'Active'), ('MET', 'SLA Met'), ('BREACHED', 'SLA Breached'), ('CANCELLED', 'Cancelled')], default='ACTIVE', max_length=20)),
('target_time', models.DateTimeField(help_text='When the SLA should be met')),
('started_at', models.DateTimeField(auto_now_add=True)),
('met_at', models.DateTimeField(blank=True, null=True)),
('breached_at', models.DateTimeField(blank=True, null=True)),
('escalation_triggered', models.BooleanField(default=False)),
('escalation_triggered_at', models.DateTimeField(blank=True, null=True)),
('escalation_level', models.PositiveIntegerField(default=0)),
('response_time', models.DurationField(blank=True, null=True)),
('resolution_time', models.DurationField(blank=True, null=True)),
('created_at', models.DateTimeField(auto_now_add=True)),
('updated_at', models.DateTimeField(auto_now=True)),
('escalation_policy', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='sla_oncall.escalationpolicy')),
('incident', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='sla_instances', to='incident_intelligence.incident')),
('sla_definition', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='sla_oncall.sladefinition')),
],
options={
'ordering': ['-created_at'],
},
),
migrations.CreateModel(
name='EscalationInstance',
fields=[
('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
('status', models.CharField(choices=[('PENDING', 'Pending'), ('TRIGGERED', 'Triggered'), ('ACKNOWLEDGED', 'Acknowledged'), ('RESOLVED', 'Resolved'), ('CANCELLED', 'Cancelled')], default='PENDING', max_length=20)),
('escalation_level', models.PositiveIntegerField(default=1)),
('current_step', models.PositiveIntegerField(default=0)),
('triggered_at', models.DateTimeField(blank=True, null=True)),
('acknowledged_at', models.DateTimeField(blank=True, null=True)),
('resolved_at', models.DateTimeField(blank=True, null=True)),
('notifications_sent', models.JSONField(default=list, help_text='List of notifications sent during escalation')),
('actions_taken', models.JSONField(default=list, help_text='List of actions taken during escalation')),
('created_at', models.DateTimeField(auto_now_add=True)),
('updated_at', models.DateTimeField(auto_now=True)),
('incident', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='escalation_instances', to='incident_intelligence.incident')),
('escalation_policy', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='sla_oncall.escalationpolicy')),
('sla_instance', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='escalation_instances', to='sla_oncall.slainstance')),
],
options={
'ordering': ['-created_at'],
},
),
migrations.AddIndex(
model_name='businesshours',
index=models.Index(fields=['is_active', 'is_default'], name='sla_oncall__is_acti_5700c2_idx'),
),
migrations.AddIndex(
model_name='escalationpolicy',
index=models.Index(fields=['escalation_type', 'is_active'], name='sla_oncall__escalat_f6341c_idx'),
),
migrations.AddIndex(
model_name='escalationpolicy',
index=models.Index(fields=['trigger_condition'], name='sla_oncall__trigger_75de52_idx'),
),
migrations.AddIndex(
model_name='notificationtemplate',
index=models.Index(fields=['template_type', 'channel_type'], name='sla_oncall__templat_a3daf6_idx'),
),
migrations.AddIndex(
model_name='notificationtemplate',
index=models.Index(fields=['is_active'], name='sla_oncall__is_acti_cb24d6_idx'),
),
migrations.AlterUniqueTogether(
name='notificationtemplate',
unique_together={('template_type', 'channel_type', 'name')},
),
migrations.AddIndex(
model_name='oncallrotation',
index=models.Index(fields=['status', 'rotation_type'], name='sla_oncall__status_0522d6_idx'),
),
migrations.AddIndex(
model_name='oncallrotation',
index=models.Index(fields=['external_system'], name='sla_oncall__externa_ad3fd1_idx'),
),
migrations.AddIndex(
model_name='oncallassignment',
index=models.Index(fields=['rotation', 'start_time'], name='sla_oncall__rotatio_2db363_idx'),
),
migrations.AddIndex(
model_name='oncallassignment',
index=models.Index(fields=['user', 'start_time'], name='sla_oncall__user_id_0776dc_idx'),
),
migrations.AddIndex(
model_name='oncallassignment',
index=models.Index(fields=['status', 'start_time'], name='sla_oncall__status_3bec52_idx'),
),
migrations.AddIndex(
model_name='sladefinition',
index=models.Index(fields=['sla_type', 'is_active'], name='sla_oncall__sla_typ_f69c8d_idx'),
),
migrations.AddIndex(
model_name='sladefinition',
index=models.Index(fields=['incident_severities'], name='sla_oncall__inciden_ba4baa_idx'),
),
migrations.AddIndex(
model_name='sladefinition',
index=models.Index(fields=['incident_categories'], name='sla_oncall__inciden_da3c38_idx'),
),
migrations.AddIndex(
model_name='slainstance',
index=models.Index(fields=['incident', 'status'], name='sla_oncall__inciden_723905_idx'),
),
migrations.AddIndex(
model_name='slainstance',
index=models.Index(fields=['sla_definition', 'status'], name='sla_oncall__sla_def_57544b_idx'),
),
migrations.AddIndex(
model_name='slainstance',
index=models.Index(fields=['target_time', 'status'], name='sla_oncall__target__b6b252_idx'),
),
migrations.AddIndex(
model_name='escalationinstance',
index=models.Index(fields=['incident', 'status'], name='sla_oncall__inciden_58c9bd_idx'),
),
migrations.AddIndex(
model_name='escalationinstance',
index=models.Index(fields=['escalation_policy', 'status'], name='sla_oncall__escalat_f748a6_idx'),
),
migrations.AddIndex(
model_name='escalationinstance',
index=models.Index(fields=['triggered_at'], name='sla_oncall__trigger_a8b2b2_idx'),
),
]