"""saved_chats.share_token: the anonymous share link (phase 51) Revision ID: 0009 Revises: 0008 Create Date: 2026-08-29 Phase 51 (share-a-chat-by-link, owner-locked 2026-08-29): a saved chat can be turned into a public link — ``/shared/`` — that anyone with the URL can read anonymously (no admin session); unsharing sets the token back to NULL and revokes the link. * ``saved_chats.share_token`` — ``UUID`` (a 128-bit ``uuid4``), NULL = not shared. One column, no new table (A10 extension unchanged — sharing reuses the already-stored row). * ``ix_saved_chats_share_token`` — UNIQUE index on the column. A unique index on a NULLable column: Postgres treats NULLs as distinct, so any number of unshared chats coexist while two identical non-NULL tokens can never exist (the ``git_sources.path`` house precedent, phase 38). """ from __future__ import annotations import sqlalchemy as sa from sqlalchemy.dialects import postgresql from alembic import op revision = "0009" down_revision = "0008" branch_labels = None depends_on = None def upgrade() -> None: op.add_column( "saved_chats", sa.Column("share_token", postgresql.UUID(as_uuid=True), nullable=True), ) op.create_index( "ix_saved_chats_share_token", "saved_chats", ["share_token"], unique=True ) def downgrade() -> None: op.drop_index("ix_saved_chats_share_token", table_name="saved_chats") op.drop_column("saved_chats", "share_token")