from __future__ import annotations from datetime import datetime from sqlalchemy import Boolean, DateTime, ForeignKey, String, Text, UniqueConstraint from sqlalchemy.orm import Mapped, mapped_column, relationship from app.db.session import Base class ClientAccount(Base): __tablename__ = "client_accounts" id: Mapped[int] = mapped_column(primary_key=True) tenant_id: Mapped[str] = mapped_column(String(64), default="default") name: Mapped[str] = mapped_column(String(255), unique=True, index=True) client_code: Mapped[str] = mapped_column(String(64), unique=True, index=True) status: Mapped[str] = mapped_column(String(32), default="active") powerbi_workspace: Mapped[str | None] = mapped_column(String(128), nullable=True) notes: Mapped[str | None] = mapped_column(Text, nullable=True) created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow) users: Mapped[list["ClientUser"]] = relationship( back_populates="client_account", cascade="all, delete-orphan", order_by="ClientUser.created_at.desc()", ) features: Mapped[list["ClientFeatureAccess"]] = relationship( back_populates="client_account", cascade="all, delete-orphan", order_by="ClientFeatureAccess.feature_group, ClientFeatureAccess.feature_name", ) audit_events: Mapped[list["ClientAccessAuditEvent"]] = relationship( back_populates="client_account", cascade="all, delete-orphan", order_by="ClientAccessAuditEvent.created_at.desc()", ) class ClientUser(Base): __tablename__ = "client_users" __table_args__ = (UniqueConstraint("client_account_id", "email", name="uq_client_user_email"),) id: Mapped[int] = mapped_column(primary_key=True) tenant_id: Mapped[str] = mapped_column(String(64), default="default") client_account_id: Mapped[int] = mapped_column(ForeignKey("client_accounts.id"), index=True) full_name: Mapped[str] = mapped_column(String(255)) email: Mapped[str] = mapped_column(String(255)) role: Mapped[str] = mapped_column(String(64), default="viewer") status: Mapped[str] = mapped_column(String(32), default="invited") is_new_user: Mapped[bool] = mapped_column(Boolean, default=True) last_login_at: Mapped[datetime | None] = mapped_column(DateTime, nullable=True) created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow) client_account: Mapped[ClientAccount] = relationship(back_populates="users") module_permissions: Mapped[list["ClientUserModulePermission"]] = relationship( back_populates="client_user", cascade="all, delete-orphan", order_by="ClientUserModulePermission.module_key", ) class ClientFeatureAccess(Base): __tablename__ = "client_feature_access" __table_args__ = (UniqueConstraint("client_account_id", "feature_key", name="uq_client_feature"),) id: Mapped[int] = mapped_column(primary_key=True) tenant_id: Mapped[str] = mapped_column(String(64), default="default") client_account_id: Mapped[int] = mapped_column(ForeignKey("client_accounts.id"), index=True) feature_key: Mapped[str] = mapped_column(String(64)) feature_name: Mapped[str] = mapped_column(String(255)) feature_group: Mapped[str] = mapped_column(String(64), default="operations") description: Mapped[str | None] = mapped_column(Text, nullable=True) enabled: Mapped[bool] = mapped_column(Boolean, default=False) updated_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow) client_account: Mapped[ClientAccount] = relationship(back_populates="features") class ClientUserModulePermission(Base): __tablename__ = "client_user_module_permissions" __table_args__ = (UniqueConstraint("client_user_id", "module_key", name="uq_client_user_module_permission"),) id: Mapped[int] = mapped_column(primary_key=True) tenant_id: Mapped[str] = mapped_column(String(64), default="default") client_account_id: Mapped[int] = mapped_column(ForeignKey("client_accounts.id"), index=True) client_user_id: Mapped[int] = mapped_column(ForeignKey("client_users.id"), index=True) module_key: Mapped[str] = mapped_column(String(64)) access_level: Mapped[str] = mapped_column(String(32), default="none") updated_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow) client_user: Mapped[ClientUser] = relationship(back_populates="module_permissions") class ClientAccessAuditEvent(Base): __tablename__ = "client_access_audit_events" id: Mapped[int] = mapped_column(primary_key=True) tenant_id: Mapped[str] = mapped_column(String(64), default="default") client_account_id: Mapped[int] = mapped_column(ForeignKey("client_accounts.id"), index=True) actor_type: Mapped[str] = mapped_column(String(32), default="client") actor_name: Mapped[str] = mapped_column(String(255)) actor_email: Mapped[str] = mapped_column(String(255)) actor_role: Mapped[str] = mapped_column(String(64)) action: Mapped[str] = mapped_column(String(128)) target_type: Mapped[str] = mapped_column(String(64)) target_id: Mapped[int | None] = mapped_column(nullable=True) module_key: Mapped[str | None] = mapped_column(String(64), nullable=True) summary: Mapped[str] = mapped_column(Text) created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow) client_account: Mapped[ClientAccount] = relationship(back_populates="audit_events")