Unify database schema: Resolve all User model conflicts and auth table incompatibilities

Major changes:
- Consolidate 3 different User models into single unified model (models/user.py)
- Use UUID primary keys throughout (matches existing database schema)
- Add comprehensive authentication fields while preserving existing data
- Remove duplicate User model from auth.py, keep APIKey/RefreshToken/TokenBlacklist
- Update all imports to use unified User model consistently
- Create database migration (002_add_auth_fields.sql) for safe schema upgrade
- Fix frontend User interface to handle UUID string IDs
- Add backward compatibility fields (name property, role field)
- Maintain relationships for authentication features (api_keys, refresh_tokens)

Schema conflicts resolved:
 Migration schema (UUID, 7 fields) + Basic model (Integer, 6 fields) + Auth model (Integer, 10 fields)
   → Unified model (UUID, 12 fields with full backward compatibility)
 Field inconsistencies (name vs full_name) resolved with compatibility property
 Database foreign key constraints updated for UUID relationships
 JWT token handling fixed for UUID user IDs

This completes the holistic database schema unification requested after quick
patching caused conflicts. All existing data preserved, full auth system functional.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
anthonyrawlins
2025-07-10 22:56:14 +10:00
parent 2547a5c2b3
commit eda5b2d6d3
8 changed files with 203 additions and 85 deletions

View File

@@ -61,7 +61,7 @@ def get_current_active_user(
db: Session = Depends(get_db),
) -> Dict[str, Any]:
"""Get current authenticated and active user."""
from app.models.auth import User
from app.models.user import User
user = db.query(User).filter(User.id == user_context["user_id"]).first()
if not user:

View File

@@ -5,19 +5,18 @@ Creates all tables and sets up initial data.
import logging
from sqlalchemy.orm import Session
from app.core.database import engine, SessionLocal
from app.models.auth import Base as AuthBase, User, API_SCOPES
from app.models.auth import APIKey
from app.core.database import engine, SessionLocal, Base
from app.models.user import User
from app.models.auth import API_SCOPES, APIKey
# Import other model bases here as they're created
# from app.models.workflows import Base as WorkflowsBase
# from app.models.agents import Base as AgentsBase
# Import all models to ensure they're registered with Base
from app.models import user, auth, agent, project
def create_tables():
"""Create all database tables."""
try:
# Create auth tables
AuthBase.metadata.create_all(bind=engine)
# Create all tables using the unified Base
Base.metadata.create_all(bind=engine)
# Add other model bases here
# WorkflowsBase.metadata.create_all(bind=engine)

View File

@@ -224,8 +224,8 @@ class AuthManager:
raise AuthenticationError("Token has been revoked")
# Get user information
user_id = int(payload.get("sub"))
from app.models.auth import User
user_id = payload.get("sub") # UUID as string
from app.models.user import User
user = session.query(User).filter(User.id == user_id).first()
if not user or not user.is_active:
@@ -279,7 +279,7 @@ def create_token_response(user_id: int, user_data: Dict[str, Any]) -> Dict[str,
def get_password_hash(password: str) -> str:
"""Hash a password for storage."""
from app.models.auth import User
from app.models.user import User
return User.hash_password(password)