Files
nick-doc/04 - Flows/Telegram Mini App.md
Siavash Sameni a5d71bcc05 docs: sync documentation with latest codebase state
- Update Activity Log with 108 missing commits (48 backend + 60 frontend)
- Update version references: backend v2.8.79, frontend v2.8.94
- Update migration count: 18 migrations (0000-0017)
- Update Telegram Mini App Flow to v2.8.94
- Update Payment Flow - Scanner to 2026-06-05
- Update all architectural and database references

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
2026-06-05 07:34:49 +04:00

32 KiB
Raw Blame History

title, tags, related_models, related_apis, task
title tags related_models related_apis task
Telegram Mini App Flow
flow
telegram
mini-app
auth
bilingual
RTL
shop
cart
User
POST /api/auth/telegram
Auth API
5.4

Last updated: 2026-06-03 Status: IN PROGRESS — Task 5.4 (dependencies: 5.1 auth infra, 5.2 Telegram sign-in endpoint) Frontend branch: integrate-main-into-development · v2.8.94 Entry point: src/sections/telegram/ · route /telegram

Telegram Mini App Flow

End-to-end specification for the Amaneh Telegram Mini App — a fully self-contained marketplace shell surfaced inside Telegram's in-app browser via the WebApp SDK. Buyers and sellers can browse requests, create new escrow requests, shop seller templates, manage a cart, review offer state, follow payments, and message each other without leaving Telegram.


1. Architecture Overview

