← All projects

Automation · n8n · LLM · PostgreSQL · Supabase · Prompt engineering

Finance tracker inside Telegram

A personal finance tracker that lives in Telegram: free-text messages become structured records, and an intent-routed advisor answers questions about my own data. Built with n8n, Gemini and Supabase.

Hand-drawn diagram: a Telegram message goes through an LLM into a database, and an advisor answers questions about it.

The problem

I was earning a salary every month and had no idea where it went. I wanted visibility, but I knew how finance apps usually end: you install one, use it for a few weeks and forget it exists. Choosing where to track was only half the problem. Sticking with it was the other half.

The idea: fit into a tool I already use

I changed the question. The system had to be compatible with what I already use every day. I open Telegram all day anyway, so the whole tracker lives there. I text a message like "lunch 850", in Darija, French or English, and it is logged in my own database. I can also ask questions about my money in the same chat.

Hand-drawn diagram of the finance tracker in two parts. Top: a Telegram message is parsed by an LLM, placed in the right pay cycle, saved to a database and confirmed. Bottom: a question goes through an intent router and a read-only guard, the database returns rows and an advisor replies. Screenshots show an example chat, with numbers changed in the advisor example.

Technical depth

Capture: free text to structured data

A Gemini model in JSON mode turns each message into a record with a date, type, category, amount and a short description. The prompt copies category names from a closed list character by character, and anything that is not clearly about money returns an IGNORE flag instead of a guess. That keeps the table clean enough to run analytics on without any cleanup step.

Pay cycles instead of calendar months

My month starts on payday, not on the 1st. Each record gets a financial month and a financial year, computed in a code step, and every cycle question filters on both columns together. The advisor also knows how far into the current cycle we are, so it flags a half-finished cycle instead of comparing it to a complete one.

Diagram of two pay cycles on a timeline, each running from the 15th to the 14th. A purchase on the 14th lands in cycle A and one on the 15th lands in cycle B. The calendar 1st is ignored.

Intent routing

Before anything touches the database, a first model classifies the message into one of four intents: small talk, advice that needs no data, a data lookup, or a data question that also needs advice. A router sends only the last two to the database. The intent flag also tells the advisor how to answer: numbers only for a lookup, numbers plus advice and the user profile for the rest.

Diagram of an intent router. Four example messages go to different paths: a greeting and a request for saving tips skip the database, while a spending question returns numbers only and an on-track question returns numbers plus advice.

Conversation memory

Each user gets a window of recent messages keyed by their Telegram id. The router keeps a short window and the advisor a longer one, so follow-ups like "and last month?" work without repeating the context.

Safeguards

  • Closed category list: the model cannot invent categories.
  • Non-money messages are ignored, so chit-chat never becomes a record.
  • Query guard: model-written SQL is checked for destructive keywords such as DROP, DELETE and UPDATE before it runs.
  • Readable errors: database and network failures are mapped from Postgres, PostgREST and HTTP codes to a clear message.
  • Clean output: replies are stripped of markdown so they render properly in Telegram.
Diagram of four checks between a message and the database: a closed category list, ignoring non-money messages, a SQL guard, and clear error messages.

The advisor

The advisor answers in the language the user writes in, shows amounts with thousands separators and leads with the numbers before any insight. It checks the SQL and its description before drawing a conclusion, and it divides multi-cycle totals before comparing them to monthly income.

Example advisor reply listing expense categories with amounts, a total and a short comment. The numbers are not real.

Skills used

  • Workflow automation with n8n, webhooks and the Telegram Bot API
  • LLM prompt design: structured JSON output, closed vocabularies, intent classification, system prompts for an advisor
  • PostgreSQL on Supabase: schema design, SQL, RPC functions
  • Text-to-SQL with guardrails and error handling
  • Conversation memory design and multilingual input (Darija, French, English)
  • Data modelling for non-calendar periods
  • Product thinking: reducing friction so people keep using the system

Value for a company

  • Adoption comes from low friction. Data only exists if people enter it. Putting capture inside a tool people already open all day is how I kept it going for a year, and the same idea applies to expense reports, field notes or support logs.
  • Free text becomes structured, analysis-ready data. A closed vocabulary and an ignore rule produce clean tables without manual cleanup.
  • Numbers for non-technical people. Anyone can ask a question in plain language without knowing SQL, and the access path is guarded.
  • LLM features that are safe to ship. Intent routing, query checks and error handling are the pieces that turn a demo into something dependable.
  • Fast, low-cost build. Low-code orchestration plus a managed Postgres took a working system from idea to daily use quickly.

A natural next step is the same pattern for solo entrepreneurs and small shops that have no time for accounting software, using a chat they already use every day. That is an idea I want to explore, not something I have built.

Results

I used it for a year. At my yearly review the data answered three questions I could never answer before: which categories drain my bank account, how my spending splits across them, and how to lower my costs and where. For the first time I was not guessing.

What I would improve next

  • Compute totals and percentages in SQL and let the model only explain them, because language models can slip on arithmetic.
  • Filter every generated query by user and use row-level security instead of a broad service key, so the advisor is safe for several users.
  • Replace the keyword blocklist with an allow-list or parameterised read-only queries.
  • Apply each user's own pay-cycle day in the cycle logic, which today is fixed in code.
  • Add an audit log and automated tests for the prompts.
LET’S TALK · SAY HELLO ·

Let’s talk about your project.

Got a project in mind? Let’s create something great. I can help turn that idea into a real, working product.

Get in Touch