Skip to content

WantbeFree/ifly-time-bot

Β 
Β 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

12 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Raspil iFLY 2.0

Raspil iFLY 2.0 bot avatar

Split iFLY flight-time packages inside Telegram.

Telegram Mini App + bot for collecting participants, calculating package cost, and coordinating the final purchase group.

Live Next.js React Supabase Vercel Telegram

Raspil iFLY 2.0 turns a Telegram group into a lightweight buying pool for a shared iFLY time package. Users join from a Telegram Mini App, choose how many hours they can buy, see price and savings immediately, and the bot keeps the current split visible at the bottom of the chat.

When enough time is collected, the bot finalizes the split, sends private instructions, helps create a separate discussion group, and shows purchase details only inside that private group.

πŸš€ Live

Public docs intentionally do not include bot tokens, group IDs, webhook secrets, Supabase project refs, or direct webhook URLs.

πŸŒͺ️ What it solves

Problem What Raspil iFLY does
People coordinate iFLY package purchases manually in chat Keeps one current split message at the bottom of the Telegram group
Users need to know price before joining Calculates package price instantly in the Mini App
People can buy exact time or only a range Supports Π’ΠΎΡ‡Π½ΠΎΠ΅ and Π”ΠΈΠ°ΠΏΠ°Π·ΠΎΠ½ slider modes
Package closes when enough hours are collected Finalizes automatically at 10+ total hours
Final purchase needs private account data Shows iFLY account data only in the split discussion group
Multiple users may try to create separate discussion groups First group claims the split; later attempts get the existing link

βœ… Core product rules

Rule Value
Package size 10 hours minimum
Participants limit 4 people maximum
Package price 10 500 BYN / 10h
Base hourly price 1 050 BYN/h
Standard comparison price 1 200 BYN/h
Helmet option +50 BYN/h
Time validity Purchased time can be flown within 6 months

Savings are calculated only from package time price: (1 200 - 1 050) * hours. Helmet cost does not affect savings.

🧠 How matching works

Users can create either:

  • exact request: 4h;
  • range request: 1-2.5h.

The split finalizes when total max hours reaches at least 10h. Final allocation then converts all ranges into exact hours:

  1. Sum all minimum hours.
  2. Set target hours to max(10, total minimum hours).
  3. Add extra hours to range participants until target is reached.
  4. Store final exact hours on matched requests.

Example:

Participant Request Final
User A 1h 1h
User B 1-9h 9h

The package closes as 10h; final price is calculated for 10h, not 2h.

πŸ“± Mini App

The Mini App is mobile-first and follows Telegram system theme.

Screen Purpose
Π‘ΠΎΠ·Π΄Π°Ρ‚ΡŒ Create, edit, or leave a split request
Мои заявки Active requests and split history with pull-to-refresh
ΠŸΡ€ΠΎΡ„ΠΈΠ»ΡŒ Total savings, split stats, bought hours, and private iFLY account data

UX details:

  • Telegram/system theme only; no visible theme toggle.
  • Bottom tab bar with mobile-app navigation.
  • Sticky CTA with always-visible price summary.
  • Radix UI slider for exact/range hour selection.
  • Telegram vertical swipe protection to avoid closing the Mini App while scrolling.
  • Haptic feedback and lightweight toast states for Telegram clients that support them.

πŸ€– Bot behavior

Main work group

The bot keeps a single active split message at the bottom of the chat:

  • deletes the old message;
  • sends the updated message after user messages;
  • shows participants and remaining hours;
  • changes inline button by state:
    • no requests: Π‘ΠΎΠ·Π΄Π°Ρ‚ΡŒ распил;
    • active requests: ΠžΡ‚ΠΊΡ€Ρ‹Ρ‚ΡŒ / Π’ΠΏΠΈΡΠ°Ρ‚ΡŒΡΡ!.

Successful split

When the package is collected:

  1. Pending requests become matched.
  2. A short split code is generated.
  3. The main group gets a compact success message with participant nicknames and hours.
  4. Participants receive private instructions.
  5. A separate message asks them to create a discussion group and add the bot.

Discussion group

The first user who adds the bot to a new group and makes it an admin claims the group for the split.

