Refactor to manager-centric model, add team calendar for all users

Key changes:
- Removed office-centric model (deleted offices.py, office-rules)
- Renamed to team-rules, managers are part of their own team
- Team calendar visible to all (read-only for employees)
- Admins can have a manager assigned
This commit is contained in:
Stefano Manfredi
2025-12-02 13:30:04 +00:00
parent 2ad8ba3424
commit 7168fa4b72
30 changed files with 1016 additions and 910 deletions

View File

@@ -36,4 +36,7 @@ def get_db_session():
def init_db():
"""Create all tables"""
from database.models import Base
print(f"[init_db] Initializing database at {config.DATABASE_URL}")
Base.metadata.create_all(bind=engine)
print(f"[init_db] Tables created: {list(Base.metadata.tables.keys())}")

View File

@@ -17,7 +17,7 @@ class User(Base):
password_hash = Column(Text)
name = Column(Text)
role = Column(Text, nullable=False, default="employee") # admin, manager, employee
office_id = Column(Text, ForeignKey("offices.id"))
manager_id = Column(Text, ForeignKey("users.id")) # Who manages this user (any user can have a manager)
# Manager-specific fields (only relevant for role='manager')
manager_parking_quota = Column(Integer, default=0) # Number of spots this manager controls
@@ -37,51 +37,13 @@ class User(Base):
updated_at = Column(Text)
# Relationships
office = relationship("Office", back_populates="users")
manager = relationship("User", remote_side=[id], backref="managed_users")
presences = relationship("UserPresence", back_populates="user", cascade="all, delete-orphan")
assignments = relationship("DailyParkingAssignment", back_populates="user", foreign_keys="DailyParkingAssignment.user_id")
managed_offices = relationship("OfficeMembership", back_populates="user", cascade="all, delete-orphan")
__table_args__ = (
Index('idx_user_email', 'email'),
Index('idx_user_office', 'office_id'),
)
class Office(Base):
"""Office locations - containers for grouping employees"""
__tablename__ = "offices"
id = Column(Text, primary_key=True)
name = Column(Text, nullable=False)
location = Column(Text)
# Note: parking_spots removed - spots are now managed at manager level
created_at = Column(Text)
updated_at = Column(Text)
# Relationships
users = relationship("User", back_populates="office")
managers = relationship("OfficeMembership", back_populates="office", cascade="all, delete-orphan")
class OfficeMembership(Base):
"""Manager-Office relationship (which managers manage which offices)"""
__tablename__ = "office_memberships"
id = Column(Text, primary_key=True)
user_id = Column(Text, ForeignKey("users.id", ondelete="CASCADE"), nullable=False)
office_id = Column(Text, ForeignKey("offices.id", ondelete="CASCADE"), nullable=False)
created_at = Column(Text)
# Relationships
user = relationship("User", back_populates="managed_offices")
office = relationship("Office", back_populates="managers")
__table_args__ = (
Index('idx_membership_user', 'user_id'),
Index('idx_membership_office', 'office_id'),
Index('idx_membership_unique', 'user_id', 'office_id', unique=True),
Index('idx_user_manager', 'manager_id'),
)
@@ -128,7 +90,7 @@ class DailyParkingAssignment(Base):
class ManagerClosingDay(Base):
"""Specific date closing days for a manager's offices (holidays, special closures)"""
"""Specific date closing days for a manager's parking pool (holidays, special closures)"""
__tablename__ = "manager_closing_days"
id = Column(Text, primary_key=True)
@@ -145,7 +107,7 @@ class ManagerClosingDay(Base):
class ManagerWeeklyClosingDay(Base):
"""Weekly recurring closing days for a manager's offices (e.g., Saturday and Sunday)"""
"""Weekly recurring closing days for a manager's parking pool (e.g., Saturday and Sunday)"""
__tablename__ = "manager_weekly_closing_days"
id = Column(Text, primary_key=True)