Back to Home

Telegram Procurement System: No-Code Agentic Development Case

Technical Leader Created a Telegram Procurement System Without Writing Code, Using Agent Systems and Simple Stack. Case Demonstrates Importance of Architecture, Manageability, and State System Design. Lessons Applicable to Internal Tool Development.

Agentic Development: How to Create a Telegram Procurement System Without Code
Advertisement 728x90

# How a Tech Lead Built a Procurement System in Telegram Without Writing Code: An Agentic Development Case Study

When internal procurement in the team turned into chaos with lost requests and uncoordinated queries, the tech lead decided to create a system based on Telegram. Without writing a single line of code, using agentic systems and a clear architecture, he built a solution with OCR, moderation, and secure deployment. Here's how to do it without losing control over quality.

Problem: Chaos Instead of a Procurement Process

In small teams, procurement often starts with informal agreements. First come scraps of paper, then notes, then a dedicated Telegram thread. A process emerges: drop the link, price, quantity, and justification. But in practice, some requests get lost, others slip through, some lack price or justification, and people forget their own requests. As a result, the tech lead spends time fighting chaos instead of managing procurement. Key takeaway: if a process involves money, it shouldn't exist as free-form chat.

Infrastructure Requirements: From "Little Bot" to Full System

The initial idea—a simple Telegram bot—quickly ran into infrastructure challenges. Due to Telegram's instability without VPN, it required:

Google AdInline article slot
  • Foreign VPS
  • Custom VPN setup
  • Reliable auto-restart
  • Convenient deployment
  • Rollback mechanism for failed releases

This is no longer a "quick evening script," but a full engineering pipeline. Experience shows: "simple automation" often hides complex infrastructure underneath.

Agentic Development: Accelerator, Not Replacement for Thinking

The project was implemented using ChatGPT and an agentic system, but the tech lead's active involvement was essential. The process included:

  • Formulating the task and assigning roles
  • Clarifying business logic
  • Manual testing of scenarios
  • Identifying contradictions and bugs
  • Iterating on targeted fixes
  • Retesting

The agent accelerated the cycle: shortening the time between spotting a problem and verifying a new implementation. Key takeaway: you can delegate code syntax, but systems thinking and architecture remain critical. Without a clear process model, the agent just speeds up implementing flawed logic.

Google AdInline article slot

Ditching "Magic": Switching to a Wizard Flow

The first hypothesis—automatic data extraction from links—proved unviable due to:

  • Site diversity
  • Unstable page structures
  • Ambiguous prices
  • Complex data rendering
  • Hostile marketplace logic

Instead, a wizard flow was implemented:

  • Attach screenshot
  • Provide link
  • Write justification
  • Specify quantity
  • Manually enter price if needed (if OCR failed)
  • Review final card before confirming

This approach is less "wow," but ensures controllability—the key factor for operational processes.

Google AdInline article slot

Why LLM Wasn't the System's Core

Though tempting to use LLM for request processing, a simple stack was chosen:

  • Python
  • Telegram bot framework
  • SQLite
  • Local OCR
  • HTML reports on templates
  • systemd for services and timers

Rationale:

  • Runs on low-spec VPS
  • No runtime dependency on external APIs
  • No paid inference per request
  • Easy debugging
  • Predictable behavior

This choice highlights a key principle: not every task benefits from AI. Sometimes strict FSM and validation deliver more value than complex models.

State Machine: Foundation of Reliability

A request is an entity with a lifecycle including statuses:

  • Draft
  • Awaiting image
  • Awaiting link
  • Awaiting justification
  • Awaiting confirmation
  • Pending moderation
  • Returned for revision
  • Deferred to next period
  • Urgent
  • Sent

FSM was used to manage this cycle. Code example:

class PurchaseWizard(StatesGroup):
    waiting_for_image = State()
    waiting_for_link = State()
    waiting_for_reason = State()
    waiting_for_qty_lots = State()
    waiting_for_lot_size = State()
    waiting_for_manual_price = State()
    waiting_for_confirmation = State()

and domain statuses:

class PurchaseStatus(str, Enum):
    DRAFT = "draft"
    AWAITING_IMAGE = "awaiting_image"
    AWAITING_LINK = "awaiting_link"
    AWAITING_REASON = "awaiting_reason"
    AWAITING_QTY = "awaiting_qty_lots"
    AWAITING_CONFIRMATION = "awaiting_confirmation"
    COMPLETE = "complete"
    PENDING_MODERATION = "pending_moderation"
    RETURNED_FOR_REVISION = "returned_for_revision"
    APPROVED = "approved"
    CANCELLED = "cancelled"
    SENT = "sent"

When roles, money, and deadlines are involved, shift from message handling to state management.

Architecture: Simplicity as a Sign of Maturity

System diagram:

Telegram user
    ↓
Bot handlers / FSM
    ↓
Purchase service
    ├── SQLite
    ├── OCR service
    ├── Moderation logic
    ├── HTML report builder
    └── Reminder / maintenance jobs
            ↓
        systemd service + timers

Project structure:

purchase_bot/
├── app/
│   ├── bot/
│   ├── db/
│   ├── services/
│   ├── templates/
│   └── main.py
├── data/
│   ├── uploads/
│   ├── reports/
│   └── bot.db
├── scripts/
├── deploy/
└── README.md

Skipping Docker and heavy DBs in the first version allowed focus on functionality. For internal tools, simple architecture is a sign of maturity, not weakness.

Telegram UX: Interface Over Message Stream

Working with Telegram revealed challenges:

  • Persistent old buttons
  • Overlapping cards
  • Parallel old and new request versions
  • Notification delays
  • Inconsistent "Back" button behavior
  • Screen looping
  • Chat clutter

Solution: design the bot as a screen-based state system. Core principles:

  • Single active screen
  • Deleting outdated messages
  • Safe handling of old callback buttons
  • Separate rules for menus, notifications, and work cards

This approach, while not flashy, ensures daily usability.

Real Processes Break Symmetry

Implementing moderation, urgent requests, and period deferrals showed real processes don't match neat diagrams. For example, a second moderation stage can add unnecessary friction if the first fully handled the request. Logic had to be rebuilt for real needs, not diagrams. Tech leads know this pattern: if the scheme hinders flow, break the scheme.

Sneakiest Bugs at Layer Boundaries

Critical errors arose not in core features, but at layer intersections. For example:

  • "Confirm" button hung due to timezone-aware vs. timezone-naive object comparison
  • Data format mismatches between modules
  • State sync issues on updates

These bugs underscore the importance of careful component interface design.

Key Takeaways

  • Architecture over agents: Even with agentic systems, clear architecture and systems thinking are mandatory. Agents speed up implementation but don't replace design.
  • Controllability over "smartness": For operational processes, reliability and simplicity trump complex automation. Wizard flows often outperform full automation attempts.
  • States, not messages: With roles, money, and deadlines, design as a managed lifecycle with explicit statuses.
  • Simplicity as strategy: For internal tools, avoid architectural bloat. Minimal stack on modest hardware ensures reliability and easy maintenance.
  • Telegram UX demands discipline: Bots should be designed as screen systems, not message streams. Deleting outdated elements and a single screen are critical for user experience.

— Editorial Team

Advertisement 728x90

Read Next