telegram Case study
Management Bot + Owner Daily Report
An owner should not have to collect the day's numbers from six chats and two dashboards. For a watch and jewellery retailer I built the management layer as one thing: a Telegram assistant that keeps order cards current and answers the finance question, one report every night, and a PWA that shows the same numbers on a phone, even offline.
The business problem
The owner was getting the business in fragments: order notifications in one group, a manager card in the evening, the AI sales assistant posting its own daily note, staff work reports somewhere else. Each send had its own schedule and its own query, so the same question could get a different answer depending on where it was asked.
Underneath, the numbers themselves had a quiet defect. The shop's first-party event beacon passed three independent throttles, and the default ceiling was three events per visitor per five minutes. The beacon answered success even when the event was dropped, so no dashboard showed anything wrong while call and social taps were being thrown away for a month.
What I delivered
- A Telegram assistant bot that turns every paid order into a live card with the product image and a Jalali date, and edits that same message in place as the order changes: status, product swap, price correction, balance payment, discount breakdown. No reply spam.
- An admin menu on the same bot: sales for today, week, month and year; a Shamsi month picker with per-gateway shares; management reports (overview, trend, AOV, abandonment rate, top products, province, gateway success); CSV export; order search; a CRM customer card; and a finance card that answers the commission question.
- One multi-part report to the owner just before midnight: today panel, CRM operator card, shift actions and lead backlog, ops, bots including the sales assistant's summary, and team performance. It replaced the scattered legacy sends: the evening group card is disabled, the sales assistant's own daily post is switched off, and the work group now only collects and scores staff reports.
- An installable owner PWA with eight tabs (today, sales, products, customers and club, traffic, operations, site health, staff) plus cards for customer moods, stock on the shelf versus the company warehouse, SMS patterns and bot health, all on Jalali date windows with charts. Offline it shows the last numbers under a stale banner.
- First-party event logging: the shop's own event table (page views, popup views and submits, call and social taps, carts, checkouts, purchases) with UTM columns, rolled up daily for the dashboard. Intent events now have their own throttle bucket.
- A customer-DNA loop from the AI sales assistant: every conversation is observed into a per-person behavioural profile, synced daily into CRM contacts, read by the operator card and the PWA's bots tab, and used to attribute sales that follow a bot conversation. The bots tab flags a sync older than 48 hours.
Technical approach
- The bot lives where Telegram is reachable and treats the store purely as a data source over REST: the WooCommerce API plus two custom namespaces, a token header and an IP allowlist. In the same month I revoked the bot server's root SSH key to the site; a reporting bot has no business holding one.
- The PWA is fast because it is allowed less. Panel requests run with plugins disabled, which took the floor from 1.8 s to 1.0 s; each tab is cached for thirty minutes per window and a fifteen-minute cron keeps the default window warm. Counting products by brand had a JOIN returning 193k rows for a 25k-product shop; a sub-select cut that from 9.8 s to 1.9 s. Windows longer than 45 days read a daily roll-up table instead of the raw events.
- Dates are where this site bites. wp_date returns Jalali here, which cost two rewrites before I gave the panel a non-localised SQL date helper; the event table is UTC while every other table is Tehran-local; and the bot derives local time from an external source so the nightly job fires even when the host clock has drifted.
- The throttle fix was not "raise the ceiling". Intent events got their own bucket of forty per five minutes, and taps from the link page get the same allowance keyed on a visitor cookie, so a whole carrier NAT does not share one bucket. Page views moved from a ten percent sample to full logging with their own allowance of thirty per five minutes.
- Windows Task Scheduler earned its own lessons. Tasks run as SYSTEM with no python on PATH, so a .bat calling bare python fails every run yet works when double-clicked; and the DNA sync died for four days because its task needed an interactive logon, and nothing reported it. The sync was caught up, and the PWA now flags any sync older than 48 hours.
Result and evidence
The result I care about is agreement. One month's totals in the PWA were verified against the commission page, and the bot's finance card gives the same figure, so the owner gets one answer whether they ask the page, the app or the bot. The throttle bug is the honest part: call taps had fallen roughly tenfold while visits fell forty percent, and every intent trend across that month is up to ten times low. It went unnoticed because the beacon reported success; it was fixed with a dedicated bucket, and the window is marked so nobody trends across it. And the scattered sends are gone: the owner now receives one report a night, and the legacy manager messages are gated off.
Commercial value
An owner who has to reconcile three sources stops reading all of them. One report a night, a phone app that still shows numbers without a connection, and a bot that answers the finance question with the same figure as the commission page, is what makes the numbers get used. The throttle lesson transfers to any first-party analytics: a beacon that says OK while dropping events is worse than no beacon, because it removes the reason to check.
Readable implementation brief
implementation_brief {
project: "Management bot + owner daily report"
client: "a watch and jewellery retailer"
bot: "python-telegram-bot; WooCommerce REST + two custom
namespaces, token header, IP allowlist; SQLite maps
order <-> card message; captions edited in place"
report: "one multi-part send just before midnight: today,
CRM operator card, shift actions + lead backlog,
ops, bots (sales-brain summary), team performance"
pwa: "eight tabs, Jalali windows, Chart.js; 30-min tab cache,
15-min warm cron; offline = last numbers + stale banner"
events: "own table, UTC, UTM columns; three throttle gates;
intent bucket 40/5min, page views 30/5min"
dna: "chat -> per-person profile -> daily sync -> CRM contact;
PWA flags a sync older than 48h"
lesson: "a beacon that answers OK while dropping events hid
a month of intent taps"
}What this project shows
The throttle bug is what I would want a reviewer to read. Nothing was broken, every request returned success, and the dashboards were confidently wrong for a month. Fixing it as a separate bucket, and marking the window instead of quietly back-filling it, is the difference between analytics that can be trusted and analytics that look fine.
Replacing four sends with one report sounds like cleanup; it is actually a data decision. When the owner's report, the app and the bot draw on the same numbers, a disagreement becomes a bug to fix rather than an argument about which chat to believe.