2026-10-24 11:02:47 -04:00
import { sql } from "drizzle-orm" ;
import {
bigint ,
check ,
foreignKey ,
index ,
integer ,
jsonb ,
pgTable ,
primaryKey ,
text ,
timestamp ,
unique ,
uniqueIndex ,
uuid ,
varchar ,
} from "drizzle-orm/pg-core" ;
import { workspaceMembers } from "./objects" ;
import { workspaces } from "./workspaces" ;
export const chatChannels = pgTable (
"chat_channels" ,
{
id : uuid ( "id" ) . primaryKey ( ) . defaultRandom ( ) ,
workspaceId : uuid ( "workspace_id" )
. notNull ( )
. references ( ( ) = > workspaces . id , { onDelete : "cascade" } ) ,
kind : varchar ( "kind" , { length : 16 } )
. notNull ( )
. $type < "public" | "private" | "direct" > ( ) ,
name : varchar ( "name" , { length : 200 } ) ,
ownerUserId : uuid ( "owner_user_id" ) . notNull ( ) ,
directKey : text ( "direct_key" ) ,
nextSequence : bigint ( "next_sequence" , { mode : "bigint" } )
. notNull ( )
. default ( sql ` 1 ` ) ,
2026-10-29 15:30:20 -04:00
nextMutationSequence : bigint ( "next_mutation_sequence" , { mode : "bigint" } )
. notNull ( )
. default ( sql ` 1 ` ) ,
2026-10-24 11:02:47 -04:00
/** Structural signal; transaction policy must reject writes when this is non-null. */
archivedAt : timestamp ( "archived_at" , { withTimezone : true } ) ,
createdAt : timestamp ( "created_at" , { withTimezone : true } )
. defaultNow ( )
. notNull ( ) ,
updatedAt : timestamp ( "updated_at" , { withTimezone : true } )
. defaultNow ( )
. notNull ( ) ,
} ,
( table ) = > ( {
workspaceIdx : index ( "chat_channels_workspace_id_idx" ) . on ( table . workspaceId ) ,
workspaceIdUnique : unique ( "chat_channels_workspace_id_id_unique" ) . on (
table . workspaceId ,
table . id ,
) ,
ownerFk : foreignKey ( {
columns : [ table . workspaceId , table . ownerUserId ] ,
foreignColumns : [ workspaceMembers . workspaceId , workspaceMembers . userId ] ,
name : "chat_channels_owner_member_fk" ,
} ) ,
directKeyUnique : uniqueIndex ( "chat_channels_workspace_id_direct_key_unique" )
. on ( table . workspaceId , table . directKey )
. where ( sql ` ${ table . directKey } is not null ` ) ,
kindCheck : check (
"chat_channels_kind_check" ,
sql ` ${ table . kind } in ('public', 'private', 'direct') ` ,
) ,
directKeyCheck : check (
"chat_channels_direct_key_check" ,
sql ` ( ${ table . kind } = 'direct' and ${ table . directKey } is not null and ${ table . name } is null) or ( ${ table . kind } <> 'direct' and ${ table . directKey } is null) ` ,
) ,
sequenceCheck : check (
"chat_channels_next_sequence_check" ,
sql ` ${ table . nextSequence } > 0 ` ,
) ,
} ) ,
) ;
export const chatChannelMembers = pgTable (
"chat_channel_members" ,
{
workspaceId : uuid ( "workspace_id" )
. notNull ( )
. references ( ( ) = > workspaces . id , { onDelete : "cascade" } ) ,
channelId : uuid ( "channel_id" ) . notNull ( ) ,
userId : uuid ( "user_id" ) . notNull ( ) ,
joinedAt : timestamp ( "joined_at" , { withTimezone : true } )
. defaultNow ( )
. notNull ( ) ,
} ,
( table ) = > ( {
pk : primaryKey ( {
columns : [ table . workspaceId , table . channelId , table . userId ] ,
} ) ,
workspaceIdx : index ( "chat_channel_members_workspace_id_idx" ) . on (
table . workspaceId ,
) ,
userIdx : index ( "chat_channel_members_workspace_id_user_id_idx" ) . on (
table . workspaceId ,
table . userId ,
) ,
channelFk : foreignKey ( {
columns : [ table . workspaceId , table . channelId ] ,
foreignColumns : [ chatChannels . workspaceId , chatChannels . id ] ,
name : "chat_channel_members_channel_fk" ,
} ) . onDelete ( "cascade" ) ,
memberFk : foreignKey ( {
columns : [ table . workspaceId , table . userId ] ,
foreignColumns : [ workspaceMembers . workspaceId , workspaceMembers . userId ] ,
name : "chat_channel_members_workspace_member_fk" ,
} ) ,
} ) ,
) ;
export const chatMessages = pgTable (
"chat_messages" ,
{
id : uuid ( "id" ) . primaryKey ( ) . defaultRandom ( ) ,
workspaceId : uuid ( "workspace_id" )
. notNull ( )
. references ( ( ) = > workspaces . id , { onDelete : "cascade" } ) ,
channelId : uuid ( "channel_id" ) . notNull ( ) ,
sequence : bigint ( "sequence" , { mode : "bigint" } ) . notNull ( ) ,
parentMessageId : uuid ( "parent_message_id" ) ,
authorType : varchar ( "author_type" , { length : 16 } )
. notNull ( )
. $type < "human" | "agent" | "system" > ( ) ,
authorUserId : uuid ( "author_user_id" ) ,
/** Opaque, pinned agent identity until the agent registry schema exists. */
authorAgentId : uuid ( "author_agent_id" ) ,
body : text ( "body" ) . notNull ( ) ,
2026-10-29 15:30:20 -04:00
/** Pinned send intent survives edits and tombstones. */
sendIntentFingerprint : text ( "send_intent_fingerprint" ) ,
revision : integer ( "revision" ) . notNull ( ) . default ( 1 ) ,
2026-10-24 11:02:47 -04:00
status : varchar ( "status" , { length : 16 } )
. notNull ( )
. default ( "sent" )
. $type < "sent" | "edited" | "deleted" > ( ) ,
clientIdempotencyKey : varchar ( "client_idempotency_key" , {
length : 200 ,
} ) . notNull ( ) ,
createdAt : timestamp ( "created_at" , { withTimezone : true } )
. defaultNow ( )
. notNull ( ) ,
editedAt : timestamp ( "edited_at" , { withTimezone : true } ) ,
deletedAt : timestamp ( "deleted_at" , { withTimezone : true } ) ,
} ,
( table ) = > ( {
workspaceIdx : index ( "chat_messages_workspace_id_idx" ) . on ( table . workspaceId ) ,
2026-10-29 15:30:20 -04:00
revisionCheck : check (
"chat_messages_revision_check" ,
sql ` ${ table . revision } > 0 ` ,
) ,
2026-10-24 11:02:47 -04:00
workspaceIdUnique : unique ( "chat_messages_workspace_id_id_unique" ) . on (
table . workspaceId ,
table . id ,
) ,
workspaceChannelIdUnique : unique (
"chat_messages_workspace_channel_id_unique" ,
) . on ( table . workspaceId , table . channelId , table . id ) ,
channelSequenceUnique : unique (
"chat_messages_workspace_channel_sequence_unique" ,
) . on ( table . workspaceId , table . channelId , table . sequence ) ,
clientKeyUnique : unique (
"chat_messages_workspace_channel_client_key_unique" ,
) . on ( table . workspaceId , table . channelId , table . clientIdempotencyKey ) ,
channelFk : foreignKey ( {
columns : [ table . workspaceId , table . channelId ] ,
foreignColumns : [ chatChannels . workspaceId , chatChannels . id ] ,
name : "chat_messages_channel_fk" ,
} ) . onDelete ( "cascade" ) ,
parentFk : foreignKey ( {
columns : [ table . workspaceId , table . channelId , table . parentMessageId ] ,
foreignColumns : [ table . workspaceId , table . channelId , table . id ] ,
name : "chat_messages_parent_fk" ,
} ) ,
humanAuthorFk : foreignKey ( {
columns : [ table . workspaceId , table . authorUserId ] ,
foreignColumns : [ workspaceMembers . workspaceId , workspaceMembers . userId ] ,
name : "chat_messages_human_author_member_fk" ,
} ) ,
authorCheck : check (
"chat_messages_author_check" ,
sql ` ( ${ table . authorType } = 'human' and ${ table . authorUserId } is not null and ${ table . authorAgentId } is null) or ( ${ table . authorType } = 'agent' and ${ table . authorUserId } is null and ${ table . authorAgentId } is not null) or ( ${ table . authorType } = 'system' and ${ table . authorUserId } is null and ${ table . authorAgentId } is null) ` ,
) ,
statusCheck : check (
"chat_messages_status_check" ,
sql ` ${ table . status } in ('sent', 'edited', 'deleted') ` ,
) ,
sequenceCheck : check (
"chat_messages_sequence_check" ,
sql ` ${ table . sequence } >= 0 ` ,
) ,
} ) ,
) ;
export const chatMessageMentions = pgTable (
"chat_message_mentions" ,
{
workspaceId : uuid ( "workspace_id" )
. notNull ( )
. references ( ( ) = > workspaces . id , { onDelete : "cascade" } ) ,
messageId : uuid ( "message_id" ) . notNull ( ) ,
userId : uuid ( "user_id" ) . notNull ( ) ,
} ,
( table ) = > ( {
pk : primaryKey ( {
columns : [ table . workspaceId , table . messageId , table . userId ] ,
} ) ,
workspaceIdx : index ( "chat_message_mentions_workspace_id_idx" ) . on (
table . workspaceId ,
) ,
messageFk : foreignKey ( {
columns : [ table . workspaceId , table . messageId ] ,
foreignColumns : [ chatMessages . workspaceId , chatMessages . id ] ,
name : "chat_message_mentions_message_fk" ,
} ) . onDelete ( "cascade" ) ,
mentionedMemberFk : foreignKey ( {
columns : [ table . workspaceId , table . userId ] ,
foreignColumns : [ workspaceMembers . workspaceId , workspaceMembers . userId ] ,
name : "chat_message_mentions_workspace_member_fk" ,
} ) ,
} ) ,
) ;
2026-10-29 15:30:20 -04:00
export const chatMessageMutations = pgTable (
"chat_message_mutations" ,
{
id : uuid ( "id" ) . primaryKey ( ) . defaultRandom ( ) ,
workspaceId : uuid ( "workspace_id" )
. notNull ( )
. references ( ( ) = > workspaces . id , { onDelete : "cascade" } ) ,
channelId : uuid ( "channel_id" ) . notNull ( ) ,
messageId : uuid ( "message_id" ) . notNull ( ) ,
mutationSequence : bigint ( "mutation_sequence" , { mode : "bigint" } ) . notNull ( ) ,
revision : integer ( "revision" ) . notNull ( ) ,
kind : varchar ( "kind" , { length : 16 } )
. notNull ( )
. $type < "edited" | "deleted" > ( ) ,
createdAt : timestamp ( "created_at" , { withTimezone : true } )
. defaultNow ( )
. notNull ( ) ,
} ,
( table ) = > ( {
workspaceIdx : index ( "chat_message_mutations_workspace_id_idx" ) . on (
table . workspaceId ,
) ,
sequenceUnique : unique ( "chat_message_mutations_channel_sequence_unique" ) . on (
table . workspaceId ,
table . channelId ,
table . mutationSequence ,
) ,
channelFk : foreignKey ( {
columns : [ table . workspaceId , table . channelId ] ,
foreignColumns : [ chatChannels . workspaceId , chatChannels . id ] ,
name : "chat_message_mutations_channel_fk" ,
} ) . onDelete ( "cascade" ) ,
messageFk : foreignKey ( {
columns : [ table . workspaceId , table . messageId ] ,
foreignColumns : [ chatMessages . workspaceId , chatMessages . id ] ,
name : "chat_message_mutations_message_fk" ,
} ) . onDelete ( "cascade" ) ,
revisionCheck : check (
"chat_message_mutations_revision_check" ,
sql ` ${ table . revision } > 1 ` ,
) ,
} ) ,
) ;
2026-10-24 11:02:47 -04:00
export const chatReadCursors = pgTable (
"chat_read_cursors" ,
{
workspaceId : uuid ( "workspace_id" )
. notNull ( )
. references ( ( ) = > workspaces . id , { onDelete : "cascade" } ) ,
channelId : uuid ( "channel_id" ) . notNull ( ) ,
userId : uuid ( "user_id" ) . notNull ( ) ,
sequence : bigint ( "sequence" , { mode : "bigint" } )
. notNull ( )
. default ( sql ` 0 ` ) ,
updatedAt : timestamp ( "updated_at" , { withTimezone : true } )
. defaultNow ( )
. notNull ( ) ,
} ,
( table ) = > ( {
pk : primaryKey ( {
columns : [ table . workspaceId , table . channelId , table . userId ] ,
} ) ,
workspaceIdx : index ( "chat_read_cursors_workspace_id_idx" ) . on (
table . workspaceId ,
) ,
channelFk : foreignKey ( {
columns : [ table . workspaceId , table . channelId ] ,
foreignColumns : [ chatChannels . workspaceId , chatChannels . id ] ,
name : "chat_read_cursors_channel_fk" ,
} ) . onDelete ( "cascade" ) ,
readerMemberFk : foreignKey ( {
columns : [ table . workspaceId , table . userId ] ,
foreignColumns : [ workspaceMembers . workspaceId , workspaceMembers . userId ] ,
name : "chat_read_cursors_workspace_member_fk" ,
} ) ,
sequenceCheck : check (
"chat_read_cursors_sequence_check" ,
sql ` ${ table . sequence } >= 0 ` ,
) ,
} ) ,
) ;
export const chatMutationReceipts = pgTable (
"chat_mutation_receipts" ,
{
workspaceId : uuid ( "workspace_id" )
. notNull ( )
. references ( ( ) = > workspaces . id , { onDelete : "cascade" } ) ,
actorUserId : uuid ( "actor_user_id" ) . notNull ( ) ,
clientMutationId : uuid ( "client_mutation_id" ) . notNull ( ) ,
operation : varchar ( "operation" , { length : 50 } ) . notNull ( ) ,
fingerprint : text ( "fingerprint" ) . notNull ( ) ,
result : jsonb ( "result" ) . $type < Record < string , unknown > > ( ) . notNull ( ) ,
createdAt : timestamp ( "created_at" , { withTimezone : true } )
. defaultNow ( )
. notNull ( ) ,
} ,
( table ) = > ( {
pk : primaryKey ( {
columns : [ table . workspaceId , table . actorUserId , table . clientMutationId ] ,
} ) ,
workspaceIdx : index ( "chat_mutation_receipts_workspace_id_idx" ) . on (
table . workspaceId ,
) ,
actorFk : foreignKey ( {
columns : [ table . workspaceId , table . actorUserId ] ,
foreignColumns : [ workspaceMembers . workspaceId , workspaceMembers . userId ] ,
name : "chat_mutation_receipts_workspace_member_fk" ,
} ) . onDelete ( "cascade" ) ,
} ) ,
) ;
export const chatOutbox = pgTable (
"chat_outbox" ,
{
id : uuid ( "id" ) . primaryKey ( ) . defaultRandom ( ) ,
workspaceId : uuid ( "workspace_id" )
. notNull ( )
. references ( ( ) = > workspaces . id , { onDelete : "cascade" } ) ,
channelId : uuid ( "channel_id" ) . notNull ( ) ,
messageId : uuid ( "message_id" ) ,
eventVersion : integer ( "event_version" ) . notNull ( ) . default ( 1 ) ,
eventType : varchar ( "event_type" , { length : 100 } ) . notNull ( ) ,
dedupeKey : varchar ( "dedupe_key" , { length : 250 } ) . notNull ( ) ,
payload : jsonb ( "payload" ) . $type < Record < string , unknown > > ( ) . notNull ( ) ,
createdAt : timestamp ( "created_at" , { withTimezone : true } )
. defaultNow ( )
. notNull ( ) ,
publishedAt : timestamp ( "published_at" , { withTimezone : true } ) ,
attempts : integer ( "attempts" ) . notNull ( ) . default ( 0 ) ,
lastError : text ( "last_error" ) ,
} ,
( table ) = > ( {
workspaceIdx : index ( "chat_outbox_workspace_id_idx" ) . on ( table . workspaceId ) ,
unpublishedIdx : index ( "chat_outbox_unpublished_idx" )
. on ( table . createdAt )
. where ( sql ` ${ table . publishedAt } is null ` ) ,
dedupeUnique : unique ( "chat_outbox_workspace_id_dedupe_key_unique" ) . on (
table . workspaceId ,
table . dedupeKey ,
) ,
channelFk : foreignKey ( {
columns : [ table . workspaceId , table . channelId ] ,
foreignColumns : [ chatChannels . workspaceId , chatChannels . id ] ,
name : "chat_outbox_channel_fk" ,
} ) . onDelete ( "cascade" ) ,
messageFk : foreignKey ( {
columns : [ table . workspaceId , table . messageId ] ,
foreignColumns : [ chatMessages . workspaceId , chatMessages . id ] ,
name : "chat_outbox_message_fk" ,
} ) . onDelete ( "cascade" ) ,
versionCheck : check (
"chat_outbox_event_version_check" ,
sql ` ${ table . eventVersion } > 0 ` ,
) ,
attemptsCheck : check (
"chat_outbox_attempts_check" ,
sql ` ${ table . attempts } >= 0 ` ,
) ,
} ) ,
) ;