"""Workspace models for VoIdea. Personal workspace (1 per user, free) + Team workspaces (tariff-gated). """ from typing import Optional from sqlalchemy import Boolean, ForeignKey, Integer, String, Text from sqlalchemy.dialects.postgresql import UUID from sqlalchemy.orm import Mapped, mapped_column, relationship from app.core.base import SQLBase, TimestampMixin, UUIDMixin class Workspace(SQLBase, UUIDMixin, TimestampMixin): __tablename__ = "workspaces" name: Mapped[str] = mapped_column( String(255), nullable=False ) type: Mapped[str] = mapped_column( String(20), nullable=False, default="personal", index=True ) owner_id: Mapped[UUID] = mapped_column( UUID(as_uuid=True), ForeignKey("users.id", ondelete="CASCADE"), nullable=False, index=True, ) description: Mapped[Optional[str]] = mapped_column( Text, nullable=True, default="" ) owner = relationship("User", backref="owned_workspaces", lazy="selectin") members = relationship( "WorkspaceMembership", back_populates="workspace", lazy="selectin", cascade="all, delete-orphan", ) class WorkspaceMembership(SQLBase, UUIDMixin, TimestampMixin): __tablename__ = "workspace_memberships" workspace_id: Mapped[UUID] = mapped_column( UUID(as_uuid=True), ForeignKey("workspaces.id", ondelete="CASCADE"), nullable=False, index=True, ) user_id: Mapped[UUID] = mapped_column( UUID(as_uuid=True), ForeignKey("users.id", ondelete="CASCADE"), nullable=False, index=True, ) role: Mapped[str] = mapped_column( String(20), nullable=False, default="member" ) workspace = relationship( "Workspace", back_populates="members", lazy="selectin" ) user = relationship("User", backref="workspace_memberships", lazy="selectin")