Inspiration
Sales on Telegram is real business done in a tool that remembers nothing. Founders, agencies and Web3 teams close deals in DMs, then re-type everything into a CRM that has no idea the conversation happened. The tools that exist are Telegram-first: they bolt CRM columns onto a chat list. I wanted the opposite — a real CRM where Telegram is a first-class channel, so every chat is attached to a contact and a deal, and an incoming message can actually do something.
What it does
Cavyro is a multi-tenant CRM (companies, contacts, deals, pipelines, custom fields, docs, reports) with Telegram wired through the middle of it:
- Personal-account mirror (MTProto) — links your real Telegram account, not a bot. Dialogs and messages mirror into the app in real time over WebSocket, with full-text search across history and a team inbox with per-chat "hide from team".
- Messages as automation triggers — an inbound DM is matched to a contact and published as telegram.message_received on the domain-event bus, so it fires the same automation engine as any other CRM event.
- Outbound is warm-only — automations can message a contact only from an account that already has a dialog with them, and always from the account that spoke to them last. Deliberate anti-ban contract, not a limitation I forgot to lift.
- AI that acts, not just summarizes — an assistant bot inside Telegram plus an MCP gateway exposing ~94 CRM tools, so an agent can create a deal, search activity or log a note straight from the chat.
- The rest of a real CRM — reports with working-hours first-response-time and P90, collaborative docs, outbound webhooks, public API, Paddle billing.
How I built it
Solo, over ~6 months (first commit 22 Mar 2026), across seven repos and ~1,500 commits:
- cavyro-backend — Rails 8.1 JSON API, PostgreSQL, acts_as_tenant for tenancy, action_policy for authorization, SolidQueue for jobs. The single source of truth; everything else is a client.
- cavyro-frontend — React 19 + Vite + TypeScript, shadcn/ui, TanStack Query, bulletproof-react feature slices; REST + ActionCable.
- cavyro-telegram — Fastify + GramJS (MTProto mirror) + grammY (assistant bot), Prisma on its own Postgres. Encrypted StringSession per account (AES-256-GCM), a client pool for multi-account, and a write-through message store so the mirror isn't a live proxy.
- cavyro-ai — stateless Fastify gateway exposing POST /mcp and POST /chat; holds no data, translates tool calls into backend REST using the caller's own token, so permissions hold all the way down.
- Ops — Coolify on a single host, Paddle as merchant of record, Bugsnag, Langfuse, Better Stack with a job-queue heartbeat, weekly develop → main release.
Challenges I ran into
- MTProto punishes carelessness. Cold outreach gets accounts banned, so outbound had to become a hard warm-only contract enforced in the service (no dialog → permanent, non-retryable failure) instead of a setting someone can switch off.
- There is no replay. GramJS's catchUp() is an empty stub, so downtime silently loses updates. Fixed with reconcileRecent on every subscribe plus a 20s sweep over an ingested_at queue — a trigger fires instantly, or within ~20s worst case.
- Ingestion couldn't depend on a browser tab. Automations that only work while someone is looking at the inbox are not automations; sessions are now subscribed at boot, staggered, always on.
- Media without storing media. No bytes are persisted, so every image would be a live download. Telegram's ~200-byte stripped thumbnail gets turned into a data: URI and stored — bubbles paint with zero requests, and history keeps rendering even after the session is revoked.
- Two people's privacy in one inbox. A shared inbox over someone's personal account needs a fail-closed authorization boundary — membership resolved from /me, never a client header, with per-chat hiding and per-message sender attribution.
Accomplishments that I'm proud of
- Telegram and the automations engine talk both directions — inbound message → domain event → automation → warm reply, end to end.
- An AI surface that does real work: ~94 MCP tools over the whole CRM, plus the assistant bot living inside Telegram itself.
- The mirror survives failure honestly: sessions are marked dead, never deleted; the store backs up a slow or rate-limited Telegram.
- Response-time reporting with a working-hours clock, FRT modes, P90 and distribution — not flat averages.
- Shipped as a live paid product on Paddle, released weekly, run by one person.
What I learned
- Write-through beats live proxy. Persisting on the way through bought search, deletion resolution, rate-limit resilience and the substrate for the inbox and ingestion — all from one decision.
- Constraints are positioning. Warm-only sending looks like a missing feature until you frame it as the reason accounts don't get banned.
- Fail-closed defaults, and know your limits apart — the bot limit and the mirrored-accounts limit are separate plan features, and conflating them breaks billing in ways tests don't catch.
- Let the event bus be the seam. Telegram never calls automations; it publishes. Adding the next channel is adding a publisher.
- Solo scale comes from written knowledge. A dedicated knowledge base of conventions, domain rules and gotchas — read by coding agents on every session — is what made seven repos maintainable by one person.
What's next for Cavyro - Telegram CRM
- Tasks — due date, priority, assignee, attachable to contact/deal; the biggest structural gap today.
- Store-backed reports — read the mirror store instead of live MTProto: instant load, multi-account aggregation, no 92-day / 2,000-message / flood-wait ceilings.
- Team Performance + SLA alerts — per-member reply metrics (the data is already there) and thresholds like "no reply in 30 min → notify".
- Group and channel ingestion — today only private chats trigger automations.
- Per-chat scheduled messages and follow-up reminders, plus Range streaming so video plays inline in Safari.
Log in or sign up for Devpost to join the conversation.