Telegram Client
  └─ Mini App iframe (https://amn.gg/telegram)
       └─ TelegramMiniAppView           ← shell orchestrator
            ├─ useTelegramLiveContext   ← SDK probe + polling
            ├─ useTelegramLanguage      ← EN / FA detection
            ├─ useTelegramAutoSignIn    ← silent JWT exchange
            ├─ useTelegramMainButton    ← native chrome sync
            ├─ useTelegramBackButton    ← native chrome sync
            ├─ useTelegramHaptic        ← haptic wrapper
            ├─ useTelegramCart          ← shared localStorage cart
            │
            ├─ [state: loading]         → TelegramLoadingState
            ├─ [state: unsupported]     → TelegramUnsupportedState
            ├─ [state: unlinked]        → TelegramUnlinkedState
            └─ [state: linked]
                 ├─ TelegramHeader
                 ├─ TelegramTabBar (Home / Shop / Requests / Chat / Account)
                 │
                 ├─ TelegramHomeView
                 ├─ TelegramShopView → TelegramSellerShopView
                 ├─ TelegramRequestsView → TelegramRequestDetailView
                 ├─ TelegramChatView → TelegramChatThreadView
                 ├─ TelegramAccountView
                 └─ [overlay] TelegramNewRequestView
                 └─ [overlay] TelegramNotificationsView
                 └─ [overlay] TelegramCartView

The shell is a single-page, no-router design: all navigation (tabs, overlays, detail drilldowns) is pure React state in TelegramMiniAppView. window.location.assign is only used as a final escape hatch to the full web dashboard.


2. Launch Points

Entry Mechanism startapp context
Bot profile User opens bot → taps "Open App" none
Menu button Pinned button in any chat with the bot none
Inline button Bot sends a card with an embedded button req_<requestId>
Direct deep link https://t.me/AmanehBot/app?startapp=req_<id> req_<requestId>
Web fallback Browser at /telegram none (unsupported state)

startapp / tgWebAppStartParam is read from either the WebApp SDK (window.Telegram.WebApp) or from URL query/hash params (for older Telegram clients that append them directly).


3. SDK Initialisation & Context Probe

File: src/utils/telegram-webapp.ts · getTelegramContext()

The function assembles a TelegramContext object from:

  1. window.Telegram.WebApp — primary SDK surface (available when the app is opened inside Telegram).
  2. URL query/hash fallback — tgWebAppStartParam, tgWebAppData, tgWebAppVersion, tgWebAppPlatform — used by older clients or during dev testing.

Fields extracted:

Field Source Notes
isMiniApp Any Telegram signal present Drives unsupported vs unlinked state
initData webApp.initData or tgWebAppData URL param HMAC-signed payload sent to /api/auth/telegram
initDataUnsafe webApp.initDataUnsafe Client-side user identity (not trusted)
safeArea contentSafeAreaInset or safe_area_insets Parsed to {top, right, bottom, left} in px
theme webApp.themeParams Both camelCase and snake_case normalised
platform webApp.platform or URL param e.g. ios, android, tdesktop
startParam startapp / tgWebAppStartParam / start_param Deep-link context
isUnsupported !webApp && Boolean(startParam) Partial signal — no SDK but has URL param

Polling on mount (useTelegramLiveContext): Telegram sometimes finishes injecting the WebApp object after the first React render. The hook re-probes at 0 ms, 100 ms, 500 ms, and 1000 ms after mount, and also re-probes on hashchange events (triggered by the native back-button on some platforms).


4. Shell State Machine

getTelegramStatus(context, hasWebAccount) returns one of three states:

unsupported ─── !context.isMiniApp
                (opened in browser, not Telegram)

unlinked ─────── isMiniApp && (!user || !telegramUser.id)
                (inside Telegram but no JWT session linked)

linked ──────── isMiniApp && user && telegramUser.id
                (authenticated, full shell rendered)

State transitions occur on:

  • Auth session check completing (loading → false)
  • Telegram auto sign-in completing (tgAuthLoading → false)
  • Manual sign-in button tap (unlinked → linked)

5. Authentication Flow

5.1 Silent Auto Sign-In

Hook: useTelegramAutoSignIn · File: hooks/use-telegram-auto-sign-in.ts

On mount, if context.isMiniApp && context.initData && !user:

  1. Exchange initData for a JWT by calling signInWithTelegram({ initData })POST /api/auth/telegram.
  2. On success, call checkUserSession() to refresh the auth context.
  3. If the backend returns isNewUser: true, show TelegramOnboardingSheet.
  4. A useRef deduplication guard (attemptedInitDataRef) prevents re-runs under React Strict Mode's double-effect behaviour.

5.2 Manual Sign-In (Unlinked State)

When initData is present but auto sign-in failed (or hasn't run yet), TelegramUnlinkedState renders:

  • Continue with Telegram — calls the same signIn() function from useTelegramAutoSignIn.
  • Sign in with emailwindow.location.assign(paths.auth.jwt.signIn).
  • Create an accountwindow.location.assign(paths.auth.jwt.register).

When initData is absent (accessed via a path that skips Telegram context), only the email/register buttons appear.

5.3 Backend Endpoint

POST /api/auth/telegram — expects { initData: string }. Backend verifies the HMAC using the Telegram bot token, extracts user from the payload, upserts a User record (telegramId, telegramVerified: true), and issues a JWT + refresh token. Returns { token, refreshToken, isNewUser }.


6. Navigation Model

All navigation is in-shell React state — no Next.js router is involved.

activeTab           : 'home' | 'shop' | 'requests' | 'chat' | 'account'
overlayScreen       : 'new-request' | 'notifications' | 'cart' | null
openConversationId  : string | null
openRequestId       : string | null
openSellerId        : string | null

Priority rendering (first match wins):

  1. openConversationIdTelegramChatThreadView
  2. openRequestIdTelegramRequestDetailView
  3. openSellerIdTelegramSellerShopView
  4. overlayScreen === 'cart'TelegramCartView
  5. overlayScreen === 'notifications'TelegramNotificationsView
  6. overlayScreen === 'new-request'TelegramNewRequestView
  7. activeTab → appropriate tab view

Back button (Telegram native BackButton) dismisses in reverse priority order: chat thread → request detail → seller shop → overlay → returns to home tab.

BackButton visibility: shown whenever state === 'linked' and either an overlay/drilldown is active, or activeTab !== 'home'.

MainButton visibility: hidden while any overlay is open. When visible:

  • Linked → "New Request" (opens overlayScreen = 'new-request')
  • Unlinked → "Sign In" (navigates to the JWT sign-in page)

Both chrome buttons are styled with the amaneh saffron palette (color: #C2410C, text_color: #FFFFFF) via setParams (WebApp SDK >= 6.1).


7. Tab Structure

The shell has five bottom tabs rendered by TelegramTabBar:

Tab Icon View Purpose
Home house TelegramHomeView Welcome banner, quick-action cards, escrow-state chips
Shop storefront TelegramShopView Sellers list; drill into seller store; add templates to cart
Requests list TelegramRequestsView User's escrow requests with status stepper
Chat speech bubble TelegramChatView Conversation list + support entry
Account person TelegramAccountView Profile, preferences, links to web dashboard sections

handleTabSelect clears all overlays and drill-down IDs before switching tab.


8. Supported Flows

8.1 Home Tab

TelegramHomeView is the landing screen shown on first open. It contains:

  • Welcome banner (TelegramWelcomeBanner): escrow account summary, primary CTA.
  • Quick-action cards (TelegramQuickActions): shortcuts to Requests, Payments, Chat.
  • Escrow state chips (TelegramEscrowStateChips): legend of status values visible in the platform.

8.2 Shop Tab — Sellers List

TelegramShopView (telegram-shop-view.tsx):

  • Fetches all sellers via useTelegramShops() → SWR wrapping getTemplateSellers()GET /api/request-templates/sellers.
  • Renders TelegramShopRow per seller: avatar, name, rating, template count, sales count.
  • Shows a floating cart badge button in the header when totalItems > 0; tap opens overlayScreen = 'cart'.
  • Tap a seller row → sets openSellerId → navigates to TelegramSellerShopView.

8.3 Shop Tab — Seller Store

TelegramSellerShopView (telegram-seller-shop-view.tsx):

  • Fetches seller + active templates via useTelegramSellerShop(sellerId)GET /api/request-templates/sellers/:id.
  • Dark header: seller avatar, name, rating, template count, description.
  • Each template card shows: image, title, 2-line description, budget range, usage count.
  • Two actions per template:
    • Add to cart / Remove from cart — toggles item in useTelegramCart (localStorage, no API). Button is filled blue when not in cart, outline when added.
    • Order this template<a href> to /dashboard/request/from-template?shareableLink=.... Exits the Mini App to the web dashboard (single-template direct order, bypasses cart).
  • Floating "Cart · N templates" sticky button at bottom when totalItems > 0; tap calls onOpenCart().

8.4 Shopping Cart Overlay

TelegramCartView (telegram-cart-view.tsx):

  • Rendered as overlayScreen = 'cart'; dismissed by Telegram BackButton.
  • Lists each cart item: image, name, seller name, USDT price × quantity, +/ quantity controls, remove button.
  • Subtotal/total in USDT, locale-formatted (fa-IR for Persian, en-US for English); amounts always dir="ltr".
  • "Continue to payment" — plain <a href={paths.shops.checkout}> link; exits Mini App to web checkout.

Cart storage (useTelegramCart):

  • Reads/writes localStorage key app-request-template-checkout — the same key the web RequestTemplateCheckoutProvider reads. This is the cart handoff mechanism: the cart built in Telegram IS the cart the web checkout page hydrates.
  • Dispatches a custom tg-cart-changed DOM event on every write; listens on both that event and the native storage event so all open tabs stay in sync.
  • Operations: addTemplate(template, seller), removeItem(itemId), changeQuantity(itemId, qty), isInCart(templateId).
  • No API calls — cart is purely client-side until checkout.
  • Cart item model: id, templateId, name, description, price (from template.budget.min), quantity, image, sellerId, sellerName, category, shareableLink, deliveryInfo, maxUsage, usageCount, remainingCapacity.

8.5 Web Checkout Handoff

Destination: /dashboard/shops/checkoutRequestTemplateCheckoutView wrapped by RequestTemplateCheckoutProvider.

The provider reads the shared localStorage key and hydrates the TMA cart. The checkout is a 3-step stepper:

Step Component Description
0 (Cart review) RequestTemplateCheckoutCart Item list, quantities, remove, totals, discount/shipping
1 (Address) RequestTemplateCheckoutBillingAddress Physical address or online delivery email
2 (Payment) RequestTemplateCheckoutPayment Wallet payment + socket confirmation
Complete RequestTemplateCheckoutOrderComplete Confirmation dialog, cart reset

Payment execution calls convertTemplatesToRequests() to create escrow records, then awaits a template-checkout-payment-confirmed socket event. A guard checks createdRequestIds is non-empty before advancing (prevents stray global socket events from triggering premature completion). Stock validation clamps or removes items exceeding remainingCapacity before payment.

8.6 Browse Requests (Requests Tab)

  • TelegramRequestsView fetches the user's purchase requests via useTelegramMyRequests (GET /api/requests).
  • Displays a skeleton loader, then a scrollable list of TelegramRequestRow items.
  • Each row shows: title, status chip, budget, creation date.
  • Tap → sets openRequestId → renders TelegramRequestDetailView.

8.7 Request Detail with Stepper

  • TelegramRequestDetailView fetches a single request via useTelegramRequest.
  • Renders TelegramRequestStepper — a visual timeline of the escrow status flow from pending_paymentcompleted.
  • determineCurrentStepFromStatus maps the current status to a step index.
  • Also renders: budget, description, creation date, category, urgency.
  • Dates formatted via toLocaleDateString with fa-IR locale for Persian.

8.8 Create New Request

  • TelegramNewRequestView is a full-screen overlay (not a routed page).
  • Form fields: title, description, category (fetched from /api/categories), budget min/max, urgency.
  • On submit: calls createPurchaseRequest() → POST /api/purchase-requests.
  • On success: closes overlay, switches activeTab to 'requests'.
  • MainButton is hidden while the overlay is open (submit lives in the form itself).

8.9 Chat Tab

  • TelegramChatView shows the user's active conversations via useTelegramConversations.
  • Includes a Support row that calls createSupportChat()POST /api/chat/support, then opens TelegramChatThreadView with the returned conversation ID.
  • Tap a conversation row → sets openConversationId → renders TelegramChatThreadView.
  • TelegramChatThreadView loads messages via useTelegramChatThread, renders TelegramChatBubble items, and includes TelegramChatComposer for sending.
  • Optimistic send: message appears immediately, confirmed/rolled back on API response.
  • Real-time updates via Socket.IO events; SWR is mutated on new-notification and unread-count-update events.

8.10 Account Tab

TelegramAccountView (telegram-account-view.tsx):

The account tab has four sections. All user data is passed as props from the shell (loaded via useAuthContext() — no fetch on mount).

Profile header:

  • Avatar (from user.profile.avatar, falls back to initials), full name, Telegram @username, role chip (buyer / seller / admin / resolver / guard).
  • Verification chips: "Telegram Verified" (if user.telegramVerified) and "Email Verified" (if user.isEmailVerified).

Preferences section:

  • Language toggle (FA / EN, in-shell via TelegramLanguageToggle).
  • General Settings → /dashboard/account (web, labeled "Opens in the web dashboard").
  • Wallet → truncated address (0x1234…abcd) or "not connected" → /dashboard/account/wallet (web).
  • Notifications → opens TelegramNotificationsView overlay in-shell.
  • Addresses → /dashboard/account/address (web).
  • Passkey → /dashboard/account/passkey (web).

Help section:

  • Support → createSupportChat() → opens TelegramChatThreadView in-shell.
  • Terms & Conditions → placeholder, "coming soon".

Session section:

  • Sign Out → TelegramBottomSheet confirmation dialog → authSignOut() + window.location.assign(paths.auth.jwt.signIn).

8.11 Notifications Overlay

  • TelegramNotificationsView is rendered as overlayScreen = 'notifications'.
  • Fetches via useTelegramNotificationsgetNotifications(userId, 1, 50)GET /api/notifications?userId=...&page=1&limit=50.
  • Real-time updates: Socket.IO events new-notification, unread-count-update trigger SWR mutate.
  • "Mark all read" calls markAllNotificationsAsRead(userId)PATCH /api/notifications/mark-all-read.

9. API Calls

Action Hook / call Backend endpoint
Auto sign-in useTelegramAutoSignInsignInWithTelegram({initData}) POST /api/auth/telegram
Sellers list useTelegramShopsgetTemplateSellers() GET /api/request-templates/sellers
Seller + templates useTelegramSellerShopgetSellerWithTemplates(id) GET /api/request-templates/sellers/:id
Marketplace sellers useTelegramSellersgetSellers() GET /api/marketplace/sellers
My requests useTelegramMyRequests GET /api/requests
Single request useTelegramRequest GET /api/purchase-requests/:id
Create request shell → createPurchaseRequest() POST /api/purchase-requests
Conversations useTelegramConversations GET /api/chat/conversations
Chat thread useTelegramChatThread GET /api/chat/:id + Socket.IO real-time
Support chat createSupportChat() POST /api/chat/support
Notifications useTelegramNotifications GET /api/notifications?userId=...&page=1&limit=50
Mark all read markAllNotificationsAsRead(userId) PATCH /api/notifications/mark-all-read
Auth sign-out authSignOut() JWT sign-out endpoint

Cart operations (add/remove/quantity) are pure localStorage — no API calls until web checkout.


10. Bilingual Support (EN / FA)

Language detection priority (useTelegramLanguage):

  1. ?lang= URL query param — dev preview override.
  2. localStorage key amn_tg_lang — user's persisted manual selection.
  3. initDataUnsafe.user.language_code — Telegram-reported language ("fa" or "fa-IR" → Persian).
  4. Fallback → English.

Language toggle: TelegramLanguageToggle in the header — two buttons [ EN | فا ]. On tap: haptic light + language switch + persist to localStorage.

RTL layout:

Element EN (LTR) FA (RTL)
Root dir attribute ltr rtl
Font family IBM Plex Sans Vazirmatn
Arrow icons
Text alignment left right (inherits from dir)
Chip list wrap left-to-right right-to-left
Amounts always dir="ltr" always dir="ltr"

Font size bumps for Persian: body 13 px → 14 px, labels 10 px → 11 px (Vazirmatn renders optically smaller).

Translation structure:

// src/sections/telegram/locales/en.ts + fa.ts
const TR = {
  en: { loading, unsupported, unlinked, header, home, shop, requests,
        chat, account, newRequest, tabs, main, onboarding, errors, displayName, dir },
  fa: { /* same keys, Farsi strings, dir: 'rtl' */ },
};

All JSX uses t.<section>.<key> — no inline strings in components.


11. Design System

File: src/sections/telegram/constants.ts · src/sections/telegram/telegram-shell-css.ts

The Mini App has a distinct visual identity (cream/saffron Persian palette) that does not inherit from the main dashboard theme. All tokens are feature-scoped.

Palette: TG_PALETTE

Token Hex Usage
cream50 #FBF6EB Page background
ink900 #1C1410 Primary text
ink600 #6B5D4E Secondary text / labels
saffron600 #C2410C Primary action, MainButton
saffron500 #D97757 Hover states
pistachio700 #3D6B4F Success / released states
pomegranate700 #8E2424 Error / disputed states
bgPage #E7DFCB Shell outer background

Fonts: TG_FONTS — Source Serif 4 (headings), IBM Plex Sans (body LTR), Vazirmatn (body RTL), IBM Plex Mono (amounts/addresses).

CSS: buildTelegramShellCss() injects a <style> tag at shell root with all class utilities (.tg-chip, .tg-shell, .tg-tab-bar, .tg-header, etc.). Theme CSS variables (--cream-50, --ink-900, etc.) are set on .tg-shell root.

Safe area: getTelegramSafeAreaStyle(safeArea) maps the Telegram-reported safe area insets to CSS padding using max(${px}px, env(safe-area-inset-*)) to handle both Telegram-native and iOS/Android safe areas.


12. Telegram SDK Usage Patterns

12.1 Safe-Area Inset

// TelegramContext.safeArea = { top, right, bottom, left } (px)
// Source: webApp.contentSafeAreaInset || webApp.safe_area_insets
// Normalised to number via parseNumber() — rejects non-finite strings
const topInset = (context.safeArea?.top ?? 0) as number;

All views receive topInset / bottomInset props and add them as explicit paddingTop / paddingBottom to avoid content being obscured by the Telegram chrome.

12.2 Haptic Feedback

// useTelegramHaptic(webApp) → haptic('light' | 'medium')
webApp?.HapticFeedback?.impactOccurred?.(type)

Used on: tab switches (light), new-request CTA (medium), language toggle (light), back button (light). All calls are wrapped in try/catch — the API may be absent on older clients.

12.3 Back Button

useTelegramBackButton({ webApp, isVisible, onClick })
// Calls webApp.BackButton.show() / hide() and registers onClick handler
// Cleanup: offClick() on unmount / visibility change

12.4 Main Button

useTelegramMainButton({ webApp, isReady, text, onClick })
// Calls webApp.MainButton.show() / hide(), setText(), setParams()
// Saffron palette: color: '#C2410C', text_color: '#FFFFFF'
// setParams requires WebApp >= 6.1; silent fallback for older clients

12.5 Theme Integration

Telegram's themeParams is normalised (both camelCase and snake_case accepted) and injected as CSS custom properties on the shell root (--telegram-shell-bg, --telegram-shell-text, etc.). The amaneh palette overrides these for the Mini App's own UI, but components can reference them for adaptive behaviours.


13. Edge Cases

Scenario Detection Handling
Opened in browser (not Telegram) context.isMiniApp === false TelegramUnsupportedState — shows "Open in Telegram" badge, web dashboard link
Partial Telegram signal (URL params but no SDK) !webApp && Boolean(startParam)isUnsupported: true Same unsupported state
Telegram SDK injected late useTelegramLiveContext polls at 0/100/500/1000 ms Re-probes until SDK is ready; seed context bypasses polling
initData absent (no auth data) !context.initData in unlinked state Sign-in button triggers error string t.errors.no_init_data; email/create buttons remain available
Auto sign-in replay (React Strict Mode) attemptedInitDataRef.current === context.initData Deduplication ref — second effect is a no-op
Backend sign-in failure Catch block in useTelegramAutoSignIn Error string displayed in TelegramUnlinkedState; retry via "Continue with Telegram"
New user first login result.isNewUser === true TelegramOnboardingSheet shown over the shell; dismissed to account settings or "Later"
Expired session inside Mini App Auth context user === null after session check Shell falls back to unlinked state
Old Telegram client (< 6.1) setParams throws Try/catch silences it; button shows without saffron colour
RTL + keyboard overlap Viewport shrinks on soft keyboard open flex: 1 + overflowY: auto on content area; bottom safe-area inset on tab bar
Persian locale date formatting lang === 'fa' toLocaleDateString('fa-IR', ...) in formatDate helper
Cart cross-tab sync Multiple tabs / Mini App + web tg-cart-changed DOM event + storage event both trigger re-render
Template at capacity remainingCapacity === 0 at checkout Stock validation clamps/removes over-capacity items before payment
Stray global socket on checkout template-checkout-payment-confirmed fires unexpectedly Guard checks createdRequestIds.length > 0 before advancing to completion step

14. File Map

src/
  app/telegram/page.tsx                        # Next.js route (thin shell, no auth guard)
  utils/telegram-webapp.ts                     # SDK probe, context types, shell style helpers
  sections/telegram/
    constants.ts                               # TG_PALETTE, TG_FONTS, TG_EASE, status maps
    telegram-shell-css.ts                      # buildTelegramShellCss() — inlined CSS blob
    index.ts                                   # barrel
    locales/
      types.ts                                 # TelegramDict, TelegramLang, TelegramTabId
      en.ts                                    # English strings
      fa.ts                                    # Persian strings
      index.ts                                 # getTelegramDict(lang)
    hooks/
      use-telegram-live-context.ts             # SDK polling
      use-telegram-language.ts                 # EN/FA detection + ?lang= + localStorage persist
      use-telegram-auto-sign-in.ts             # initData → JWT exchange
      use-telegram-main-button.ts              # MainButton lifecycle
      use-telegram-back-button.ts              # BackButton lifecycle
      use-telegram-haptic.ts                   # HapticFeedback wrapper
      use-telegram-cart.ts                     # localStorage cart (shared with web checkout)
      use-telegram-shops.ts                    # GET /api/request-templates/sellers
      use-telegram-seller-shop.ts              # GET /api/request-templates/sellers/:id
      use-telegram-sellers.ts                  # GET /api/marketplace/sellers
      use-telegram-my-requests.ts              # GET /api/requests
      use-telegram-request.ts                  # GET /api/purchase-requests/:id
      use-telegram-conversations.ts            # Chat conversation list
      use-telegram-chat-thread.ts              # Chat thread + optimistic send
      use-telegram-notifications.ts            # GET /api/notifications
      index.ts
    view/
      telegram-mini-app-view.tsx               # Shell orchestrator (all state lives here)
      telegram-home-view.tsx                   # Home tab
      telegram-shop-view.tsx                   # Shop tab — sellers list
      telegram-seller-shop-view.tsx            # Seller store drill-down + cart actions
      telegram-cart-view.tsx                   # Cart overlay
      telegram-requests-view.tsx               # Requests list tab
      telegram-request-detail-view.tsx         # Request drilldown + stepper
      telegram-new-request-view.tsx            # New request overlay form
      telegram-chat-view.tsx                   # Chat conversation list tab
      telegram-chat-thread-view.tsx            # Chat thread drilldown
      telegram-account-view.tsx                # Account + preferences + sign-out tab
      telegram-notifications-view.tsx          # Notifications overlay
      index.ts
    components/
      telegram-header.tsx                      # AMN logo + subtitle + language toggle
      telegram-tab-bar.tsx                     # Bottom tab bar (5 tabs)
      telegram-welcome-banner.tsx              # Home: escrow account banner + CTA
      telegram-quick-actions.tsx               # Home: action cards (Requests / Payments / Chat)
      telegram-escrow-state-chips.tsx          # Home: status chip legend
      telegram-shop-row.tsx                    # Shop: seller list row
      telegram-request-row.tsx                 # Requests: list row
      telegram-request-stepper.tsx             # Detail: visual escrow timeline
      telegram-list-row.tsx                    # Generic list row primitive
      telegram-list-skeleton.tsx               # Skeleton loader for lists
      telegram-chat-row.tsx                    # Chat: conversation list row
      telegram-chat-bubble.tsx                 # Chat: message bubble
      telegram-chat-composer.tsx               # Chat: message input
      telegram-loading-state.tsx               # Loading spinner state
      telegram-unlinked-state.tsx              # Unlinked / sign-in prompt state
      telegram-unsupported-state.tsx           # Not-in-Telegram fallback state
      telegram-onboarding-sheet.tsx            # New-user onboarding bottom sheet
      telegram-empty-state.tsx                 # Generic empty list state
      telegram-language-toggle.tsx             # EN | FA header toggle
      telegram-bottom-sheet.tsx                # Generic bottom sheet primitive
      telegram-form-field.tsx                  # Form field + input style helper
      telegram-seal-mark.tsx                   # SealMark logo component
      telegram-icons.tsx                       # Telegram-scoped icon set
      index.ts

15. Current Implementation Status (v2.8.94)

Area Status Notes
Shell + state machine Done TelegramMiniAppView — all states wired
SDK probe + live context Done Polling + hashchange listener
Auto sign-in Done Deduped initData exchange
Manual sign-in (unlinked) Done Email + create account fallbacks
Bilingual EN/FA Done Full string inventory, RTL layout, Vazirmatn font
Language toggle Done Header toggle + localStorage persist
?lang= dev preview param Done URL param override added to useTelegramLanguage
Home tab Done Banner + quick actions + state chips
Shop tab — sellers list Done API-backed with skeleton + empty states, cart badge
Shop tab — seller store Done Templates list, add/remove cart, direct order link
Shopping cart (localStorage) Done Shared key with web checkout; cross-tab sync
Cart overlay Done Quantity controls, remove, total, checkout link
Web checkout handoff Done localStorage handoff; stock guard; socket guard
Requests list Done API-backed with skeleton + empty states
Request detail + stepper Done Status timeline, budget, dates with fa-IR locale
New request form Done In-shell overlay, category fetch, validation
Chat list Done API-backed conversation list + support row
Chat thread Done Messages + optimistic send + Socket.IO real-time
Account tab Done Profile, preferences, help, web-dashboard links, sign-out
Notifications overlay Done API-backed; Socket.IO real-time; mark-all-read
Telegram chrome (MainButton / BackButton) Done Saffron palette, lifecycle hooks
Haptic feedback Done All tap interactions
Safe area insets Done Normalised from SDK + CSS env() fallback
Deep link startapp context Partial Parsed but not yet used to auto-navigate to a request
Bilingual onboarding sheet Done Shown on isNewUser flag
Unsupported / browser fallback Done Web dashboard link

Open Items

  • startapp deep link routing: if context.startParam matches req_<id>, auto-open TelegramRequestDetailView on first render.
  • Backend room-scoped Socket.IO for real-time chat updates (global socket event broadcast was fixed client-side in v2.8.4; server-side scoping is a follow-up).