A modular backend service for building flow-based chatbots on WhatsApp Business API. Designed with extensibility, clean architecture, and session handling in mind. Built in Go 1.24 using Chi, Postgres, and Gemini LLM integration.
⚠️ Note: This project is a work-in-progress. It can run locally using your own WhatsApp Cloud API credentials, but full deployment is currently blocked by Meta's Tech Provider approval requirements.
- ✅ JWT-based user authentication (with GitHub and Google OAuth via Goth)
- ✅ Graph-based conversation flow (nodes + edges)
- ✅ WhatsApp webhook + message logging
- ✅ Gemini API integration (LLM-assisted responses)
- ✅ Session & user management with Gorilla sessions
- ✅ Swagger API docs (
swaggo/swag
) - ✅ Docker-ready with
.env
support
Layer | Tools / Libraries |
---|---|
Framework | chi , gorilla/sessions , cors , uuid |
Auth | jwt , goth (Google, GitHub) |
LLM | google.golang.org/genai (Gemini) |
DB | Postgres / SQLite via lib/pq , go-sqlite3 |
ORM | sqlc + raw SQL files for fine-grained control |
Docs | swaggo/swag , auto-generates Swagger UI |
Logging | custom middleware + color logs (fatih/color ) |
Misc | godotenv , go-password , http-swagger |
.
├── cmd/ # Entrypoints (main.go per module)
│ ├── server/ # Main API server
│ ├── dbFlow/ # CLI for DB flow seeding/testing
│ └── reactflow/ # Flow engine logic
├── internal/ # App logic (handlers, repos, services)
│ ├── handlers/ # Webhook, user auth, messaging
│ ├── models/ # Data models (User, Message, Flow)
│ ├── repositories/ # DB access (Postgres)
│ ├── router/ # Routes and middleware
│ └── services/ # Business logic (flow engine, LLM)
├── sql/ # Raw SQL + generated code (via sqlc)
│ ├── queries/ # .sql source files
│ └── database/ # sqlc-generated Go code
├── docs/ # Swagger doc files
├── pkg/utils/ # Helpers (cookies, JWT, password)
├── docker-compose.yaml
├── Makefile
├── .env.example
└── README.md
This project supports flow-based conversation logic via JSON-defined node/edge graphs. Below is an example schema used to seed a basic welcome flow:
{
"start_node_id": "node_start",
"nodes": [
{ "id": "node_start", "type": "start", "data": {} },
{ "id": "node_greet", "type": "send_message", "data": { "message": "Hi there! What's your name?", "message_type": "text" } },
{ "id": "node_get_name", "type": "receive_input", "data": { "variable_name": "userName" } },
{ "id": "node_reply_name", "type": "send_message", "data": { "message": "Nice to meet you, {{userName}}! How can I assist you today?", "message_type": "text" } },
{ "id": "node_ask_interest", "type": "send_message", "data": { "message": "Are you interested in services or support?", "message_type": "button", "buttons": [ { "text": "Services", "payload": "interested_services" }, { "text": "Support", "payload": "interested_support" } ] } },
{ "id": "node_handle_interest", "type": "conditional", "data": { "variable_to_check": "lastUserPayload", "conditions": [ { "operator": "equals", "value": "interested_services", "next_node_id": "node_services_info" }, { "operator": "equals", "value": "interested_support", "next_node_id": "node_support_info" }, { "operator": "default", "next_node_id": "node_reprompt_interest" } ] } },
{ "id": "node_services_info", "type": "send_message", "data": { "message": "Great! We offer X, Y, Z services.", "message_type": "text" } },
{ "id": "node_support_info", "type": "send_message", "data": { "message": "Please describe your support issue.", "message_type": "text" } },
{ "id": "node_reprompt_interest", "type": "send_message", "data": { "message": "Please choose from 'Services' or 'Support'.", "message_type": "text" } },
{ "id": "node_end_flow", "type": "end", "data": { "message": "Terimakasih", "message_type": "text" } }
],
"edges": [
{ "id": "e1", "source": "node_start", "target": "node_greet" },
{ "id": "e2", "source": "node_greet", "target": "node_get_name" },
{ "id": "e3", "source": "node_get_name", "target": "node_reply_name" },
{ "id": "e4", "source": "node_reply_name", "target": "node_ask_interest" },
{ "id": "e5", "source": "node_ask_interest", "target": "node_handle_interest" },
{ "id": "e6", "source": "node_handle_interest", "source_handle": "interested_services", "target": "node_services_info" },
{ "id": "e7", "source": "node_handle_interest", "source_handle": "interested_support", "target": "node_support_info" },
{ "id": "e8", "source": "node_handle_interest", "source_handle": "default", "target": "node_reprompt_interest" },
{ "id": "e9", "source": "node_services_info", "target": "node_end_flow" },
{ "id": "e10", "source": "node_support_info", "target": "node_end_flow" },
{ "id": "e11", "source": "node_reprompt_interest", "target": "node_ask_interest" }
],
"global_variables": {
"llm_api_key": "sk-...",
"default_greeting": "Hello!"
}
}
🧪 You can use this schema to seed flows into the database or simulate flows locally. Each node represents a specific message or logic step in the conversation.
Copy .env.example
to .env
and fill in:
PORT=1234
DB_URL=postgres://postgres:root@localhost:5432/my-database?sslmode=disable
SECRET_KEY=YtEkgKL1Gz0Hx3R
WEBHOOK_VERIFY_TOKEN=happy
# WhatsApp Cloud API
WHATSAPP_CLOUD_API_ACCESS_TOKEN=...
WHATSAPP_CLOUD_API_PHONE_NUMBER_ID=...
...
# Gemini
GEMINI_API_KEY=...
# OAuth
GOOGLE_KEY=...
GOOGLE_SECRET=...
GITHUB_KEY=...
GITHUB_SECRET=...
make run-server
Or manually:
go run cmd/server/main.go
Run Swagger docs:
swag init
View docs at: http://localhost:1234/swagger/index.html
- ❌ Meta Tech Provider approval still required for public WhatsApp access.
- ✅ System works with private/test API credentials.
- 🛠️ Admin panel and flow UI planned (React-based).
- Web-based chat flow builder UI
- Unit tests and CI pipeline
- Multi-tenant flow management
- Multi-channel support (Telegram, LINE, etc.)
Billy Mosis Priambodo 🌐 billymosis.com 🐙 github.com/billymosis 📫 edo.billy@gmail.com