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
|
|
@ -145,6 +145,30 @@ export const deleteUser = mutation({
|
|||
);
|
||||
}
|
||||
|
||||
// Preserve requester snapshot on tickets where this user is the requester
|
||||
const requesterTickets = await ctx.db
|
||||
.query("tickets")
|
||||
.withIndex("by_tenant_requester", (q) => q.eq("tenantId", user.tenantId).eq("requesterId", userId))
|
||||
.collect();
|
||||
if (requesterTickets.length > 0) {
|
||||
const requesterSnapshot = {
|
||||
name: user.name,
|
||||
email: user.email,
|
||||
avatarUrl: user.avatarUrl ?? undefined,
|
||||
teams: user.teams ?? undefined,
|
||||
};
|
||||
for (const t of requesterTickets) {
|
||||
const needsPatch = !t.requesterSnapshot ||
|
||||
t.requesterSnapshot.name !== requesterSnapshot.name ||
|
||||
t.requesterSnapshot.email !== requesterSnapshot.email ||
|
||||
t.requesterSnapshot.avatarUrl !== requesterSnapshot.avatarUrl ||
|
||||
JSON.stringify(t.requesterSnapshot.teams ?? []) !== JSON.stringify(requesterSnapshot.teams ?? []);
|
||||
if (needsPatch) {
|
||||
await ctx.db.patch(t._id, { requesterSnapshot });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await ctx.db.delete(userId);
|
||||
return { status: "deleted" };
|
||||
},
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue