feat: add reports table and report status enum for generated Markdown reports

This commit is contained in:
Anish Sarkar 2026-02-11 16:28:56 +05:30
parent 1d1e2c6b48
commit b6c0406d10
2 changed files with 135 additions and 0 deletions

View file

@ -0,0 +1,88 @@
"""Add reports table
Revision ID: 99
Revises: 98
Create Date: 2026-02-11
Adds report_status enum and reports table for storing generated Markdown reports.
"""
from collections.abc import Sequence
from alembic import op
revision: str = "99"
down_revision: str | None = "98"
branch_labels: str | Sequence[str] | None = None
depends_on: str | Sequence[str] | None = None
def upgrade() -> None:
# Create the report_status enum type
op.execute(
"""
DO $$ BEGIN
CREATE TYPE report_status AS ENUM ('ready', 'failed');
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
"""
)
# Create the reports table
op.execute(
"""
CREATE TABLE IF NOT EXISTS reports (
id SERIAL PRIMARY KEY,
title VARCHAR(500) NOT NULL,
content TEXT,
report_metadata JSONB,
status report_status NOT NULL DEFAULT 'ready',
report_style VARCHAR(100),
search_space_id INTEGER NOT NULL
REFERENCES searchspaces(id) ON DELETE CASCADE,
thread_id INTEGER
REFERENCES new_chat_threads(id) ON DELETE SET NULL,
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW()
);
"""
)
# Add indexes
op.execute(
"""
CREATE INDEX IF NOT EXISTS ix_reports_status
ON reports(status);
"""
)
op.execute(
"""
CREATE INDEX IF NOT EXISTS ix_reports_search_space_id
ON reports(search_space_id);
"""
)
op.execute(
"""
CREATE INDEX IF NOT EXISTS ix_reports_thread_id
ON reports(thread_id);
"""
)
op.execute(
"""
CREATE INDEX IF NOT EXISTS ix_reports_created_at
ON reports(created_at);
"""
)
def downgrade() -> None:
op.execute("DROP INDEX IF EXISTS ix_reports_created_at")
op.execute("DROP INDEX IF EXISTS ix_reports_thread_id")
op.execute("DROP INDEX IF EXISTS ix_reports_search_space_id")
op.execute("DROP INDEX IF EXISTS ix_reports_status")
op.execute("DROP TABLE IF EXISTS reports")
op.execute("DROP TYPE IF EXISTS report_status")

View file

@ -100,6 +100,11 @@ class PodcastStatus(str, Enum):
FAILED = "failed"
class ReportStatus(str, Enum):
READY = "ready"
FAILED = "failed"
class DocumentStatus:
"""
Helper class for document processing status (stored as JSONB).
@ -1031,6 +1036,42 @@ class Podcast(BaseModel, TimestampMixin):
thread = relationship("NewChatThread")
class Report(BaseModel, TimestampMixin):
"""Report model for storing generated Markdown reports."""
__tablename__ = "reports"
title = Column(String(500), nullable=False)
content = Column(Text, nullable=True) # Markdown body
report_metadata = Column(JSONB, nullable=True) # section headings, word count, etc.
status = Column(
SQLAlchemyEnum(
ReportStatus,
name="report_status",
create_type=False,
values_callable=lambda x: [e.value for e in x],
),
nullable=False,
default=ReportStatus.READY,
server_default="ready",
index=True,
)
report_style = Column(String(100), nullable=True) # e.g. "executive_summary", "deep_research"
search_space_id = Column(
Integer, ForeignKey("searchspaces.id", ondelete="CASCADE"), nullable=False
)
search_space = relationship("SearchSpace", back_populates="reports")
thread_id = Column(
Integer,
ForeignKey("new_chat_threads.id", ondelete="SET NULL"),
nullable=True,
index=True,
)
thread = relationship("NewChatThread")
class ImageGenerationConfig(BaseModel, TimestampMixin):
"""
Dedicated configuration table for image generation models.
@ -1185,6 +1226,12 @@ class SearchSpace(BaseModel, TimestampMixin):
order_by="Podcast.id.desc()",
cascade="all, delete-orphan",
)
reports = relationship(
"Report",
back_populates="search_space",
order_by="Report.id.desc()",
cascade="all, delete-orphan",
)
image_generations = relationship(
"ImageGeneration",
back_populates="search_space",