مخزن اختصاصی برنامهٔ وب؛ محتوای پوشهٔ web در ریشهٔ مخزن قرار گرفت. تاریخچهٔ پروژهٔ ربات (agy-bot) در این مخزن وجود ندارد و هیچ وابستگی runtime به آن نیست.
896 lines
38 KiB
Python
896 lines
38 KiB
Python
"""SQLAlchemy ORM tables.
|
|
|
|
This is the *only* module that knows about the relational schema. The domain
|
|
layer is expressed as plain dataclasses in ``app.domain.*``; repositories map
|
|
between the two. Keeping the schema here means a migration change never forces
|
|
a change to domain logic.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from datetime import datetime
|
|
|
|
from sqlalchemy import (
|
|
JSON,
|
|
Boolean,
|
|
DateTime,
|
|
Float,
|
|
ForeignKey,
|
|
Index,
|
|
Integer,
|
|
String,
|
|
Text,
|
|
UniqueConstraint,
|
|
)
|
|
from sqlalchemy.orm import Mapped, mapped_column
|
|
|
|
from app.core.database import Base
|
|
from app.domain.base import new_id, utcnow
|
|
|
|
|
|
def _pk() -> Mapped[str]:
|
|
return mapped_column(String(32), primary_key=True, default=new_id)
|
|
|
|
|
|
def _created() -> Mapped[datetime]:
|
|
return mapped_column(DateTime(timezone=True), default=utcnow, nullable=False)
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Identity & Access
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
class UserRow(Base):
|
|
__tablename__ = "users"
|
|
|
|
id: Mapped[str] = _pk()
|
|
email: Mapped[str] = mapped_column(String(320), unique=True, index=True, nullable=False)
|
|
password_hash: Mapped[str] = mapped_column(String(255), nullable=False)
|
|
name: Mapped[str] = mapped_column(String(160), default="", nullable=False)
|
|
avatar_url: Mapped[str | None] = mapped_column(String(512), nullable=True)
|
|
is_platform_owner: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False)
|
|
is_active: Mapped[bool] = mapped_column(Boolean, default=True, nullable=False)
|
|
created_at: Mapped[datetime] = _created()
|
|
updated_at: Mapped[datetime] = mapped_column(
|
|
DateTime(timezone=True), default=utcnow, onupdate=utcnow, nullable=False
|
|
)
|
|
|
|
|
|
class OrganizationRow(Base):
|
|
__tablename__ = "organizations"
|
|
|
|
id: Mapped[str] = _pk()
|
|
name: Mapped[str] = mapped_column(String(160), nullable=False)
|
|
slug: Mapped[str] = mapped_column(String(64), unique=True, index=True, nullable=False)
|
|
owner_user_id: Mapped[str] = mapped_column(ForeignKey("users.id"), nullable=False, index=True)
|
|
created_at: Mapped[datetime] = _created()
|
|
|
|
|
|
class MembershipRow(Base):
|
|
__tablename__ = "memberships"
|
|
__table_args__ = (
|
|
UniqueConstraint("organization_id", "user_id", name="uq_membership_org_user"),
|
|
Index("ix_membership_org_role", "organization_id", "role"),
|
|
)
|
|
|
|
id: Mapped[str] = _pk()
|
|
organization_id: Mapped[str] = mapped_column(
|
|
ForeignKey("organizations.id", ondelete="CASCADE"), nullable=False, index=True
|
|
)
|
|
user_id: Mapped[str] = mapped_column(
|
|
ForeignKey("users.id", ondelete="CASCADE"), nullable=False, index=True
|
|
)
|
|
role: Mapped[str] = mapped_column(String(16), default="member", nullable=False)
|
|
status: Mapped[str] = mapped_column(String(16), default="active", nullable=False)
|
|
created_at: Mapped[datetime] = _created()
|
|
|
|
|
|
class InviteRow(Base):
|
|
__tablename__ = "invites"
|
|
__table_args__ = (Index("ix_invite_org_email", "organization_id", "email"),)
|
|
|
|
id: Mapped[str] = _pk()
|
|
organization_id: Mapped[str] = mapped_column(
|
|
ForeignKey("organizations.id", ondelete="CASCADE"), nullable=False, index=True
|
|
)
|
|
email: Mapped[str] = mapped_column(String(320), nullable=False)
|
|
role: Mapped[str] = mapped_column(String(16), default="member", nullable=False)
|
|
token_hash: Mapped[str] = mapped_column(String(128), unique=True, nullable=False)
|
|
invited_by_user_id: Mapped[str | None] = mapped_column(
|
|
ForeignKey("users.id"), nullable=True, index=True
|
|
)
|
|
expires_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), nullable=False)
|
|
accepted_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
|
|
created_at: Mapped[datetime] = _created()
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# AI Control Plane (platform-owner only)
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
class AiProviderRow(Base):
|
|
__tablename__ = "ai_providers"
|
|
|
|
id: Mapped[str] = _pk()
|
|
name: Mapped[str] = mapped_column(String(120), unique=True, nullable=False)
|
|
type: Mapped[str] = mapped_column(String(32), default="mock", nullable=False)
|
|
base_url: Mapped[str] = mapped_column(String(512), default="", nullable=False)
|
|
is_active: Mapped[bool] = mapped_column(Boolean, default=True, nullable=False)
|
|
created_at: Mapped[datetime] = _created()
|
|
|
|
|
|
class AiModelCredentialRow(Base):
|
|
__tablename__ = "ai_model_credentials"
|
|
|
|
id: Mapped[str] = _pk()
|
|
provider_id: Mapped[str] = mapped_column(
|
|
ForeignKey("ai_providers.id", ondelete="CASCADE"), nullable=False, index=True
|
|
)
|
|
name: Mapped[str] = mapped_column(String(120), nullable=False)
|
|
encrypted_api_key: Mapped[str] = mapped_column(Text, default="", nullable=False)
|
|
is_active: Mapped[bool] = mapped_column(Boolean, default=True, nullable=False)
|
|
created_at: Mapped[datetime] = _created()
|
|
|
|
|
|
class AiModelRow(Base):
|
|
__tablename__ = "ai_models"
|
|
__table_args__ = (
|
|
UniqueConstraint("provider_id", "internal_name", name="uq_model_provider_name"),
|
|
)
|
|
|
|
id: Mapped[str] = _pk()
|
|
provider_id: Mapped[str] = mapped_column(
|
|
ForeignKey("ai_providers.id", ondelete="CASCADE"), nullable=False, index=True
|
|
)
|
|
internal_name: Mapped[str] = mapped_column(String(160), nullable=False)
|
|
display_name_for_admin: Mapped[str] = mapped_column(String(160), nullable=False)
|
|
capabilities: Mapped[list] = mapped_column(JSON, default=list, nullable=False)
|
|
input_price_per_1m: Mapped[float] = mapped_column(Float, default=0.0, nullable=False)
|
|
output_price_per_1m: Mapped[float] = mapped_column(Float, default=0.0, nullable=False)
|
|
is_active: Mapped[bool] = mapped_column(Boolean, default=True, nullable=False)
|
|
created_at: Mapped[datetime] = _created()
|
|
|
|
|
|
class RoutingPolicyRow(Base):
|
|
__tablename__ = "routing_policies"
|
|
|
|
id: Mapped[str] = _pk()
|
|
name: Mapped[str] = mapped_column(String(120), unique=True, nullable=False)
|
|
description: Mapped[str] = mapped_column(Text, default="", nullable=False)
|
|
mode: Mapped[str] = mapped_column(String(16), default="balanced", nullable=False)
|
|
fallback_policy_json: Mapped[dict] = mapped_column(JSON, default=dict, nullable=False)
|
|
budget_limits_json: Mapped[dict] = mapped_column(JSON, default=dict, nullable=False)
|
|
is_default: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False)
|
|
is_active: Mapped[bool] = mapped_column(Boolean, default=True, nullable=False)
|
|
created_at: Mapped[datetime] = _created()
|
|
|
|
|
|
class RateCardRow(Base):
|
|
__tablename__ = "rate_cards"
|
|
|
|
id: Mapped[str] = _pk()
|
|
name: Mapped[str] = mapped_column(String(120), nullable=False)
|
|
unit: Mapped[str] = mapped_column(String(40), unique=True, nullable=False)
|
|
customer_price: Mapped[float] = mapped_column(Float, default=0.0, nullable=False)
|
|
internal_cost_estimate: Mapped[float] = mapped_column(Float, default=0.0, nullable=False)
|
|
is_active: Mapped[bool] = mapped_column(Boolean, default=True, nullable=False)
|
|
created_at: Mapped[datetime] = _created()
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Projects & Git
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
class ProjectRow(Base):
|
|
__tablename__ = "projects"
|
|
__table_args__ = (
|
|
UniqueConstraint("organization_id", "slug", name="uq_project_org_slug"),
|
|
# The project list is always scoped to one organization and ordered by
|
|
# creation, so one composite index serves both the filter and the sort.
|
|
Index("ix_project_org_created", "organization_id", "created_at"),
|
|
)
|
|
|
|
id: Mapped[str] = _pk()
|
|
organization_id: Mapped[str] = mapped_column(
|
|
ForeignKey("organizations.id", ondelete="CASCADE"), nullable=False, index=True
|
|
)
|
|
name: Mapped[str] = mapped_column(String(160), nullable=False)
|
|
slug: Mapped[str] = mapped_column(String(64), nullable=False)
|
|
description: Mapped[str] = mapped_column(Text, default="", nullable=False)
|
|
created_by_user_id: Mapped[str | None] = mapped_column(
|
|
ForeignKey("users.id"), nullable=True, index=True
|
|
)
|
|
default_branch: Mapped[str] = mapped_column(String(80), default="main", nullable=False)
|
|
created_at: Mapped[datetime] = _created()
|
|
|
|
|
|
class ProjectRepositoryRow(Base):
|
|
__tablename__ = "project_repositories"
|
|
|
|
id: Mapped[str] = _pk()
|
|
project_id: Mapped[str] = mapped_column(
|
|
ForeignKey("projects.id", ondelete="CASCADE"), unique=True, nullable=False, index=True
|
|
)
|
|
provider: Mapped[str] = mapped_column(String(32), default="gitea", nullable=False)
|
|
owner: Mapped[str] = mapped_column(String(120), default="", nullable=False)
|
|
repo_name: Mapped[str] = mapped_column(String(160), default="", nullable=False)
|
|
clone_url: Mapped[str] = mapped_column(String(512), default="", nullable=False)
|
|
web_url: Mapped[str] = mapped_column(String(512), default="", nullable=False)
|
|
default_branch: Mapped[str] = mapped_column(String(80), default="main", nullable=False)
|
|
created_at: Mapped[datetime] = _created()
|
|
|
|
|
|
class ProjectGitCredentialRow(Base):
|
|
__tablename__ = "project_git_credentials"
|
|
|
|
id: Mapped[str] = _pk()
|
|
project_id: Mapped[str] = mapped_column(
|
|
ForeignKey("projects.id", ondelete="CASCADE"), unique=True, nullable=False, index=True
|
|
)
|
|
username: Mapped[str] = mapped_column(String(160), nullable=False)
|
|
encrypted_password: Mapped[str] = mapped_column(Text, nullable=False)
|
|
created_at: Mapped[datetime] = _created()
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Preview domain routing
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
class PreviewPortRow(Base):
|
|
__tablename__ = "preview_ports"
|
|
__table_args__ = (
|
|
UniqueConstraint("project_id", "service_name", name="uq_preview_port_project_service"),
|
|
UniqueConstraint("port", name="uq_preview_port_port"),
|
|
)
|
|
|
|
id: Mapped[str] = _pk()
|
|
organization_id: Mapped[str] = mapped_column(
|
|
ForeignKey("organizations.id", ondelete="CASCADE"), nullable=False, index=True
|
|
)
|
|
project_id: Mapped[str] = mapped_column(
|
|
ForeignKey("projects.id", ondelete="CASCADE"), nullable=False, index=True
|
|
)
|
|
service_name: Mapped[str] = mapped_column(String(80), default="web", nullable=False)
|
|
port: Mapped[int] = mapped_column(Integer, nullable=False)
|
|
status: Mapped[str] = mapped_column(String(16), default="active", nullable=False)
|
|
created_at: Mapped[datetime] = _created()
|
|
|
|
|
|
class PreviewDomainRow(Base):
|
|
__tablename__ = "preview_domains"
|
|
__table_args__ = (
|
|
UniqueConstraint("host", name="uq_preview_domain_host"),
|
|
Index("ix_preview_domain_org_created", "organization_id", "created_at"),
|
|
)
|
|
|
|
id: Mapped[str] = _pk()
|
|
organization_id: Mapped[str] = mapped_column(
|
|
ForeignKey("organizations.id", ondelete="CASCADE"), nullable=False, index=True
|
|
)
|
|
project_id: Mapped[str] = mapped_column(
|
|
ForeignKey("projects.id", ondelete="CASCADE"), nullable=False, index=True
|
|
)
|
|
host: Mapped[str] = mapped_column(String(255), nullable=False)
|
|
port: Mapped[int] = mapped_column(Integer, nullable=False)
|
|
status: Mapped[str] = mapped_column(String(16), default="active", nullable=False)
|
|
protected: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False)
|
|
created_by_user_id: Mapped[str | None] = mapped_column(
|
|
ForeignKey("users.id"), nullable=True, index=True
|
|
)
|
|
created_at: Mapped[datetime] = _created()
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Sandbox
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
class SandboxTemplateRow(Base):
|
|
__tablename__ = "sandbox_templates"
|
|
|
|
id: Mapped[str] = _pk()
|
|
name: Mapped[str] = mapped_column(String(120), unique=True, nullable=False)
|
|
provider: Mapped[str] = mapped_column(String(32), default="mock", nullable=False)
|
|
image: Mapped[str] = mapped_column(String(255), default="python:3.13-slim", nullable=False)
|
|
description: Mapped[str] = mapped_column(Text, default="", nullable=False)
|
|
default_cpu: Mapped[float] = mapped_column(Float, default=1.0, nullable=False)
|
|
default_memory_mb: Mapped[int] = mapped_column(Integer, default=1024, nullable=False)
|
|
default_disk_mb: Mapped[int] = mapped_column(Integer, default=2048, nullable=False)
|
|
is_system: Mapped[bool] = mapped_column(Boolean, default=True, nullable=False)
|
|
created_at: Mapped[datetime] = _created()
|
|
|
|
|
|
class WorkspaceRow(Base):
|
|
__tablename__ = "workspaces"
|
|
__table_args__ = (Index("ix_workspace_project_created", "project_id", "created_at"),)
|
|
|
|
id: Mapped[str] = _pk()
|
|
organization_id: Mapped[str] = mapped_column(
|
|
ForeignKey("organizations.id", ondelete="CASCADE"), nullable=False, index=True
|
|
)
|
|
project_id: Mapped[str] = mapped_column(
|
|
ForeignKey("projects.id", ondelete="CASCADE"), nullable=False, index=True
|
|
)
|
|
template_id: Mapped[str] = mapped_column(
|
|
ForeignKey("sandbox_templates.id"), nullable=False, index=True
|
|
)
|
|
provider: Mapped[str] = mapped_column(String(32), default="mock", nullable=False)
|
|
external_workspace_id: Mapped[str | None] = mapped_column(String(160), nullable=True)
|
|
status: Mapped[str] = mapped_column(String(16), default="pending", nullable=False)
|
|
created_at: Mapped[datetime] = _created()
|
|
|
|
|
|
class SandboxSessionRow(Base):
|
|
__tablename__ = "sandbox_sessions"
|
|
|
|
id: Mapped[str] = _pk()
|
|
workspace_id: Mapped[str] = mapped_column(
|
|
ForeignKey("workspaces.id", ondelete="CASCADE"), nullable=False, index=True
|
|
)
|
|
external_session_id: Mapped[str | None] = mapped_column(String(160), nullable=True)
|
|
status: Mapped[str] = mapped_column(String(16), default="starting", nullable=False)
|
|
started_at: Mapped[datetime] = _created()
|
|
stopped_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
|
|
last_active_at: Mapped[datetime] = _created()
|
|
|
|
|
|
class CommandRunRow(Base):
|
|
__tablename__ = "command_runs"
|
|
|
|
id: Mapped[str] = _pk()
|
|
session_id: Mapped[str] = mapped_column(
|
|
ForeignKey("sandbox_sessions.id", ondelete="CASCADE"), nullable=False, index=True
|
|
)
|
|
command: Mapped[str] = mapped_column(Text, nullable=False)
|
|
exit_code: Mapped[int | None] = mapped_column(Integer, nullable=True)
|
|
stdout_ref: Mapped[str] = mapped_column(Text, default="", nullable=False)
|
|
stderr_ref: Mapped[str] = mapped_column(Text, default="", nullable=False)
|
|
duration_ms: Mapped[int] = mapped_column(Integer, default=0, nullable=False)
|
|
truncated: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False)
|
|
created_at: Mapped[datetime] = _created()
|
|
|
|
|
|
class SnapshotRow(Base):
|
|
__tablename__ = "snapshots"
|
|
|
|
id: Mapped[str] = _pk()
|
|
workspace_id: Mapped[str] = mapped_column(
|
|
ForeignKey("workspaces.id", ondelete="CASCADE"), nullable=False, index=True
|
|
)
|
|
name: Mapped[str] = mapped_column(String(120), nullable=False)
|
|
external_snapshot_id: Mapped[str | None] = mapped_column(String(160), nullable=True)
|
|
created_at: Mapped[datetime] = _created()
|
|
|
|
|
|
class PreviewUrlRow(Base):
|
|
__tablename__ = "preview_urls"
|
|
|
|
id: Mapped[str] = _pk()
|
|
workspace_id: Mapped[str] = mapped_column(
|
|
ForeignKey("workspaces.id", ondelete="CASCADE"), nullable=False, index=True
|
|
)
|
|
port: Mapped[int] = mapped_column(Integer, nullable=False)
|
|
url: Mapped[str] = mapped_column(String(512), nullable=False)
|
|
created_at: Mapped[datetime] = _created()
|
|
|
|
|
|
class SandboxResourceLimitRow(Base):
|
|
__tablename__ = "sandbox_resource_limits"
|
|
__table_args__ = (UniqueConstraint("scope", "scope_id", name="uq_limit_scope"),)
|
|
|
|
id: Mapped[str] = _pk()
|
|
scope: Mapped[str] = mapped_column(String(32), default="organization", nullable=False)
|
|
scope_id: Mapped[str | None] = mapped_column(String(32), nullable=True)
|
|
cpu: Mapped[float] = mapped_column(Float, default=1.0, nullable=False)
|
|
memory_mb: Mapped[int] = mapped_column(Integer, default=1024, nullable=False)
|
|
disk_mb: Mapped[int] = mapped_column(Integer, default=2048, nullable=False)
|
|
timeout_seconds: Mapped[int] = mapped_column(Integer, default=120, nullable=False)
|
|
max_output_bytes: Mapped[int] = mapped_column(Integer, default=200_000, nullable=False)
|
|
network_policy: Mapped[str] = mapped_column(String(16), default="deny_all", nullable=False)
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Workforce: templates, employees, chat, tasks, runs, artifacts
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
class AgentTemplateRow(Base):
|
|
__tablename__ = "agent_templates"
|
|
|
|
id: Mapped[str] = _pk()
|
|
name: Mapped[str] = mapped_column(String(120), unique=True, nullable=False)
|
|
role_key: Mapped[str] = mapped_column(String(32), nullable=False)
|
|
description: Mapped[str] = mapped_column(Text, default="", nullable=False)
|
|
default_prompt: Mapped[str] = mapped_column(Text, default="", nullable=False)
|
|
default_tools_json: Mapped[list] = mapped_column(JSON, default=list, nullable=False)
|
|
default_routing_policy_id: Mapped[str | None] = mapped_column(String(32), nullable=True)
|
|
is_system: Mapped[bool] = mapped_column(Boolean, default=True, nullable=False)
|
|
created_at: Mapped[datetime] = _created()
|
|
|
|
|
|
class EmployeeRow(Base):
|
|
__tablename__ = "employees"
|
|
__table_args__ = (Index("ix_employee_org_created", "organization_id", "created_at"),)
|
|
|
|
id: Mapped[str] = _pk()
|
|
organization_id: Mapped[str] = mapped_column(
|
|
ForeignKey("organizations.id", ondelete="CASCADE"), nullable=False, index=True
|
|
)
|
|
project_id: Mapped[str | None] = mapped_column(
|
|
ForeignKey("projects.id", ondelete="SET NULL"), nullable=True, index=True
|
|
)
|
|
template_id: Mapped[str | None] = mapped_column(String(32), nullable=True)
|
|
name: Mapped[str] = mapped_column(String(160), nullable=False)
|
|
role_key: Mapped[str] = mapped_column(String(32), nullable=False)
|
|
status: Mapped[str] = mapped_column(String(16), default="active", nullable=False)
|
|
routing_policy_id: Mapped[str | None] = mapped_column(String(32), nullable=True)
|
|
budget_limit_json: Mapped[dict] = mapped_column(JSON, default=dict, nullable=False)
|
|
created_at: Mapped[datetime] = _created()
|
|
|
|
|
|
class PromptVersionRow(Base):
|
|
__tablename__ = "prompt_versions"
|
|
__table_args__ = (
|
|
UniqueConstraint("employee_id", "version", name="uq_prompt_employee_version"),
|
|
)
|
|
|
|
id: Mapped[str] = _pk()
|
|
employee_id: Mapped[str] = mapped_column(
|
|
ForeignKey("employees.id", ondelete="CASCADE"), nullable=False, index=True
|
|
)
|
|
version: Mapped[int] = mapped_column(Integer, nullable=False)
|
|
content: Mapped[str] = mapped_column(Text, nullable=False)
|
|
created_by_user_id: Mapped[str | None] = mapped_column(
|
|
ForeignKey("users.id"), nullable=True, index=True
|
|
)
|
|
created_at: Mapped[datetime] = _created()
|
|
|
|
|
|
class EmployeeToolPermissionRow(Base):
|
|
__tablename__ = "employee_tool_permissions"
|
|
__table_args__ = (
|
|
UniqueConstraint("employee_id", "tool_key", name="uq_employee_tool"),
|
|
)
|
|
|
|
id: Mapped[str] = _pk()
|
|
employee_id: Mapped[str] = mapped_column(
|
|
ForeignKey("employees.id", ondelete="CASCADE"), nullable=False, index=True
|
|
)
|
|
tool_key: Mapped[str] = mapped_column(String(80), nullable=False)
|
|
allowed: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False)
|
|
policy_json: Mapped[dict] = mapped_column(JSON, default=dict, nullable=False)
|
|
|
|
|
|
class ThreadRow(Base):
|
|
__tablename__ = "threads"
|
|
__table_args__ = (Index("ix_thread_org_created", "organization_id", "created_at"),)
|
|
|
|
id: Mapped[str] = _pk()
|
|
organization_id: Mapped[str] = mapped_column(
|
|
ForeignKey("organizations.id", ondelete="CASCADE"), nullable=False, index=True
|
|
)
|
|
project_id: Mapped[str | None] = mapped_column(
|
|
ForeignKey("projects.id", ondelete="SET NULL"), nullable=True, index=True
|
|
)
|
|
title: Mapped[str] = mapped_column(String(255), default="", nullable=False)
|
|
created_by_user_id: Mapped[str | None] = mapped_column(
|
|
ForeignKey("users.id"), nullable=True, index=True
|
|
)
|
|
created_at: Mapped[datetime] = _created()
|
|
|
|
|
|
class MessageRow(Base):
|
|
__tablename__ = "messages"
|
|
# A conversation is always read as "one thread, oldest first", so the
|
|
# composite index serves the filter and the ordering in one lookup.
|
|
__table_args__ = (Index("ix_message_thread_created", "thread_id", "created_at"),)
|
|
|
|
id: Mapped[str] = _pk()
|
|
thread_id: Mapped[str] = mapped_column(
|
|
ForeignKey("threads.id", ondelete="CASCADE"), nullable=False, index=True
|
|
)
|
|
role: Mapped[str] = mapped_column(String(16), nullable=False)
|
|
content: Mapped[str] = mapped_column(Text, default="", nullable=False)
|
|
employee_id: Mapped[str | None] = mapped_column(String(32), nullable=True, index=True)
|
|
created_at: Mapped[datetime] = _created()
|
|
|
|
|
|
class TaskRow(Base):
|
|
__tablename__ = "tasks"
|
|
__table_args__ = (
|
|
Index("ix_task_org_status", "organization_id", "status"),
|
|
Index("ix_task_org_created", "organization_id", "created_at"),
|
|
)
|
|
|
|
id: Mapped[str] = _pk()
|
|
organization_id: Mapped[str] = mapped_column(
|
|
ForeignKey("organizations.id", ondelete="CASCADE"), nullable=False, index=True
|
|
)
|
|
project_id: Mapped[str | None] = mapped_column(
|
|
ForeignKey("projects.id", ondelete="SET NULL"), nullable=True, index=True
|
|
)
|
|
thread_id: Mapped[str | None] = mapped_column(
|
|
ForeignKey("threads.id", ondelete="SET NULL"), nullable=True, index=True
|
|
)
|
|
title: Mapped[str] = mapped_column(String(255), nullable=False)
|
|
description: Mapped[str] = mapped_column(Text, default="", nullable=False)
|
|
status: Mapped[str] = mapped_column(String(24), default="new", nullable=False)
|
|
assigned_employee_id: Mapped[str | None] = mapped_column(
|
|
String(32), nullable=True, index=True
|
|
)
|
|
created_by_user_id: Mapped[str | None] = mapped_column(
|
|
ForeignKey("users.id"), nullable=True, index=True
|
|
)
|
|
created_at: Mapped[datetime] = _created()
|
|
updated_at: Mapped[datetime] = mapped_column(
|
|
DateTime(timezone=True), default=utcnow, onupdate=utcnow, nullable=False
|
|
)
|
|
|
|
|
|
class RunRow(Base):
|
|
__tablename__ = "runs"
|
|
# A run has no organization_id of its own: it is scoped through its task,
|
|
# which is the object that carries the tenant. Indexing a column that does
|
|
# not exist here would be wrong, so the composite stays on task_id.
|
|
__table_args__ = (Index("ix_run_task_created", "task_id", "created_at"),)
|
|
|
|
id: Mapped[str] = _pk()
|
|
task_id: Mapped[str] = mapped_column(
|
|
ForeignKey("tasks.id", ondelete="CASCADE"), nullable=False, index=True
|
|
)
|
|
employee_id: Mapped[str | None] = mapped_column(String(32), nullable=True, index=True)
|
|
status: Mapped[str] = mapped_column(String(24), default="queued", nullable=False)
|
|
error: Mapped[str | None] = mapped_column(Text, nullable=True)
|
|
started_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
|
|
finished_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
|
|
created_at: Mapped[datetime] = _created()
|
|
|
|
|
|
class RunStepRow(Base):
|
|
__tablename__ = "run_steps"
|
|
__table_args__ = (Index("ix_run_step_run_index", "run_id", "index"),)
|
|
|
|
id: Mapped[str] = _pk()
|
|
run_id: Mapped[str] = mapped_column(
|
|
ForeignKey("runs.id", ondelete="CASCADE"), nullable=False, index=True
|
|
)
|
|
index: Mapped[int] = mapped_column(Integer, default=0, nullable=False)
|
|
kind: Mapped[str] = mapped_column(String(40), default="note", nullable=False)
|
|
title: Mapped[str] = mapped_column(String(255), default="", nullable=False)
|
|
payload_json: Mapped[dict] = mapped_column(JSON, default=dict, nullable=False)
|
|
created_at: Mapped[datetime] = _created()
|
|
|
|
|
|
class ToolCallRow(Base):
|
|
__tablename__ = "tool_calls"
|
|
__table_args__ = (
|
|
Index("ix_tool_call_run_created", "run_id", "created_at"),
|
|
# The pending-approval queue is "one organization, still awaiting a
|
|
# decision", which is a filter on status plus a join back to the run.
|
|
Index("ix_tool_call_status", "status"),
|
|
)
|
|
|
|
id: Mapped[str] = _pk()
|
|
run_id: Mapped[str] = mapped_column(
|
|
ForeignKey("runs.id", ondelete="CASCADE"), nullable=False, index=True
|
|
)
|
|
tool_key: Mapped[str] = mapped_column(String(80), nullable=False)
|
|
arguments_json: Mapped[dict] = mapped_column(JSON, default=dict, nullable=False)
|
|
result_json: Mapped[dict] = mapped_column(JSON, default=dict, nullable=False)
|
|
status: Mapped[str] = mapped_column(String(24), default="pending", nullable=False)
|
|
requires_approval: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False)
|
|
approved_by_user_id: Mapped[str | None] = mapped_column(
|
|
ForeignKey("users.id"), nullable=True, index=True
|
|
)
|
|
created_at: Mapped[datetime] = _created()
|
|
|
|
|
|
class ArtifactRow(Base):
|
|
__tablename__ = "artifacts"
|
|
__table_args__ = (Index("ix_artifact_org_created", "organization_id", "created_at"),)
|
|
|
|
id: Mapped[str] = _pk()
|
|
organization_id: Mapped[str] = mapped_column(
|
|
ForeignKey("organizations.id", ondelete="CASCADE"), nullable=False, index=True
|
|
)
|
|
project_id: Mapped[str | None] = mapped_column(
|
|
ForeignKey("projects.id", ondelete="SET NULL"), nullable=True, index=True
|
|
)
|
|
run_id: Mapped[str | None] = mapped_column(
|
|
ForeignKey("runs.id", ondelete="SET NULL"), nullable=True, index=True
|
|
)
|
|
name: Mapped[str] = mapped_column(String(255), nullable=False)
|
|
kind: Mapped[str] = mapped_column(String(32), default="file", nullable=False)
|
|
content_ref: Mapped[str] = mapped_column(Text, default="", nullable=False)
|
|
size_bytes: Mapped[int] = mapped_column(Integer, default=0, nullable=False)
|
|
created_at: Mapped[datetime] = _created()
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Billing & Usage
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
class PlanRow(Base):
|
|
__tablename__ = "plans"
|
|
|
|
id: Mapped[str] = _pk()
|
|
name: Mapped[str] = mapped_column(String(120), unique=True, nullable=False)
|
|
monthly_price: Mapped[float] = mapped_column(Float, default=0.0, nullable=False)
|
|
included_credit: Mapped[float] = mapped_column(Float, default=0.0, nullable=False)
|
|
features_json: Mapped[dict] = mapped_column(JSON, default=dict, nullable=False)
|
|
is_active: Mapped[bool] = mapped_column(Boolean, default=True, nullable=False)
|
|
created_at: Mapped[datetime] = _created()
|
|
|
|
|
|
class SubscriptionRow(Base):
|
|
__tablename__ = "subscriptions"
|
|
|
|
id: Mapped[str] = _pk()
|
|
organization_id: Mapped[str] = mapped_column(
|
|
ForeignKey("organizations.id", ondelete="CASCADE"), nullable=False, index=True
|
|
)
|
|
plan_id: Mapped[str] = mapped_column(ForeignKey("plans.id"), nullable=False, index=True)
|
|
status: Mapped[str] = mapped_column(String(16), default="active", nullable=False)
|
|
external_subscription_id: Mapped[str | None] = mapped_column(String(160), nullable=True)
|
|
current_period_end: Mapped[datetime | None] = mapped_column(
|
|
DateTime(timezone=True), nullable=True
|
|
)
|
|
created_at: Mapped[datetime] = _created()
|
|
|
|
|
|
class CreditWalletRow(Base):
|
|
__tablename__ = "credit_wallets"
|
|
|
|
id: Mapped[str] = _pk()
|
|
organization_id: Mapped[str] = mapped_column(
|
|
ForeignKey("organizations.id", ondelete="CASCADE"), unique=True, nullable=False, index=True
|
|
)
|
|
balance: Mapped[float] = mapped_column(Float, default=0.0, nullable=False)
|
|
currency: Mapped[str] = mapped_column(String(8), default="USD", nullable=False)
|
|
low_balance_threshold: Mapped[float] = mapped_column(Float, default=5.0, nullable=False)
|
|
updated_at: Mapped[datetime] = mapped_column(
|
|
DateTime(timezone=True), default=utcnow, onupdate=utcnow, nullable=False
|
|
)
|
|
|
|
|
|
class UsageEventRow(Base):
|
|
__tablename__ = "usage_events"
|
|
__table_args__ = (
|
|
Index("ix_usage_org_created", "organization_id", "created_at"),
|
|
Index("ix_usage_org_unit", "organization_id", "unit"),
|
|
)
|
|
|
|
id: Mapped[str] = _pk()
|
|
organization_id: Mapped[str] = mapped_column(
|
|
ForeignKey("organizations.id", ondelete="CASCADE"), nullable=False, index=True
|
|
)
|
|
project_id: Mapped[str | None] = mapped_column(String(32), nullable=True, index=True)
|
|
user_id: Mapped[str | None] = mapped_column(String(32), nullable=True)
|
|
employee_id: Mapped[str | None] = mapped_column(String(32), nullable=True, index=True)
|
|
run_id: Mapped[str | None] = mapped_column(String(32), nullable=True, index=True)
|
|
unit: Mapped[str] = mapped_column(String(40), nullable=False)
|
|
quantity: Mapped[float] = mapped_column(Float, default=0.0, nullable=False)
|
|
unit_price: Mapped[float] = mapped_column(Float, default=0.0, nullable=False)
|
|
internal_cost_estimate: Mapped[float] = mapped_column(Float, default=0.0, nullable=False)
|
|
total_price: Mapped[float] = mapped_column(Float, default=0.0, nullable=False)
|
|
metadata_json: Mapped[dict] = mapped_column(JSON, default=dict, nullable=False)
|
|
created_at: Mapped[datetime] = _created()
|
|
|
|
|
|
class InvoiceRow(Base):
|
|
__tablename__ = "invoices"
|
|
|
|
id: Mapped[str] = _pk()
|
|
organization_id: Mapped[str] = mapped_column(
|
|
ForeignKey("organizations.id", ondelete="CASCADE"), nullable=False, index=True
|
|
)
|
|
amount: Mapped[float] = mapped_column(Float, default=0.0, nullable=False)
|
|
currency: Mapped[str] = mapped_column(String(8), default="USD", nullable=False)
|
|
status: Mapped[str] = mapped_column(String(16), default="draft", nullable=False)
|
|
external_invoice_id: Mapped[str | None] = mapped_column(String(160), nullable=True)
|
|
period_start: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
|
|
period_end: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
|
|
created_at: Mapped[datetime] = _created()
|
|
|
|
|
|
class PaymentRow(Base):
|
|
__tablename__ = "payments"
|
|
|
|
id: Mapped[str] = _pk()
|
|
organization_id: Mapped[str] = mapped_column(
|
|
ForeignKey("organizations.id", ondelete="CASCADE"), nullable=False, index=True
|
|
)
|
|
amount: Mapped[float] = mapped_column(Float, default=0.0, nullable=False)
|
|
status: Mapped[str] = mapped_column(String(16), default="pending", nullable=False)
|
|
provider: Mapped[str] = mapped_column(String(32), default="mock", nullable=False)
|
|
external_payment_id: Mapped[str | None] = mapped_column(String(160), nullable=True)
|
|
invoice_id: Mapped[str | None] = mapped_column(String(32), nullable=True)
|
|
created_at: Mapped[datetime] = _created()
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Knowledge
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
class KnowledgeSourceRow(Base):
|
|
__tablename__ = "knowledge_sources"
|
|
|
|
id: Mapped[str] = _pk()
|
|
organization_id: Mapped[str] = mapped_column(
|
|
ForeignKey("organizations.id", ondelete="CASCADE"), nullable=False, index=True
|
|
)
|
|
project_id: Mapped[str | None] = mapped_column(String(32), nullable=True, index=True)
|
|
name: Mapped[str] = mapped_column(String(255), nullable=False)
|
|
kind: Mapped[str] = mapped_column(String(16), default="text", nullable=False)
|
|
uri: Mapped[str] = mapped_column(String(512), default="", nullable=False)
|
|
created_at: Mapped[datetime] = _created()
|
|
|
|
|
|
class DocumentRow(Base):
|
|
__tablename__ = "documents"
|
|
|
|
id: Mapped[str] = _pk()
|
|
source_id: Mapped[str] = mapped_column(
|
|
ForeignKey("knowledge_sources.id", ondelete="CASCADE"), nullable=False, index=True
|
|
)
|
|
title: Mapped[str] = mapped_column(String(255), default="", nullable=False)
|
|
content: Mapped[str] = mapped_column(Text, default="", nullable=False)
|
|
created_at: Mapped[datetime] = _created()
|
|
|
|
|
|
class DocumentChunkRow(Base):
|
|
__tablename__ = "document_chunks"
|
|
__table_args__ = (Index("ix_chunk_document_index", "document_id", "index"),)
|
|
|
|
id: Mapped[str] = _pk()
|
|
document_id: Mapped[str] = mapped_column(
|
|
ForeignKey("documents.id", ondelete="CASCADE"), nullable=False, index=True
|
|
)
|
|
index: Mapped[int] = mapped_column(Integer, default=0, nullable=False)
|
|
content: Mapped[str] = mapped_column(Text, default="", nullable=False)
|
|
embedding_json: Mapped[list] = mapped_column(JSON, default=list, nullable=False)
|
|
|
|
|
|
class EmbeddingJobRow(Base):
|
|
__tablename__ = "embedding_jobs"
|
|
|
|
id: Mapped[str] = _pk()
|
|
source_id: Mapped[str] = mapped_column(
|
|
ForeignKey("knowledge_sources.id", ondelete="CASCADE"), nullable=False, index=True
|
|
)
|
|
status: Mapped[str] = mapped_column(String(16), default="pending", nullable=False)
|
|
error: Mapped[str | None] = mapped_column(Text, nullable=True)
|
|
created_at: Mapped[datetime] = _created()
|
|
|
|
|
|
class RetrievalPolicyRow(Base):
|
|
__tablename__ = "retrieval_policies"
|
|
|
|
id: Mapped[str] = _pk()
|
|
organization_id: Mapped[str] = mapped_column(
|
|
ForeignKey("organizations.id", ondelete="CASCADE"), nullable=False, index=True
|
|
)
|
|
name: Mapped[str] = mapped_column(String(120), nullable=False)
|
|
scope_json: Mapped[dict] = mapped_column(JSON, default=dict, nullable=False)
|
|
created_at: Mapped[datetime] = _created()
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Audit & Observability
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
class AuditEventRow(Base):
|
|
__tablename__ = "audit_events"
|
|
__table_args__ = (
|
|
Index("ix_audit_org_created", "organization_id", "created_at"),
|
|
Index("ix_audit_action", "action"),
|
|
)
|
|
|
|
id: Mapped[str] = _pk()
|
|
organization_id: Mapped[str | None] = mapped_column(String(32), nullable=True, index=True)
|
|
actor_user_id: Mapped[str | None] = mapped_column(String(32), nullable=True, index=True)
|
|
action: Mapped[str] = mapped_column(String(80), nullable=False)
|
|
target_type: Mapped[str] = mapped_column(String(40), default="", nullable=False)
|
|
target_id: Mapped[str] = mapped_column(String(64), default="", nullable=False)
|
|
metadata_json: Mapped[dict] = mapped_column(JSON, default=dict, nullable=False)
|
|
ip_address: Mapped[str] = mapped_column(String(64), default="", nullable=False)
|
|
user_agent: Mapped[str] = mapped_column(String(255), default="", nullable=False)
|
|
created_at: Mapped[datetime] = _created()
|
|
|
|
|
|
class TraceRow(Base):
|
|
__tablename__ = "traces"
|
|
|
|
id: Mapped[str] = _pk()
|
|
organization_id: Mapped[str] = mapped_column(String(32), nullable=False, index=True)
|
|
run_id: Mapped[str | None] = mapped_column(String(32), nullable=True, index=True)
|
|
name: Mapped[str] = mapped_column(String(160), default="", nullable=False)
|
|
created_at: Mapped[datetime] = _created()
|
|
|
|
|
|
class SpanRow(Base):
|
|
__tablename__ = "spans"
|
|
|
|
id: Mapped[str] = _pk()
|
|
trace_id: Mapped[str] = mapped_column(
|
|
ForeignKey("traces.id", ondelete="CASCADE"), nullable=False, index=True
|
|
)
|
|
parent_span_id: Mapped[str | None] = mapped_column(String(32), nullable=True)
|
|
name: Mapped[str] = mapped_column(String(160), nullable=False)
|
|
kind: Mapped[str] = mapped_column(String(32), default="internal", nullable=False)
|
|
attributes_json: Mapped[dict] = mapped_column(JSON, default=dict, nullable=False)
|
|
started_at: Mapped[datetime] = _created()
|
|
ended_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True), nullable=True)
|
|
|
|
|
|
class ErrorEventRow(Base):
|
|
"""Persisted failures — the table the error console reads.
|
|
|
|
Wide on purpose: a row that lacks the request path or the exception class
|
|
forces whoever is debugging to reproduce the bug to learn what it was. The
|
|
indexes cover the three access patterns — filter by tenant, filter by
|
|
"still open", and group by fingerprint.
|
|
"""
|
|
|
|
__tablename__ = "error_events"
|
|
__table_args__ = (
|
|
# Grouping view: "how often did this exact bug happen, and when last?"
|
|
Index("ix_error_events_fingerprint_created", "fingerprint", "created_at"),
|
|
# Feed view: "show me the newest failures for this tenant."
|
|
Index("ix_error_events_org_created", "organization_id", "created_at"),
|
|
)
|
|
|
|
id: Mapped[str] = _pk()
|
|
organization_id: Mapped[str | None] = mapped_column(String(32), nullable=True, index=True)
|
|
run_id: Mapped[str | None] = mapped_column(String(32), nullable=True, index=True)
|
|
kind: Mapped[str] = mapped_column(String(80), nullable=False)
|
|
message: Mapped[str] = mapped_column(Text, default="", nullable=False)
|
|
stack: Mapped[str] = mapped_column(Text, default="", nullable=False)
|
|
metadata_json: Mapped[dict] = mapped_column(JSON, default=dict, nullable=False)
|
|
|
|
# --- classification -----------------------------------------------------
|
|
source: Mapped[str] = mapped_column(String(16), default="http", nullable=False)
|
|
severity: Mapped[str] = mapped_column(String(16), default="error", nullable=False)
|
|
error_type: Mapped[str] = mapped_column(String(200), default="", nullable=False)
|
|
#: Groups identical failures. Empty string rather than NULL so the grouping
|
|
#: index never has to deal with a NULL key.
|
|
fingerprint: Mapped[str] = mapped_column(String(64), default="", nullable=False, index=True)
|
|
|
|
# --- transport context --------------------------------------------------
|
|
status_code: Mapped[int | None] = mapped_column(Integer, nullable=True)
|
|
method: Mapped[str] = mapped_column(String(10), default="", nullable=False)
|
|
path: Mapped[str] = mapped_column(String(512), default="", nullable=False)
|
|
|
|
# --- actor context ------------------------------------------------------
|
|
user_id: Mapped[str | None] = mapped_column(String(32), nullable=True)
|
|
request_id: Mapped[str] = mapped_column(String(64), default="", nullable=False)
|
|
ip: Mapped[str] = mapped_column(String(64), default="", nullable=False)
|
|
user_agent: Mapped[str] = mapped_column(String(255), default="", nullable=False)
|
|
|
|
# --- triage -------------------------------------------------------------
|
|
resolved_at: Mapped[datetime | None] = mapped_column(
|
|
DateTime(timezone=True), nullable=True, index=True
|
|
)
|
|
resolved_note: Mapped[str] = mapped_column(Text, default="", nullable=False)
|
|
|
|
created_at: Mapped[datetime] = _created()
|
|
|
|
|
|
class QualityMetricRow(Base):
|
|
__tablename__ = "quality_metrics"
|
|
__table_args__ = (Index("ix_metric_org_name", "organization_id", "name"),)
|
|
|
|
id: Mapped[str] = _pk()
|
|
organization_id: Mapped[str] = mapped_column(String(32), nullable=False, index=True)
|
|
name: Mapped[str] = mapped_column(String(120), nullable=False)
|
|
value: Mapped[float] = mapped_column(Float, default=0.0, nullable=False)
|
|
dimensions_json: Mapped[dict] = mapped_column(JSON, default=dict, nullable=False)
|
|
created_at: Mapped[datetime] = _created()
|