I'm building a telegram bot to remind me changing my car oil part 3

I'm building a telegram bot to remind me changing my car oil part 3

Progress, progress, sweet progress
3 min read
Apr 3, 2022 4:00 PM (17 days ago)

Welcome to the part 3 of my journey to create a telegram bot that will remind me changing my car oil.

Checkout part 1 (opens new window) and part 2 (opens new window) for context.

# Today was productive AF

# Demo Preview

I got the bot to ask questions and record answers. Here's a demo 👇!


Full demo can be found on Imugr 👉 https://imgur.com/a/gPkI95A (opens new window);

# Ask Questions and record answers

Oilly now can ask questions like, "what is your current mileage?", and make sure to correctly record the answers in the database.

# Telegram persistance problem

Unfortunately telegram wont let you send any custom data with the message you have to debend on the text you send to record answers and here where I get stuck for 3 hours trying to find a way around.

Let me explain the problem in another way:

When Oilly asks the user What is the current mileage in (km) as shown in your car dashboard? and waits for an answer there's no way for me to know wither the following text will be answer for this question or not because telegram doesn't return the message id in this case the question id, nor let you send custom data with the message.

	bot.sendMessage(chat.id, "What is the current mileage in (km) as shown in your car dashboard?", {
		reply_markup: {
            // Options that doesn't contain custom data

1 cup of coffee and 21 Google results later I had this idea: Question Session .

# Question Session

When Oilly asks the user a question it opens a session for that user with a question id and waits for an answers, then the user type the answer and tap done.

Tap to Next question

Question Session Table

# Database Structure

# Users Table (Collection)

Started with simple table that holds user information from the telegram user object (opens new window).

Firebase users table

# Questions answers Table (Collection)

After every answer user have to tap Done to record the answer. A collection called questions_answers will get the latest answer from question_sessions collection and record answer in a document with a unique key telegramChatId_question_id

Firebase questions answers table

# Project Structure

Project Structure

I made some changes to the project structure like extracting every question logic into it's own file on questions folder.

That helped me organinsing the code even more here's an example from the current-mileage.js question file.

const askCurrentMileage = async (/** @type {TelegramBot.Chat}*/ chat) => {
	bot.sendMessage(chat.id, lang.__('current_mileage_question'), {
		reply_markup: {
			force_reply: true,
			selective: true,
			input_field_placeholder: '25000',

	// open question session
	const questionSessionData = {
		id: 1,
		question: 'current_mileage_question',
		answer: null,
		created_at: serverTimestamp(),

	await setDoc(doc(db, 'question_sessions', String(chat.id).toString()), { ...questionSessionData, created_at: serverTimestamp() });

	bot.sendMessage(chat.id, lang.__('enter_correct_then_done'), {
		reply_markup: {
			inline_keyboard: [
						text: lang.__('Done'),
						callback_data: JSON.stringify({
							type: 'done_answer',
							value: 1,

const validationLogicForCurrentMileage = (answer) => {
	return isNumber(answer) && answer > 0;

# Multiple Language support ❤ 🌎

I believe that everyone no matter what lanague they speak deserve a chance to experience software at their native language.

Added language support using i18n npm package (opens new window) and I intend to opensource this bot so other people can contribute to translating it!

# What next

  • Implement the calculation algorithm.
  • Implement the cronjobs logic.
  • Deploy to vercel.
  • Test
  • Opensouce

To be continue...

My Newsletter

I send out an email every so often about cool stuff I'm working on or launching. If you dig, go ahead and sign up!

No spam, only goldden nuggets 💎


Ahmed Nagi - Powerd By Vuepress . Hosted with GitHub and Netlify .