import { defineSchema, defineTable } from 'convex/server'; import { v } from 'convex/values'; export default defineSchema({ users: defineTable({ telegramId: v.int64(), telegramChatId: v.optional(v.int64()), geminiApiKey: v.optional(v.string()), systemPrompt: v.optional(v.string()), followUpPrompt: v.optional(v.string()), model: v.string(), followUpModel: v.optional(v.string()), activeChatId: v.optional(v.id('chats')), ragCollectionMode: v.optional( v.object({ ragDatabaseId: v.id('ragDatabases'), activeSince: v.number() }) ) }).index('by_telegram_id', ['telegramId']), chats: defineTable({ userId: v.id('users'), mnemonic: v.string(), createdAt: v.number() }).index('by_mnemonic', ['mnemonic']), messages: defineTable({ chatId: v.id('chats'), role: v.union(v.literal('user'), v.literal('assistant')), content: v.string(), imageBase64: v.optional(v.string()), imageMediaType: v.optional(v.string()), imageStorageId: v.optional(v.id('_storage')), imagesBase64: v.optional(v.array(v.string())), imagesMediaTypes: v.optional(v.array(v.string())), followUpOptions: v.optional(v.array(v.string())), source: v.union(v.literal('telegram'), v.literal('web')), createdAt: v.number(), isStreaming: v.optional(v.boolean()) }) .index('by_chat_id', ['chatId']) .index('by_chat_id_and_created_at', ['chatId', 'createdAt']), pendingGenerations: defineTable({ userId: v.id('users'), chatId: v.id('chats'), userMessage: v.string(), imagesBase64: v.optional(v.array(v.string())), imagesMediaTypes: v.optional(v.array(v.string())), createdAt: v.number() }), pendingGenerationImages: defineTable({ pendingGenerationId: v.id('pendingGenerations'), base64: v.string(), mediaType: v.string(), order: v.number() }).index('by_pending_generation_id', ['pendingGenerationId']), messageImages: defineTable({ messageId: v.id('messages'), base64: v.string(), mediaType: v.string(), order: v.number() }).index('by_message_id', ['messageId']), devicePairings: defineTable({ chatId: v.id('chats'), deviceId: v.string(), hasCamera: v.boolean(), pairedWithDeviceId: v.optional(v.string()), lastSeen: v.number() }).index('by_chat_id', ['chatId']), pairingRequests: defineTable({ chatId: v.id('chats'), fromDeviceId: v.string(), status: v.union(v.literal('pending'), v.literal('accepted'), v.literal('rejected')), createdAt: v.number() }).index('by_chat_id', ['chatId']), photoRequests: defineTable({ chatId: v.id('chats'), requesterId: v.string(), captureDeviceId: v.optional(v.string()), status: v.union( v.literal('pending'), v.literal('countdown'), v.literal('capture_now'), v.literal('captured'), v.literal('accepted'), v.literal('rejected') ), photoBase64: v.optional(v.string()), photoMediaType: v.optional(v.string()), thumbnailBase64: v.optional(v.string()), createdAt: v.number() }).index('by_chat_id', ['chatId']), photoDrafts: defineTable({ chatId: v.id('chats'), deviceId: v.string(), base64: v.string(), mediaType: v.string(), createdAt: v.number() }).index('by_chat_id_and_device_id', ['chatId', 'deviceId']), ragDatabases: defineTable({ userId: v.id('users'), name: v.string(), createdAt: v.number() }) .index('by_user_id', ['userId']) .index('by_user_id_and_name', ['userId', 'name']), ragConnections: defineTable({ userId: v.id('users'), ragDatabaseId: v.id('ragDatabases'), isGlobal: v.boolean(), createdAt: v.number() }) .index('by_user_id', ['userId']) .index('by_user_id_and_rag_database_id', ['userId', 'ragDatabaseId']) .index('by_rag_database_id', ['ragDatabaseId']) });