kofdai's picture
Upload folder using huggingface_hub
594ed40 verified
from sqlalchemy import Column, String, DateTime, JSON, Boolean, ForeignKey, Text, Integer, Float
from sqlalchemy.orm import declarative_base, relationship
from datetime import datetime
import uuid
Base = declarative_base()
class User(Base):
"""ユーザーモデル - 複数の認証方法をサポート"""
__tablename__ = "users"
id = Column(String, primary_key=True, default=lambda: str(uuid.uuid4()))
email = Column(String, unique=True, nullable=True, index=True) # OAuth時はnullable
username = Column(String, unique=True, nullable=True, index=True)
display_name = Column(String, nullable=True)
hashed_password = Column(String, nullable=True) # OAuth時はnullable
# 認証プロバイダー情報
auth_provider = Column(String, default="local") # local, google, github, orcid
google_id = Column(String, unique=True, nullable=True, index=True)
github_id = Column(String, unique=True, nullable=True, index=True)
orcid_id = Column(String, unique=True, nullable=True, index=True)
# 権限とステータス
role = Column(String, default="viewer", nullable=False) # viewer, expert, reviewer, curator, admin
is_expert = Column(Boolean, default=False)
is_guest = Column(Boolean, default=False)
expert_verification_status = Column(String, default="none") # none, pending, approved, rejected
expert_credentials = Column(JSON)
# プロフィール情報
avatar_url = Column(String, nullable=True)
bio = Column(Text, nullable=True)
affiliation = Column(String, nullable=True)
# OAuth tokens (暗号化して保存すべき)
google_access_token = Column(String, nullable=True)
google_refresh_token = Column(String, nullable=True)
github_access_token = Column(String, nullable=True)
orcid_access_token = Column(String, nullable=True)
orcid_refresh_token = Column(String, nullable=True)
# タイムスタンプ
created_at = Column(DateTime, default=datetime.utcnow)
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
last_login_at = Column(DateTime, nullable=True)
# リレーションシップ
workspaces = relationship("Workspace", back_populates="owner", cascade="all, delete-orphan")
workspace_members = relationship("WorkspaceMember", back_populates="user", cascade="all, delete-orphan")
proposals = relationship("Proposal", back_populates="proposer", foreign_keys="[Proposal.proposer_id]")
reviews = relationship("Proposal", back_populates="reviewer", foreign_keys="[Proposal.reviewer_id]")
contributions = relationship("KnowledgeTile", back_populates="contributor", foreign_keys="[KnowledgeTile.contributor_id]")
class KnowledgeTile(Base):
"""知識タイルモデル"""
__tablename__ = "knowledge_tiles"
id = Column(String, primary_key=True, default=lambda: f"ktile_{uuid.uuid4().hex}")
workspace_id = Column(String, ForeignKey("workspaces.id"), nullable=False, index=True)
domain_id = Column(String, index=True)
topic = Column(String, nullable=False)
content = Column(Text, nullable=False)
tags = Column(JSON, nullable=True)
# 6次元座標 [x, y, z, c, g, v]
# [x, y, z]: ドメイン固有の3次元空間
# [c, g, v]: メタ空間 (Certainty, Granularity, Verification)
coordinates = Column(JSON, nullable=True) # Example: [0.5, 0.3, 0.8, 0.9, 0.7, 0.85]
# バージョン管理
version = Column(Integer, default=1)
is_latest_version = Column(Boolean, default=True)
based_on_version = Column(Integer, nullable=True)
# 貢献者と検証
contributor_id = Column(String, ForeignKey("users.id"), nullable=True)
confidence_score = Column(Float, default=0.0)
verification_type = Column(String, default="none", index=True) # none, community, expert, multi_expert
verification_count = Column(Integer, default=0)
last_verified_by_id = Column(String, ForeignKey("users.id"), nullable=True)
last_verified_at = Column(DateTime)
created_at = Column(DateTime, default=datetime.utcnow)
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
workspace = relationship("Workspace")
contributor = relationship("User", back_populates="contributions", foreign_keys=[contributor_id])
last_verified_by = relationship("User", foreign_keys=[last_verified_by_id])
proposals = relationship("Proposal", back_populates="tile")
class Proposal(Base):
"""編集提案モデル"""
__tablename__ = "proposals"
id = Column(String, primary_key=True, default=lambda: f"prop_{uuid.uuid4().hex}")
workspace_id = Column(String, ForeignKey("workspaces.id"), nullable=False, index=True)
tile_id = Column(String, ForeignKey("knowledge_tiles.id"), nullable=True) # 新規作成時はnull
proposer_id = Column(String, ForeignKey("users.id"), nullable=False)
status = Column(String, default="pending", index=True) # pending, approved, rejected
proposal_type = Column(String, nullable=False) # create, update, delete
justification = Column(Text)
proposed_content = Column(JSON)
reviewer_id = Column(String, ForeignKey("users.id"), nullable=True)
reviewer_comment = Column(Text)
reviewed_at = Column(DateTime)
created_at = Column(DateTime, default=datetime.utcnow)
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
workspace = relationship("Workspace")
tile = relationship("KnowledgeTile", back_populates="proposals")
proposer = relationship("User", back_populates="proposals", foreign_keys=[proposer_id])
reviewer = relationship("User", back_populates="reviews", foreign_keys=[reviewer_id])
class Workspace(Base):
"""ワークスペース - ユーザーごとの独立したDB環境"""
__tablename__ = "workspaces"
id = Column(String, primary_key=True, default=lambda: str(uuid.uuid4()))
name = Column(String, nullable=False)
slug = Column(String, unique=True, nullable=False, index=True) # URLフレンドリーな識別子
description = Column(Text, nullable=True)
# オーナー情報
owner_id = Column(String, ForeignKey("users.id"), nullable=False)
# 設定
is_public = Column(Boolean, default=False) # 公開ワークスペース
allow_guest_edit = Column(Boolean, default=True) # ゲストによる編集を許可
allow_guest_view = Column(Boolean, default=True) # ゲストによる閲覧を許可
# データベース設定
db_type = Column(String, default="sqlite") # sqlite, postgresql
db_path = Column(String, nullable=True) # SQLiteの場合のファイルパス
db_connection_string = Column(String, nullable=True) # PostgreSQLの場合
# 統計情報
tile_count = Column(Integer, default=0)
domain_count = Column(Integer, default=0)
member_count = Column(Integer, default=1)
# タイムスタンプ
created_at = Column(DateTime, default=datetime.utcnow)
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
# リレーションシップ
owner = relationship("User", back_populates="workspaces")
members = relationship("WorkspaceMember", back_populates="workspace", cascade="all, delete-orphan")
class WorkspaceMember(Base):
"""ワークスペースメンバー - 共同作業者の管理"""
__tablename__ = "workspace_members"
id = Column(String, primary_key=True, default=lambda: str(uuid.uuid4()))
workspace_id = Column(String, ForeignKey("workspaces.id"), nullable=False)
user_id = Column(String, ForeignKey("users.id"), nullable=False)
# 権限
role = Column(String, default="viewer") # viewer, editor, admin
can_read = Column(Boolean, default=True)
can_write = Column(Boolean, default=False)
can_delete = Column(Boolean, default=False)
can_invite = Column(Boolean, default=False)
# タイムスタンプ
joined_at = Column(DateTime, default=datetime.utcnow)
# リレーションシップ
workspace = relationship("Workspace", back_populates="members")
user = relationship("User", back_populates="workspace_members")
class OAuthState(Base):
"""OAuth認証の一時的なstate管理"""
__tablename__ = "oauth_states"
id = Column(String, primary_key=True, default=lambda: str(uuid.uuid4()))
state = Column(String, unique=True, nullable=False, index=True)
provider = Column(String, nullable=False) # google, orcid
redirect_url = Column(String, nullable=True)
user_id = Column(String, ForeignKey("users.id"), nullable=True) # 既存ユーザーとの連携時
created_at = Column(DateTime, default=datetime.utcnow)
expires_at = Column(DateTime, nullable=False) # 10分で期限切れ
def is_expired(self):
return datetime.utcnow() > self.expires_at