Skip to content

feat(models): implementación de esquema de base de datos y entidades SQLAlchemy#4

Merged
Ochoa-Stack merged 4 commits into
developfrom
feature/sqlalchemy-models
Jun 7, 2026
Merged

feat(models): implementación de esquema de base de datos y entidades SQLAlchemy#4
Ochoa-Stack merged 4 commits into
developfrom
feature/sqlalchemy-models

Conversation

@Ochoa-Stack

@Ochoa-Stack Ochoa-Stack commented Jun 7, 2026

Copy link
Copy Markdown
Owner

feature/sqlalchemy-models

Descripción

Se implementa la capa de datos completa mapeando el diagrama Entidad-Relación oficial a modelos de SQLAlchemy. Este bloque establece la estructura base para la interacción con PostgreSQL, asegurando la integridad referencial, la Tercera Forma Normal (3FN) y la delegación de restricciones de negocio al motor de base de datos.

Decisiones técnicas integradas:

  • Entidades Base: Category, City (con server_default='MX'), User (roles restringidos vía CheckConstraint a nivel tabla).
  • Entidades de Primer Nivel: Skill (nombre canónico único), Job (description_hash para rastreo de duplicidad, city_id nulo para vacantes remotas), Backup.
  • Entidades Asociativas y Analíticas: JobSkill (llave primaria compuesta), Alert, TrendSnapshot (UniqueConstraint multicampo para unicidad temporal y geográfica).
  • Exportación: Accesibilidad limpia de todos los modelos a través de app/models/__init__.py.

Tipo de cambio

  • feat
  • fix
  • refactor
  • chore
  • docs
  • test

Cómo probar

  1. Tras el merge, actualizar la rama base localmente: git checkout develop && git pull origin develop
  2. Navegar a la raíz del backend: cd backend
  3. Asegurar que el entorno virtual esté activo y abrir la interfaz interactiva de la aplicación:
    flask --app run shell
  4. Ejecutar la prueba de resolución de dependencias del ORM (no debe retornar ningún error):
    from app.models import User, Job, Skill, TrendSnapshot
  5. Salir del entorno interactivo ejecutando exit().

Checklist

  • Sigue las convenciones de commits del proyecto
  • Las pruebas existentes pasan sin errores
  • Se agregaron pruebas para el nuevo comportamiento (si aplica)
  • No se incluyen archivos .env ni credenciales

Copilot AI review requested due to automatic review settings June 7, 2026 05:08
@Ochoa-Stack Ochoa-Stack merged commit ac3715d into develop Jun 7, 2026
1 check passed
@Ochoa-Stack Ochoa-Stack deleted the feature/sqlalchemy-models branch June 7, 2026 05:10

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Este PR implementa la capa de datos del backend definiendo modelos SQLAlchemy que mapean el esquema ER (entidades principales, tablas asociativas y restricciones) para su uso con PostgreSQL, y centraliza la exportación de modelos desde app.models.

Changes:

  • Se agregan modelos SQLAlchemy para entidades base y de dominio (Category, City, Skill, Job, User, etc.) con relaciones y restricciones (UNIQUE/CHECK/PK compuesta).
  • Se define la tabla asociativa JobSkill con llave primaria compuesta y se agregan entidades analíticas como TrendSnapshot.
  • Se expone un punto de importación único de modelos vía backend/app/models/__init__.py y se hace un ajuste menor de formato.

Reviewed changes

Copilot reviewed 11 out of 11 changed files in this pull request and generated 11 comments.

Show a summary per file
File Description
backend/app/models/user.py Modelo User con constraint de roles y relaciones a alertas/respaldos.
backend/app/models/trend_snapshot.py Modelo analítico TrendSnapshot con unicidad compuesta por skill/ciudad/fecha.
backend/app/models/skill.py Modelo Skill con canonical_name único y relaciones a jobs/alertas/snapshots.
backend/app/models/job.py Modelo Job con salarios, hash de descripción y relación con JobSkill.
backend/app/models/job_skill.py Tabla asociativa JobSkill con PK compuesta (job_id, skill_id).
backend/app/models/city.py Modelo City con default de país y relaciones a jobs/snapshots.
backend/app/models/category.py Modelo Category y relación 1-N a skills.
backend/app/models/backup.py Modelo Backup con constraint de status y FK opcional a usuario.
backend/app/models/alert.py Modelo Alert (tabla user_alerts) con FKs a usuario y skill.
backend/app/models/init.py Export centralizado de todos los modelos (__all__).
backend/app/init.py Ajuste menor de formato (whitespace) en respuesta de health check.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(50), nullable=False, unique=True)

skills = db.relationship('Skill', backref='category', lazy=True) No newline at end of file
Comment on lines +9 to +10
# Establecemos México como default tanto a nivel aplicación como base de datos
country = db.Column(db.String(10), default='MX', server_default='MX', nullable=True)
Comment on lines +14 to +15
jobs = db.relationship('Job', backref='city', lazy=True)
trend_snapshots = db.relationship('TrendSnapshot', backref='city', lazy=True) No newline at end of file
Comment on lines +12 to +14
job_skills = db.relationship('JobSkill', backref='skill', lazy=True)
alerts = db.relationship('Alert', backref='skill', lazy=True)
trend_snapshots = db.relationship('TrendSnapshot', backref='skill', lazy=True) No newline at end of file
email = db.Column(db.String(255), unique=True, nullable=False)
password_hash = db.Column(db.String(255), nullable=False)
role = db.Column(db.String(20), nullable=False)
created_at = db.Column(db.DateTime, default=lambda: datetime.now(timezone.utc))
Comment thread backend/app/models/job.py
Comment on lines +21 to +22
created_at = db.Column(db.DateTime, default=lambda: datetime.now(timezone.utc))
updated_at = db.Column(db.DateTime, default=lambda: datetime.now(timezone.utc), onupdate=lambda: datetime.now(timezone.utc))
Comment thread backend/app/models/job.py
created_at = db.Column(db.DateTime, default=lambda: datetime.now(timezone.utc))
updated_at = db.Column(db.DateTime, default=lambda: datetime.now(timezone.utc), onupdate=lambda: datetime.now(timezone.utc))

job_skills = db.relationship('JobSkill', backref='job', lazy=True) No newline at end of file
skill_id = db.Column(db.Integer, db.ForeignKey('skills.id'), primary_key=True)

confidence_score = db.Column(db.Numeric(4, 3), nullable=False)
created_at = db.Column(db.DateTime, default=lambda: datetime.now(timezone.utc)) No newline at end of file
user_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=True)
filename = db.Column(db.String(255), nullable=False)
storage_url = db.Column(db.String(500), nullable=False)
created_at = db.Column(db.DateTime, default=lambda: datetime.now(timezone.utc))
skill_id = db.Column(db.Integer, db.ForeignKey('skills.id'), nullable=False)
threshold = db.Column(db.Integer, nullable=False)
active = db.Column(db.Boolean, default=True, nullable=False)
created_at = db.Column(db.DateTime, default=lambda: datetime.now(timezone.utc)) No newline at end of file
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants