- Update backend, frontend, scanner, deployment, amanat-assist service docs - Update System Overview, Scanner Architecture, Telegram Mini App flow - Update 10 - Services/README.md - Add Tenant data model, Tenant API reference, Tenant Storefront Flow - Add Multi-Shop Branch Project Scan (2026-06-10) - Add tenant.md service doc - Append activity log entry - Reflects archived/search/stats route fix and new E2E test suite Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
789 lines
46 KiB
Markdown
789 lines
46 KiB
Markdown
---
|
||
title: Telegram Mini App Flow
|
||
tags: [flow, telegram, mini-app, auth, bilingual, RTL, shop, cart, payment]
|
||
related_models: ["[[User]]"]
|
||
related_apis: ["POST /api/auth/telegram", "[[Auth API]]"]
|
||
task: "5.4"
|
||
---
|
||
|
||
> **Last updated:** 2026-06-12
|
||
> **Status:** LARGELY COMPLETE — Task 5.4 core implementation done; open items are `startapp` deep-link auto-routing, backend Socket.IO room scoping, archived-chat surfacing, review-prompt integration, and cross-platform QA.
|
||
> **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.
|
||
|
||
> **Two separate Mini Apps exist on this platform.** This document covers the **main marketplace Mini App** (`amn.gg/telegram`) built inside the primary Next.js frontend. For the AI-assisted request-creation Mini App, see [[amanat-assist]].
|
||
|
||
---
|
||
|
||
## 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 (disabled)
|
||
├─ useTelegramBackButton ← native chrome sync
|
||
├─ useTelegramHaptic ← haptic wrapper
|
||
├─ useTelegramCart ← shared localStorage cart
|
||
├─ useTelegramNotifications ← unread badge count
|
||
│
|
||
├─ [state: loading] → TelegramLoadingState
|
||
├─ [state: unsupported] → TelegramUnsupportedState
|
||
├─ [state: unlinked] → TelegramUnlinkedState
|
||
└─ [state: linked]
|
||
├─ TelegramHeader
|
||
├─ TelegramTabBar (Home / Shop / Requests / Chat / Account)
|
||
│
|
||
├─ [drilldown] TelegramPaymentView ← highest priority
|
||
├─ [drilldown] TelegramChatThreadView
|
||
├─ [drilldown] TelegramRequestDetailView
|
||
├─ [drilldown] TelegramTemplateDetailView
|
||
├─ [drilldown] TelegramSellerShopView
|
||
│
|
||
├─ [overlay] TelegramPointsView
|
||
├─ [overlay] TelegramSettingsView
|
||
├─ [overlay] TelegramAddressesView
|
||
├─ [overlay] TelegramCartView
|
||
├─ [overlay] TelegramCheckoutView
|
||
├─ [overlay] TelegramNotificationsView
|
||
├─ [overlay] TelegramNewRequestView
|
||
│
|
||
├─ TelegramHomeView
|
||
├─ TelegramShopView → TelegramSellerShopView
|
||
├─ TelegramRequestsView → TelegramRequestDetailView
|
||
├─ TelegramChatView → TelegramChatThreadView
|
||
└─ TelegramAccountView
|
||
```
|
||
|
||
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 used only as a final escape hatch to external URLs. `openTelegramExternalLink` is used for deep links into the web dashboard, which opens inside Telegram's WebView or an external browser depending on the Telegram client.
|
||
|
||
---
|
||
|
||
## 2. Launch Points
|
||
|
||
| Entry | Mechanism | `startapp` context | Result |
|
||
|---|---|---|---|
|
||
| Bot profile | User opens bot → taps "Open App" | none | Shell loads at Home tab |
|
||
| Menu button | Pinned button in any chat with the bot | none | Shell loads at Home tab |
|
||
| Inline button | Bot sends a message card with an embedded button | `req_<requestId>` | Shell loads; request deep-link (see below) |
|
||
| Direct deep link | `https://t.me/AmanehBot/app?startapp=req_<id>` | `req_<requestId>` | Shell loads; request deep-link (see below) |
|
||
| Web fallback | Browser at `/telegram` (no Telegram SDK) | none | `TelegramUnsupportedState` — "Open in Telegram" prompt + web dashboard link |
|
||
|
||
### 2.1 startapp Context Parsing
|
||
|
||
`startapp` / `tgWebAppStartParam` is read from two sources in priority order:
|
||
|
||
1. `window.Telegram.WebApp.initDataUnsafe.start_param` — primary source when the SDK is injected.
|
||
2. URL query/hash params (`tgWebAppStartParam`) — fallback for older Telegram clients that append params directly to the URL.
|
||
|
||
Both are normalised into `context.startParam` by `getTelegramContext()` in `src/utils/telegram-webapp.ts`.
|
||
|
||
### 2.2 startapp Deep-Link Routing (Partial)
|
||
|
||
When `context.startParam` matches `req_<requestId>`, the intent is to auto-open `TelegramRequestDetailView` for that request on first render. **This routing is not yet wired** — `startParam` is parsed and available in context but the shell does not yet act on it. This is open item #1 in section 16.
|
||
|
||
---
|
||
|
||
## 3. amanat-assist vs Main Mini App
|
||
|
||
Two distinct Telegram Mini Apps exist for this platform:
|
||
|
||
| Property | Main Mini App (this doc) | amanat-assist |
|
||
|---|---|---|
|
||
| URL | `amn.gg/telegram` | `assist.amn.gg` |
|
||
| Bot | AmanehBot | AmanehBot (same) |
|
||
| Codebase | `frontend/` (Next.js, `src/sections/telegram/`) | `/amanat-assist` (React + Vite, separate repo) |
|
||
| Purpose | Full marketplace shell: browse, buy, sell, chat, manage account | Conversational LLM wizard to create one purchase request |
|
||
| LLM | None | Mistral → DeepSeek fallback (via `amanat-llm-proxy` on port 3001) |
|
||
| Backend access | Direct calls to `api.amn.gg` | Proxied through `amanat-llm-proxy` which holds the LLM API keys |
|
||
| Auth | Telegram `initData` → `POST /api/auth/telegram` | Same endpoint; also supports web redirect via `?access_token=` |
|
||
| Deep links between apps | Main Mini App has "New Request" overlay with an "Open Assist" CTA that navigates `window.location.href` to `assist.amn.gg?access_token=...` | Assist submits the finished request then the user returns to the main app |
|
||
| Status | In production | Live at `assist.amn.gg` v1.1.0 |
|
||
|
||
**Hand-off from main app to assist:** `handleOpenAssist()` in `TelegramMiniAppView` constructs a URL to `https://assist.amn.gg` with `access_token`, `user_json`, `theme`, and `source=miniapp` query params. `window.location.href` is used (not `openLink`) to keep the navigation inside Telegram's WebView rather than opening Safari on iOS.
|
||
|
||
---
|
||
|
||
## 4. 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).
|
||
|
||
---
|
||
|
||
## 5. 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)
|
||
|
||
---
|
||
|
||
## 6. Authentication Flow
|
||
|
||
### 6.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.
|
||
|
||
### 6.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.
|
||
|
||
### 6.3 Backend Endpoint
|
||
|
||
`POST /api/auth/telegram` — expects `{ initData: string }`.
|
||
|
||
**Verification steps (backend):**
|
||
1. Parse the `initData` query string into key-value pairs.
|
||
2. Extract `hash` from the pairs; remove it from the set.
|
||
3. Build the data-check string: sort remaining pairs alphabetically, join as `key=value\n`.
|
||
4. Compute `HMAC-SHA256(data_check_string, HMAC-SHA256("WebAppData", TELEGRAM_BOT_TOKEN))`.
|
||
5. Compare computed hash with the extracted `hash` — reject with 401 on mismatch.
|
||
6. Parse `user` JSON from `initDataUnsafe`; upsert `User` record with `telegramId`, `telegramVerified: true`.
|
||
7. Issue JWT + refresh token. Return `{ token, refreshToken, isNewUser }`.
|
||
|
||
Registered at `authRoutes.ts` line 24: `router.post("/telegram", ctrl.telegramAuth.bind(ctrl))` — public route, no auth middleware required (HMAC is the authentication proof).
|
||
|
||
### 6.4 Session Linking (Telegram ↔ Amaneh Account)
|
||
|
||
The `POST /api/auth/telegram` endpoint both creates and links accounts:
|
||
|
||
- **New Telegram user, no existing Amanat account:** a new `User` is created with `telegramId` set; `isNewUser: true` is returned and the onboarding sheet is shown.
|
||
- **Existing Amanat account with the same `telegramId`:** the existing user is returned; session continues.
|
||
- **Existing Amanat account that has never used Telegram:** `telegramId` and `telegramVerified: true` are written onto the existing record (matched by Telegram user id).
|
||
|
||
After the JWT is issued the standard `checkUserSession()` re-hydrates the React auth context. The Mini App shell reads `user.telegramVerified` and `user.isEmailVerified` from this context to render verification chips in the Account tab.
|
||
|
||
---
|
||
|
||
## 7. 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' | 'checkout'
|
||
| 'points' | 'settings' | 'addresses' | null
|
||
openConversationId : string | null
|
||
openRequestId : string | null
|
||
openPaymentRequestId : string | null ← payment drilldown (highest priority)
|
||
paymentCheckoutFlow : boolean ← true when reached from shop checkout
|
||
openSellerId : string | null
|
||
openTemplate : { template, seller } | null
|
||
```
|
||
|
||
**Priority rendering** (first match wins):
|
||
|
||
1. `openPaymentRequestId` → `TelegramPaymentView` ← new, highest priority
|
||
2. `openConversationId` → `TelegramChatThreadView`
|
||
3. `openRequestId` → `TelegramRequestDetailView`
|
||
4. `openTemplate` → `TelegramTemplateDetailView` ← new
|
||
5. `openSellerId` → `TelegramSellerShopView`
|
||
6. `overlayScreen === 'points'` → `TelegramPointsView` ← new
|
||
7. `overlayScreen === 'settings'` → `TelegramSettingsView` ← new
|
||
8. `overlayScreen === 'addresses'` → `TelegramAddressesView` ← new
|
||
9. `overlayScreen === 'cart'` → `TelegramCartView`
|
||
10. `overlayScreen === 'checkout'` → `TelegramCheckoutView` ← new (replaces web handoff)
|
||
11. `overlayScreen === 'notifications'` → `TelegramNotificationsView`
|
||
12. `overlayScreen === 'new-request'` → `TelegramNewRequestView`
|
||
13. `activeTab` → appropriate tab view
|
||
|
||
**Back button** (Telegram native `BackButton`) dismisses in reverse priority order:
|
||
- Payment drilldown → if `paymentCheckoutFlow`, steps back to cart; otherwise clears payment state.
|
||
- Chat thread → clears `openConversationId`.
|
||
- Request detail → clears `openRequestId`.
|
||
- Template detail → clears `openTemplate`.
|
||
- Seller shop → clears `openSellerId`.
|
||
- Overlay (`checkout` steps back to `cart`) → clears `overlayScreen`.
|
||
- Non-home tab → returns to `home`.
|
||
|
||
`BackButton` visibility: shown whenever `state === 'linked'` and either an overlay/drilldown is active, or `activeTab !== 'home'`.
|
||
|
||
`MainButton` visibility: **intentionally disabled** (`isReady: false`) — the native Telegram MainButton cannot use the project font and duplicates in-shell CTAs, so it is kept hidden. All primary actions live inside the shell UI itself.
|
||
|
||
Both chrome buttons retain the amaneh saffron palette (`color: #C2410C`, `text_color: #FFFFFF`) via `setParams` (WebApp SDK >= 6.1) as a fallback should the MainButton ever be re-enabled.
|
||
|
||
---
|
||
|
||
## 8. 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.
|
||
|
||
---
|
||
|
||
## 9. Supported Flows
|
||
|
||
### 9.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.
|
||
- **"New Request" CTA** → opens `overlayScreen = 'new-request'`.
|
||
- **"Open Assist" CTA** → calls `handleOpenAssist()` to navigate to `assist.amn.gg` in the same WebView (see section 3).
|
||
|
||
### 9.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 (`TelegramCartFab`) in the header when `totalItems > 0`; tap opens `overlayScreen = 'cart'`.
|
||
- Tap a seller row → sets `openSellerId` → navigates to `TelegramSellerShopView`.
|
||
|
||
### 9.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).
|
||
- **View template details** — sets `openTemplate` → navigates to `TelegramTemplateDetailView`.
|
||
- Floating "Cart · N templates" sticky button at bottom when `totalItems > 0`; tap calls `onOpenCart()`.
|
||
|
||
### 9.4 Shop Tab — Template Detail
|
||
|
||
**`TelegramTemplateDetailView`** (`telegram-template-detail-view.tsx`):
|
||
- Full-screen view of a single template.
|
||
- Shows full description, seller info, price, delivery info, usage/capacity counters.
|
||
- Add/remove cart action; direct "Order this template" link to `/dashboard/request/from-template?shareableLink=...` (exits to web dashboard).
|
||
- Back button returns to the seller store (`openTemplate` cleared, `openSellerId` retained).
|
||
|
||
### 9.5 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"** → calls `onCheckout()` which sets `overlayScreen = 'checkout'` (in-shell checkout, replacing the previous web handoff).
|
||
|
||
**Cart storage (`useTelegramCart`):**
|
||
- Reads/writes `localStorage` key **`app-request-template-checkout`** — the same key the web `RequestTemplateCheckoutProvider` reads. This enables the web dashboard checkout to hydrate the same cart.
|
||
- 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.
|
||
|
||
### 9.6 In-Shell Checkout Overlay
|
||
|
||
**`TelegramCheckoutView`** (`telegram-checkout-view.tsx`):
|
||
- Rendered as `overlayScreen = 'checkout'`; BackButton steps back to `overlayScreen = 'cart'`.
|
||
- A 3-step stepper running entirely inside the Mini App shell:
|
||
- **Step 0 (Cart review):** item list, quantities, totals, discount.
|
||
- **Step 1 (Address):** physical address or online delivery email.
|
||
- **Step 2 (Payment):** wallet-based payment execution.
|
||
- On successful order (`onPlaced(reqId)` callback):
|
||
- If a `reqId` is returned, sets `paymentCheckoutFlow = true` and `openPaymentRequestId = reqId` → immediately opens the payment view.
|
||
- If no `reqId`, switches `activeTab` to `'requests'`.
|
||
- Stock validation clamps or removes items exceeding `remainingCapacity` before payment.
|
||
- Integrates with `onManageAddresses()` to open the `addresses` overlay mid-flow.
|
||
|
||
### 9.7 Payment View (In-Shell)
|
||
|
||
**`TelegramPaymentView`** (`telegram-payment-view.tsx`):
|
||
- Highest-priority drilldown (rendered before all other overlays).
|
||
- Loaded for a specific `requestId`. Used from two entry points:
|
||
- **Shop checkout flow** (`paymentCheckoutFlow = true`): after `TelegramCheckoutView` creates the requests. Shows a 3-step progress header (cart → address → payment).
|
||
- **Requests tab** (`paymentCheckoutFlow = false`): buyer taps "Pay" on an existing request. No progress header.
|
||
- Fetches request details via `useTelegramRequest`.
|
||
- Fetches offers via `useTelegramOffers`.
|
||
- Calls `getPaymentOptions()` → `GET /api/payment/options` and `createDirectBalanceIntent()` → `POST /api/payment/direct-balance`.
|
||
- Polls `checkDirectBalancePayment()` for confirmation.
|
||
- On successful payment: calls `onPaid()` → clears `openPaymentRequestId`, switches to `activeTab = 'requests'`.
|
||
- Back button: if `paymentCheckoutFlow`, steps back to `overlayScreen = 'cart'`; otherwise clears the payment state.
|
||
|
||
### 9.8 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`.
|
||
|
||
### 9.9 Request Detail with Stepper and Offers
|
||
|
||
- `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.
|
||
- **Offer review:** fetches offers via `useTelegramOffers`; renders offer cards with seller info, price, and accept/reject actions.
|
||
- **Pay action:** renders a "Pay" button when request is in a payable state → calls `onPay(id)` → sets `openPaymentRequestId`.
|
||
- **Web fallback:** "View full details" → `openTelegramExternalLink(context.webApp, path)`.
|
||
- **Chat seller:** taps the seller chat icon → calls `onChatSeller(sellerId)` → `createConversation` + sets `openConversationId`.
|
||
- Role-aware: `role` prop is `'seller'` or `'buyer'` based on `user.role`.
|
||
- Dates formatted via `toLocaleDateString` with `fa-IR` locale for Persian.
|
||
|
||
### 9.10 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.
|
||
- Includes an **"Open Assist"** button that delegates to `handleOpenAssist()` for users who prefer the conversational LLM flow.
|
||
- On submit: calls `createPurchaseRequest()` → POST `/api/purchase-requests`.
|
||
- On success: closes overlay, switches `activeTab` to `'requests'`.
|
||
|
||
### 9.11 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.
|
||
|
||
### 9.12 Account Tab
|
||
|
||
**`TelegramAccountView`** (`telegram-account-view.tsx`):
|
||
|
||
**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`).
|
||
- **Settings** → opens `overlayScreen = 'settings'` (in-shell `TelegramSettingsView`).
|
||
- **Points** → opens `overlayScreen = 'points'` (in-shell `TelegramPointsView`).
|
||
- Wallet → truncated address (`0x1234…abcd`) or "not connected" → `/dashboard/account/wallet` (web via `openTelegramExternalLink`).
|
||
- Notifications → opens `TelegramNotificationsView` overlay in-shell.
|
||
- **Addresses** → opens `overlayScreen = 'addresses'` (in-shell `TelegramAddressesView`).
|
||
- 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)`.
|
||
|
||
### 9.13 Settings Overlay
|
||
|
||
**`TelegramSettingsView`** (`telegram-settings-view.tsx`):
|
||
- Rendered as `overlayScreen = 'settings'`.
|
||
- Allows editing profile fields (name, bio) in-shell.
|
||
- On save: calls `onSaved()` which triggers `checkUserSession()` to refresh the auth context.
|
||
|
||
### 9.14 Addresses Overlay
|
||
|
||
**`TelegramAddressesView`** (`telegram-addresses-view.tsx`):
|
||
- Rendered as `overlayScreen = 'addresses'`.
|
||
- Fetches addresses via `use-telegram-addresses.ts`.
|
||
- Used both from the Account tab and as a mid-flow step from `TelegramCheckoutView`.
|
||
|
||
### 9.15 Points Overlay
|
||
|
||
**`TelegramPointsView`** (`telegram-points-view.tsx`):
|
||
- Rendered as `overlayScreen = 'points'`.
|
||
- Fetches user points via `use-telegram-points.ts`.
|
||
- Shows points balance and transaction history.
|
||
|
||
### 9.16 Dispute Surface
|
||
|
||
The Mini App does not yet have a dedicated dispute-filing view. Dispute access is handled via two escape hatches:
|
||
|
||
- **Request detail "View full details" link** (`openTelegramExternalLink`) — opens the web dashboard request detail page where dispute filing is available.
|
||
- **Support chat** — buyer or seller can reach a support agent from the Account tab or the Home tab quick-action cards; the support agent can escalate to a formal dispute.
|
||
|
||
A native in-shell dispute flow (matching the web dashboard `DisputeView`) is planned but not yet implemented. This is a known gap for the Task 5.4 feature surface.
|
||
|
||
### 9.17 Notifications Overlay
|
||
|
||
- `TelegramNotificationsView` is rendered as `overlayScreen = 'notifications'`.
|
||
- Fetches via `useTelegramNotifications` → `getNotifications(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`.
|
||
- Unread count is also surfaced in the `TelegramHeader` bell icon badge.
|
||
|
||
---
|
||
|
||
## 10. API Calls
|
||
|
||
| Action | Hook / call | Backend endpoint |
|
||
|---|---|---|
|
||
| Auto sign-in | `useTelegramAutoSignIn` → `signInWithTelegram({initData})` | `POST /api/auth/telegram` |
|
||
| Sellers list | `useTelegramShops` → `getTemplateSellers()` | `GET /api/request-templates/sellers` |
|
||
| Seller + templates | `useTelegramSellerShop` → `getSellerWithTemplates(id)` | `GET /api/request-templates/sellers/:id` |
|
||
| Marketplace sellers | `useTelegramSellers` → `getSellers()` | `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` |
|
||
| Offers for request | `useTelegramOffers` → `getOffers(requestId)` | `GET /api/marketplace/offers?requestId=...` |
|
||
| Payment options | `getPaymentOptions()` | `GET /api/payment/options` |
|
||
| Create payment intent | `createDirectBalanceIntent()` | `POST /api/payment/direct-balance` |
|
||
| Poll payment status | `checkDirectBalancePayment()` | `GET /api/payment/:id` |
|
||
| Update request status | `updateRequestStatus()` | `PATCH /api/marketplace/requests/:id/status` |
|
||
| Conversations | `useTelegramConversations` | `GET /api/chat/conversations` |
|
||
| Chat thread | `useTelegramChatThread` | `GET /api/chat/:id` + Socket.IO real-time |
|
||
| Support chat | `createSupportChat()` | `POST /api/chat/support` |
|
||
| Direct conversation | `createConversation({ type: 'direct', participantIds })` | `POST /api/chat/conversations` |
|
||
| 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 |
|
||
| Addresses | `use-telegram-addresses.ts` | `GET /api/user/addresses` |
|
||
| Points | `use-telegram-points.ts` | `GET /api/user/points` |
|
||
|
||
Cart operations (add/remove/quantity) are **pure localStorage** — no API calls until checkout.
|
||
|
||
Dispute endpoints (`POST /api/disputes`, `GET /api/disputes/:id`) are not yet called from the Mini App shell — dispute access is delegated to the web dashboard via `openTelegramExternalLink`.
|
||
|
||
---
|
||
|
||
## 11. 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:**
|
||
|
||
```ts
|
||
// 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.
|
||
|
||
---
|
||
|
||
## 12. 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 |
|
||
| `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. Dark mode: `.tg-shell--dark` class toggled from `themeScheme`.
|
||
|
||
**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.
|
||
|
||
---
|
||
|
||
## 13. Telegram SDK Usage Patterns
|
||
|
||
### 13.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.
|
||
|
||
### 13.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), payment actions (medium). All calls are wrapped in try/catch — the API may be absent on older clients.
|
||
|
||
### 13.3 Back Button
|
||
|
||
```ts
|
||
useTelegramBackButton({ webApp, isVisible, onClick })
|
||
// Calls webApp.BackButton.show() / hide() and registers onClick handler
|
||
// Cleanup: offClick() on unmount / visibility change
|
||
```
|
||
|
||
### 13.4 Main Button
|
||
|
||
```ts
|
||
useTelegramMainButton({ webApp, isReady: false, text: '', onClick: mainButtonAction })
|
||
// isReady is always false — MainButton is intentionally kept hidden.
|
||
// The hook is retained so it can be re-enabled without structural changes.
|
||
```
|
||
|
||
### 13.5 External Links
|
||
|
||
```ts
|
||
openTelegramExternalLink(context.webApp, path)
|
||
// Uses webApp.openLink() for fully external URLs (opens browser).
|
||
// Uses window.location.href for same-origin navigation that must stay in WebView.
|
||
```
|
||
|
||
### 13.6 Theme Integration
|
||
|
||
Telegram's `themeParams` is normalised (both camelCase and snake_case accepted) and injected as CSS custom properties on the shell root. The amaneh palette overrides these for the Mini App's own UI.
|
||
|
||
---
|
||
|
||
## 14. 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 |
|
||
| Payment from shop checkout | `paymentCheckoutFlow === true` | BackButton steps back to cart; progress header shows 3-step flow |
|
||
| Display name resolution | User may have no name set in DB | Falls back to Telegram profile name (`first_name` / `last_name`), then generic label |
|
||
| Seller chat from request detail | `onChatSeller(sellerId)` | `createConversation({ type: 'direct', participantIds: [sellerId] })` → opens chat thread in-shell |
|
||
| Assist hand-off on iOS | `webApp.openLink()` opens Safari | `window.location.href` used instead to keep navigation in the Telegram WebView |
|
||
|
||
---
|
||
|
||
## 15. 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
|
||
avatar-url.ts # avatar URL helper
|
||
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 (kept, isReady=false)
|
||
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-theme.ts # dark/light theme detection
|
||
use-telegram-realtime.ts # shared Socket.IO real-time helper
|
||
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-offers.ts # GET /api/marketplace/offers?requestId=...
|
||
use-telegram-conversations.ts # Chat conversation list
|
||
use-telegram-chat-thread.ts # Chat thread + optimistic send
|
||
use-telegram-notifications.ts # GET /api/notifications
|
||
use-telegram-addresses.ts # GET /api/user/addresses
|
||
use-telegram-points.ts # GET /api/user/points
|
||
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-template-detail-view.tsx # Template full detail + cart/order actions
|
||
telegram-cart-view.tsx # Cart overlay
|
||
telegram-checkout-view.tsx # In-shell 3-step checkout overlay
|
||
telegram-payment-view.tsx # In-shell payment drilldown
|
||
telegram-requests-view.tsx # Requests list tab
|
||
telegram-request-detail-view.tsx # Request drilldown + stepper + offers
|
||
telegram-new-request-view.tsx # New request overlay form + Assist CTA
|
||
telegram-chat-view.tsx # Chat conversation list tab
|
||
telegram-chat-thread-view.tsx # Chat thread drilldown
|
||
telegram-archived-chats-view.tsx # Archived conversations
|
||
telegram-account-view.tsx # Account + preferences + sign-out tab
|
||
telegram-notifications-view.tsx # Notifications overlay
|
||
telegram-settings-view.tsx # In-shell profile/settings overlay
|
||
telegram-addresses-view.tsx # In-shell address management overlay
|
||
telegram-points-view.tsx # In-shell points/loyalty overlay
|
||
index.ts
|
||
components/
|
||
telegram-header.tsx # AMN logo + subtitle + language toggle + bell
|
||
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-list-controls.tsx # List sort/filter controls
|
||
telegram-chat-row.tsx # Chat: conversation list row
|
||
telegram-chat-bubble.tsx # Chat: message bubble
|
||
telegram-chat-composer.tsx # Chat: message input
|
||
telegram-review-prompt.tsx # Post-transaction review prompt
|
||
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-theme-toggle.tsx # Dark / light theme toggle
|
||
telegram-bottom-sheet.tsx # Generic bottom sheet primitive
|
||
telegram-form-field.tsx # Form field + input style helper
|
||
telegram-cart-fab.tsx # Floating cart badge button
|
||
telegram-support-fab.tsx # Floating support chat button
|
||
telegram-seal-mark.tsx # SealMark logo component
|
||
telegram-icons.tsx # Telegram-scoped icon set
|
||
index.ts
|
||
```
|
||
|
||
---
|
||
|
||
## 16. 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 |
|
||
| `?lang=` dev preview param | Done | URL param override |
|
||
| Dark mode | Done | `.tg-shell--dark` class, `use-telegram-theme` |
|
||
| Home tab | Done | Banner + quick actions + state chips + Assist CTA |
|
||
| Shop tab — sellers list | Done | API-backed with skeleton + empty states, cart FAB |
|
||
| Shop tab — seller store | Done | Templates list, add/remove cart, template detail drilldown |
|
||
| Template detail drilldown | Done | Full detail, cart/order actions |
|
||
| Shopping cart (localStorage) | Done | Shared key with web checkout; cross-tab sync |
|
||
| Cart overlay | Done | Quantity controls, remove, total, in-shell checkout CTA |
|
||
| In-shell checkout | Done | 3-step cart→address→payment; replaces web handoff |
|
||
| In-shell payment view | Done | Direct balance intent + polling; checkout-flow back-nav |
|
||
| Requests list | Done | API-backed with skeleton + empty states |
|
||
| Request detail + stepper | Done | Status timeline, budget, dates with fa-IR locale |
|
||
| Offer review in request detail | Done | Offers fetched via `useTelegramOffers`; accept/reject |
|
||
| New request form | Done | In-shell overlay, category fetch, validation, Assist CTA |
|
||
| Chat list | Done | API-backed conversation list + support row |
|
||
| Chat thread | Done | Messages + optimistic send + Socket.IO real-time |
|
||
| Direct seller chat | Done | `createConversation` from request detail |
|
||
| Account tab | Done | Profile, preferences, help, sign-out |
|
||
| Settings overlay | Done | In-shell profile editing |
|
||
| Addresses overlay | Done | In-shell address management; reachable from checkout |
|
||
| Points overlay | Done | In-shell points/loyalty |
|
||
| Notifications overlay | Done | API-backed; Socket.IO real-time; mark-all-read |
|
||
| Notifications unread badge | Done | Bell icon in header |
|
||
| Telegram chrome (BackButton) | Done | Full back-stack with checkout flow awareness |
|
||
| Telegram MainButton | Disabled | Intentionally hidden (`isReady: false`); hook retained |
|
||
| Haptic feedback | Done | All tap interactions |
|
||
| Safe area insets | Done | Normalised from SDK + CSS env() fallback |
|
||
| amanat-assist integration | Done | "Open Assist" CTA in Home + New Request; window.location hand-off with access_token |
|
||
| Deep link `startapp` routing | Partial | `startParam` parsed; auto-navigation to specific request not yet wired |
|
||
| Backend room-scoped Socket.IO | Partial | Global socket broadcast fixed client-side (v2.8.4); server-side room scoping is a follow-up |
|
||
| Dispute filing (in-shell) | Not started | Escape hatch via web dashboard link + support chat; native view planned |
|
||
| Review prompt integration | Partial | `TelegramReviewPrompt` component exists; trigger point (post-payment/delivery) not yet wired |
|
||
| Archived chats | Partial | `TelegramArchivedChatsView` exists; not yet surfaced in navigation |
|
||
| Client matrix QA (iOS/Android/Desktop) | Pending | Needs cross-platform testing pass |
|
||
|
||
### Open Items
|
||
|
||
1. **`startapp` deep link routing:** if `context.startParam` matches `req_<id>`, auto-open `TelegramRequestDetailView` on first render. `startParam` is already parsed and available in context; the shell needs a one-time effect on mount to act on it.
|
||
2. **Backend room-scoped Socket.IO:** server-side scoping for real-time chat and notification events (follow-up from client-side provider gate in v2.8.4 that fixed global cart-wipe).
|
||
3. **In-shell dispute filing:** add `TelegramDisputeView` matching the web dashboard dispute surface; currently only accessible via `openTelegramExternalLink` escape hatch.
|
||
4. **Review prompt:** wire `TelegramReviewPrompt` to trigger after payment confirmation or delivery acknowledgement.
|
||
5. **Archived chats:** surface `TelegramArchivedChatsView` from `TelegramChatView` (e.g. an "Archived" row at the bottom of the conversation list).
|
||
6. **Client matrix QA:** iOS Telegram, Android Telegram, Telegram Desktop, and web clients all need a full feature pass with particular attention to safe-area insets and BackButton behaviour on each platform.
|
||
|
||
---
|
||
|
||
## 17. Related Documents
|
||
|
||
- [[amanat-assist]] — the separate AI-driven Mini App for LLM-assisted request creation
|
||
- [[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
|
||
- [[Request Template Checkout]] — web checkout flow; the Mini App now has its own in-shell checkout, but the localStorage cart key is shared
|