# PRD — Mini App & Marketplace Sprint (v2.11)

**Status:** Shipped  
**Version:** frontend v2.11.0 → v2.11.2 / backend v2.11.0 → v2.11.1  
**Date:** 2026-06-08  
**Scope:** Telegram Mini App UX, purchase-request archive, payment history, seller shop settings, category filters

---

## 1. Summary

This sprint shipped 10 planned tasks plus several hotfixes discovered in production. The main themes were:
- **Archive system** — buyers can archive completed/cancelled requests to keep the active list clean
- **Payment history** — web dashboard table + mini-app overlay showing full escrow transaction history
- **Seller category selection** — sellers pick categories in shop settings; buyers use them to filter the marketplace
- **Mini App home dashboard** — stats strip, recent requests, archive shortcut, AI assistant overlay
- **Correctness fixes** — payment token validation, Telegram link env-var, notification deep-link

---

## 2. Features Shipped

### 2.1 Purchase Request Archive

**Problem:** Completed and cancelled requests pile up in the buyer's request list, making it hard to find active ones.

**Solution:** Three-layer archive system:
- Requests with status `completed` or `cancelled` are **auto-archived** on status transition (backend service layer)
- Buyer can manually archive any request via a row action in the web dashboard list
- Bulk-archive available via checkbox selection
- Archived requests hidden by default; accessible via "Archived" toggle in the web app and the archive overlay in the mini app

**Backend changes:**
- `purchase_requests` table: added `is_archived`, `archived_at`, `archived_by` columns (migration `0029_purchase_request_archive.sql`)
- Self-healing boot guard (`ensurePurchaseRequestArchiveColumns`) added to `connectDatabase()` to survive cold deployments where the migration hasn't been applied yet
- New routes: `GET /marketplace/purchase-requests/archived`, `POST /marketplace/purchase-requests/:id/archive`, `POST /marketplace/purchase-requests/bulk-archive`
- `getMyPurchaseRequests` filters out archived by default; accepts `?includeArchived=true`

**Frontend changes:**
- `buyer-request-list-view.tsx`: archive row action, `showArchived` toggle, bulk selection
- `TelegramArchivedRequestsView`: full-screen overlay in mini app
- Archive menu row on mini app home screen (home → archived requests)

**Production incident:** Migration `0029` wasn't applied before the first deploy of v2.11.0. All `GET /marketplace/purchase-requests` calls returned HTTP 500 because Drizzle's schema referenced columns that didn't exist in production. Fixed by adding the self-healing boot guard and documenting the manual SQL path.

---

### 2.2 Payment History

**Problem:** No way to see a consolidated list of all escrow payments (as buyer or seller) in either the web app or the mini app.

**Backend:** New endpoint `GET /payment/history?role=buyer|seller|all` — returns payments filtered by the caller's role.

**Web app:** `PaymentHistoryView` — data-grid table with columns: date, request ID, counterparty, amount, status, payment method. Accessible from the "تاریخچه" nav item under Payments in the dashboard sidebar.

**Mini app:** `TelegramPaymentHistoryView` — scrollable list with icon/status/direction/amount per row. Opened via the "پرداخت‌ها و امانت" quick-action row on the home screen (previously this row only navigated to the account tab).

---

### 2.3 Seller Category Selection

**Problem:** Sellers had no way to tag their shop with categories. Buyers filtering the marketplace by category got back all sellers regardless.

**Backend:** Added `category_ids jsonb` column to `shop_settings` (additive migration via `ensurePostgresShopSettingsSchema`). `normalizeSellerListing` now derives `categoryIds` from the seller's active templates if not set manually.

**Web app:**
- `ShopSettingsGeneral`: Autocomplete multi-select using real `useGetCategories()` data
- `seller-filters-drawer.tsx` / `seller-filters-result.tsx`: category filter now uses `{value, label}[]` objects; label shown in active-filter chips

---

### 2.4 Mini App Home Dashboard

**Problem:** Home screen was a plain banner with quick-action links — no at-a-glance status.

**Added:**
- `TelegramHomeStats` — 3-up stat strip: total requests (tappable → requests tab), active escrow payments (tappable → payment history overlay), unread notifications (tappable → notifications overlay)
- Recent activity section: the 3 most recent requests rendered as tappable rows
- Archive shortcut row: direct entry to the archived-requests overlay
- `TelegramWelcomeBanner`: personalized greeting using Telegram display name with fallback to "کاربر" / "User"

