Files
ITWorx_MCP_Hub-Public/services/control_api/persistence/models.py
T

551 lines
26 KiB
Python

"""Hub-owned SQLAlchemy rows and constraints.
The model intentionally does not contain gateway tables or foreign keys to the
ContextForge database. Cross-system identity is represented only by opaque
external IDs and is reconciled by a later adapter.
"""
from __future__ import annotations
from datetime import datetime
from typing import Any
from uuid import UUID, uuid4
import sqlalchemy as sa
from sqlalchemy.dialects import postgresql
from sqlalchemy.orm import Mapped, mapped_column
from .db import Base, utc_now
JSON_TYPE = sa.JSON().with_variant(postgresql.JSONB(), "postgresql")
UUID_TYPE = sa.Uuid(as_uuid=True)
class TimestampMixin:
created_at: Mapped[datetime] = mapped_column(
sa.DateTime(timezone=True), default=utc_now, nullable=False
)
updated_at: Mapped[datetime] = mapped_column(
sa.DateTime(timezone=True), default=utc_now, onupdate=utc_now, nullable=False
)
revision: Mapped[int] = mapped_column(sa.Integer, default=1, nullable=False)
class WorkspaceRow(TimestampMixin, Base):
__tablename__ = "workspaces"
__table_args__ = (sa.UniqueConstraint("slug", name="uq_workspaces_slug"),)
id: Mapped[UUID] = mapped_column(UUID_TYPE, primary_key=True, default=uuid4)
slug: Mapped[str] = mapped_column(sa.String(63), nullable=False)
name: Mapped[str] = mapped_column(sa.String(160), nullable=False)
status: Mapped[str] = mapped_column(sa.String(32), nullable=False, default="active")
class ProjectRow(TimestampMixin, Base):
__tablename__ = "projects"
__table_args__ = (
sa.UniqueConstraint("workspace_id", "slug", name="uq_projects_workspace_slug"),
sa.UniqueConstraint("workspace_id", "id", name="uq_projects_workspace_id"),
)
id: Mapped[UUID] = mapped_column(UUID_TYPE, primary_key=True, default=uuid4)
workspace_id: Mapped[UUID] = mapped_column(sa.ForeignKey("workspaces.id"), nullable=False)
slug: Mapped[str] = mapped_column(sa.String(63), nullable=False)
name: Mapped[str] = mapped_column(sa.String(160), nullable=False)
description: Mapped[str | None] = mapped_column(sa.String(1000))
status: Mapped[str] = mapped_column(sa.String(32), nullable=False, default="active")
repository_provider: Mapped[str | None] = mapped_column(sa.String(32))
repository_owner: Mapped[str | None] = mapped_column(sa.String(120))
repository_name: Mapped[str | None] = mapped_column(sa.String(120))
classification: Mapped[str] = mapped_column(sa.String(32), nullable=False, default="internal")
owner_metadata: Mapped[dict[str, Any]] = mapped_column(JSON_TYPE, default=dict, nullable=False)
class EnvironmentRow(TimestampMixin, Base):
__tablename__ = "environments"
__table_args__ = (
sa.ForeignKeyConstraint(
["workspace_id", "project_id"],
["projects.workspace_id", "projects.id"],
name="fk_environments_project_scope",
),
sa.UniqueConstraint("workspace_id", "project_id", "id", name="uq_environments_scope_id"),
sa.UniqueConstraint("project_id", "name", name="uq_environments_project_name"),
)
id: Mapped[UUID] = mapped_column(UUID_TYPE, primary_key=True, default=uuid4)
workspace_id: Mapped[UUID] = mapped_column(nullable=False)
project_id: Mapped[UUID] = mapped_column(nullable=False)
name: Mapped[str] = mapped_column(sa.String(32), nullable=False)
classification: Mapped[str] = mapped_column(sa.String(32), nullable=False)
base_url: Mapped[str | None] = mapped_column(sa.String(2048))
status: Mapped[str] = mapped_column(sa.String(32), nullable=False, default="active")
class ConnectorRow(TimestampMixin, Base):
__tablename__ = "connectors"
__table_args__ = (
sa.ForeignKeyConstraint(
["workspace_id", "project_id"],
["projects.workspace_id", "projects.id"],
name="fk_connectors_project_scope",
),
sa.ForeignKeyConstraint(
["workspace_id", "project_id", "environment_id"],
["environments.workspace_id", "environments.project_id", "environments.id"],
name="fk_connectors_environment_scope",
),
sa.UniqueConstraint(
"workspace_id",
"project_id",
"environment_scope",
"slug",
name="uq_connectors_scope_slug",
),
sa.CheckConstraint(
"health_state in ("
"'unconfigured','checking','healthy','degraded','unavailable','misconfigured','disabled')",
name="ck_connectors_health_state",
),
)
id: Mapped[UUID] = mapped_column(UUID_TYPE, primary_key=True, default=uuid4)
workspace_id: Mapped[UUID] = mapped_column(nullable=False)
project_id: Mapped[UUID] = mapped_column(nullable=False)
environment_id: Mapped[UUID | None] = mapped_column()
environment_scope: Mapped[str] = mapped_column(
sa.String(36), nullable=False, default="__project__"
)
type: Mapped[str] = mapped_column(sa.String(64), nullable=False)
slug: Mapped[str] = mapped_column(sa.String(63), nullable=False)
endpoint: Mapped[str | None] = mapped_column(sa.String(2048))
credential_reference: Mapped[str | None] = mapped_column(sa.String(512))
configuration: Mapped[dict[str, Any]] = mapped_column(JSON_TYPE, default=dict, nullable=False)
enabled: Mapped[bool] = mapped_column(sa.Boolean, nullable=False, default=False)
health_state: Mapped[str] = mapped_column(sa.String(32), nullable=False, default="unconfigured")
last_check_at: Mapped[datetime | None] = mapped_column(sa.DateTime(timezone=True))
latency_ms: Mapped[int | None] = mapped_column(sa.Integer)
stable_error_code: Mapped[str | None] = mapped_column(sa.String(128))
sanitized_error: Mapped[str | None] = mapped_column(sa.String(1000))
class RiskClassRow(Base):
__tablename__ = "risk_classes"
code: Mapped[str] = mapped_column(sa.String(64), primary_key=True)
description: Mapped[str] = mapped_column(sa.String(500), nullable=False)
allows_writes: Mapped[bool] = mapped_column(sa.Boolean, nullable=False, default=False)
max_output_bytes: Mapped[int] = mapped_column(sa.Integer, nullable=False, default=65536)
class CapabilityRow(TimestampMixin, Base):
__tablename__ = "capabilities"
__table_args__ = (
sa.ForeignKeyConstraint(
["risk_class"], ["risk_classes.code"], name="fk_capabilities_risk_class"
),
sa.UniqueConstraint("canonical_name", "version", name="uq_capabilities_name_version"),
)
id: Mapped[UUID] = mapped_column(UUID_TYPE, primary_key=True, default=uuid4)
canonical_name: Mapped[str] = mapped_column(sa.String(120), nullable=False)
version: Mapped[str] = mapped_column(sa.String(32), nullable=False)
description: Mapped[str] = mapped_column(sa.String(1000), nullable=False)
risk_class: Mapped[str] = mapped_column(sa.String(64), nullable=False)
enabled: Mapped[bool] = mapped_column(sa.Boolean, nullable=False, default=True)
class ToolDefinitionRow(TimestampMixin, Base):
__tablename__ = "tool_definitions"
__table_args__ = (
sa.ForeignKeyConstraint(
["workspace_id", "project_id"],
["projects.workspace_id", "projects.id"],
name="fk_tools_project_scope",
),
sa.ForeignKeyConstraint(["connector_id"], ["connectors.id"], name="fk_tools_connector"),
sa.UniqueConstraint("canonical_name", "version", name="uq_tools_name_version"),
)
id: Mapped[UUID] = mapped_column(UUID_TYPE, primary_key=True, default=uuid4)
workspace_id: Mapped[UUID] = mapped_column(nullable=False)
project_id: Mapped[UUID] = mapped_column(nullable=False)
connector_id: Mapped[UUID] = mapped_column(nullable=False)
canonical_name: Mapped[str] = mapped_column(sa.String(120), nullable=False)
version: Mapped[str] = mapped_column(sa.String(32), nullable=False)
input_schema: Mapped[dict[str, Any]] = mapped_column(JSON_TYPE, default=dict, nullable=False)
output_schema: Mapped[dict[str, Any]] = mapped_column(JSON_TYPE, default=dict, nullable=False)
timeout_ms: Mapped[int] = mapped_column(sa.Integer, nullable=False, default=10000)
output_limit_bytes: Mapped[int] = mapped_column(sa.Integer, nullable=False, default=65536)
rate_limit_per_minute: Mapped[int] = mapped_column(sa.Integer, nullable=False, default=60)
redaction_profile: Mapped[str] = mapped_column(sa.String(64), nullable=False, default="default")
lifecycle_status: Mapped[str] = mapped_column(sa.String(32), nullable=False, default="active")
class VirtualServerRow(TimestampMixin, Base):
__tablename__ = "virtual_servers"
__table_args__ = (
sa.ForeignKeyConstraint(
["workspace_id", "project_id"],
["projects.workspace_id", "projects.id"],
name="fk_virtual_servers_project_scope",
),
sa.ForeignKeyConstraint(
["workspace_id", "project_id", "environment_id"],
["environments.workspace_id", "environments.project_id", "environments.id"],
name="fk_virtual_servers_environment_scope",
),
sa.UniqueConstraint("workspace_id", "project_id", "id", name="uq_virtual_servers_scope_id"),
sa.UniqueConstraint("slug", name="uq_virtual_servers_slug"),
)
id: Mapped[UUID] = mapped_column(UUID_TYPE, primary_key=True, default=uuid4)
workspace_id: Mapped[UUID] = mapped_column(nullable=False)
project_id: Mapped[UUID] = mapped_column(nullable=False)
environment_id: Mapped[UUID] = mapped_column(nullable=False)
slug: Mapped[str] = mapped_column(sa.String(63), nullable=False)
gateway_external_id: Mapped[str | None] = mapped_column(sa.String(256))
desired_hash: Mapped[str] = mapped_column(sa.String(128), nullable=False)
enabled: Mapped[bool] = mapped_column(sa.Boolean, nullable=False, default=False)
protocol: Mapped[str] = mapped_column(sa.String(64), nullable=False, default="streamable-http")
health_state: Mapped[str] = mapped_column(sa.String(32), nullable=False, default="unconfigured")
record_metadata: Mapped[dict[str, Any]] = mapped_column(JSON_TYPE, default=dict, nullable=False)
class VirtualServerCapabilityRow(Base):
__tablename__ = "virtual_server_capabilities"
__table_args__ = (
sa.ForeignKeyConstraint(
["workspace_id", "project_id", "virtual_server_id"],
["virtual_servers.workspace_id", "virtual_servers.project_id", "virtual_servers.id"],
name="fk_vs_capabilities_server_scope",
),
sa.ForeignKeyConstraint(
["capability_id"], ["capabilities.id"], name="fk_vs_capabilities_capability"
),
sa.UniqueConstraint(
"virtual_server_id", "capability_id", name="uq_vs_capabilities_binding"
),
)
id: Mapped[UUID] = mapped_column(UUID_TYPE, primary_key=True, default=uuid4)
workspace_id: Mapped[UUID] = mapped_column(nullable=False)
project_id: Mapped[UUID] = mapped_column(nullable=False)
virtual_server_id: Mapped[UUID] = mapped_column(nullable=False)
capability_id: Mapped[UUID] = mapped_column(nullable=False)
desired_state_source: Mapped[str] = mapped_column(
sa.String(64), nullable=False, default="catalog"
)
created_at: Mapped[datetime] = mapped_column(
sa.DateTime(timezone=True), default=utc_now, nullable=False
)
updated_at: Mapped[datetime] = mapped_column(
sa.DateTime(timezone=True), default=utc_now, nullable=False
)
class ClientRow(TimestampMixin, Base):
__tablename__ = "clients"
__table_args__ = (
sa.ForeignKeyConstraint(["workspace_id"], ["workspaces.id"], name="fk_clients_workspace"),
sa.UniqueConstraint("workspace_id", "id", name="uq_clients_workspace_id"),
sa.UniqueConstraint("workspace_id", "issuer", "subject", name="uq_clients_principal"),
sa.CheckConstraint(
"status in ('pending','active','disabled','revoked')", name="ck_clients_status"
),
)
id: Mapped[UUID] = mapped_column(UUID_TYPE, primary_key=True, default=uuid4)
workspace_id: Mapped[UUID] = mapped_column(nullable=False)
subject: Mapped[str] = mapped_column(sa.String(256), nullable=False)
issuer: Mapped[str] = mapped_column(sa.String(512), nullable=False)
client_type: Mapped[str] = mapped_column(sa.String(32), nullable=False, default="mcp")
status: Mapped[str] = mapped_column(sa.String(32), nullable=False, default="pending")
revoked_at: Mapped[datetime | None] = mapped_column(sa.DateTime(timezone=True))
last_seen_at: Mapped[datetime | None] = mapped_column(sa.DateTime(timezone=True))
record_metadata: Mapped[dict[str, Any]] = mapped_column(JSON_TYPE, default=dict, nullable=False)
class ClientBindingRow(TimestampMixin, Base):
__tablename__ = "client_bindings"
__table_args__ = (
sa.ForeignKeyConstraint(
["workspace_id", "project_id"],
["projects.workspace_id", "projects.id"],
name="fk_client_bindings_project_scope",
),
sa.ForeignKeyConstraint(
["workspace_id", "client_id"],
["clients.workspace_id", "clients.id"],
name="fk_client_bindings_client_scope",
),
sa.ForeignKeyConstraint(
["workspace_id", "project_id", "virtual_server_id"],
["virtual_servers.workspace_id", "virtual_servers.project_id", "virtual_servers.id"],
name="fk_client_bindings_server_scope",
),
sa.UniqueConstraint(
"client_id", "virtual_server_id", "capability_pack", name="uq_client_bindings"
),
)
id: Mapped[UUID] = mapped_column(UUID_TYPE, primary_key=True, default=uuid4)
workspace_id: Mapped[UUID] = mapped_column(nullable=False)
project_id: Mapped[UUID] = mapped_column(nullable=False)
client_id: Mapped[UUID] = mapped_column(nullable=False)
virtual_server_id: Mapped[UUID] = mapped_column(nullable=False)
capability_pack: Mapped[str | None] = mapped_column(sa.String(128))
constraints: Mapped[dict[str, Any]] = mapped_column(JSON_TYPE, default=dict, nullable=False)
enabled: Mapped[bool] = mapped_column(sa.Boolean, nullable=False, default=False)
class PolicyRow(TimestampMixin, Base):
__tablename__ = "policies"
__table_args__ = (
sa.ForeignKeyConstraint(["workspace_id"], ["workspaces.id"], name="fk_policies_workspace"),
sa.ForeignKeyConstraint(
["workspace_id", "project_id"],
["projects.workspace_id", "projects.id"],
name="fk_policies_project_scope",
),
sa.UniqueConstraint("workspace_id", "slug", name="uq_policies_workspace_slug"),
sa.CheckConstraint(
"decision in ('allow','allow_if_conditions','deny','deny_and_alert','enforce')",
name="ck_policies_decision",
),
)
id: Mapped[UUID] = mapped_column(UUID_TYPE, primary_key=True, default=uuid4)
workspace_id: Mapped[UUID] = mapped_column(nullable=False)
project_id: Mapped[UUID | None] = mapped_column()
slug: Mapped[str] = mapped_column(sa.String(63), nullable=False)
priority: Mapped[int] = mapped_column(sa.Integer, nullable=False)
description: Mapped[str] = mapped_column(sa.String(1000), nullable=False)
match_json: Mapped[dict[str, Any]] = mapped_column(JSON_TYPE, default=dict, nullable=False)
conditions_json: Mapped[dict[str, Any]] = mapped_column(JSON_TYPE, default=dict, nullable=False)
decision: Mapped[str] = mapped_column(sa.String(32), nullable=False)
terminal: Mapped[bool] = mapped_column(sa.Boolean, nullable=False, default=False)
source: Mapped[str] = mapped_column(sa.String(64), nullable=False, default="catalog")
enabled: Mapped[bool] = mapped_column(sa.Boolean, nullable=False, default=True)
class PolicyDecisionRow(Base):
__tablename__ = "policy_decisions"
id: Mapped[UUID] = mapped_column(UUID_TYPE, primary_key=True, default=uuid4)
workspace_id: Mapped[UUID] = mapped_column(sa.ForeignKey("workspaces.id"), nullable=False)
project_id: Mapped[UUID | None] = mapped_column()
policy_id: Mapped[UUID | None] = mapped_column(sa.ForeignKey("policies.id"))
decision: Mapped[str] = mapped_column(sa.String(32), nullable=False)
matched_rule_ids: Mapped[list[str]] = mapped_column(JSON_TYPE, default=list, nullable=False)
decision_trace: Mapped[list[dict[str, Any]]] = mapped_column(
JSON_TYPE, default=list, nullable=False
)
reason_code: Mapped[str | None] = mapped_column(sa.String(128))
trace_id: Mapped[str] = mapped_column(sa.String(128), nullable=False)
retention_until: Mapped[datetime | None] = mapped_column(sa.DateTime(timezone=True))
created_at: Mapped[datetime] = mapped_column(
sa.DateTime(timezone=True), default=utc_now, nullable=False
)
class ReconcileRunRow(TimestampMixin, Base):
__tablename__ = "reconcile_runs"
__table_args__ = (
sa.ForeignKeyConstraint(
["workspace_id", "project_id"],
["projects.workspace_id", "projects.id"],
name="fk_reconcile_runs_project_scope",
),
sa.CheckConstraint(
"status in ("
"'created','planning','planned','applying','verifying','succeeded','invalid','failed')",
name="ck_reconcile_runs_status",
),
)
id: Mapped[UUID] = mapped_column(UUID_TYPE, primary_key=True, default=uuid4)
workspace_id: Mapped[UUID] = mapped_column(nullable=False)
project_id: Mapped[UUID] = mapped_column(nullable=False)
desired_hash: Mapped[str] = mapped_column(sa.String(128), nullable=False)
current_hash: Mapped[str | None] = mapped_column(sa.String(128))
plan_hash: Mapped[str | None] = mapped_column(sa.String(128))
status: Mapped[str] = mapped_column(sa.String(32), nullable=False, default="created")
planned_changes: Mapped[list[dict[str, Any]]] = mapped_column(
JSON_TYPE, default=list, nullable=False
)
applied_changes: Mapped[list[dict[str, Any]]] = mapped_column(
JSON_TYPE, default=list, nullable=False
)
verification: Mapped[dict[str, Any]] = mapped_column(JSON_TYPE, default=dict, nullable=False)
started_at: Mapped[datetime | None] = mapped_column(sa.DateTime(timezone=True))
completed_at: Mapped[datetime | None] = mapped_column(sa.DateTime(timezone=True))
class OperationRow(TimestampMixin, Base):
__tablename__ = "operations"
__table_args__ = (
sa.ForeignKeyConstraint(
["workspace_id", "project_id"],
["projects.workspace_id", "projects.id"],
name="fk_operations_project_scope",
),
sa.ForeignKeyConstraint(
["workspace_id", "project_id", "environment_id"],
["environments.workspace_id", "environments.project_id", "environments.id"],
name="fk_operations_environment_scope",
),
sa.UniqueConstraint("workspace_id", "project_id", "id", name="uq_operations_project_id"),
sa.CheckConstraint(
"state in ("
"'requested','planned','approval_required','approved','executing','verifying','succeeded','rejected','failed','rollback_pending','rolled_back','rollback_failed')",
name="ck_operations_state",
),
)
id: Mapped[UUID] = mapped_column(UUID_TYPE, primary_key=True, default=uuid4)
workspace_id: Mapped[UUID] = mapped_column(nullable=False)
project_id: Mapped[UUID] = mapped_column(nullable=False)
environment_id: Mapped[UUID] = mapped_column(nullable=False)
operation_type: Mapped[str] = mapped_column(sa.String(64), nullable=False)
target_ref: Mapped[str] = mapped_column(sa.String(512), nullable=False)
plan_hash: Mapped[str] = mapped_column(sa.String(128), nullable=False)
state: Mapped[str] = mapped_column(sa.String(32), nullable=False, default="requested")
requested_by: Mapped[str] = mapped_column(sa.String(256), nullable=False)
expires_at: Mapped[datetime | None] = mapped_column(sa.DateTime(timezone=True))
verification: Mapped[dict[str, Any]] = mapped_column(JSON_TYPE, default=dict, nullable=False)
class ApprovalRow(TimestampMixin, Base):
__tablename__ = "approvals"
__table_args__ = (
sa.ForeignKeyConstraint(
["workspace_id", "project_id", "operation_id"],
["operations.workspace_id", "operations.project_id", "operations.id"],
name="fk_approvals_operation_scope",
),
sa.CheckConstraint(
"state in ('pending','approved','rejected','expired')", name="ck_approvals_state"
),
)
id: Mapped[UUID] = mapped_column(UUID_TYPE, primary_key=True, default=uuid4)
workspace_id: Mapped[UUID] = mapped_column(nullable=False)
project_id: Mapped[UUID] = mapped_column(nullable=False)
operation_id: Mapped[UUID] = mapped_column(nullable=False)
plan_hash: Mapped[str] = mapped_column(sa.String(128), nullable=False)
state: Mapped[str] = mapped_column(sa.String(32), nullable=False, default="pending")
actor: Mapped[str] = mapped_column(sa.String(256), nullable=False)
reason: Mapped[str | None] = mapped_column(sa.String(1000))
expires_at: Mapped[datetime] = mapped_column(sa.DateTime(timezone=True), nullable=False)
approved_at: Mapped[datetime | None] = mapped_column(sa.DateTime(timezone=True))
class AuditEventRow(Base):
__tablename__ = "audit_events"
__table_args__ = (
sa.ForeignKeyConstraint(
["workspace_id"], ["workspaces.id"], name="fk_audit_events_workspace"
),
sa.Index("ix_audit_events_occurred_at_id", "occurred_at", "id"),
)
id: Mapped[UUID] = mapped_column(UUID_TYPE, primary_key=True, default=uuid4)
occurred_at: Mapped[datetime] = mapped_column(
sa.DateTime(timezone=True), default=utc_now, nullable=False
)
trace_id: Mapped[str] = mapped_column(sa.String(128), nullable=False)
workspace_id: Mapped[UUID] = mapped_column(nullable=False)
project_id: Mapped[UUID | None] = mapped_column()
environment_id: Mapped[UUID | None] = mapped_column()
event_type: Mapped[str] = mapped_column(sa.String(128), nullable=False)
principal_issuer: Mapped[str | None] = mapped_column(sa.String(512))
principal_subject: Mapped[str | None] = mapped_column(sa.String(256))
client_id: Mapped[UUID | None] = mapped_column()
virtual_server_id: Mapped[UUID | None] = mapped_column()
tool_name: Mapped[str | None] = mapped_column(sa.String(256))
policy_decision: Mapped[str | None] = mapped_column(sa.String(32))
matched_rule_ids: Mapped[list[str]] = mapped_column(JSON_TYPE, default=list, nullable=False)
policy_trace: Mapped[list[dict[str, Any]]] = mapped_column(
JSON_TYPE, default=list, nullable=False
)
arguments_hash: Mapped[str | None] = mapped_column(sa.String(128))
sanitized_arguments: Mapped[dict[str, Any]] = mapped_column(
JSON_TYPE, default=dict, nullable=False
)
duration_ms: Mapped[int | None] = mapped_column(sa.Integer)
outcome: Mapped[str] = mapped_column(sa.String(32), nullable=False)
error_code: Mapped[str | None] = mapped_column(sa.String(128))
retention_until: Mapped[datetime | None] = mapped_column(sa.DateTime(timezone=True))
operation_id: Mapped[UUID | None] = mapped_column()
class KnowledgeSourceRow(TimestampMixin, Base):
__tablename__ = "knowledge_sources"
__table_args__ = (
sa.ForeignKeyConstraint(
["workspace_id", "project_id"],
["projects.workspace_id", "projects.id"],
name="fk_knowledge_sources_project_scope",
),
sa.UniqueConstraint("project_id", "slug", name="uq_knowledge_sources_project_slug"),
)
id: Mapped[UUID] = mapped_column(UUID_TYPE, primary_key=True, default=uuid4)
workspace_id: Mapped[UUID] = mapped_column(nullable=False)
project_id: Mapped[UUID] = mapped_column(nullable=False)
slug: Mapped[str] = mapped_column(sa.String(63), nullable=False)
source_type: Mapped[str] = mapped_column(sa.String(64), nullable=False)
uri: Mapped[str] = mapped_column(sa.String(2048), nullable=False)
visibility: Mapped[str] = mapped_column(sa.String(32), nullable=False, default="project")
state: Mapped[str] = mapped_column(sa.String(32), nullable=False, default="registered")
configuration: Mapped[dict[str, Any]] = mapped_column(JSON_TYPE, default=dict, nullable=False)
last_indexed_at: Mapped[datetime | None] = mapped_column(sa.DateTime(timezone=True))
class KnowledgeDocumentRow(TimestampMixin, Base):
__tablename__ = "knowledge_documents"
__table_args__ = (
sa.ForeignKeyConstraint(
["workspace_id", "project_id"],
["projects.workspace_id", "projects.id"],
name="fk_knowledge_documents_project_scope",
),
sa.ForeignKeyConstraint(
["source_id"], ["knowledge_sources.id"], name="fk_knowledge_documents_source"
),
sa.UniqueConstraint("source_id", "external_ref", name="uq_knowledge_documents_source_ref"),
)
id: Mapped[UUID] = mapped_column(UUID_TYPE, primary_key=True, default=uuid4)
workspace_id: Mapped[UUID] = mapped_column(nullable=False)
project_id: Mapped[UUID] = mapped_column(nullable=False)
source_id: Mapped[UUID] = mapped_column(nullable=False)
external_ref: Mapped[str] = mapped_column(sa.String(1024), nullable=False)
title: Mapped[str] = mapped_column(sa.String(500), nullable=False)
content_hash: Mapped[str] = mapped_column(sa.String(128), nullable=False)
document_version: Mapped[int] = mapped_column(sa.Integer, nullable=False, default=1)
state: Mapped[str] = mapped_column(sa.String(32), nullable=False, default="registered")
content_bytes: Mapped[int] = mapped_column(sa.Integer, nullable=False, default=0)
record_metadata: Mapped[dict[str, Any]] = mapped_column(JSON_TYPE, default=dict, nullable=False)
class KnowledgeChunkRow(TimestampMixin, Base):
__tablename__ = "knowledge_chunks"
__table_args__ = (
sa.ForeignKeyConstraint(
["document_id"], ["knowledge_documents.id"], name="fk_knowledge_chunks_document"
),
sa.UniqueConstraint("document_id", "chunk_index", name="uq_knowledge_chunks_index"),
)
id: Mapped[UUID] = mapped_column(UUID_TYPE, primary_key=True, default=uuid4)
workspace_id: Mapped[UUID] = mapped_column(nullable=False)
project_id: Mapped[UUID] = mapped_column(nullable=False)
document_id: Mapped[UUID] = mapped_column(nullable=False)
chunk_index: Mapped[int] = mapped_column(sa.Integer, nullable=False)
text: Mapped[str] = mapped_column(sa.Text, nullable=False)
content_hash: Mapped[str] = mapped_column(sa.String(128), nullable=False)
token_count: Mapped[int] = mapped_column(sa.Integer, nullable=False, default=0)
record_metadata: Mapped[dict[str, Any]] = mapped_column(JSON_TYPE, default=dict, nullable=False)