feat(tickets): preserve requester/assignee/company snapshots + timeline fallbacks; chore: add requester index\n\n- Add requesterSnapshot, assigneeSnapshot, companySnapshot to tickets\n- Use snapshots as fallback in list/get/play\n- Update snapshots on assignee changes/startWork\n- Preserve snapshots before deleting users/companies\n- Add index tickets.by_tenant_requester\n- Add migrations.backfillTicketSnapshots\n\nchore(convex): upgrade to ^1.28.0 and run codegen\nchore(next): upgrade Next.js to 15.5.6 and update React/eslint-config-next\nfix: remove any and lint warnings; tighten types across API routes and components\ndocs: add docs/ticket-snapshots.md
This commit is contained in:
parent
0d82162a0e
commit
216feca971
16 changed files with 884 additions and 552 deletions
|
|
@ -779,3 +779,59 @@ export const syncMachineCompanyReferences = mutation({
|
|||
}
|
||||
},
|
||||
})
|
||||
|
||||
export const backfillTicketSnapshots = mutation({
|
||||
args: { tenantId: v.string(), limit: v.optional(v.number()) },
|
||||
handler: async (ctx, { tenantId, limit }) => {
|
||||
const tickets = await ctx.db
|
||||
.query("tickets")
|
||||
.withIndex("by_tenant", (q) => q.eq("tenantId", tenantId))
|
||||
.collect()
|
||||
|
||||
let processed = 0
|
||||
for (const t of tickets) {
|
||||
if (limit && processed >= limit) break
|
||||
const patch: Record<string, unknown> = {}
|
||||
if (!t.requesterSnapshot) {
|
||||
const requester = await ctx.db.get(t.requesterId)
|
||||
if (requester) {
|
||||
patch.requesterSnapshot = {
|
||||
name: requester.name,
|
||||
email: requester.email,
|
||||
avatarUrl: requester.avatarUrl ?? undefined,
|
||||
teams: requester.teams ?? undefined,
|
||||
}
|
||||
}
|
||||
}
|
||||
if (t.assigneeId && !t.assigneeSnapshot) {
|
||||
const assignee = await ctx.db.get(t.assigneeId)
|
||||
if (assignee) {
|
||||
patch.assigneeSnapshot = {
|
||||
name: assignee.name,
|
||||
email: assignee.email,
|
||||
avatarUrl: assignee.avatarUrl ?? undefined,
|
||||
teams: assignee.teams ?? undefined,
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!t.companySnapshot) {
|
||||
const companyId = t.companyId
|
||||
if (companyId) {
|
||||
const company = await ctx.db.get(companyId)
|
||||
if (company) {
|
||||
patch.companySnapshot = {
|
||||
name: company.name,
|
||||
slug: company.slug,
|
||||
isAvulso: company.isAvulso ?? undefined,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (Object.keys(patch).length > 0) {
|
||||
await ctx.db.patch(t._id, patch)
|
||||
}
|
||||
processed += 1
|
||||
}
|
||||
return { processed }
|
||||
},
|
||||
})
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue