feat: route-centric rules, approve popup, emoji picker, 5-column sync table

- Schema: SyncRouteRuleMap junction table, ruleIntent on TenantRule,
  ForwardFormat/Frequency/ApprovalMode columns on SyncRoute, INTEREST
  match type
- Worker: remove global AUTO_APPROVE forwarding; per-route rule evaluation
  in ingest processor — POSITIVE rules auto-forward that route, NEGATIVE
  rules block it, fallback to approvalMode
- API: PATCH /routes/:id, rule assign/unassign endpoints, approve now
  accepts targetGroupIds, new GET /messages/:id/routes for popup data
- Web: 5-column route table with settings + rules dialogs, ForwardTarget
  popup with rule-based pre-selection, ruleIntent toggle + emoji dropdown
  (👍/👎 only) + INTEREST type in rules manager

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-25 13:58:02 +05:30
parent e598073dc7
commit 73956fd1e3
24 changed files with 1277 additions and 225 deletions
+3 -1
View File
@@ -16,8 +16,9 @@ export interface ApproveMessageResult {
export async function approveMessage(
messageId: string,
tenantId: string,
adminId: string, // JID of the reactor or system
adminId: string,
prisma: any,
targetGroupIds?: string[],
): Promise<ApproveMessageResult | null> {
const message = await prisma.message.findUnique({
where: { id: messageId },
@@ -60,6 +61,7 @@ export async function approveMessage(
const forwardJobs: ForwardJobData[] = (message.sourceGroup?.syncRoutesFrom ?? [])
.filter((route: any) => route.targetGroup != null)
.filter((route: any) => !targetGroupIds || targetGroupIds.includes(route.targetGroupId))
.map((route: any) => ({
tenantId: message.tenantId,
messageId: message.id,