Most "AI integrations" in modern SaaS are glorified ChatGPT wrappers that summarize support tickets or generate marketing copy. For operational ERP software, that approach is worse than useless.
A smartphone repair technician with screwdrivers in hand, or a mechanic standing under a car lift, doesn't need open-ended conversational fluff. They need to execute transactions in 3 seconds flat without clicking through 4 separate modal forms:
"Emre paid his debt, gave 10,000."
Behind that single Turkish sentence lies complex domain logic:
Finding the right customer entity.
Checking existing debit balances (e.g., 4,800 TL).
Detecting an overpayment (5,200 TL excess) and allocating it to active work orders or advance customer credit.
Mutating cash ledgers, accounting tables, and staging a WhatsApp receipt draft.
To solve this for real-world repair shops and local businesses, I engineered Mokoko, the conversational execution engine powering İşletme Yönetim.
Here is the engineering breakdown of how we achieved deterministic state mutations, two-phase confirmation, and cost-efficient execution on top of Laravel.
- Hybrid Routing: The Zero-Token Fast-Path Not every query needs an LLM. Making an expensive API call just to check "Who owes money today?" burns tokens and introduces 1,500ms of unnecessary latency.
We built a dual-channel router:
Deterministic Fast-Path (Buttons & Common Queries): Routine checks like "Who has outstanding debt?", "Today's agenda", or daily cash totals match strict regex patterns or direct UI shortcuts. They hit pre-indexed SQL views directly. 0ms LLM latency, zero token cost.
LLM Reasoning Pipeline (Mutative Intent): Free-form sentences ("Add 2 phone cases at 150 each, cash payment, deduct stock") are routed to the LLM solely for entity extraction and tool parameter generation.
[User Input (Voice or Text)]
│
├───► [Regex / Fast-Path Router] ───► Direct Cached SQL (0ms, $0)
│
▼ (Complex Intent)
[LLM Entity Extraction]
│
▼ (Strict JSON Schema)
[Staged Draft Card] ─── User Confirms? ───► DB Transaction + 30m Undo Window
- Two-Phase Commit: No Unconfirmed Mutations The biggest hazard of conversational tools in financial apps is silent hallucination. An AI must never mutate database tables autonomously based on a probabilistic prompt.
We implemented a Two-Phase Commit pattern:
Stage & Preview: The LLM parses the input, maps it to a JSON schema, and returns a structured UI draft card.
Explicit Human Confirmation: The preview shows the exact financial breakdown. For example:
Customer: Emre Çelik
Received: 10,000 ₺ (Cash)
Current Debt: 4,800 ₺
Warning: 5,200 ₺ excess detected. Allocated to active work orders / prepayment.
Commit: The database transaction runs only when the user taps "Onayla" (Confirm). If they dismiss or ignore it, nothing changes.
- Compensating Transactions: The 30-Minute Undo Engine When technicians work fast at the counter, mistakes happen. If an action updates inventory, customer debit, and cash logs simultaneously, a simple mistake could corrupt books.
Instead of complicated manual rollbacks, we built an atomic snapshot engine:
PHP
class ReversibleActionManager
{
public function execute(Tenant $tenant, StagedAction $action): ExecutedActionResult
{
return DB::transaction(function () use ($tenant, $action) {
// 1. Take state snapshot of affected rows
$snapshot = $this->createStateSnapshot($tenant, $action->targetEntities());
// 2. Execute business mutations
$result = $action->handler()->execute($action->payload());
// 3. Store reversible snapshot token in Redis with 30-min TTL
Cache::put(
key: "undo_token:{$result->transactionId}",
value: serialize($snapshot),
ttl: now()->addMinutes(30)
);
return $result;
});
}
public function rollback(string $transactionId): bool
{
$snapshot = Cache::pull("undo_token:{$transactionId}");
if (!$snapshot) {
throw new ExpiredRollbackWindowException("Rollback window expired.");
}
return $this->revertToSnapshot(unserialize($snapshot));
}
}
If the user taps "↩ Geri al" (Undo) within 30 minutes:
Deducted inventory increments back to stock.
Ledger entries are reversed.
Customer debt balance is restored down to the exact penny.
- Pragmatic External Communication: WhatsApp Deep-Links Many SaaS teams attempt to automate customer notifications using unofficial WhatsApp web scrapers or third-party bot gateways. This inevitably results in suspended numbers, API downtime, or privacy leaks.
Instead of running risky bot daemons, Mokoko constructs pre-filled https://wa.me/ URI schemes:
When a repair ticket is marked "Ready", Mokoko prepares the personalized message and bill summary.
It presents a single "WhatsApp ile Gönder" button.
Tapping the button launches the shopkeeper's official WhatsApp client with the recipient and text pre-filled.
The shop owner reviews the text and hits send from their own verified phone number. Zero bot infrastructure, zero risk of provider bans, 100% human-verified delivery.
- Essential Guardrails When building conversational workflows for non-technical users, defensive guardrails are mandatory:
Hard-Blocked Destructive Prompts: Commands like "Delete all customers" or "Wipe inventory" are blocked at the validation layer. Record deletion is strictly limited to single-entity, explicit name matches.
Role-Based Access (RBAC): Junior apprentices and staff members cannot execute queries involving profit margins, cash drawer totals, or record deletions. Context validation happens before any tool execution.
Tenant Isolation: The LLM prompt context contains zero internal database keys. The database tenant scope is resolved exclusively from the authenticated HTTP session.
Conversational AI in vertical SaaS shouldn't be about writing poetry or generating filler copy. Its real power is friction reduction—eliminating tedious CRUD forms so business owners can focus on running their shops.
You can inspect the live workflow and interactive demo here:
Top comments (0)