resource-portal / backend /models.py
Gowrisankar
Align Projects planner with Runn: thin timeline, phases, and row menus.
872046b
from datetime import date, datetime
from sqlalchemy import (
Boolean,
Column,
Date,
DateTime,
Float,
ForeignKey,
Integer,
String,
Table,
Text,
UniqueConstraint,
)
from sqlalchemy.orm import Mapped, mapped_column, relationship
from database import Base
person_tags = Table(
"person_tags",
Base.metadata,
Column("person_id", ForeignKey("people.id", ondelete="CASCADE"), primary_key=True),
Column("tag_id", ForeignKey("tags.id", ondelete="CASCADE"), primary_key=True),
)
project_tags = Table(
"project_tags",
Base.metadata,
Column("project_id", ForeignKey("projects.id", ondelete="CASCADE"), primary_key=True),
Column("tag_id", ForeignKey("tags.id", ondelete="CASCADE"), primary_key=True),
)
class User(Base):
__tablename__ = "users"
id: Mapped[int] = mapped_column(Integer, primary_key=True, index=True)
username: Mapped[str] = mapped_column(String, unique=True, nullable=False, index=True)
password_hash: Mapped[str] = mapped_column(String, nullable=False)
role: Mapped[str] = mapped_column(String, default="viewer", nullable=False)
created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow, nullable=False)
class Role(Base):
__tablename__ = "roles"
id: Mapped[int] = mapped_column(Integer, primary_key=True, index=True)
name: Mapped[str] = mapped_column(String, unique=True, nullable=False)
created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow, nullable=False)
people: Mapped[list["Person"]] = relationship(back_populates="role")
class Team(Base):
__tablename__ = "teams"
id: Mapped[int] = mapped_column(Integer, primary_key=True, index=True)
name: Mapped[str] = mapped_column(String, unique=True, nullable=False)
created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow, nullable=False)
people: Mapped[list["Person"]] = relationship(back_populates="team")
class Tag(Base):
__tablename__ = "tags"
id: Mapped[int] = mapped_column(Integer, primary_key=True, index=True)
name: Mapped[str] = mapped_column(String, unique=True, nullable=False)
color: Mapped[str] = mapped_column(String, default="#7c3aed", nullable=False)
created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow, nullable=False)
class PersonSkill(Base):
__tablename__ = "person_skills"
__table_args__ = (UniqueConstraint("person_id", "skill_id", name="uq_person_skill"),)
person_id: Mapped[int] = mapped_column(ForeignKey("people.id"), primary_key=True)
skill_id: Mapped[int] = mapped_column(ForeignKey("skills.id"), primary_key=True)
proficiency: Mapped[str] = mapped_column(String, default="intermediate", nullable=False)
person: Mapped["Person"] = relationship(back_populates="person_skills")
skill: Mapped["Skill"] = relationship(back_populates="person_skills")
class Person(Base):
__tablename__ = "people"
id: Mapped[int] = mapped_column(Integer, primary_key=True, index=True)
name: Mapped[str] = mapped_column(String, nullable=False)
email: Mapped[str] = mapped_column(String, unique=True, nullable=False, index=True)
role_id: Mapped[int] = mapped_column(ForeignKey("roles.id"), nullable=False, index=True)
team_id: Mapped[int | None] = mapped_column(ForeignKey("teams.id"), index=True)
weekly_capacity_hrs: Mapped[float] = mapped_column(Float, default=40.0, nullable=False)
start_date: Mapped[date | None] = mapped_column(Date)
end_date: Mapped[date | None] = mapped_column(Date)
is_active: Mapped[bool] = mapped_column(Boolean, default=True, nullable=False)
avatar_color: Mapped[str] = mapped_column(String, default="#2563eb", nullable=False)
created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow, nullable=False)
role: Mapped[Role] = relationship(back_populates="people", lazy="selectin")
team: Mapped[Team | None] = relationship(back_populates="people", lazy="selectin")
tags: Mapped[list[Tag]] = relationship(secondary=person_tags, lazy="selectin")
person_skills: Mapped[list[PersonSkill]] = relationship(back_populates="person", cascade="all, delete-orphan")
allocations: Mapped[list["Allocation"]] = relationship(back_populates="person")
leaves: Mapped[list["Leave"]] = relationship(back_populates="person")
owned_projects: Mapped[list["Project"]] = relationship(back_populates="owner")
class Skill(Base):
__tablename__ = "skills"
id: Mapped[int] = mapped_column(Integer, primary_key=True, index=True)
name: Mapped[str] = mapped_column(String, unique=True, nullable=False)
category: Mapped[str | None] = mapped_column(String)
person_skills: Mapped[list[PersonSkill]] = relationship(back_populates="skill")
class Project(Base):
__tablename__ = "projects"
id: Mapped[int] = mapped_column(Integer, primary_key=True, index=True)
name: Mapped[str] = mapped_column(String, nullable=False)
description: Mapped[str | None] = mapped_column(Text)
status: Mapped[str] = mapped_column(String, default="planning", nullable=False)
type: Mapped[str] = mapped_column(String, default="other", nullable=False)
start_date: Mapped[date] = mapped_column(Date, nullable=False)
end_date: Mapped[date] = mapped_column(Date, nullable=False)
is_tentative: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False)
is_active: Mapped[bool] = mapped_column(Boolean, default=True, nullable=False)
color: Mapped[str] = mapped_column(String, default="#0ea5e9", nullable=False)
owner_id: Mapped[int | None] = mapped_column(ForeignKey("people.id"))
team_id: Mapped[int | None] = mapped_column(ForeignKey("teams.id"))
created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow, nullable=False)
owner: Mapped[Person | None] = relationship(back_populates="owned_projects")
team: Mapped["Team | None"] = relationship()
milestones: Mapped[list["Milestone"]] = relationship(back_populates="project", cascade="all, delete-orphan")
phases: Mapped[list["ProjectPhase"]] = relationship(back_populates="project", cascade="all, delete-orphan")
allocations: Mapped[list["Allocation"]] = relationship(back_populates="project")
tags: Mapped[list[Tag]] = relationship(secondary=project_tags, lazy="selectin")
class ProjectPhase(Base):
__tablename__ = "project_phases"
id: Mapped[int] = mapped_column(Integer, primary_key=True, index=True)
project_id: Mapped[int] = mapped_column(ForeignKey("projects.id"), nullable=False)
name: Mapped[str] = mapped_column(String, nullable=False)
start_date: Mapped[date] = mapped_column(Date, nullable=False)
end_date: Mapped[date] = mapped_column(Date, nullable=False)
color: Mapped[str] = mapped_column(String, default="#14b8a6", nullable=False)
project: Mapped[Project] = relationship(back_populates="phases")
class Milestone(Base):
__tablename__ = "milestones"
id: Mapped[int] = mapped_column(Integer, primary_key=True, index=True)
project_id: Mapped[int] = mapped_column(ForeignKey("projects.id"), nullable=False)
name: Mapped[str] = mapped_column(String, nullable=False)
due_date: Mapped[date] = mapped_column(Date, nullable=False)
is_completed: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False)
project: Mapped[Project] = relationship(back_populates="milestones")
class Allocation(Base):
__tablename__ = "allocations"
id: Mapped[int] = mapped_column(Integer, primary_key=True, index=True)
person_id: Mapped[int] = mapped_column(ForeignKey("people.id"), nullable=False)
project_id: Mapped[int] = mapped_column(ForeignKey("projects.id"), nullable=False)
start_date: Mapped[date] = mapped_column(Date, nullable=False)
end_date: Mapped[date] = mapped_column(Date, nullable=False)
allocation_pct: Mapped[float] = mapped_column(Float, nullable=False)
note: Mapped[str | None] = mapped_column(Text)
created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow, nullable=False)
person: Mapped[Person] = relationship(back_populates="allocations")
project: Mapped[Project] = relationship(back_populates="allocations")
class Leave(Base):
__tablename__ = "leaves"
id: Mapped[int] = mapped_column(Integer, primary_key=True, index=True)
person_id: Mapped[int | None] = mapped_column(ForeignKey("people.id"))
leave_type: Mapped[str] = mapped_column(String, nullable=False)
start_date: Mapped[date] = mapped_column(Date, nullable=False)
end_date: Mapped[date] = mapped_column(Date, nullable=False)
note: Mapped[str | None] = mapped_column(Text)
approved: Mapped[bool] = mapped_column(Boolean, default=True, nullable=False)
person: Mapped[Person | None] = relationship(back_populates="leaves")