AI Development Team
feat: Add Google/Facebook OAuth, profile page, and responsive UI
4004da2
"""
Database models for Neon Postgres
"""
from sqlalchemy import Column, String, Text, DateTime, ForeignKey, UniqueConstraint, Index
from sqlalchemy.dialects.postgresql import UUID
from sqlalchemy.sql import func
import uuid
from database.db import Base
class User(Base):
__tablename__ = "users"
id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
email = Column(String(255), unique=True, nullable=False, index=True)
password_hash = Column(String(255), nullable=True) # Nullable for OAuth users
full_name = Column(String(255), nullable=True)
software_background = Column(Text, nullable=True)
hardware_background = Column(Text, nullable=True)
experience_level = Column(String(50), nullable=True, default="Intermediate")
# OAuth fields
oauth_provider = Column(String(50), nullable=True) # 'google', 'facebook', or None
oauth_id = Column(String(255), nullable=True) # Provider's user ID
profile_picture = Column(String(500), nullable=True) # Profile picture URL from OAuth
created_at = Column(DateTime(timezone=True), server_default=func.now())
updated_at = Column(DateTime(timezone=True), onupdate=func.now())
# Index for OAuth lookup
__table_args__ = (
Index('idx_user_oauth', 'oauth_provider', 'oauth_id'),
)
class Personalization(Base):
__tablename__ = "personalizations"
id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
user_id = Column(UUID(as_uuid=True), ForeignKey("users.id", ondelete="CASCADE"), nullable=False, index=True)
chapter_id = Column(String(255), nullable=False, index=True)
personalized_content = Column(Text, nullable=False)
created_at = Column(DateTime(timezone=True), server_default=func.now())
updated_at = Column(DateTime(timezone=True), onupdate=func.now())
# Composite unique constraint: one personalization per user per chapter
__table_args__ = (
UniqueConstraint('user_id', 'chapter_id', name='uq_user_chapter'),
)
class Translation(Base):
__tablename__ = "translations"
id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
chapter_id = Column(String(255), nullable=False, index=True)
content_hash = Column(String(64), nullable=False, index=True)
source_language = Column(String(10), nullable=False, default="english")
target_language = Column(String(10), nullable=False, index=True)
original_content = Column(Text, nullable=False)
translated_content = Column(Text, nullable=False)
user_id = Column(UUID(as_uuid=True), ForeignKey("users.id", ondelete="CASCADE"), nullable=False, index=True)
created_at = Column(DateTime(timezone=True), server_default=func.now())
updated_at = Column(DateTime(timezone=True), onupdate=func.now())
# Composite unique constraint: one translation per (chapter_id, content_hash, target_language)
__table_args__ = (
UniqueConstraint('chapter_id', 'content_hash', 'target_language', name='uq_chapter_hash_language'),
Index('idx_translations_lookup', 'chapter_id', 'content_hash', 'target_language'),
)