-
Notifications
You must be signed in to change notification settings - Fork 0
Consolidación de entorno DevBox, mejoras en CPython Builder y documentación integral #106
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
2-Coatl
wants to merge
2
commits into
develop
from
claude/check-agent-status-011CUtU91SoS4ke8mnxfSng4
Closed
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,109 @@ | ||
| # CODEOWNERS para proyecto IACT | ||
| # Referencia: https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners | ||
|
|
||
| # Por defecto, el equipo de backend revisa todos los cambios | ||
| * @2-Coatl/backend-team | ||
|
|
||
| # Configuracion y CI/CD | ||
| /.github/ @2-Coatl/devops-team | ||
| /scripts/ @2-Coatl/devops-team | ||
| /Vagrantfile @2-Coatl/devops-team | ||
| /.devcontainer/ @2-Coatl/devops-team | ||
|
|
||
| # Backend - Django | ||
| /api/ @2-Coatl/backend-team | ||
|
|
||
| # Modelos y Migraciones - Requiere revision especial | ||
| /api/callcentersite/callcentersite/apps/*/models.py @2-Coatl/backend-team @2-Coatl/dba-team | ||
| /api/callcentersite/callcentersite/apps/*/migrations/ @2-Coatl/backend-team @2-Coatl/dba-team | ||
|
|
||
| # Sistema de Permisos - Seguridad critica | ||
| /api/callcentersite/callcentersite/apps/permissions/ @2-Coatl/backend-team @2-Coatl/security-team | ||
| /docs/backend/permisos/ @2-Coatl/backend-team @2-Coatl/security-team | ||
| /docs/adr/ADR-012*.md @2-Coatl/backend-team @2-Coatl/security-team | ||
|
|
||
| # Modulos Operativos (Prioridad 3) | ||
| /api/callcentersite/callcentersite/apps/llamadas/ @2-Coatl/backend-team @2-Coatl/operations-team | ||
| /api/callcentersite/callcentersite/apps/tickets/ @2-Coatl/backend-team @2-Coatl/support-team | ||
| /api/callcentersite/callcentersite/apps/clientes/ @2-Coatl/backend-team @2-Coatl/operations-team | ||
| /api/callcentersite/callcentersite/apps/metricas/ @2-Coatl/backend-team @2-Coatl/analytics-team | ||
| /api/callcentersite/callcentersite/apps/reportes/ @2-Coatl/backend-team @2-Coatl/analytics-team | ||
| /api/callcentersite/callcentersite/apps/alertas/ @2-Coatl/backend-team @2-Coatl/operations-team | ||
|
|
||
| # Modulos de Gestion (Prioridad 4) | ||
| /api/callcentersite/callcentersite/apps/equipos/ @2-Coatl/backend-team @2-Coatl/management-team | ||
| /api/callcentersite/callcentersite/apps/horarios/ @2-Coatl/backend-team @2-Coatl/management-team | ||
| /api/callcentersite/callcentersite/apps/evaluaciones/ @2-Coatl/backend-team @2-Coatl/quality-team | ||
| /api/callcentersite/callcentersite/apps/audit/ @2-Coatl/backend-team @2-Coatl/security-team | ||
|
|
||
| # Modulos Financieros (Prioridad 5) - Revision critica | ||
| /api/callcentersite/callcentersite/apps/pagos/ @2-Coatl/backend-team @2-Coatl/finance-team @2-Coatl/security-team | ||
| /api/callcentersite/callcentersite/apps/facturas/ @2-Coatl/backend-team @2-Coatl/finance-team | ||
| /api/callcentersite/callcentersite/apps/cobranza/ @2-Coatl/backend-team @2-Coatl/finance-team | ||
|
|
||
| # Modulos Estrategicos (Prioridad 6) - Solo directores | ||
| /api/callcentersite/callcentersite/apps/presupuestos/ @2-Coatl/backend-team @2-Coatl/executive-team | ||
| /api/callcentersite/callcentersite/apps/politicas/ @2-Coatl/backend-team @2-Coatl/executive-team | ||
|
|
||
| # Frontend - React | ||
| /ui/ @2-Coatl/frontend-team | ||
|
|
||
| # Componentes compartidos | ||
| /ui/src/components/ @2-Coatl/frontend-team | ||
| /ui/src/state/ @2-Coatl/frontend-team | ||
|
|
||
| # Modulos frontend por funcionalidad | ||
| /ui/src/modules/permissions/ @2-Coatl/frontend-team @2-Coatl/security-team | ||
| /ui/src/modules/llamadas/ @2-Coatl/frontend-team @2-Coatl/operations-team | ||
| /ui/src/modules/tickets/ @2-Coatl/frontend-team @2-Coatl/support-team | ||
| /ui/src/modules/clientes/ @2-Coatl/frontend-team @2-Coatl/operations-team | ||
| /ui/src/modules/metricas/ @2-Coatl/frontend-team @2-Coatl/analytics-team | ||
| /ui/src/modules/reportes/ @2-Coatl/frontend-team @2-Coatl/analytics-team | ||
|
|
||
| # Mock data para desarrollo | ||
| /ui/src/mocks/ @2-Coatl/frontend-team @2-Coatl/qa-team | ||
|
|
||
| # Documentacion | ||
| /docs/ @2-Coatl/documentation-team | ||
|
|
||
| # ADRs - Decisiones arquitectonicas | ||
| /docs/adr/ @2-Coatl/backend-team @2-Coatl/frontend-team @2-Coatl/architecture-team | ||
|
|
||
| # Documentacion backend | ||
| /docs/backend/ @2-Coatl/backend-team @2-Coatl/documentation-team | ||
|
|
||
| # Documentacion frontend | ||
| /docs/frontend/ @2-Coatl/frontend-team @2-Coatl/documentation-team | ||
|
|
||
| # Guias operativas | ||
| /docs/guias/ @2-Coatl/devops-team @2-Coatl/documentation-team | ||
|
|
||
| # Metricas DORA | ||
| /dora_metrics/ @2-Coatl/devops-team | ||
| /docs/backend/devops/metricas-dora.md @2-Coatl/devops-team | ||
|
|
||
| # Tests - QA debe revisar | ||
| /api/**/tests/ @2-Coatl/backend-team @2-Coatl/qa-team | ||
| /ui/**/*.test.* @2-Coatl/frontend-team @2-Coatl/qa-team | ||
| /ui/**/*.spec.* @2-Coatl/frontend-team @2-Coatl/qa-team | ||
|
|
||
| # Scripts de validacion - DevOps + Security | ||
| /scripts/check_no_emojis.py @2-Coatl/devops-team | ||
| /scripts/validate_critical_restrictions.sh @2-Coatl/devops-team @2-Coatl/security-team | ||
|
|
||
| # Configuracion sensible - Multiples equipos | ||
| /api/callcentersite/callcentersite/settings/ @2-Coatl/backend-team @2-Coatl/devops-team @2-Coatl/security-team | ||
|
|
||
| # Base de datos - DBA debe aprobar | ||
| /api/callcentersite/callcentersite/database_router.py @2-Coatl/backend-team @2-Coatl/dba-team | ||
|
|
||
| # IVR Legacy - Protegido, solo lectura | ||
| /api/callcentersite/callcentersite/apps/ivr_legacy/ @2-Coatl/backend-team @2-Coatl/dba-team @2-Coatl/legacy-team | ||
|
|
||
| # README y archivos raiz | ||
| /README.md @2-Coatl/documentation-team | ||
| /CONTRIBUTING.md @2-Coatl/documentation-team | ||
| /LICENSE @2-Coatl/legal-team | ||
|
|
||
| # Este archivo | ||
| /CODEOWNERS @2-Coatl/architecture-team @2-Coatl/devops-team |
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| """Django app configuration para Llamadas.""" | ||
|
|
||
| from django.apps import AppConfig | ||
|
|
||
|
|
||
| class LlamadasConfig(AppConfig): | ||
| """Configuracion de la app Llamadas.""" | ||
|
|
||
| default_auto_field = 'django.db.models.BigAutoField' | ||
| name = 'callcentersite.apps.llamadas' | ||
| verbose_name = 'Llamadas' |
Empty file.
147 changes: 147 additions & 0 deletions
147
api/callcentersite/callcentersite/apps/llamadas/models.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,147 @@ | ||
| """ | ||
| Modelos para gestión de Llamadas. | ||
|
|
||
| Sistema de Permisos Granular - Prioridad 3: Módulo Operativo Llamadas | ||
| REF: ADR-012-sistema-permisos-sin-roles-jerarquicos.md | ||
| """ | ||
|
|
||
| from django.db import models | ||
| from django.contrib.auth import get_user_model | ||
| from django.utils import timezone | ||
| import uuid | ||
|
|
||
|
|
||
| User = get_user_model() | ||
|
|
||
|
|
||
| class EstadoLlamada(models.Model): | ||
| """Estados posibles de una llamada.""" | ||
|
|
||
| codigo = models.CharField(max_length=50, unique=True, help_text='Codigo unico del estado') | ||
| nombre = models.CharField(max_length=100, help_text='Nombre del estado') | ||
| descripcion = models.TextField(blank=True, help_text='Descripcion del estado') | ||
| es_final = models.BooleanField(default=False, help_text='Si es un estado final') | ||
| activo = models.BooleanField(default=True, help_text='Si esta activo') | ||
| created_at = models.DateTimeField(auto_now_add=True) | ||
|
|
||
| class Meta: | ||
| db_table = 'llamadas_estados' | ||
| verbose_name = 'Estado de Llamada' | ||
| verbose_name_plural = 'Estados de Llamadas' | ||
| ordering = ['nombre'] | ||
|
|
||
| def __str__(self): | ||
| return self.nombre | ||
|
|
||
|
|
||
| class TipoLlamada(models.Model): | ||
| """Tipos de llamadas.""" | ||
|
|
||
| codigo = models.CharField(max_length=50, unique=True, help_text='Codigo unico del tipo') | ||
| nombre = models.CharField(max_length=100, help_text='Nombre del tipo') | ||
| descripcion = models.TextField(blank=True, help_text='Descripcion del tipo') | ||
| activo = models.BooleanField(default=True, help_text='Si esta activo') | ||
| created_at = models.DateTimeField(auto_now_add=True) | ||
|
|
||
| class Meta: | ||
| db_table = 'llamadas_tipos' | ||
| verbose_name = 'Tipo de Llamada' | ||
| verbose_name_plural = 'Tipos de Llamadas' | ||
| ordering = ['nombre'] | ||
|
|
||
| def __str__(self): | ||
| return self.nombre | ||
|
|
||
|
|
||
| class Llamada(models.Model): | ||
| """Registro de llamadas telefónicas.""" | ||
|
|
||
| codigo = models.CharField(max_length=50, unique=True, editable=False, help_text='Codigo unico generado') | ||
| numero_telefono = models.CharField(max_length=20, help_text='Numero telefonico') | ||
| tipo = models.ForeignKey(TipoLlamada, on_delete=models.PROTECT, related_name='llamadas') | ||
| estado = models.ForeignKey(EstadoLlamada, on_delete=models.PROTECT, related_name='llamadas') | ||
| agente = models.ForeignKey(User, on_delete=models.PROTECT, related_name='llamadas_atendidas') | ||
|
|
||
| # Informacion del cliente | ||
| cliente_nombre = models.CharField(max_length=200, blank=True, null=True) | ||
| cliente_email = models.EmailField(blank=True, null=True) | ||
| cliente_id = models.IntegerField(blank=True, null=True, help_text='ID del cliente si existe') | ||
|
|
||
| # Fechas y tiempos | ||
| fecha_inicio = models.DateTimeField(default=timezone.now) | ||
| fecha_fin = models.DateTimeField(blank=True, null=True) | ||
|
|
||
| # Metadata | ||
| metadata = models.JSONField(default=dict, blank=True, help_text='Datos adicionales JSON') | ||
| notas = models.TextField(blank=True, help_text='Notas de la llamada') | ||
|
|
||
| created_at = models.DateTimeField(auto_now_add=True) | ||
| updated_at = models.DateTimeField(auto_now=True) | ||
|
|
||
| class Meta: | ||
| db_table = 'llamadas' | ||
| verbose_name = 'Llamada' | ||
| verbose_name_plural = 'Llamadas' | ||
| ordering = ['-fecha_inicio'] | ||
| indexes = [ | ||
| models.Index(fields=['numero_telefono']), | ||
| models.Index(fields=['agente', 'fecha_inicio']), | ||
| models.Index(fields=['estado']), | ||
| models.Index(fields=['fecha_inicio']), | ||
| ] | ||
|
|
||
| def save(self, *args, **kwargs): | ||
| """Generar codigo unico al crear.""" | ||
| if not self.codigo: | ||
| self.codigo = f"CALL-{uuid.uuid4().hex[:12].upper()}" | ||
| super().save(*args, **kwargs) | ||
|
|
||
| def calcular_duracion(self): | ||
| """Calcular duracion de la llamada en segundos.""" | ||
| if self.fecha_fin: | ||
| delta = self.fecha_fin - self.fecha_inicio | ||
| return int(delta.total_seconds()) | ||
| return None | ||
|
|
||
| def __str__(self): | ||
| return f"{self.codigo} - {self.numero_telefono}" | ||
|
|
||
|
|
||
| class LlamadaTranscripcion(models.Model): | ||
| """Transcripción de llamadas.""" | ||
|
|
||
| llamada = models.ForeignKey(Llamada, on_delete=models.CASCADE, related_name='transcripciones') | ||
| texto = models.TextField(help_text='Texto transcrito') | ||
| timestamp_inicio = models.IntegerField(help_text='Segundo de inicio en la grabacion') | ||
| timestamp_fin = models.IntegerField(help_text='Segundo de fin en la grabacion') | ||
| hablante = models.CharField(max_length=50, help_text='Identificador del hablante (agente/cliente)') | ||
| confianza = models.FloatField(blank=True, null=True, help_text='Nivel de confianza de la transcripcion') | ||
| created_at = models.DateTimeField(auto_now_add=True) | ||
|
|
||
| class Meta: | ||
| db_table = 'llamadas_transcripciones' | ||
| verbose_name = 'Transcripcion de Llamada' | ||
| verbose_name_plural = 'Transcripciones de Llamadas' | ||
| ordering = ['llamada', 'timestamp_inicio'] | ||
|
|
||
| def __str__(self): | ||
| return f"Transcripcion {self.llamada.codigo} - {self.hablante}" | ||
|
|
||
|
|
||
| class LlamadaGrabacion(models.Model): | ||
| """Grabaciones de llamadas.""" | ||
|
|
||
| llamada = models.OneToOneField(Llamada, on_delete=models.CASCADE, related_name='grabacion') | ||
| archivo_url = models.URLField(max_length=500, help_text='URL del archivo de grabacion') | ||
| formato = models.CharField(max_length=10, help_text='Formato del audio (mp3, wav, etc)') | ||
| duracion_segundos = models.IntegerField(help_text='Duracion en segundos') | ||
| tamano_bytes = models.BigIntegerField(blank=True, null=True, help_text='Tamano del archivo en bytes') | ||
| created_at = models.DateTimeField(auto_now_add=True) | ||
|
|
||
| class Meta: | ||
| db_table = 'llamadas_grabaciones' | ||
| verbose_name = 'Grabacion de Llamada' | ||
| verbose_name_plural = 'Grabaciones de Llamadas' | ||
|
|
||
| def __str__(self): | ||
| return f"Grabacion {self.llamada.codigo}" | ||
80 changes: 80 additions & 0 deletions
80
api/callcentersite/callcentersite/apps/llamadas/serializers.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,80 @@ | ||
| """ | ||
| Serializers para Llamadas. | ||
|
|
||
| Sistema de Permisos Granular - Prioridad 3: Módulo Operativo Llamadas | ||
| """ | ||
|
|
||
| from rest_framework import serializers | ||
| from callcentersite.apps.llamadas.models import ( | ||
| EstadoLlamada, | ||
| TipoLlamada, | ||
| Llamada, | ||
| LlamadaTranscripcion, | ||
| LlamadaGrabacion, | ||
| ) | ||
|
|
||
|
|
||
| class EstadoLlamadaSerializer(serializers.ModelSerializer): | ||
| """Serializer para EstadoLlamada.""" | ||
|
|
||
| class Meta: | ||
| model = EstadoLlamada | ||
| fields = ['id', 'codigo', 'nombre', 'descripcion', 'es_final', 'activo', 'created_at'] | ||
| read_only_fields = ['id', 'created_at'] | ||
|
|
||
|
|
||
| class TipoLlamadaSerializer(serializers.ModelSerializer): | ||
| """Serializer para TipoLlamada.""" | ||
|
|
||
| class Meta: | ||
| model = TipoLlamada | ||
| fields = ['id', 'codigo', 'nombre', 'descripcion', 'activo', 'created_at'] | ||
| read_only_fields = ['id', 'created_at'] | ||
|
|
||
|
|
||
| class LlamadaSerializer(serializers.ModelSerializer): | ||
| """Serializer para Llamada.""" | ||
|
|
||
| duracion = serializers.SerializerMethodField() | ||
| agente_username = serializers.CharField(source='agente.username', read_only=True) | ||
| estado_nombre = serializers.CharField(source='estado.nombre', read_only=True) | ||
| tipo_nombre = serializers.CharField(source='tipo.nombre', read_only=True) | ||
|
|
||
| class Meta: | ||
| model = Llamada | ||
| fields = [ | ||
| 'id', 'codigo', 'numero_telefono', 'tipo', 'estado', 'agente', | ||
| 'cliente_nombre', 'cliente_email', 'cliente_id', | ||
| 'fecha_inicio', 'fecha_fin', 'metadata', 'notas', | ||
| 'created_at', 'updated_at', | ||
| 'duracion', 'agente_username', 'estado_nombre', 'tipo_nombre' | ||
| ] | ||
| read_only_fields = ['id', 'codigo', 'created_at', 'updated_at'] | ||
|
|
||
| def get_duracion(self, obj): | ||
| """Obtener duracion calculada.""" | ||
| return obj.calcular_duracion() | ||
|
|
||
|
|
||
| class LlamadaTranscripcionSerializer(serializers.ModelSerializer): | ||
| """Serializer para LlamadaTranscripcion.""" | ||
|
|
||
| class Meta: | ||
| model = LlamadaTranscripcion | ||
| fields = [ | ||
| 'id', 'llamada', 'texto', 'timestamp_inicio', 'timestamp_fin', | ||
| 'hablante', 'confianza', 'created_at' | ||
| ] | ||
| read_only_fields = ['id', 'created_at'] | ||
|
|
||
|
|
||
| class LlamadaGrabacionSerializer(serializers.ModelSerializer): | ||
| """Serializer para LlamadaGrabacion.""" | ||
|
|
||
| class Meta: | ||
| model = LlamadaGrabacion | ||
| fields = [ | ||
| 'id', 'llamada', 'archivo_url', 'formato', 'duracion_segundos', | ||
| 'tamano_bytes', 'created_at' | ||
| ] | ||
| read_only_fields = ['id', 'created_at'] |
Empty file.
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The new Llamadas app introduces multiple models (
EstadoLlamada,TipoLlamada,Llamada, etc.) yetcallcentersite/apps/llamadas/migrations/still contains only an empty__init__.py. Because no migration was added, Django will never create the underlying tables and any view, service or test touching these models will fail withProgrammingError: relation "llamadas" does not exist. Please generate and commit the initial migration for this app.Useful? React with 👍 / 👎.