From 6d3c2efe5ad4a8af8aa2b022cd6300554e9c8afc Mon Sep 17 00:00:00 2001 From: wirabasalamah Date: Sat, 23 May 2026 09:37:32 +0700 Subject: [PATCH] Add webhook prod check script and update handoff --- backend/src/auth/auth.controller.ts | 8 +-- docs/CODEX_HANDOFF.md | 16 +++++ .../src/components/conversations-inbox.tsx | 4 +- scripts/check-webhook-prod.sh | 62 +++++++++++++++++++ 4 files changed, 82 insertions(+), 8 deletions(-) create mode 100755 scripts/check-webhook-prod.sh diff --git a/backend/src/auth/auth.controller.ts b/backend/src/auth/auth.controller.ts index 620f028..fe7eb6e 100644 --- a/backend/src/auth/auth.controller.ts +++ b/backend/src/auth/auth.controller.ts @@ -1,4 +1,4 @@ -import { Body, Controller, Get, Param, Patch, Post, Req, UseGuards } from '@nestjs/common'; +import { Body, Controller, Get, Inject, Param, Patch, Post, Req, UseGuards } from '@nestjs/common'; import type { Request } from 'express'; import { AuthService } from './auth.service'; import { LoginDto } from './dto/login.dto'; @@ -15,11 +15,7 @@ import { ChangePasswordDto } from './dto/change-password.dto'; @Controller('auth') export class AuthController { - private readonly authService: AuthService; - - constructor(authService: AuthService) { - this.authService = authService; - } + constructor(@Inject(AuthService) private readonly authService: AuthService) {} @Post('login') signIn(@Req() request: Request, @Body() body: LoginDto) { diff --git a/docs/CODEX_HANDOFF.md b/docs/CODEX_HANDOFF.md index 0226106..429ed3f 100644 --- a/docs/CODEX_HANDOFF.md +++ b/docs/CODEX_HANDOFF.md @@ -2,6 +2,22 @@ Snapshot tanggal: `2026-05-22` +Perubahan terbaru (sesi ini, 23 Mei 2026): + +- Menambahkan script pemeriksaan webhook production: `scripts/check-webhook-prod.sh` + - Otomatis cek `webhook_events`, `jobs` queue `webhooks`, summary status, korelasi inbound vs `conversation_messages`, dan sample `contacts`. + - Script otomatis handle koneksi via `psql` lokal atau fallback ke container Docker PostgreSQL. +- Menyetel key React pada activity list di `frontend/src/components/conversations-inbox.tsx` agar tidak duplicate: + - dari `key={item.title}-{item.meta}` + - menjadi `key={item.title}-{item.meta}-{index}`. +- Perbaikan kecil controller DI pada `backend/src/auth/auth.controller.ts`: + - constructor injection diringkas via parameter property + `@Inject(AuthService)` agar konsisten style. + +Catatan diagnosa dari output terakhir: +- Webhook `POST /api/webhooks/whatsapp` sudah masuk ke DB dan diproses (`processing_status=processed`, `jobs` `webhooks` berstatus `processed`, tidak ada `queued/failed`). +- Event `message.inbound` juga sudah terhubung ke `conversation_messages` dan memiliki contact, sehingga data percakapan sudah tersimpan. +- Jika UI belum nampak, kemungkinan di sisi fetch/render dashboard perlu refresh/target contact yang sesuai, bukan di jalur webhook. + Dokumen ini adalah ringkasan kondisi terakhir BizOne Portal supaya sesi Codex berikutnya bisa lanjut tanpa bongkar ulang dari nol. ## Ringkasan Cepat diff --git a/frontend/src/components/conversations-inbox.tsx b/frontend/src/components/conversations-inbox.tsx index 83112a2..60b45b5 100644 --- a/frontend/src/components/conversations-inbox.tsx +++ b/frontend/src/components/conversations-inbox.tsx @@ -533,8 +533,8 @@ export function ConversationsInbox({

{labels.recentActivity}

- {activeConversation?.activity.map((item) => ( -
+ {activeConversation?.activity.map((item, index) => ( +
{item.title} diff --git a/scripts/check-webhook-prod.sh b/scripts/check-webhook-prod.sh new file mode 100755 index 0000000..27eaf6f --- /dev/null +++ b/scripts/check-webhook-prod.sh @@ -0,0 +1,62 @@ +#!/usr/bin/env bash +set -euo pipefail + +DB_URL=${DB_URL:-"postgresql://bizone:%2BQ%26xN%2486LbSA%3Cav%3C@127.0.0.1:5432/wa_dashboard"} + +run_psql() { + psql "$DB_URL" -c "$1" +} + +run_with_docker() { + local container="$1" + docker exec -i "$container" psql "$DB_URL" -c "$2" +} + +if command -v psql >/dev/null 2>&1; then + echo "=== WEBHOOK EVENTS (DB) ===" + run_psql "SELECT event_id,event_type,processing_status,verified,created_at,sender_phone,recipient_phone FROM webhook_events ORDER BY created_at DESC LIMIT 20;" + + echo "=== WEBHOOK JOBS ===" + run_psql "SELECT id,queue_name,job_type,status,attempts,max_attempts,error_message,created_at FROM jobs WHERE queue_name='webhooks' ORDER BY created_at DESC LIMIT 20;" + + echo "=== WEBHOOK SUMMARY ===" + run_psql "SELECT COUNT(*) FILTER (WHERE event_type='message.inbound') AS inbound_count, COUNT(*) FILTER (WHERE processing_status='received') AS received_count, COUNT(*) FILTER (WHERE processing_status='queued') AS queued_count, COUNT(*) FILTER (WHERE processing_status='processed') AS processed_count, COUNT(*) FILTER (WHERE processing_status='failed') AS failed_count FROM webhook_events;" + + echo "=== INBOUND EVENTS VS CONVERSATION MESSAGES ===" + run_psql "SELECT w.event_id, w.sender_phone, w.recipient_phone, w.created_at AS event_at, w.processing_status, w.verified, c.id AS contact_id, c.phone_number, cm.id AS conversation_message_id, cm.direction, cm.body, cm.occurred_at AS message_at FROM webhook_events w LEFT JOIN conversation_messages cm ON cm.webhook_event_id = w.event_id LEFT JOIN contacts c ON c.id = cm.contact_id WHERE w.event_type = 'message.inbound' ORDER BY w.created_at DESC LIMIT 20;" + + echo "=== CONTACTS TO CHECK (for manual validation) ===" + run_psql "SELECT id, phone_number, name, created_at, updated_at FROM contacts ORDER BY updated_at DESC LIMIT 20;" +elif command -v docker >/dev/null 2>&1; then + CONTAINER=$(docker ps --filter "ancestor=postgres" --format '{{.Names}}' | head -n 1) + + if [ -z "${CONTAINER}" ]; then + CONTAINER=$(docker ps --filter "name=postgres" --format '{{.Names}}' | head -n 1) + fi + + if [ -z "${CONTAINER}" ]; then + echo "Container postgres tidak ketemu via docker ps." + echo "Isi container yang ada:" + docker ps --format '{{.Names}}\t{{.Image}}' + exit 1 + fi + + echo "Menggunakan container: ${CONTAINER}" + echo "=== WEBHOOK EVENTS (DB via container) ===" + run_with_docker "$CONTAINER" "SELECT event_id,event_type,processing_status,verified,created_at,sender_phone,recipient_phone FROM webhook_events ORDER BY created_at DESC LIMIT 20;" + + echo "=== WEBHOOK JOBS (DB via container) ===" + run_with_docker "$CONTAINER" "SELECT id,queue_name,job_type,status,attempts,max_attempts,error_message,created_at FROM jobs WHERE queue_name='webhooks' ORDER BY created_at DESC LIMIT 20;" + + echo "=== WEBHOOK SUMMARY (DB via container) ===" + run_with_docker "$CONTAINER" "SELECT COUNT(*) FILTER (WHERE event_type='message.inbound') AS inbound_count, COUNT(*) FILTER (WHERE processing_status='received') AS received_count, COUNT(*) FILTER (WHERE processing_status='queued') AS queued_count, COUNT(*) FILTER (WHERE processing_status='processed') AS processed_count, COUNT(*) FILTER (WHERE processing_status='failed') AS failed_count FROM webhook_events;" + + echo "=== INBOUND EVENTS VS CONVERSATION MESSAGES (via container) ===" + run_with_docker "$CONTAINER" "SELECT w.event_id, w.sender_phone, w.recipient_phone, w.created_at AS event_at, w.processing_status, w.verified, c.id AS contact_id, c.phone_number, cm.id AS conversation_message_id, cm.direction, cm.body, cm.occurred_at AS message_at FROM webhook_events w LEFT JOIN conversation_messages cm ON cm.webhook_event_id = w.event_id LEFT JOIN contacts c ON c.id = cm.contact_id WHERE w.event_type = 'message.inbound' ORDER BY w.created_at DESC LIMIT 20;" + + echo "=== CONTACTS TO CHECK (via container) ===" + run_with_docker "$CONTAINER" "SELECT id, phone_number, name, created_at, updated_at FROM contacts ORDER BY updated_at DESC LIMIT 20;" +else + echo "Tidak ada psql dan docker CLI di server ini." + exit 1 +fi