docs: update PG migration status, data models, architecture + add Telegram Mini App flow (v2.8.59)
- 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>
This commit is contained in:
441
04 - Flows/Telegram Mini App.md
Normal file
441
04 - Flows/Telegram Mini App.md
Normal file
@@ -0,0 +1,441 @@
|
||||
---
|
||||
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
|
||||
Reference in New Issue
Block a user