---

### 2.5 AI Assistant In-App Overlay

**Problem:** "دستیار هوشمند" CTA previously opened `assist.amn.gg` in a full WebView navigation, which destroyed the mini app session — the back button led nowhere.

**Solution:** Assistant now loads inside an `<iframe>` overlay with a manual back button at the top. The mini app stays mounted underneath. Auth token and user profile JSON passed as URL params so the assistant can authenticate without a cross-origin `fetch`.

---

### 2.6 Notification Deep-Link Fix

**Problem:** Clicking a notification that had an `actionUrl` (e.g. `/dashboard/buyer/marketplace/request/{id}`) called `router.push()` which navigated the Next.js router to a web-app URL. Inside the Telegram WebView this produced a 404.

**Fix:** `TelegramNotificationsView` no longer uses `router.push`. It extracts the request ID from the `actionUrl` via regex (`/marketplace\/requests?\/([a-zA-Z0-9_-]+)/`) and calls `onOpenRequest(id)` — which sets `openRequestId` in the mini-app shell, closing the notifications overlay and opening the request detail overlay in-app.

---

### 2.7 Telegram Mini App Link — Env Variable

**Problem:** `NEXT_PUBLIC_TELEGRAM_MINI_APP_URL` was hardcoded in two places (`telegram-app-button.tsx`, `tonconnect-provider.tsx`), causing the `twaReturnUrl` to point to the wrong environment in staging.

**Fix:** Centralised to `src/utils/telegram-link.ts` → `getTelegramMiniAppUrl()` reading the env var with a safe fallback.

---

### 2.8 Payment Token Validation

**Problem:** `paymentService.ts` had `currency: 'USDT'` hardcoded. If a request was priced in USDC the payment record stored the wrong token, causing downstream balance-check mismatches.

**Fix:** `resolvePaymentCurrency(token)` validates against `DEFAULT_ALLOWED_TOKENS = ['USDC', 'USDT']` and throws if the token is unsupported. AmnScanner webhook handler logs a warning when the scanned token doesn't match the payment record.

---

### 2.9 Mini App Requests Pagination

**Problem:** Buyers with many requests saw an endless scroll — the entire list rendered at once inside the Telegram WebView, which has no native scroll chrome.

**Fix:** `TelegramRequestsView` renders 8 items at a time (`PAGE_SIZE = 8`). A "نمایش بیشتر (N)" button appends the next page. Changing search/filter/sort resets to page 1.

---

## 3. Migration Notes

### `0029_purchase_request_archive.sql`

Idempotent — safe to run multiple times:

```sql
ALTER TABLE purchase_requests ADD COLUMN IF NOT EXISTS is_archived   BOOLEAN   NOT NULL DEFAULT false;
ALTER TABLE purchase_requests ADD COLUMN IF NOT EXISTS archived_at   TIMESTAMP;
ALTER TABLE purchase_requests ADD COLUMN IF NOT EXISTS archived_by   TEXT;
CREATE INDEX IF NOT EXISTS idx_purchase_requests_is_archived ON purchase_requests (is_archived);
```

Apply via:
```bash
docker exec -i amanat-postgres psql -U amanat -d amanat < src/db/migrations/0029_purchase_request_archive.sql
```

Or redeploy backend — the boot guard runs `ADD COLUMN IF NOT EXISTS` on startup automatically.

---

## 4. Deployment Checklist

- [x] Backend: redeploy via Arcane (does NOT auto-deploy on push)
- [x] Frontend: auto-deploys on push to `main`
- [x] DB migration `0029` applied (or rely on boot guard)
- [ ] Verify `NEXT_PUBLIC_TELEGRAM_MINI_APP_URL` is set in production env

---

## 5. Known Limitations / Follow-up

- Payment history view shows `direction: 'in'/'out'` from the backend's `IPayment` record; if `direction` is not set, defaults to buyer (outgoing). May need backend to populate `direction` reliably for all historical records.
- Mini app payment history does not yet support pagination — fetches up to 100 records at once. Sufficient for current user volumes.
- Task 10 (UI like wallet + tutorial videos) was descoped from this sprint. The wallet-style home stats strip is the v1 of that work.
