Pablan, as it stands
Self-hosted knowledge management for SMEs: a split-screen Markdown editor whose sections an LLM refines while you write, and RAG question answering over the documents that result. FastAPI + Postgres/pgvector on the back, SvelteKit on the front, everything OpenAI-compatible and self-hostable. Squashed into a single commit; the development history stays local. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CA43ZJda8Rbp2hKXNy8f6b
This commit is contained in:
co-authored by
Claude Opus 5
parent
68d3a43191
commit
784b76baf7
@@ -0,0 +1,94 @@
|
||||
"""document events audit trail
|
||||
|
||||
An append-only history of who changed or reviewed a document, and when.
|
||||
Content-bearing events (created / edited) snapshot the Markdown source of truth
|
||||
so a past version can be viewed or diffed; the disposable chunks are never
|
||||
snapshotted. `actor_id` is SET NULL so the trail outlives its actor's account;
|
||||
events cascade with their document.
|
||||
|
||||
Revision ID: d5a9c1e3b7f2
|
||||
Revises: c4f7a1b2e9d3
|
||||
Create Date: 2026-07-22 00:00:00.000000
|
||||
|
||||
"""
|
||||
|
||||
from typing import Sequence, Union
|
||||
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy.dialects import postgresql
|
||||
|
||||
from alembic import op
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision: str = "d5a9c1e3b7f2"
|
||||
down_revision: Union[str, Sequence[str], None] = "c4f7a1b2e9d3"
|
||||
branch_labels: Union[str, Sequence[str], None] = None
|
||||
depends_on: Union[str, Sequence[str], None] = None
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
"""Upgrade schema."""
|
||||
op.create_table(
|
||||
"document_events",
|
||||
sa.Column("document_id", sa.Uuid(), nullable=False),
|
||||
sa.Column("actor_id", sa.Uuid(), nullable=True),
|
||||
sa.Column(
|
||||
"action",
|
||||
sa.Enum(
|
||||
"created",
|
||||
"edited",
|
||||
"published",
|
||||
"archived",
|
||||
"visibility_changed",
|
||||
"review_requested",
|
||||
"review_resolved",
|
||||
name="documenteventaction",
|
||||
native_enum=False,
|
||||
length=32,
|
||||
),
|
||||
nullable=False,
|
||||
),
|
||||
sa.Column("content_md", sa.Text(), nullable=True),
|
||||
sa.Column("title", sa.String(length=500), nullable=True),
|
||||
sa.Column(
|
||||
"visibility",
|
||||
sa.Enum(
|
||||
"public",
|
||||
"department",
|
||||
"restricted",
|
||||
name="documentvisibility",
|
||||
native_enum=False,
|
||||
length=32,
|
||||
),
|
||||
nullable=True,
|
||||
),
|
||||
sa.Column("meta", postgresql.JSONB(astext_type=sa.Text()), nullable=True),
|
||||
sa.Column("id", sa.Uuid(), nullable=False),
|
||||
sa.Column(
|
||||
"created_at",
|
||||
sa.DateTime(timezone=True),
|
||||
server_default=sa.text("now()"),
|
||||
nullable=False,
|
||||
),
|
||||
sa.Column(
|
||||
"updated_at",
|
||||
sa.DateTime(timezone=True),
|
||||
server_default=sa.text("now()"),
|
||||
nullable=False,
|
||||
),
|
||||
sa.ForeignKeyConstraint(["document_id"], ["documents.id"], ondelete="CASCADE"),
|
||||
sa.ForeignKeyConstraint(["actor_id"], ["users.id"], ondelete="SET NULL"),
|
||||
sa.PrimaryKeyConstraint("id"),
|
||||
)
|
||||
op.create_index(
|
||||
op.f("ix_document_events_document_id"),
|
||||
"document_events",
|
||||
["document_id"],
|
||||
unique=False,
|
||||
)
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
"""Downgrade schema."""
|
||||
op.drop_index(op.f("ix_document_events_document_id"), table_name="document_events")
|
||||
op.drop_table("document_events")
|
||||
Reference in New Issue
Block a user