import { defineSchema, defineTable } from "convex/server"; import { v } from "convex/values"; export default defineSchema({ users: defineTable({ tenantId: v.string(), name: v.string(), email: v.string(), role: v.optional(v.string()), avatarUrl: v.optional(v.string()), teams: v.optional(v.array(v.string())), }) .index("by_tenant_email", ["tenantId", "email"]) .index("by_tenant_role", ["tenantId", "role"]), queues: defineTable({ tenantId: v.string(), name: v.string(), slug: v.string(), teamId: v.optional(v.id("teams")), }) .index("by_tenant_slug", ["tenantId", "slug"]) .index("by_tenant", ["tenantId"]), teams: defineTable({ tenantId: v.string(), name: v.string(), description: v.optional(v.string()), }).index("by_tenant_name", ["tenantId", "name"]), slaPolicies: defineTable({ tenantId: v.string(), name: v.string(), description: v.optional(v.string()), timeToFirstResponse: v.optional(v.number()), // minutes timeToResolution: v.optional(v.number()), // minutes }).index("by_tenant_name", ["tenantId", "name"]), tickets: defineTable({ tenantId: v.string(), reference: v.number(), subject: v.string(), summary: v.optional(v.string()), status: v.string(), priority: v.string(), channel: v.string(), queueId: v.optional(v.id("queues")), requesterId: v.id("users"), assigneeId: v.optional(v.id("users")), slaPolicyId: v.optional(v.id("slaPolicies")), dueAt: v.optional(v.number()), // ms since epoch firstResponseAt: v.optional(v.number()), resolvedAt: v.optional(v.number()), closedAt: v.optional(v.number()), updatedAt: v.number(), createdAt: v.number(), tags: v.optional(v.array(v.string())), }) .index("by_tenant_status", ["tenantId", "status"]) .index("by_tenant_queue", ["tenantId", "queueId"]) .index("by_tenant_assignee", ["tenantId", "assigneeId"]) .index("by_tenant_reference", ["tenantId", "reference"]), ticketComments: defineTable({ ticketId: v.id("tickets"), authorId: v.id("users"), visibility: v.string(), // PUBLIC | INTERNAL body: v.string(), attachments: v.optional( v.array( v.object({ storageId: v.id("_storage"), name: v.string(), size: v.optional(v.number()), type: v.optional(v.string()), }) ) ), createdAt: v.number(), updatedAt: v.number(), }).index("by_ticket", ["ticketId"]), ticketEvents: defineTable({ ticketId: v.id("tickets"), type: v.string(), payload: v.optional(v.any()), createdAt: v.number(), }).index("by_ticket", ["ticketId"]), });