After admin rights are granted, the bot:

  • finds the newest fresh split for that user within 24 hours;
  • creates or reuses an invite link;
  • stores the discussion group link on the matched split;
  • renames the group to Распил iFLY (#CODE) Β· 10Ρ‡;
  • sends invites to participants who are not already in that group;
  • posts the private purchase summary inside the group.

When a participant joins the discussion group, the bot reposts the summary at the bottom and deletes the old copy so the latest info stays visible.

If a different participant tries to create another group for the same latest split, the bot does not rebind the split. It sends the already claimed group link instead.

🧩 Commands

Command Context Action
/start private chat Allows the bot to send private group links later
/fake N main group Creates fake pending test requests; /fake 0 clears fake requests
/add CODE discussion group Manually attaches a group to a collected split

Custom emoji helper: send a custom emoji or sticker to the bot in private chat. It replies with emoji = custom_emoji_id pairs for reuse in bot messages.

πŸ—οΈ Architecture

flowchart LR
  tgUser["Telegram user"] --> mainChat["Main Telegram group"]
  mainChat --> botWebhook["Bot webhook"]
  tgUser --> miniApp["Telegram Mini App"]
  miniApp --> nextApi["Next.js API routes"]
  botWebhook --> nextApi
  nextApi --> supabase["Supabase Postgres"]
  nextApi --> telegramApi["Telegram Bot API"]
  telegramApi --> mainChat
  telegramApi --> privateDm["Private DMs"]
  telegramApi --> discussionGroup["Split discussion group"]
Loading

πŸ—‚οΈ Repository map

.
β”œβ”€β”€ miniapp/                    # Production runtime: Next.js UI + API + Telegram webhook
β”‚   β”œβ”€β”€ app/                    # App Router pages and API routes
β”‚   β”œβ”€β”€ lib/server/ifly.ts      # Domain logic, Telegram API calls, Supabase access
β”‚   β”œβ”€β”€ public/                 # Mini App icon and instruction images
β”‚   └── vercel.json             # Region and cron configuration
β”œβ”€β”€ supabase/migrations/        # Postgres schema migrations
β”œβ”€β”€ assets/                     # Source images and repo branding
└── README.md

Production source of truth is miniapp/.

🧱 Data model

Table Purpose
ifly_chats Telegram chat state, sticky message id, discussion setup metadata
ifly_launch_contexts Short-lived Mini App launch tokens bound to Telegram chats
ifly_requests Pending, matched, and cancelled user requests
ifly_user_profiles Private iFLY account data keyed by Telegram user id
ifly_bot_config Optional bot-level configuration

Discussion group state is stored in ifly_chats.sticky_text as compact JSON metadata:

  • pending_split_token;
  • discussion_split_token;
  • discussion_message_id;
  • discussion_setup_claim_token;
  • discussion_setup_claimed_at;
  • discussion_setup_completed_at.

πŸ”Œ API routes

Method Path Purpose
GET /api/request Full Mini App state
POST /api/request Create or replace a request
DELETE /api/request Cancel the current pending request
POST /api/profile Save private iFLY profile data
POST /api/telegram/webhook Telegram Bot API webhook receiver
GET /api/cron/expire-requests Scheduled cleanup for expired requests
GET /api/health Health check

Mini App API calls use Telegram WebApp init data:

Authorization: tma <telegram initData>

Webhook and cron routes are protected by secrets stored outside the repository.

πŸ› οΈ Build from source

Requirements:

  • Node.js 20+
  • npm
  • Supabase project with migrations applied
  • Telegram bot token
  • Vercel project or compatible Node.js hosting

Install and run locally:

cd miniapp
npm install
npm run dev

Production build:

cd miniapp
npm run build

βš™οΈ Environment variables

Runtime configuration lives in Vercel environment variables. Local .env files are for development only and must not be committed.

Variable Required Notes
SUPABASE_URL yes Supabase API URL
SUPABASE_ANON_KEY yes Supabase anon key used with backend secret policy
IFLY_APP_SECRET yes Private backend secret checked by RLS
TELEGRAM_BOT_TOKEN yes Telegram Bot API token
ALLOWED_GROUP_ID yes Main Telegram group id
WEBAPP_BASE_URL local Public Mini App base URL; Vercel can infer it in production
WEBHOOK_SECRET yes Telegram webhook secret token
CRON_SECRET yes Bearer token for cron route
BOT_USERNAME optional Defaults to raspiliflybot
MINIAPP_SHORT_NAME optional Telegram Mini App short name
APP_TIMEZONE optional Defaults to Europe/Minsk
NEXT_PUBLIC_API_BASE_URL optional Defaults to /api
NEXT_PUBLIC_BOT_USERNAME optional Defaults to raspiliflybot

Do not publish concrete values for tokens, group IDs, webhook secrets, project refs, or database credentials.

🚒 Deploy

Production deploy uses Vercel:

cd miniapp
npx vercel deploy . --prod -y

Health check:

curl -sL https://miniapp-lemon-beta.vercel.app/api/health

Expected response:

{"ok":true}

πŸ”’ Privacy and security

  • No bot tokens or database secrets are stored in the repository.
  • Telegram Mini App requests verify initData.hash.
  • Telegram auth_date older than 24 hours is rejected.
  • Telegram webhook requests require WEBHOOK_SECRET.
  • Cron requests require CRON_SECRET.
  • Supabase tables use RLS and a backend secret check.
  • iFLY account data is shown only in the discussion group for the collected split.
  • Main group messages never show phone, email, or full iFLY profile data.
  • Public docs omit direct webhook URLs, Supabase project refs, and private deployment identifiers.

🧯 Troubleshooting

Symptom Fix
Mini App says bot cannot message the user Open @raspiliflybot in private chat and press Start
Bot was added to a discussion group but does not create a link Make the bot an admin with invite/manage permissions
Telegram redirects to private bot chat during admin assignment This is Telegram behavior; return to the group after confirming rights
Another user tries to create a second discussion group The bot should return the already claimed group link
Sticky message is not at the bottom Send any message in the main group
Need test participants Run /fake 3 in the main group; /fake 0 clears them

❓ FAQ

Is this a standalone website?

No. It is designed as a Telegram Mini App. Opening the production URL in a browser is useful for health and hosting checks, but real auth and chat context come from Telegram.

Can a split have more than 10 hours?

Yes. 10h is the minimum package size. If users request more time or ranges allocate above 10 hours, the final split can exceed 10 hours.

Can more than four people join a split?

No. A split is capped at four participants.

Does helmet change savings?

No. Helmet adds cost, but savings are based only on package time price compared with the standard hourly price.

Where is private iFLY account data visible?

Only inside the discussion group for the collected split. The main work group only receives nicknames and hours.

🧭 Repository standards

  • Keep all production app and bot logic in miniapp/.
  • Put database changes in supabase/migrations/.
  • Keep secrets and deployment-specific IDs outside public docs.
  • Escape user-facing Telegram HTML.
  • Treat Telegram updates as retryable and duplicate-prone.
  • Do not rebind discussion groups after a split already has discussion_link.
  • Run npm run build before deploying production changes.

Releases

Packages

Contributors

Languages