- Postgres Runtime Cutover Status: 17 migrations (0000–0017), dual-write repo matrix - Backend Architecture: dual-DB architecture, repo factory, MONGO_CONNECT_MODE modes - Data Model Overview: 23-model index with PG table names and migration status - User, PurchaseRequest, SellerOffer, Chat, Dispute: Drizzle schema + cutover status added - 04 - Flows/Telegram Mini App.md: new doc covering Mini App architecture and flows - mongo-to-pg-migration-prd.md: status block prepended with 2026-06-03 milestone tracking Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
442 lines
21 KiB
Markdown
442 lines
21 KiB
Markdown
---
|
|
title: Telegram Mini App Flow
|
|
tags: [flow, telegram, mini-app, auth, bilingual, RTL]
|
|
related_models: ["[[User]]"]
|
|
related_apis: ["POST /api/auth/telegram", "[[Auth API]]"]
|
|
task: "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.44
|
|
> **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, 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
|
|
│
|
|
├─ [state: loading] → TelegramLoadingState
|
|
├─ [state: unsupported] → TelegramUnsupportedState
|
|
├─ [state: unlinked] → TelegramUnlinkedState
|
|
└─ [state: linked]
|
|
├─ TelegramHeader
|
|
├─ TelegramTabBar (Home / Requests / Chat / Account)
|
|
│
|
|
├─ TelegramHomeView
|
|
├─ TelegramRequestsView → TelegramRequestDetailView
|
|
├─ TelegramChatView → TelegramChatThreadView
|
|
├─ TelegramAccountView
|
|
└─ [overlay] TelegramNewRequestView
|
|
```
|
|
|
|
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 email** — `window.location.assign(paths.auth.jwt.signIn)`.
|
|
- **Create an account** — `window.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' | 'requests' | 'chat' | 'account'
|
|
overlayScreen : 'new-request' | null
|
|
openConversationId : string | null
|
|
openRequestId : string | null
|
|
```
|
|
|
|
**Priority rendering** (first match wins):
|
|
|
|
1. `openConversationId` → `TelegramChatThreadView`
|
|
2. `openRequestId` → `TelegramRequestDetailView`
|
|
3. `overlayScreen === 'new-request'` → `TelegramNewRequestView`
|
|
4. `activeTab` → appropriate tab view
|
|
|
|
**Back button** (Telegram native `BackButton`) dismisses in reverse priority order: chat thread → request detail → 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. Supported Flows
|
|
|
|
### 7.1 Browse Requests (Requests Tab)
|
|
|
|
- `TelegramRequestsView` fetches the user's purchase requests via `useTelegramMyRequests` (GET `/api/purchase-requests/my`).
|
|
- 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`.
|
|
|
|
### 7.2 Request Detail with Stepper
|
|
|
|
- `TelegramRequestDetailView` fetches a single request via `useTelegramRequest`.
|
|
- Renders `TelegramRequestStepper` — a visual timeline of the escrow status flow from `pending_payment` → `completed`.
|
|
- `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.
|
|
|
|
### 7.3 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).
|
|
|
|
### 7.4 Chat
|
|
|
|
- `TelegramChatView` shows the user's active conversations via `useTelegramConversations`.
|
|
- Tap a 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.
|
|
|
|
### 7.5 Account
|
|
|
|
- `TelegramAccountView` shows profile info (name, email, Telegram username, `telegramVerified` status), linked wallet (if any), and notification preferences.
|
|
- Contains sign-out action and language toggle.
|
|
|
|
---
|
|
|
|
## 8. Bilingual Support (EN / FA)
|
|
|
|
**Language detection priority** (`useTelegramLanguage`):
|
|
|
|
1. `localStorage` key `amn_tg_lang` — user's persisted manual selection.
|
|
2. `initDataUnsafe.user.language_code` — Telegram-reported language (`"fa"` or `"fa-IR"` → Persian).
|
|
3. 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 |
|
|
|
|
Font size bumps for Persian: body 13 px → 14 px, labels 10 px → 11 px (Vazirmatn renders optically smaller).
|
|
|
|
**Translation structure:**
|
|
|
|
```ts
|
|
// src/sections/telegram/locales/en.ts + fa.ts
|
|
const TR = {
|
|
en: { loading, unsupported, unlinked, header, home, 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.
|
|
|
|
---
|
|
|
|
## 9. 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.
|
|
|
|
---
|
|
|
|
## 10. Telegram SDK Usage Patterns
|
|
|
|
### 10.1 Safe-Area Inset
|
|
|
|
```ts
|
|
// 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.
|
|
|
|
### 10.2 Haptic Feedback
|
|
|
|
```ts
|
|
// 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.
|
|
|
|
### 10.3 Back Button
|
|
|
|
```ts
|
|
useTelegramBackButton({ webApp, isVisible, onClick })
|
|
// Calls webApp.BackButton.show() / hide() and registers onClick handler
|
|
// Cleanup: offClick() on unmount / visibility change
|
|
```
|
|
|
|
### 10.4 Main Button
|
|
|
|
```ts
|
|
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
|
|
```
|
|
|
|
### 10.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.
|
|
|
|
---
|
|
|
|
## 11. 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 |
|
|
|
|
---
|
|
|
|
## 12. 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 + 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-my-requests.ts # GET /api/purchase-requests/my
|
|
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
|
|
index.ts
|
|
view/
|
|
telegram-mini-app-view.tsx # Shell orchestrator (all state lives here)
|
|
telegram-home-view.tsx # Home tab
|
|
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 + sign-out tab
|
|
index.ts
|
|
components/
|
|
telegram-header.tsx # AMN logo + subtitle + language toggle
|
|
telegram-tab-bar.tsx # Bottom tab bar (4 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-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
|
|
```
|
|
|
|
---
|
|
|
|
## 13. Current Implementation Status
|
|
|
|
| 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 |
|
|
| Home tab | Done | Banner + quick actions + state chips |
|
|
| 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 |
|
|
| Chat thread | Done | Messages + optimistic send |
|
|
| Account view | Done | Profile, wallet stub, sign-out |
|
|
| 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 |
|
|
| Bilingual PRD (Task 5.4 scope) | IN PROGRESS | String extraction done; `?lang=fa` dev preview param pending |
|
|
|
|
### Open Items (Task 5.4)
|
|
|
|
- `?lang=fa` URL override for browser dev preview (one-line addition to `useTelegramLanguage`).
|
|
- `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).
|
|
|
|
---
|
|
|
|
## 14. Related Documents
|
|
|
|
- [[PRD - Telegram Mini App Bilingual (EN + FA)]] — bilingual string inventory and RTL layout spec
|
|
- [[PRD - Telegram Phone Number Authentication]] — phone-number auth as a future sign-in path
|
|
- [[Authentication Flow]] — JWT lifecycle shared with the Mini App auth
|
|
- [[Purchase Request Flow]] — escrow state machine surfaced in the stepper
|
|
- [[Chat Flow]] — real-time messaging that the Mini App embeds
|