Refactor Addition Feature
Feature Addition Plan - CloudChat Application
Rencana penambahan 10 fitur baru untuk CloudChat berdasarkan requirements yang diberikan.

User Review Required
[!IMPORTANT] Setiap fitur memiliki complexity dan dependensi yang berbeda. Harap review prioritas implementasi.
[!WARNING] Beberapa fitur memerlukan perubahan database schema dan integrasi dengan external APIs.
Daftar Fitur yang Akan Ditambahkan
- Chatbot - Waktu Aktif Bot
- Laporan Chatbot
- Mode Antrian (Queue System)
- Mode Pilih Agen
- Integrasi Ongkir (Shipping Cost API)
- Broadcast WA Official - Template Device Filter
- Template Meta - CRUD & Device Filter
- Facebook - Connection Error Info
- Icon Notifikasi Inbox
- Pipeline (100% mirip Socialchat)
Fitur 1: Chatbot - Waktu Aktif Bot
Deskripsi
Menambahkan kemampuan untuk mengatur jadwal waktu aktif chatbot. Bot hanya akan merespons dalam rentang waktu yang ditentukan.
Use Case
- Business hours: Bot aktif 09:00 - 17:00
- Weekend mode: Bot tidak aktif Sabtu-Minggu
- Multiple time slots per day
- Timezone awareness
Flow Diagram
flowchart TD
A[Pesan Masuk ke Chatbot] --> B{Cek Waktu Aktif<br/>Bot Enabled?}
B -->|Tidak| C[Proses Normal<br/>Bot Merespons]
B -->|Ya| D{Apakah Sekarang<br/>Dalam Jadwal Aktif?}
D -->|Ya| C
D -->|Tidak| E[Skip Bot Response]
E --> F{Ada Auto Reply<br/>di Luar Jam?}
F -->|Ya| G[Kirim Pesan<br/>Luar Jam Kerja]
F -->|Tidak| H[Tidak Ada Response]
G --> I[Tandai Conversation<br/>Needs Human]
H --> I
C --> J[Bot Process Normal]
Database Schema Changes
[NEW] Table: chatbot_schedules
CREATE TABLE chatbot_schedules (
id SERIAL PRIMARY KEY,
bot_id INTEGER NOT NULL REFERENCES chatbots(id) ON DELETE CASCADE,
day_of_week INTEGER NOT NULL, -- 0=Sunday, 6=Saturday
start_time TIME NOT NULL,
end_time TIME NOT NULL,
is_active BOOLEAN DEFAULT true,
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
CREATE INDEX idx_chatbot_schedules_bot_id ON chatbot_schedules(bot_id);
[MODIFY] Table: chatbots
ALTER TABLE chatbots
ADD COLUMN schedule_enabled BOOLEAN DEFAULT false,
ADD COLUMN timezone VARCHAR(50) DEFAULT 'Asia/Jakarta',
ADD COLUMN outside_hours_message TEXT;
Implementation Details
Backend
[NEW] src/controllers/chatbotScheduleController.js
// GET /api/app/chatbot/bots/:botId/schedules
// POST /api/app/chatbot/bots/:botId/schedules
// PUT /api/app/chatbot/schedules/:id
// DELETE /api/app/chatbot/schedules/:id
[NEW] src/services/chatbotScheduleService.js
Functions:
isWithinSchedule(botId, timestamp)- Check if current time is within schedulegetActiveSchedules(botId)- Get all active schedules for botvalidateSchedule(schedule)- Validate schedule data
[MODIFY] src/services/chatbotService.js
Update processMessage():
- Check schedule before processing
- Send outside hours message if configured
- Log schedule-blocked interactions
Frontend
[NEW] frontend/src/pages/Chatbot/BotScheduleSettings.js
Component untuk manage bot schedules:
- Enable/disable schedule feature
- Set timezone
- Add/edit/delete time slots
- Preview schedule in calendar view
- Set outside hours message
UI Components:
- Toggle untuk enable schedule
- Timezone selector dropdown
- Time range picker untuk setiap hari
- Textarea untuk outside hours message
Fitur 2: Laporan Chatbot
Deskripsi
Dashboard laporan untuk memonitor performa dan statistik chatbot.
Metrics yang Dilacak
-
Interaction Metrics
- Total conversations handled
- Average response time
- Success rate (resolved vs escalated)
-
Knowledge Base Performance
- Most used Q&A pairs
- Questions that failed to match
- Confidence score distribution
-
User Satisfaction
- Rating dari users (jika ada)
- Escalation rate
- Conversation resolution time
-
Time-based Analytics
- Hourly/Daily/Weekly trends
- Peak usage times
- Response time trends
Flow Diagram
flowchart LR
A[Chatbot Interaction] --> B[Log ke Database]
B --> C[chatbot_interactions<br/>table]
C --> D[Background Job<br/>Aggregate Data]
D --> E[chatbot_analytics<br/>table]
E --> F[Dashboard API]
F --> G[Frontend Charts]
H[Admin Akses<br/>Laporan] --> F
Database Schema Changes
[NEW] Table: chatbot_interactions
CREATE TABLE chatbot_interactions (
id SERIAL PRIMARY KEY,
bot_id INTEGER NOT NULL REFERENCES chatbots(id) ON DELETE CASCADE,
conversation_id INTEGER REFERENCES conversations(id) ON DELETE SET NULL,
question TEXT NOT NULL,
answer TEXT,
confidence_score DECIMAL(5,2),
matched_qa_id INTEGER REFERENCES chatbot_qa(id) ON DELETE SET NULL,
response_time_ms INTEGER,
was_escalated BOOLEAN DEFAULT false,
user_rating INTEGER, -- 1-5 stars
created_at TIMESTAMP DEFAULT NOW()
);
CREATE INDEX idx_chatbot_interactions_bot_id ON chatbot_interactions(bot_id);
CREATE INDEX idx_chatbot_interactions_created_at ON chatbot_interactions(created_at);
[NEW] Table: chatbot_analytics
CREATE TABLE chatbot_analytics (
id SERIAL PRIMARY KEY,
bot_id INTEGER NOT NULL REFERENCES chatbots(id) ON DELETE CASCADE,
date DATE NOT NULL,
hour INTEGER, -- 0-23, NULL for daily aggregates
total_interactions INTEGER DEFAULT 0,
successful_interactions INTEGER DEFAULT 0,
escalated_interactions INTEGER DEFAULT 0,
avg_response_time_ms INTEGER,
avg_confidence_score DECIMAL(5,2),
avg_rating DECIMAL(3,2),
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW(),
UNIQUE(bot_id, date, hour)
);
CREATE INDEX idx_chatbot_analytics_bot_date ON chatbot_analytics(bot_id, date);
Implementation Details
Backend
[NEW] src/controllers/chatbotReportController.js
Endpoints:
GET /api/app/chatbot/bots/:id/reports/overview- Overall statsGET /api/app/chatbot/bots/:id/reports/interactions- Interaction historyGET /api/app/chatbot/bots/:id/reports/performance- Performance trendsGET /api/app/chatbot/bots/:id/reports/failed-questions- Questions bot couldn't answerGET /api/app/chatbot/bots/:id/reports/export- Export to CSV/Excel
[NEW] src/services/chatbotReportService.js
Functions:
getOverviewStats(botId, dateRange)getInteractionTrends(botId, dateRange, groupBy)getFailedQuestions(botId, dateRange, limit)getTopQAPairs(botId, dateRange, limit)exportReport(botId, dateRange, format)
[NEW] src/queues/chatbotAnalyticsWorker.js
Background worker untuk aggregate data hourly:
- Run setiap jam
- Aggregate interactions jadi analytics
- Clean up old interaction data (retention policy)
[MODIFY] src/services/chatbotService.js
Update processMessage():
- Log interaction ke
chatbot_interactions - Record confidence score
- Track response time
Frontend
[NEW] frontend/src/pages/Chatbot/BotReportsPage.js
Dashboard dengan:
- Date range picker
- KPI cards (total interactions, success rate, avg response time, avg rating)
- Line chart untuk interaction trends
- Bar chart untuk hourly distribution
- Table untuk failed questions
- Table untuk top Q&A pairs
- Export button
Libraries:
- Chart.js atau Recharts untuk visualisasi
- react-datepicker untuk date range
Fitur 3: Mode Antrian dengan Divisi (Division-based Queue System)
Deskripsi
Sistem antrian otomatis berdasarkan Divisi/Department (Support, Billing, Umum, dll). Customer memilih divisi yang dituju, sistem auto-routing ke agen yang online di divisi tersebut, atau masukkan ke queue jika semua agen busy.
Screenshot Referensi

Cara Kerja
-
Customer mengirim pesan pertama → Sistem kirim auto-reply menu divisi
- "Selamat datang di toko kami, silahkan pilih agen yang anda tuju"
- "1. Billing"
- "2. Support"
- "3. Umum"
-
Customer pilih divisi (ketik 1, 2, 3 atau nama divisi)
- Sistem deteksi pilihan (1, "billing", dll)
- Cek agen yang online di divisi tersebut
-
Auto-routing:
- Jika ada agen online → Assign langsung ke agen
- Jika semua agen busy/offline → Masuk queue divisi tersebut
- Kirim auto-reply: "Anda akan di layani oleh tim {divisi}, Tunggu dalam antrian ke {nomor}. Tekan # untuk cek antrian"
-
Check queue: Customer ketik "#" untuk cek posisi
- Response: "Anda masih dalam antrian ke {nomor}. mohon menunggu"
-
Saat agen available → Auto-assign dari queue (FIFO per divisi)
Flow Diagram
flowchart TD
A[Customer Kirim<br/>Pesan Pertama] --> B{Queue Mode<br/>Enabled?}
B -->|Tidak| C[Proses Normal]
B -->|Ya| D[Kirim Menu Divisi<br/>Auto-Reply]
E[Customer Pilih<br/>Divisi e.g. 1] --> F[Parse Pilihan<br/>Divisi ID]
F --> G{Divisi Valid?}
G -->|Tidak| H[Kirim Ulang Menu]
G -->|Ya| I[Cek Agen Online<br/>di Divisi]
I --> J{Ada Agen<br/>Online?}
J -->|Ya| K[Auto-Assign<br/>ke Agen]
J -->|Tidak| L[Masuk Queue<br/>Divisi]
L --> M[Generate Queue<br/>Number]
M --> N[Kirim Auto-Reply<br/>Nomor Antrian]
K --> O[Mulai Chat<br/>dengan Agen]
P[Customer Ketik #] --> Q[Cek Posisi Queue]
Q --> R[Kirim Posisi<br/>Antrian]
S[Agen Online/Available] --> T[Ambil dari Queue<br/>Divisi FIFO]
T --> U[Auto-Assign<br/>Conversation]
U --> V[Notif Customer<br/>Agen Siap]
Database Schema Changes
[NEW] Table: divisions (Divisi/Department)
CREATE TABLE divisions (
id SERIAL PRIMARY KEY,
organization_id INTEGER NOT NULL REFERENCES organizations(id) ON DELETE CASCADE,
name VARCHAR(255) NOT NULL, -- e.g. "Billing", "Support", "Umum"
description TEXT,
keyword_triggers TEXT[], -- ['billing', 'tagihan', '1']
is_active BOOLEAN DEFAULT true,
position INTEGER DEFAULT 0, -- For ordering in menu
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
CREATE INDEX idx_divisions_org ON divisions(organization_id);
[NEW] Table: division_agents (Agent Assignment)
CREATE TABLE division_agents (
id SERIAL PRIMARY KEY,
division_id INTEGER NOT NULL REFERENCES divisions(id) ON DELETE CASCADE,
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
is_active BOOLEAN DEFAULT true,
created_at TIMESTAMP DEFAULT NOW(),
UNIQUE(division_id, user_id)
);
CREATE INDEX idx_division_agents_division ON division_agents(division_id);
CREATE INDEX idx_division_agents_user ON division_agents(user_id);
[NEW] Table: chat_queues
CREATE TABLE chat_queues (
id SERIAL PRIMARY KEY,
organization_id INTEGER NOT NULL REFERENCES organizations(id) ON DELETE CASCADE,
conversation_id INTEGER NOT NULL REFERENCES conversations(id) ON DELETE CASCADE,
division_id INTEGER NOT NULL REFERENCES divisions(id) ON DELETE CASCADE,
queue_number INTEGER NOT NULL, -- Queue number per division
status VARCHAR(20) DEFAULT 'waiting', -- waiting, assigned, cancelled
assigned_agent_id INTEGER REFERENCES users(id) ON DELETE SET NULL,
assigned_at TIMESTAMP,
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
CREATE INDEX idx_chat_queues_org_division ON chat_queues(organization_id, division_id, status);
CREATE INDEX idx_chat_queues_created ON chat_queues(created_at);
CREATE UNIQUE INDEX idx_chat_queues_conversation ON chat_queues(conversation_id) WHERE status = 'waiting';
[NEW] Table: queue_settings
CREATE TABLE queue_settings (
id SERIAL PRIMARY KEY,
organization_id INTEGER NOT NULL REFERENCES organizations(id) ON DELETE CASCADE UNIQUE,
is_enabled BOOLEAN DEFAULT false,
welcome_message TEXT DEFAULT 'Selamat datang di toko kami, silahkan pilih agen yang anda tuju',
queue_message_template TEXT DEFAULT 'Anda akan di layani oleh tim {division}, Tunggu dalam antrian ke {queue_number}. Tekan # untuk cek antrian',
check_queue_keyword VARCHAR(10) DEFAULT '#',
queue_position_message TEXT DEFAULT 'Anda masih dalam antrian ke {queue_number}. mohon menunggu',
no_agent_available_message TEXT DEFAULT 'Maaf, saat ini tidak ada agen yang tersedia. Anda akan dilayani secepatnya.',
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
[MODIFY] Table: conversations
ALTER TABLE conversations
ADD COLUMN division_id INTEGER REFERENCES divisions(id) ON DELETE SET NULL,
ADD COLUMN awaiting_division_selection BOOLEAN DEFAULT false;
Implementation Details
Backend
[NEW] src/controllers/divisionController.js
Division Management Endpoints:
GET /api/app/divisions- List all divisionsPOST /api/app/divisions- Create divisionPUT /api/app/divisions/:id- Update divisionDELETE /api/app/divisions/:id- Delete divisionPOST /api/app/divisions/:id/reorder- Reorder divisionsGET /api/app/divisions/:id/agents- Get agents in divisionPOST /api/app/divisions/:id/agents- Add agent to divisionDELETE /api/app/divisions/:id/agents/:userId- Remove agent from division
[NEW] src/controllers/queueController.js
Queue Endpoints:
GET /api/app/queue/settings- Get queue settingsPUT /api/app/queue/settings- Update queue settingsGET /api/app/queue/list- Get current queue (all divisions)GET /api/app/queue/division/:divisionId- Get queue for specific divisionGET /api/app/queue/stats- Queue statistics per divisionDELETE /api/app/queue/:id- Remove from queue (manual)
[NEW] src/services/queueService.js
Functions:
handleIncomingMessage(conversationId, message)- Handle new message with queue logicsendDivisionMenu(conversationId)- Send division selection menuhandleDivisionSelection(conversationId, selection)- Parse dan process divisi selectiongetAvailableAgentInDivision(divisionId)- Get online agent in divisionaddToQueue(conversationId, divisionId)- Add to division queuegetQueuePosition(conversationId)- Get position in queueautoAssignFromQueue(divisionId)- Auto-assign when agent availablehandleCheckQueueCommand(conversationId)- Handle "#" command
[NEW] src/services/divisionService.js
Functions:
createDivision(organizationId, data)- Create divisionupdateDivision(divisionId, data)- Update divisiondeleteDivision(divisionId)- Delete divisionaddAgentToDivision(divisionId, userId)- Assign agentremoveAgentFromDivision(divisionId, userId)- Remove agentgetAgentsInDivision(divisionId)- Get all agents in divisiongetOnlineAgentsInDivision(divisionId)- Get online agents only
[MODIFY] src/controllers/webhookController.js
Update handleWAWebhook():
// When new message arrives
if (queueSettings.is_enabled && !conversation.division_id) {
// First message from customer
await queueService.sendDivisionMenu(conversation.id);
await pool.query(
'UPDATE conversations SET awaiting_division_selection = true WHERE id = $1',
[conversation.id]
);
} else if (conversation.awaiting_division_selection) {
// Customer memilih divisi
await queueService.handleDivisionSelection(conversation.id, message.text);
} else if (message.text === queueSettings.check_queue_keyword) {
// Customer cek queue position
await queueService.handleCheckQueueCommand(conversation.id);
}
[NEW] Socket.IO Events
// To agents in specific division
io.to(`division:${divisionId}`).emit('queue:updated', queueData);
io.to(`agent:${agentId}`).emit('queue:assigned', conversationData);
// To customer when assigned
io.to(`conversation:${conversationId}`).emit('agent:assigned', agentInfo);
Frontend
[NEW] frontend/src/pages/Settings/DivisionManagement.js
Division Management Page (Settings > Queue & Divisi > Manajemen Divisi):
Features:
-
Division List
- Table dengan columns: Name, Keywords, Agents Count, Active Status, Actions
- Drag-and-drop untuk reorder (position)
- Add Division button
- Edit/Delete actions
-
Add/Edit Division Modal
- Division name input
- Description textarea
- Keyword triggers (comma-separated): "billing, tagihan, 1"
- Active toggle
- Agent multi-select (assign agents to this division)
-
Agent Assignment
- For each division, show assigned agents
- Add/remove agents
- Agent can be in multiple divisions
[NEW] frontend/src/pages/Settings/QueueSettingsPage.js
Queue Settings Page (Settings > Queue & Divisi > Pengaturan Antrian):
Configuration Sections:
-
Enable Queue System
- Toggle: Enable/Disable
- Info box: Penjelasan cara kerja queue
-
Welcome Message
- Textarea: Pesan sambutan
- Default: "Selamat datang di toko kami, silahkan pilih agen yang anda tuju"
- Preview: Shows how menu will look with divisions
-
Queue Message Template
- Template dengan variables:
{division},{queue_number} - Default: "Anda akan di layani oleh tim {division}, Tunggu dalam antrian ke {queue_number}. Tekan # untuk cek antrian"
- Template dengan variables:
-
Check Queue Keyword
- Input: Keyword untuk cek antrian (default: "#")
-
Queue Position Message
- Template dengan variable:
{queue_number} - Default: "Anda masih dalam antrian ke {queue_number}. mohon menunggu"
- Template dengan variable:
-
No Agent Available Message
- Message saat semua agen offline
-
Preview Section
- Live preview conversation flow
- Show menu dengan divisions yang sudah dibuat
- Show contoh queue messages
Location: Settings > Queue & Divisi
[NEW] frontend/src/components/inbox/QueuePanel.js
Queue Panel di Inbox (untuk Agents):
Features:
- Tabs per Division (jika agen di multiple divisions)
- Queue List per Division:
- Customer name
- Queue number
- Wait time
- "Ambil Chat" button
- Auto-Assignment Toggle: Enable auto-assign dari queue
- Statistics:
- Total waiting di divisi ini
- Average wait time
- Longest wait time
[MODIFY] frontend/src/pages/InboxPage.js
Updates:
- Add Queue Panel (collapsible/toggle)
- Show division badge on conversations
- Show queue number indicator
- Real-time queue updates via Socket.IO
[NEW] frontend/src/components/settings/DivisionAgentAssignment.js
Component untuk assign agents ke divisions:
- Dual list box (Available Agents <-> Assigned Agents)
- Drag & drop or click to assign/unassign
- Show agent status (online/offline)
Configuration Workflow (Setup Guide)
Step-by-step untuk Admin:
-
Enable Queue System
- Go to Settings > Queue & Divisi > Pengaturan Antrian
- Toggle "Enable Queue System" ON
-
Create Divisions
- Go to Settings > Queue & Divisi > Manajemen Divisi
- Click "Add Division"
- Input:
- Name: "Billing"
- Keywords: "billing, tagihan, 1"
- Repeat untuk divisions lain (Support, Umum, dll)
-
Assign Agents to Divisions
- For each division, click "Manage Agents"
- Select agents yang belong to divisi tersebut
- Save
-
Configure Messages
- Customize welcome message
- Customize queue message template
- Set check queue keyword (default: #)
-
Test
- Send message sebagai customer
- Verify menu divisi muncul
- Test selection
- Test queue assignment
- Test "#" command
Fitur 4: Division Selection Enhancement
Deskripsi
Enhancement untuk Fitur 3 - memberikan customer lebih banyak flexibility dalam memilih divisi dan melihat informasi divisi.
Additional Features
-
Division Description di Menu
- Saat menampilkan menu, include deskripsi divisi
- Example:
Selamat datang! Pilih divisi yang ingin Anda hubungi: 1. Billing - Untuk pertanyaan pembayaran dan invoice 2. Support - Bantuan teknis dan troubleshooting 3. Umum - Pertanyaan umum lainnya
-
Estimated Wait Time
- Show estimasi waktu tunggu per divisi
- Based on current queue + average handling time
- Example: "Support (3 antrian, ~15 menit)"
-
Smart Keyword Detection
- Detect keywords di customer message
- Auto-suggest divisi yang relevan
- Example: Customer ketik "saya mau bayar" → Auto-detect "Billing"
-
Rich Menu Options
- Support menu dengan buttons (jika platform support)
- WhatsApp: List message atau buttons
- Telegram: Inline keyboard
- Messenger: Quick replies
Database Schema Addition
[MODIFY] Table: divisions
ALTER TABLE divisions
ADD COLUMN avg_handling_time_minutes INTEGER DEFAULT 10,
ADD COLUMN show_wait_time BOOLEAN DEFAULT false,
ADD COLUMN auto_detect_keywords BOOLEAN DEFAULT false;
Implementation
[MODIFY] src/services/queueService.js
Enhanced functions:
sendDivisionMenu()- Include descriptions, wait timesdetectDivisionFromMessage(message)- Smart keyword detectiongetEstimatedWaitTime(divisionId)- Calculate wait time
[MODIFY] frontend/src/pages/Settings/DivisionManagement.js
Additional fields:
- Average handling time (minutes)
- Show estimated wait time toggle
- Auto-detect keywords toggle
Fitur 5: Integrasi Ongkir (BYOK System)
Deskripsi
Integrasi dengan RajaOngkir API menggunakan sistem BYOK (Bring Your Own Key) - setiap member membawa API Key sendiri. Member bisa mendaftar ke RajaOngkir dan memasukkan API Key mereka di CloudChat.
Use Cases
- Member daftar RajaOngkir dan dapatkan API Key
- Member input API Key di CloudChat Settings
- User tanya ongkir → Bot provide cost estimation menggunakan API Key member
- Integration dengan chatbot untuk auto-reply
- Support multiple couriers (JNE, TIKI, POS, J&T, SiCepat, dll)
- Calculate berdasarkan origin, destination, weight
Flow Diagram
flowchart TD
A[User Request Ongkir] --> B[Parse Input<br/>Origin, Dest, Weight]
B --> C{Data Lengkap?}
C -->|Tidak| D[Request Missing Data]
C -->|Ya| E[Call Ongkir API]
E --> F{API Success?}
F -->|Tidak| G[Error Message]
F -->|Ya| H[Format Results]
H --> I[Kirim ke User<br/>List Kurir + Harga]
I --> J[Log Transaction]
Database Schema Changes
[NEW] Table: ongkir_settings
CREATE TABLE ongkir_settings (
id SERIAL PRIMARY KEY,
organization_id INTEGER NOT NULL REFERENCES organizations(id) ON DELETE CASCADE UNIQUE,
rajaongkir_api_key TEXT NOT NULL, -- Member's RajaOngkir API Key
rajaongkir_account_type VARCHAR(20) DEFAULT 'starter', -- starter, basic, pro
default_origin_city_id INTEGER,
default_origin_city_name VARCHAR(255),
default_origin_province VARCHAR(255),
enabled_couriers TEXT[], -- ['jne', 'tiki', 'pos', 'jnt', 'sicepat', 'anteraja']
is_active BOOLEAN DEFAULT false,
last_verified_at TIMESTAMP, -- Last time API key was verified
api_status VARCHAR(20) DEFAULT 'unverified', -- unverified, active, invalid, quota_exceeded
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
[NEW] Table: ongkir_logs
CREATE TABLE ongkir_logs (
id SERIAL PRIMARY KEY,
organization_id INTEGER NOT NULL REFERENCES organizations(id) ON DELETE CASCADE,
conversation_id INTEGER REFERENCES conversations(id) ON DELETE SET NULL,
origin VARCHAR(255),
destination VARCHAR(255),
weight INTEGER, -- in grams
courier VARCHAR(50),
cost INTEGER,
api_response JSONB,
created_at TIMESTAMP DEFAULT NOW()
);
CREATE INDEX idx_ongkir_logs_org ON ongkir_logs(organization_id);
CREATE INDEX idx_ongkir_logs_created ON ongkir_logs(created_at);
Implementation Details
Backend
[NEW] src/controllers/ongkirController.js
Endpoints:
GET /api/app/settings/ongkir- Get current ongkir settingsPUT /api/app/settings/ongkir- Save/update API key & settingsPOST /api/app/settings/ongkir/verify- Verify API key validityPOST /api/app/ongkir/check- Check shipping cost (public for chatbot use)GET /api/app/ongkir/provinces- Get provinces list from RajaOngkirGET /api/app/ongkir/cities/:provinceId- Get cities list from RajaOngkirGET /api/app/ongkir/logs- Get usage history/logsGET /api/app/ongkir/quota- Check remaining quota (if applicable)
[NEW] src/services/ongkirService.js
Functions:
verifyApiKey(apiKey)- Verify RajaOngkir API key validitycheckCost(organizationId, origin, destination, weight, courier)- Check shipping cost using member's API keygetProvinces(organizationId)- Get provinces dari RajaOngkirgetCities(organizationId, provinceId)- Get cities dari RajaOngkirformatCostResponse(apiResponse)- Format response untuk userlogUsage(organizationId, data)- Log usage ke databasegetAccountInfo(apiKey)- Get account type & quota info
[NEW] src/services/integrations/rajaOngkirClient.js
RajaOngkir API client:
- Base URL:
https://api.rajaongkir.com/starter(atau /basic, /pro) - Headers:
key: {member's_api_key} - Endpoints:
GET /province- Get provincesGET /city- Get citiesPOST /cost- Calculate shipping cost
- Error handling untuk invalid key, quota exceeded, dll
[MODIFY] src/services/chatbotService.js
Add ongkir intent detection:
- Detect keywords (ongkir, cek ongkir, biaya kirim, dll)
- Extract parameters dari user message
- Call ongkir service
- Format dan send response
Frontend
[NEW] frontend/src/pages/Settings/OngkirSettingsPage.js
Settings page (Submenu di Settings):
UI Components:
-
Setup Guide Section
- Info box: "Cara mendapatkan API Key RajaOngkir"
- Link ke https://rajaongkir.com/dokumentasi
- Steps: Daftar → Pilih paket → Copy API Key
-
API Configuration
- Input field: RajaOngkir API Key (password type)
- Button: "Verify API Key" (check validity)
- Status indicator: ✅ Active / ❌ Invalid / ⚠️ Quota Exceeded
- Account type display (Starter/Basic/Pro) - auto-detected
-
Default Origin Settings
- Province dropdown (fetched dari RajaOngkir)
- City dropdown (filtered by province)
- Display: Selected city as default origin
-
Courier Selection
- Checkbox list: JNE, TIKI, POS, J&T, SiCepat, AnterAja, dll
- Select all / Deselect all buttons
-
Usage Statistics
- Total requests this month
- Remaining quota (if applicable)
- Last check: timestamp
-
Actions
- Save Settings button
- Test Connection button
Location: Accessible via Settings > Integrasi > Ongkir
[NEW] frontend/src/components/tools/OngkirChecker.js
Standalone tool untuk test ongkir:
- Province/city selector (origin & destination)
- Weight input
- Courier selector
- Calculate button
- Results table
Fitur 6: Broadcast WA Official - Template Device Filter
Deskripsi
Saat pilih template untuk broadcast WA Official (Meta), otomatis tampilkan template yang sesuai dengan device yang dipilih.
Flow Diagram
flowchart LR
A[User Pilih Device<br/>untuk Broadcast] --> B[Get Device Type<br/>& Meta Account]
B --> C{Device Type?}
C -->|WA Official| D[Query Meta Templates<br/>untuk WABA tersebut]
C -->|WA Device| E[Show Custom<br/>Templates]
D --> F[Filter Approved<br/>Templates Only]
F --> G[Display di Dropdown]
E --> G
Implementation Details
Backend
[MODIFY] src/controllers/broadcastController.js
Update endpoint:
GET /api/app/broadcast/templates?deviceId=X- Get templates berdasarkan device
Logic:
- Get device by ID
- Check device type (wa_official vs wa_device)
- If wa_official → fetch dari meta_templates WHERE waba_id = device.waba_id
- If wa_device → fetch custom templates
- Return filtered list
[MODIFY] src/services/metaTemplateService.js
Add function:
getTemplatesByDevice(deviceId)- Get templates for specific device
Frontend
[MODIFY] frontend/src/pages/Broadcast/CreateCampaign.js
Update logic:
- Saat user pilih device di dropdown
- Fetch templates untuk device tersebut
- Update template selector options
- Show device name di template selector untuk clarity
[MODIFY] frontend/src/pages/Broadcast/MessageTemplates.js
Update UI:
- Show device/WABA name di setiap template
- Filter templates berdasarkan selected device
- Add device indicator badge
Fitur 7: Template Meta - CRUD & Device Filter
Deskripsi
Menambahkan kemampuan CRUD (Create, Read, Update, Delete) untuk Meta templates dan filter berdasarkan device.
Use Cases
- Create custom Meta template
- Edit existing template
- Delete template
- Filter templates by device/WABA
- Info box showing which device template belongs to
Flow Diagram
flowchart TD
A[Template Management<br/>Page] --> B[List All Templates]
B --> C{Filter by Device?}
C -->|Ya| D[Filter Templates<br/>by WABA ID]
C -->|Tidak| E[Show All Templates]
F[Create Template] --> G[Select WABA/Device]
G --> H[Fill Template Data]
H --> I[Submit to Meta API]
I --> J{Success?}
J -->|Ya| K[Save to Database]
J -->|Tidak| L[Show Error]
K --> M[Show Success<br/>+ Pending Status]
N[Edit Template] --> O{Status?}
O -->|Approved| P[Cannot Edit<br/>Show Info]
O -->|Pending/Rejected| Q[Allow Edit]
Q --> I
R[Delete Template] --> S[Soft Delete<br/>in Database]
Database Schema Changes
[MODIFY] Table: meta_templates
ALTER TABLE meta_templates
ADD COLUMN IF NOT EXISTS device_id INTEGER REFERENCES devices(id) ON DELETE SET NULL,
ADD COLUMN IF NOT EXISTS deleted_at TIMESTAMP,
ADD COLUMN IF NOT EXISTS last_synced_at TIMESTAMP;
-- Add index for better filtering
CREATE INDEX IF NOT EXISTS idx_meta_templates_device ON meta_templates(device_id);
CREATE INDEX IF NOT EXISTS idx_meta_templates_waba ON meta_templates(waba_id);
Implementation Details
Backend
[MODIFY] src/controllers/metaTemplateController.js
Add/Update endpoints:
POST /api/app/meta/templates- Create new templatePUT /api/app/meta/templates/:id- Update templateDELETE /api/app/meta/templates/:id- Delete templateGET /api/app/meta/templates?deviceId=X&wabaId=Y- List with filters
[NEW] src/services/metaTemplateService.js (atau modify jika sudah ada)
Functions:
createTemplate(wabaId, templateData)- Create via Meta APIupdateTemplate(templateId, templateData)- Update via Meta APIdeleteTemplate(templateId)- Delete via Meta APIgetTemplatesByWABA(wabaId)- Get templates for WABAsyncTemplateStatus(templateId)- Sync status dari Meta
Integration dengan Meta Marketing API:
// POST https://graph.facebook.com/v18.0/{waba-id}/message_templates
// GET https://graph.facebook.com/v18.0/{waba-id}/message_templates
// DELETE https://graph.facebook.com/v18.0/{waba-id}/message_templates
Frontend
[NEW] frontend/src/pages/Integrations/MetaTemplateManager.js
Full CRUD interface:
List View:
- Table dengan columns: Name, Category, Language, Status, Device/WABA, Actions
- Filter dropdown by Device
- Search by template name
- Status badge (Approved, Pending, Rejected)
Create/Edit Form:
- WABA/Device selector
- Template name
- Category dropdown (UTILITY, MARKETING, AUTHENTICATION)
- Language selector
- Template body dengan variable placeholders
- Header (optional): Text, Image, Video, Document
- Footer (optional)
- Buttons (optional): Quick Reply, Call to Action
- Preview panel
Info Box:
- Show device name dan WABA ID
- Template status
- Rejection reason (jika rejected)
- Last synced time
[NEW] frontend/src/components/meta/TemplateBuilder.js
Visual template builder component:
- Drag & drop component builder
- Variable placeholder insertion
- Real-time preview
- Validation
Fitur 8: Facebook - Connection Error Info
Deskripsi
Jika Facebook Messenger gagal connect, tampilkan info bahwa page tersebut harus terhubung ke Business Manager (BM).
Current Issue
User tidak tahu kenapa connection gagal, tidak ada helpful error message.
Solution
Detect specific error codes dan tampilkan actionable error message.
Flow Diagram
flowchart TD
A[User Connect<br/>FB Page] --> B[Request Permissions]
B --> C{Success?}
C -->|Ya| D[Save Connection]
C -->|Tidak| E[Detect Error Type]
E --> F{Error Code?}
F -->|200| G[Show: Page belum<br/>linked ke BM]
F -->|190| H[Show: Token Invalid<br/>Login Ulang]
F -->|Other| I[Show: Generic Error<br/>+ Support Link]
G --> J[Show Instructions:<br/>Cara Link ke BM]
J --> K[Provide BM Link]
Implementation Details
Backend
[MODIFY] src/controllers/messenger/authController.js
Update handleCallback():
Add error detection:
try {
// Request to Facebook API
} catch (error) {
const errorCode = error.response?.data?.error?.code;
const errorType = error.response?.data?.error?.type;
let userMessage = 'Gagal menghubungkan page';
let actionRequired = null;
if (errorCode === 200 || errorType === 'OAuthException') {
userMessage = 'Page belum terhubung ke Business Manager';
actionRequired = 'link_to_bm';
} else if (errorCode === 190) {
userMessage = 'Sesi login sudah kadaluarsa';
actionRequired = 'reauth';
}
return res.status(400).json({
error: userMessage,
errorCode,
actionRequired,
helpUrl: 'https://business.facebook.com/...'
});
}
[NEW] src/utils/facebookErrorHandler.js
Centralized Facebook error handling:
- Map error codes to user-friendly messages
- Provide action suggestions
- Generate help URLs
Frontend
[MODIFY] frontend/src/pages/Integrations/MessengerIntegration.js
Update error handling:
catch (error) {
const { error: message, actionRequired, helpUrl } = error.response.data;
if (actionRequired === 'link_to_bm') {
// Show special alert with instructions
showBMInstructionsModal();
} else if (actionRequired === 'reauth') {
// Show re-login button
showReAuthButton();
} else {
// Generic error
showError(message);
}
}
[NEW] frontend/src/components/messenger/BMInstructionsModal.js
Modal dengan instructions:
- Step-by-step guide untuk link page ke BM
- Screenshots (embedded)
- Link ke Business Manager
- Link ke support docs
Content:
- Login ke business.facebook.com
- Pilih Business Manager
- Go to Business Settings → Accounts → Pages
- Click "Add" → "Add a Page"
- Enter page name dan claim
- Kembali connect di CloudChat
Fitur 9: Icon Notifikasi Inbox
Deskripsi
Menambahkan icon notifikasi di inbox untuk indicate unread messages atau pending actions.
Features
- Unread count badge - Show jumlah unread conversations
- Desktop notifications - Browser notifications untuk new messages
- Sound alerts - Optional sound untuk new messages
- Visual indicators - Dot/badge pada conversations yang unread
Flow Diagram
flowchart LR
A[New Message<br/>via Socket.IO] --> B{User di Inbox?}
B -->|Ya| C[Update Unread Badge]
B -->|Tidak| D[Increment Global<br/>Unread Count]
C --> E{Sound Enabled?}
D --> E
E -->|Ya| F[Play Sound]
E -->|Tidak| G[Skip Sound]
F --> H{Desktop Notif<br/>Enabled?}
G --> H
H -->|Ya| I[Show Browser<br/>Notification]
H -->|Tidak| J[End]
I --> J
Implementation Details
Backend
[MODIFY] src/controllers/inboxController.js
Update getConversations():
- Add unread_count ke response
- Add has_unread flag
Add endpoint:
GET /api/app/inbox/unread-count- Get total unread count
[MODIFY] Socket.IO Events
Update message event untuk include unread info:
io.to(`org:${orgId}`).emit('message:new', {
conversationId,
message,
unreadCount: updatedCount
});
Frontend
[NEW] frontend/src/hooks/useNotifications.js
Custom hook untuk handle notifications:
- Request notification permission
- Show desktop notification
- Play sound
- Manage notification settings
[MODIFY] frontend/src/pages/InboxPage.js
Add notification features:
- Unread count badge di header
- Desktop notification on new message
- Sound alert (optional)
- Mark as read on conversation open
[NEW] frontend/src/components/inbox/NotificationBadge.js
Badge component:
- Show count jika > 0
- Max display 99+ untuk large numbers
- Pulse animation untuk new notification
[NEW] frontend/src/pages/Settings/NotificationSettings.js
Settings page:
- Enable/disable desktop notifications
- Enable/disable sound
- Select notification sound
- Test notification button
Sound Files:
- Add notification sounds ke
/public/sounds/ - Options: notification1.mp3, notification2.mp3, dll
Fitur 10: Pipeline Management (Kanban CRM)
Deskripsi
Sistem pipeline untuk conversation management, 100% mirip dengan SocialChat. Pipeline memungkinkan user untuk organize conversations dalam stages/tahapan sebagai Kanban CRM.
Sidebar Menu Placement
Menu Pipeline ditambahkan di sidebar setelah menu Chatbot, sebelum menu lainnya.
📊 Dashboard
📥 Inbox
👥 Contacts
📢 Broadcast
🤖 Chatbot
🔄 Pipeline ← NEW MENU (setelah Chatbot)
⚙️ Settings
...
Use Cases
- Sales Pipeline: Lead → Qualified → Proposal → Negotiation → Closed
- Support Pipeline: New → In Progress → Waiting → Resolved
- Custom pipelines sesuai business process
Flow Diagram
flowchart TD
A[Create Pipeline] --> B[Define Stages]
B --> C[Set Stage Order]
C --> D[Configure Automation<br/>Optional]
E[New Conversation] --> F[Assign to Pipeline]
F --> G[Set Initial Stage]
H[Move Conversation] --> I[Drag to New Stage]
I --> J[Update Stage]
J --> K{Automation<br/>Configured?}
K -->|Ya| L[Execute Actions<br/>Tag, Assign, etc]
K -->|Tidak| M[Update Only]
N[View Pipeline] --> O[Kanban Board View]
O --> P[Cards Grouped<br/>by Stage]
Database Schema Changes
[NEW] Table: pipelines
CREATE TABLE pipelines (
id SERIAL PRIMARY KEY,
organization_id INTEGER NOT NULL REFERENCES organizations(id) ON DELETE CASCADE,
name VARCHAR(255) NOT NULL,
description TEXT,
icon VARCHAR(50),
color VARCHAR(7), -- Hex color
is_default BOOLEAN DEFAULT false,
is_active BOOLEAN DEFAULT true,
created_by INTEGER REFERENCES users(id) ON DELETE SET NULL,
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
CREATE INDEX idx_pipelines_org ON pipelines(organization_id);
[NEW] Table: pipeline_stages
CREATE TABLE pipeline_stages (
id SERIAL PRIMARY KEY,
pipeline_id INTEGER NOT NULL REFERENCES pipelines(id) ON DELETE CASCADE,
name VARCHAR(255) NOT NULL,
description TEXT,
color VARCHAR(7),
position INTEGER NOT NULL,
is_closed_stage BOOLEAN DEFAULT false, -- Mark as final stage
automation_actions JSONB, -- Auto-assign, auto-tag, etc.
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
CREATE INDEX idx_pipeline_stages_pipeline ON pipeline_stages(pipeline_id);
CREATE INDEX idx_pipeline_stages_position ON pipeline_stages(pipeline_id, position);
[MODIFY] Table: conversations
ALTER TABLE conversations
ADD COLUMN pipeline_id INTEGER REFERENCES pipelines(id) ON DELETE SET NULL,
ADD COLUMN pipeline_stage_id INTEGER REFERENCES pipeline_stages(id) ON DELETE SET NULL,
ADD COLUMN stage_changed_at TIMESTAMP;
CREATE INDEX idx_conversations_pipeline ON conversations(pipeline_id, pipeline_stage_id);
[NEW] Table: pipeline_stage_history
CREATE TABLE pipeline_stage_history (
id SERIAL PRIMARY KEY,
conversation_id INTEGER NOT NULL REFERENCES conversations(id) ON DELETE CASCADE,
pipeline_id INTEGER NOT NULL REFERENCES pipelines(id) ON DELETE CASCADE,
from_stage_id INTEGER REFERENCES pipeline_stages(id) ON DELETE SET NULL,
to_stage_id INTEGER NOT NULL REFERENCES pipeline_stages(id) ON DELETE CASCADE,
changed_by INTEGER REFERENCES users(id) ON DELETE SET NULL,
duration_seconds INTEGER, -- Time spent in previous stage
created_at TIMESTAMP DEFAULT NOW()
);
CREATE INDEX idx_pipeline_history_conversation ON pipeline_stage_history(conversation_id);
CREATE INDEX idx_pipeline_history_created ON pipeline_stage_history(created_at);
Implementation Details
Backend
[NEW] src/controllers/pipelineController.js
Endpoints:
Pipeline Management:
GET /api/app/pipelines- List all pipelinesGET /api/app/pipelines/:id- Get pipeline detail with stagesPOST /api/app/pipelines- Create pipelinePUT /api/app/pipelines/:id- Update pipelineDELETE /api/app/pipelines/:id- Delete pipelinePOST /api/app/pipelines/:id/duplicate- Duplicate pipeline
Stage Management:
POST /api/app/pipelines/:id/stages- Add stagePUT /api/app/pipelines/stages/:id- Update stageDELETE /api/app/pipelines/stages/:id- Delete stagePOST /api/app/pipelines/:id/stages/reorder- Reorder stages
Conversation Pipeline Management:
POST /api/app/conversations/:id/pipeline- Assign to pipelinePUT /api/app/conversations/:id/stage- Move to different stageGET /api/app/conversations/:id/pipeline-history- Get stage history
Analytics:
GET /api/app/pipelines/:id/analytics- Pipeline analytics (conversion rate, avg time per stage, etc.)GET /api/app/pipelines/:id/board- Get kanban board data
[NEW] src/services/pipelineService.js
Functions:
createPipeline(organizationId, data)- Create pipelineaddStage(pipelineId, stageData)- Add stagemoveConversation(conversationId, toStageId, userId)- Move conversationexecuteStageAutomation(conversationId, stageId)- Execute automationgetKanbanData(pipelineId)- Get data for kanban viewgetPipelineAnalytics(pipelineId, dateRange)- Calculate analytics
[MODIFY] src/controllers/inboxController.js
Update getConversations():
- Include pipeline_id dan pipeline_stage_id
- Support filter by pipeline
- Support filter by stage
[NEW] Socket.IO Events
// Real-time pipeline updates
io.to(`org:${orgId}`).emit('pipeline:stage-changed', {
conversationId,
pipelineId,
fromStageId,
toStageId
});
Frontend
[NEW] frontend/src/pages/Pipeline/PipelineListPage.js
List semua pipelines:
- Grid/list view
- Create new button
- Edit/Delete actions
- Duplicate button
- Analytics summary per pipeline
[NEW] frontend/src/pages/Pipeline/PipelineBoardPage.js
Kanban board view (mirip SocialChat):
Features:
- Horizontal columns untuk setiap stage
- Cards untuk conversations
- Drag & drop untuk move between stages
- Card content: Contact name, last message preview, assigned agent, time in stage
- Add conversation button
- Filter & search
- Real-time updates via Socket.IO
Libraries:
react-beautiful-dndatau@dnd-kit/coreuntuk drag & drop- Card component dengan hover effects
[NEW] frontend/src/pages/Pipeline/PipelineEditorPage.js
Pipeline editor:
- Pipeline name & description
- Icon & color picker
- Stage builder (add, edit, delete, reorder)
- Stage automation configurator
- Preview panel
[NEW] frontend/src/components/pipeline/StageCard.js
Stage column component:
- Stage header (name, count)
- Conversation cards
- Drop zone indicator
- Add conversation quick action
[NEW] frontend/src/components/pipeline/ConversationCard.js
Conversation card untuk kanban:
- Contact avatar & name
- Last message preview (truncated)
- Time in stage
- Assigned agent badge
- Priority indicator
- Click to open in inbox
[NEW] frontend/src/components/pipeline/PipelineAnalytics.js
Analytics dashboard:
- Conversion funnel chart
- Average time per stage
- Total conversations per stage
- Conversion rate
- Stage transition matrix
[MODIFY] frontend/src/pages/InboxPage.js
Add pipeline features:
- Pipeline selector di conversation detail
- Stage selector dropdown
- Pipeline filter di conversation list
- Quick stage actions
[MODIFY] frontend/src/App.jsx
Add routes:
<Route path="/app/pipelines" element={<PipelineListPage />} />
<Route path="/app/pipelines/:id/board" element={<PipelineBoardPage />} />
<Route path="/app/pipelines/:id/edit" element={<PipelineEditorPage />} />
<Route path="/app/pipelines/new" element={<PipelineEditorPage />} />
Pipeline UI Reference (SocialChat Style)
Kanban Board Layout
┌─────────────────────────────────────────────────────────────────┐
│ Pipeline: Sales Process [+ New] [⚙️] │
├─────────────────────────────────────────────────────────────────┤
│ 🔍 Search │ 👤 Filter Agent │ 🏷️ Filter Label │ 📊 Analytics │
├──────────────┬──────────────┬──────────────┬────────────────────┤
│ 📥 New Lead │ ✅ Qualified │ 📝 Proposal │ 🤝 Negotiation │
│ (12) │ (8) │ (5) │ (3) │
├──────────────┼──────────────┼──────────────┼────────────────────┤
│ ┌──────────┐ │ ┌──────────┐ │ ┌──────────┐ │ ┌──────────┐ │
│ │ John Doe │ │ │ Jane S. │ │ │ Company │ │ │ Big Corp │ │
│ │ "Hai..." │ │ │ "Sudah" │ │ │ "Draft" │ │ │ "nego" │ │
│ │ 👤 Agent1 │ │ │ 👤 Agent2│ │ │ 👤 Agent1│ │ │ 👤 Agent3│ │
│ │ ⏱️ 2h │ │ │ ⏱️ 1d │ │ │ ⏱️ 3d │ │ │ ⏱️ 5d │ │
│ └──────────┘ │ └──────────┘ │ └──────────┘ │ └──────────┘ │
└──────────────┴──────────────┴──────────────┴────────────────────┘
Summary Implementasi Priority
High Priority (Must Have)
- Fitur 3: Mode Antrian - Core feature untuk customer service
- Fitur 9: Icon Notifikasi Inbox - UX improvement yang penting
- Fitur 6: Broadcast Template Filter - Bug fix/improvement
Medium Priority (Should Have)
- Fitur 1: Chatbot Waktu Aktif - Important untuk automation
- Fitur 2: Laporan Chatbot - Analytics yang berguna
- Fitur 10: Pipeline - Powerful feature untuk sales/support
- Fitur 8: Facebook Error Info - Better UX
Low Priority (Nice to Have)
- Fitur 4: Mode Pilih Agen - Advanced feature
- Fitur 5: Integrasi Ongkir - Specific use case
- Fitur 7: Template Meta CRUD - Advanced Meta integration
Estimasi Waktu Implementasi
| Fitur | Estimasi | Complexity |
|---|---|---|
| #1 Chatbot Schedule | 3-5 hari | Medium |
| #2 Laporan Chatbot | 5-7 hari | High |
| #3 Mode Antrian | 7-10 hari | High |
| #4 Mode Pilih Agen | 5-7 hari | High |
| #5 Integrasi Ongkir | 3-5 hari | Medium |
| #6 Broadcast Template Filter | 1-2 hari | Low |
| #7 Template Meta CRUD | 5-7 hari | High |
| #8 Facebook Error Info | 1-2 hari | Low |
| #9 Icon Notifikasi | 2-3 hari | Low |
| #10 Pipeline | 10-14 hari | Very High |
Total Estimasi: 42-62 hari kerja (8-12 minggu)
Verification Plan
Automated Tests
Untuk setiap fitur, buat:
- Unit tests untuk services
- Integration tests untuk API endpoints
- Component tests untuk React components
# Run tests
npm test
# Run specific test
npm test -- pipelineService.test.js
Manual Verification
Fitur 1-2: Chatbot
- Create bot dengan schedule
- Test response dalam/luar jam
- Verify laporan data accuracy
- Export laporan
Fitur 3-4: Queue & Agent Selection
- Enable queue mode
- Send messages dari multiple users
- Verify queue order (FIFO)
- Test agent assignment
- Test queue position check
- Test agent selection dengan AI assist
Fitur 5: Ongkir
- Configure API settings
- Test dengan berbagai origin/destination
- Verify pricing accuracy
- Test chatbot integration
Fitur 6-7: Templates
- Create WA Official device
- Create Meta template
- Verify template filtering
- Test template CRUD operations
Fitur 8: Facebook
- Try connecting Facebook page (without BM)
- Verify error message
- Test dengan page yang sudah linked
Fitur 9: Notifications
- Enable notifications
- Send test message
- Verify badge count
- Test desktop notification
- Test sound alert
Fitur 10: Pipeline
- Create pipeline dengan stages
- Add conversations to pipeline
- Drag & drop between stages
- Verify automation actions
- Check analytics accuracy
- Test real-time updates
User Acceptance Testing
Deploy ke staging environment dan conduct UAT dengan real users untuk setiap fitur.
Dependencies & Prerequisites
Backend Dependencies (npm packages)
{
"node-schedule": "^2.1.1", // For chatbot schedules
"moment-timezone": "^0.5.43", // Timezone handling
"chart.js": "^4.4.0", // Analytics (if server-side rendering)
"exceljs": "^4.3.0", // Excel export
"axios": "^1.6.0" // Ongkir API calls
}
Frontend Dependencies
{
"react-beautiful-dnd": "^13.1.1", // Drag & drop for pipeline
"@dnd-kit/core": "^6.0.8", // Alternative drag & drop
"recharts": "^2.10.0", // Charts for analytics
"react-datepicker": "^4.21.0", // Date range picker
"react-select": "^5.8.0" // Better selects
}
Database Migrations
Buat migration files untuk semua schema changes yang didefinisikan di atas.
External APIs
- Meta Marketing API - Template management
- Facebook Graph API - Messenger integration
- Ongkir API - RajaOngkir/BinderByte/Custom
Risk Mitigation
[!CAUTION] Risk: Breaking changes pada existing features
- Mitigation: Extensive testing, feature flags, gradual rollout
[!WARNING] Risk: Performance impact dengan banyak real-time updates
- Mitigation: Implement throttling, debouncing, pagination
[!WARNING] Risk: External API dependencies (Meta, Facebook, Ongkir)
- Mitigation: Implement retry logic, fallback mechanisms, proper error handling