132 lines
4 KiB
TypeScript
132 lines
4 KiB
TypeScript
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()),
|
|
description: v.optional(v.string()),
|
|
status: v.string(),
|
|
priority: v.string(),
|
|
channel: v.string(),
|
|
queueId: v.optional(v.id("queues")),
|
|
categoryId: v.optional(v.id("ticketCategories")),
|
|
subcategoryId: v.optional(v.id("ticketSubcategories")),
|
|
requesterId: v.id("users"),
|
|
assigneeId: v.optional(v.id("users")),
|
|
working: v.optional(v.boolean()),
|
|
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())),
|
|
totalWorkedMs: v.optional(v.number()),
|
|
activeSessionId: v.optional(v.id("ticketWorkSessions")),
|
|
})
|
|
.index("by_tenant_status", ["tenantId", "status"])
|
|
.index("by_tenant_queue", ["tenantId", "queueId"])
|
|
.index("by_tenant_assignee", ["tenantId", "assigneeId"])
|
|
.index("by_tenant_reference", ["tenantId", "reference"])
|
|
.index("by_tenant", ["tenantId"]),
|
|
|
|
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"]),
|
|
|
|
ticketWorkSessions: defineTable({
|
|
ticketId: v.id("tickets"),
|
|
agentId: v.id("users"),
|
|
startedAt: v.number(),
|
|
stoppedAt: v.optional(v.number()),
|
|
durationMs: v.optional(v.number()),
|
|
})
|
|
.index("by_ticket", ["ticketId"])
|
|
.index("by_ticket_agent", ["ticketId", "agentId"]),
|
|
|
|
ticketCategories: defineTable({
|
|
tenantId: v.string(),
|
|
name: v.string(),
|
|
slug: v.string(),
|
|
description: v.optional(v.string()),
|
|
order: v.number(),
|
|
createdAt: v.number(),
|
|
updatedAt: v.number(),
|
|
})
|
|
.index("by_tenant_slug", ["tenantId", "slug"])
|
|
.index("by_tenant_order", ["tenantId", "order"])
|
|
.index("by_tenant", ["tenantId"]),
|
|
|
|
ticketSubcategories: defineTable({
|
|
tenantId: v.string(),
|
|
categoryId: v.id("ticketCategories"),
|
|
name: v.string(),
|
|
slug: v.string(),
|
|
order: v.number(),
|
|
createdAt: v.number(),
|
|
updatedAt: v.number(),
|
|
})
|
|
.index("by_category_order", ["categoryId", "order"])
|
|
.index("by_category_slug", ["categoryId", "slug"])
|
|
.index("by_tenant_slug", ["tenantId", "slug"]),
|
|
});
|