import { defineSchema, defineTable } from "convex/server"; import { v } from "convex/values"; export default defineSchema({ users: defineTable({ x_user_id: v.optional(v.string()), username: v.optional(v.string()), email: v.optional(v.string()), created_at: v.string(), updated_at: v.string(), }) .index("by_x_user_id", ["x_user_id"]) .index("by_username", ["username"]) .index("by_email", ["email"]), wallets: defineTable({ user_id: v.id("users"), balance_credits: v.number(), updated_at: v.string(), }).index("by_user_id", ["user_id"]), wallet_transactions: defineTable({ user_id: v.id("users"), type: v.union(v.literal("credit"), v.literal("debit"), v.literal("refund")), amount: v.number(), reason: v.optional(v.string()), idempotency_key: v.string(), balance_after: v.number(), created_at: v.string(), }) .index("by_user_id", ["user_id"]) .index("by_idempotency_key", ["idempotency_key"]), mention_events: defineTable({ mention_post_id: v.string(), mention_author_id: v.string(), parent_post_id: v.string(), status: v.string(), error_code: v.optional(v.string()), created_at: v.string(), updated_at: v.string(), }) .index("by_mention_post_id", ["mention_post_id"]) .index("by_parent_post_id", ["parent_post_id"]) .index("by_mention_author_id", ["mention_author_id"]), articles: defineTable({ x_article_id: v.optional(v.string()), parent_post_id: v.string(), author_id: v.optional(v.string()), title: v.string(), char_count: v.number(), content_hash: v.optional(v.string()), raw_content: v.optional(v.string()), created_at: v.string(), updated_at: v.string(), }) .index("by_x_article_id", ["x_article_id"]) .index("by_parent_post_id", ["parent_post_id"]) .index("by_content_hash", ["content_hash"]), audio_jobs: defineTable({ user_id: v.id("users"), mention_event_id: v.optional(v.id("mention_events")), article_id: v.id("articles"), status: v.union( v.literal("received"), v.literal("validated"), v.literal("priced"), v.literal("charged"), v.literal("synthesizing"), v.literal("uploaded"), v.literal("completed"), v.literal("failed_refunded"), v.literal("failed_not_refunded"), ), credits_charged: v.number(), tts_provider: v.optional(v.string()), tts_model: v.optional(v.string()), error: v.optional(v.string()), asset_id: v.optional(v.id("audio_assets")), created_at: v.string(), updated_at: v.string(), }) .index("by_user_id", ["user_id"]) .index("by_mention_event_id", ["mention_event_id"]) .index("by_article_id", ["article_id"]) .index("by_status", ["status"]), audio_assets: defineTable({ job_id: v.id("audio_jobs"), storage_key: v.optional(v.string()), duration_sec: v.optional(v.number()), size_bytes: v.optional(v.number()), codec: v.optional(v.string()), public_url_ttl: v.optional(v.number()), deleted_at: v.optional(v.string()), last_played_at: v.optional(v.string()), created_at: v.string(), updated_at: v.string(), }).index("by_job_id", ["job_id"]), audio_access_grants: defineTable({ audio_asset_id: v.id("audio_assets"), user_id: v.id("users"), granted_via: v.union(v.literal("owner"), v.literal("repurchase"), v.literal("admin")), credits_paid: v.number(), created_at: v.string(), }) .index("by_audio_asset_id", ["audio_asset_id"]) .index("by_user_id", ["user_id"]) .index("by_asset_and_user", ["audio_asset_id", "user_id"]), payment_events: defineTable({ provider: v.string(), provider_event_id: v.string(), status: v.string(), payload_hash: v.optional(v.string()), created_at: v.string(), updated_at: v.string(), }) .index("by_provider_event_id", ["provider_event_id"]) .index("by_provider_and_event", ["provider", "provider_event_id"]), // Legacy compatibility table while runtime is still transitioning away from snapshot persistence. state_snapshots: defineTable({ snapshot: v.any(), updatedAt: v.string(), }), });