Files
plantillas-proyectos/backend/api/v1/modules/a76/tenants/models.py
acazares 52b8fcd434 feat: Implement multi-tenancy support in middleware and security layers
- Enhanced TenantMiddleware to validate tenant information from JWT tokens.
- Added LicenseValidationMiddleware to check tenant licenses before processing requests.
- Updated security utilities to extract tenant information from tokens and validate company access.
- Introduced CompanyStore to manage active company state and handle company switching in the frontend.
- Modified API routes to include company_id in requests for better resource management.
- Improved logging and error handling throughout the middleware and API layers.
- Updated frontend components to reflect changes in company management and selection.
- Added new API route for fetching user's companies with proper authentication handling.
2025-11-11 14:15:31 -06:00

70 lines
2.2 KiB
Python

"""
Modelos ORM para gestión de tenants
"""
from sqlalchemy import Column, Integer, String, DateTime, Boolean, Text, Enum as SQLEnum
from sqlalchemy.sql import func
from sqlalchemy.orm import Mapped, mapped_column, relationship
from datetime import datetime
from typing import List, TYPE_CHECKING
from core.database import Base
import enum
if TYPE_CHECKING:
from api.v1.modules.a76.user_tenant.models import UserTenant
class TenantType(enum.Enum):
"""Tipo de tenant según tamaño y necesidades"""
SHARED = "shared" # BD compartida
DEDICATED = "dedicated" # BD dedicada
class Tenant(Base):
"""
Modelo de Tenant - Cliente/Organización en el sistema
Cada tenant puede tener BD compartida o dedicada
"""
__tablename__ = "tenants"
__table_args__ = {"schema": "a76"}
id = Column(Integer, primary_key=True, index=True)
name = Column(String(255), nullable=False, index=True)
slug = Column(String(100), unique=True, nullable=False, index=True)
# Tipo de tenant (compartido o dedicado)
type = Column(SQLEnum(TenantType), default=TenantType.SHARED, nullable=False)
# Keycloak realm asociado
keycloak_realm = Column(String(255), nullable=False)
# Configuración de BD dedicada (JSON string o NULL si usa BD compartida)
db_config = Column(Text, nullable=True) # JSON: {host, port, name, user, password}
# Información de contacto
contact_name = Column(String(255))
contact_email = Column(String(255))
contact_phone = Column(String(50))
# Estado
is_active = Column(Boolean, default=True, nullable=False)
# Timestamps
created_at: Mapped[datetime] = mapped_column(
DateTime, nullable=False, default=func.now()
)
updated_at: Mapped[datetime] = mapped_column(
DateTime, nullable=False, default=func.now(), onupdate=func.now()
)
deleted_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True)
# Relación con UserTenant
user_relations: Mapped[List["UserTenant"]] = relationship(
"UserTenant", back_populates="tenant"
)
def __repr__(self):
return f"<Tenant(id={self.id}, name={self.name}, type={self.type.value})>"