Amal Nimmy Lal
feat : updated pages
698b2c1
"""SQLAlchemy models for Project Memory."""
from sqlalchemy import Column, String, DateTime, ForeignKey, Text, Enum, JSON, Boolean
from sqlalchemy.orm import relationship
from datetime import datetime
import uuid
import enum
import random
from app.database import Base
# Special user ID for AI Agent
AI_AGENT_USER_ID = "ai-agent"
def generate_uuid() -> str:
"""Generate a new UUID string."""
return str(uuid.uuid4())
def generate_user_id(first_name: str) -> str:
"""Generate user ID: first 3 letters of firstname + 4 random digits.
Example: 'Amal' -> 'ama1234'
"""
prefix = first_name[:3].lower()
suffix = ''.join([str(random.randint(0, 9)) for _ in range(4)])
return f"{prefix}{suffix}"
class ActorType(str, enum.Enum):
"""Who performed the action."""
human = "human"
agent = "agent"
class ActionType(str, enum.Enum):
"""Type of action recorded."""
task_completed = "task_completed"
doc_generated = "doc_generated"
query_answered = "query_answered"
class TaskStatus(str, enum.Enum):
"""Task status states."""
todo = "todo"
in_progress = "in_progress"
done = "done"
class User(Base):
"""User account."""
__tablename__ = "users"
id = Column(String, primary_key=True) # Generated as first_name[:3] + 4 random digits
first_name = Column(String, nullable=False)
last_name = Column(String, nullable=False)
avatar_url = Column(String, nullable=True)
created_at = Column(DateTime, default=datetime.utcnow)
# Relationships
memberships = relationship("ProjectMembership", back_populates="user")
created_projects = relationship("Project", back_populates="creator")
log_entries = relationship("LogEntry", back_populates="user")
@property
def name(self) -> str:
"""Full name for backward compatibility."""
return f"{self.first_name} {self.last_name}"
class Project(Base):
"""Project that contains tasks and memory.
Option A: project name is also the stable project ID. We persist the ID explicitly
from the tools layer (create_project uses the provided name as id).
"""
__tablename__ = "projects"
# ID is provided by callers (equal to the project name); no UUID default
id = Column(String, primary_key=True)
name = Column(String, nullable=False)
description = Column(Text, nullable=True)
created_at = Column(DateTime, default=datetime.utcnow)
created_by = Column(String, ForeignKey("users.id"), nullable=True)
agent_enabled = Column(Boolean, default=False) # Whether AI agent is enabled for this project
# Relationships
creator = relationship("User", back_populates="created_projects")
memberships = relationship("ProjectMembership", back_populates="project")
tasks = relationship("Task", back_populates="project")
log_entries = relationship("LogEntry", back_populates="project")
class ProjectMembership(Base):
"""Association between users and projects."""
__tablename__ = "project_memberships"
id = Column(String, primary_key=True, default=generate_uuid)
project_id = Column(String, ForeignKey("projects.id"), nullable=False)
user_id = Column(String, ForeignKey("users.id"), nullable=False)
role = Column(String, default="member") # "owner" or "member"
joined_at = Column(DateTime, default=datetime.utcnow)
# Relationships
project = relationship("Project", back_populates="memberships")
user = relationship("User", back_populates="memberships")
class Task(Base):
"""Task within a project."""
__tablename__ = "tasks"
id = Column(String, primary_key=True, default=generate_uuid)
project_id = Column(String, ForeignKey("projects.id"), nullable=False)
title = Column(String, nullable=False)
description = Column(Text, nullable=True)
status = Column(Enum(TaskStatus), default=TaskStatus.todo)
assigned_to = Column(String, nullable=True) # userId or "agent"
working_by = Column(String, nullable=True) # User ID currently working on this task
created_at = Column(DateTime, default=datetime.utcnow)
completed_at = Column(DateTime, nullable=True)
# Relationships
project = relationship("Project", back_populates="tasks")
log_entries = relationship("LogEntry", back_populates="task")
class LogEntry(Base):
"""
The core of project memory.
Records what was done, by whom, and stores LLM-generated documentation.
"""
__tablename__ = "log_entries"
id = Column(String, primary_key=True, default=generate_uuid)
project_id = Column(String, ForeignKey("projects.id"), nullable=False)
task_id = Column(String, ForeignKey("tasks.id"), nullable=True)
user_id = Column(String, ForeignKey("users.id"), nullable=True)
actor_type = Column(Enum(ActorType), nullable=False)
action_type = Column(Enum(ActionType), nullable=False)
raw_input = Column(Text, nullable=False) # What user typed
code_snippet = Column(Text, nullable=True) # Optional code
generated_doc = Column(Text, nullable=False) # LLM-generated documentation
tags = Column(JSON, default=list) # Extracted tags
created_at = Column(DateTime, default=datetime.utcnow)
# Relationships
project = relationship("Project", back_populates="log_entries")
task = relationship("Task", back_populates="log_entries")
user = relationship("User", back_populates="log_entries")