Local demo · sample data · no live services connected
Docs & Export
Reference documents only — no services or endpoints are deployed.
README.md
Overview and pages · access details omitted
BACKEND.md
Postgres schema & endpoint flow
n8n-workflow.json
n8n design example · requires separate setup
API-REFERENCE.md
Webhook & REST reference
Webhook endpoints
| Method | Path | Description |
|---|---|---|
| GET/POST | /webhook-receiver | Inbound messages from Meta, WhatsApp & website widget |
| POST | /message-combine | Merge threads of the same customer across channels |
| POST | /ai-reply | Generate AI/keyword reply unless human control is on |
| POST | /chat-transfer/initiate | Start a transfer to another member |
| GET | /chat-transfer/check | Current assignee & pending transfer |
| POST | /chat-transfer/change | Change assignee immediately |
| GET | /admin-takeover/check | Is a human in control? |
| POST | /admin-takeover/start | Turn human control on/off |
| GET | /shift-schedule-check | Open now? Who is on shift? Away message |
| POST | /token-cost-counting | Log tokens & cost per AI message |
README.md
# Chatflow Commander — UST AI Control A chatbot & AI-control platform for managing Facebook, Messenger, WhatsApp and website chats in one inbox. This repository is a **frontend demo**: all data lives in your browser (localStorage). No login wall, no paid services, no external API calls. ## Demo access - Open `/admin` or `/dashboard` — instant access. - **Require confirmations** is OFF by default (Settings) — Resolve, Transfer, Delete act immediately. ## Pages | Path | What it does | |---|---| | `/` | Landing page | | `/dashboard`, `/admin` | Stats, charts, recent conversations, quick actions | | `/inbox` | Live inbox: reply, human takeover, transfer, resolve/reopen, new conversation, simulate customer message | | `/auto-replies` | Keyword rules CRUD, AI templates, global AI toggle | | `/schedules` | Working hours (Asia/Dhaka), shifts, away reply | | `/team` | Members, roles Admin/Agent/Viewer | | `/channels` | Connect channels, copy webhook URL, test webhook | | `/combine` | Cross-channel message combine settings + preview | | `/analytics` | Date-range analytics, AI vs human, token cost, per-agent/channel | | `/docs` | Documentation and downloads (README, BACKEND.md, n8n JSON, API reference) | | `/settings` | Profile, notifications, confirmations, API keys, reset/clear data | ## Backend See **BACKEND.md** for the Postgres schema (users, pages, conversations, messages, auto_replies, schedules, shifts, team_members, message_combine_settings, analytics_events, api_keys) and webhook endpoints (webhook-receiver, message-combine, ai-reply, chat-transfer initiate/check/change, admin-takeover check/start, shift-schedule-check, token-cost-counting). ## Develop ```bash bun install bun run dev ``` Reset sample data anytime: Settings → Danger zone → Reset demo data.
BACKEND.md — schema & flow
# Chatflow Commander — Backend Reference (UST AI Control)
The demo app runs entirely in the browser (localStorage). This document describes the production backend it is designed for: **Postgres** + an automation layer (n8n or serverless functions).
## Postgres schema
Tables included (all defined below): `users`, `pages` (channels), `channels` (view), `conversations`, `messages`, `auto_replies`, `schedules`, `shifts`, `team_members`, `message_combine_settings`, `analytics_events`, `api_keys`.
```sql
create table users (
id uuid primary key default gen_random_uuid(),
email text unique not null,
name text not null,
password_hash text,
created_at timestamptz default now()
);
create table pages (
id uuid primary key default gen_random_uuid(),
owner_id uuid references users(id) on delete cascade,
channel text check (channel in ('facebook','messenger','whatsapp','website')) not null,
external_page_id text not null,
access_token_encrypted text,
connected boolean default false,
webhook_verified_at timestamptz,
created_at timestamptz default now()
);
-- channels: convenience view over pages (one row per connected channel)
create view channels as
select id, owner_id, channel, external_page_id, connected, webhook_verified_at from pages;
create table team_members (
id uuid primary key default gen_random_uuid(),
user_id uuid references users(id) on delete cascade,
workspace_owner_id uuid references users(id) on delete cascade,
role text check (role in ('Admin','Agent','Viewer')) not null default 'Agent',
online boolean default false,
created_at timestamptz default now()
);
create table conversations (
id uuid primary key default gen_random_uuid(),
page_id uuid references pages(id) on delete cascade,
customer_external_id text not null,
customer_name text,
customer_phone text,
customer_email text,
status text check (status in ('open','resolved')) default 'open',
human_takeover boolean default false,
takeover_by uuid references team_members(id),
assignee_id uuid references team_members(id),
combined_into uuid references conversations(id),
unread_count int default 0,
last_message_at timestamptz,
created_at timestamptz default now()
);
create table messages (
id uuid primary key default gen_random_uuid(),
conversation_id uuid references conversations(id) on delete cascade,
sender text check (sender in ('customer','ai','human')) not null,
author_id uuid references team_members(id),
channel text not null,
body text not null,
status text check (status in ('sent','delivered','read','failed')) default 'sent',
external_message_id text,
tokens_in int default 0,
tokens_out int default 0,
created_at timestamptz default now()
);
create index on messages (conversation_id, created_at);
create table auto_replies (
id uuid primary key default gen_random_uuid(),
owner_id uuid references users(id) on delete cascade,
keyword text not null,
reply text not null,
channel text default 'all',
active boolean default true,
created_at timestamptz default now()
);
create table schedules (
id uuid primary key default gen_random_uuid(),
owner_id uuid references users(id) on delete cascade,
timezone text default 'Asia/Dhaka',
day text not null, -- Sat..Fri
is_open boolean default true,
open_time time, close_time time,
away_message text,
away_active boolean default true
);
create table shifts (
id uuid primary key default gen_random_uuid(),
member_id uuid references team_members(id) on delete cascade,
day text not null,
start_time time not null,
end_time time not null
);
create table message_combine_settings (
owner_id uuid primary key references users(id) on delete cascade,
enabled boolean default true,
window_minutes int default 30,
match_phone boolean default true,
match_email boolean default true,
match_name boolean default false,
keep_channel_tag boolean default true
);
create table analytics_events (
id bigserial primary key,
owner_id uuid references users(id) on delete cascade,
conversation_id uuid references conversations(id) on delete set null,
type text not null, -- message_in, ai_reply, human_reply, transfer, takeover, resolve
tokens int default 0,
cost_usd numeric(10,6) default 0,
meta jsonb default '{}',
created_at timestamptz default now()
);
create table api_keys (
id uuid primary key default gen_random_uuid(),
owner_id uuid references users(id) on delete cascade,
label text,
key_hash text not null, -- store sha256, never the raw key
last_used_at timestamptz,
created_at timestamptz default now()
);
```
## Webhook / API endpoints
All endpoints accept JSON and require header `x-api-key: cfc_live_...` (except Meta verification GET).
| Method | Path | Purpose |
|---|---|---|
| GET/POST | `/webhook-receiver` | Meta/WhatsApp/website inbound. GET answers `hub.challenge`; POST stores the message, runs combine + AI. |
| POST | `/message-combine` | `{conversation_id}` → merges with other open threads of the same customer inside the combine window. |
| POST | `/ai-reply` | `{conversation_id, text}` → skips if `human_takeover`; keyword rule match else LLM reply; logs tokens. |
| POST | `/chat-transfer/initiate` | `{conversation_id, to_member_id}` → creates pending transfer. |
| GET | `/chat-transfer/check?conversation_id=` | Returns current assignee + pending transfer. |
| POST | `/chat-transfer/change` | `{conversation_id, member_id}` → sets assignee immediately. |
| GET | `/admin-takeover/check?conversation_id=` | `{human_takeover, takeover_by}` — AI must call this before replying. |
| POST | `/admin-takeover/start` | `{conversation_id, member_id, on: true|false}` → toggles human control. |
| GET | `/shift-schedule-check?at=ISO` | Returns `{open, on_shift: [...], away_message}` in Asia/Dhaka. |
| POST | `/token-cost-counting` | `{message_id, tokens_in, tokens_out, model}` → writes analytics_events with cost. |
### Inbound flow
1. `webhook-receiver` → upsert conversation, insert message.
2. `message-combine` (if enabled).
3. `shift-schedule-check` → outside hours ⇒ send away message.
4. `admin-takeover/check` → if human control, stop.
5. `ai-reply` → send via channel API → `token-cost-counting`.