8.4 KiB
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
completedorcancelledare 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_requeststable: addedis_archived,archived_at,archived_bycolumns (migration0029_purchase_request_archive.sql)- Self-healing boot guard (
ensurePurchaseRequestArchiveColumns) added toconnectDatabase()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 getMyPurchaseRequestsfilters out archived by default; accepts?includeArchived=true
Frontend changes:
buyer-request-list-view.tsx: archive row action,showArchivedtoggle, bulk selectionTelegramArchivedRequestsView: 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 realuseGetCategories()dataseller-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:
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:
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
- Backend: redeploy via Arcane (does NOT auto-deploy on push)
- Frontend: auto-deploys on push to
main - DB migration
0029applied (or rely on boot guard) - Verify
NEXT_PUBLIC_TELEGRAM_MINI_APP_URLis set in production env
5. Known Limitations / Follow-up
- Payment history view shows
direction: 'in'/'out'from the backend'sIPaymentrecord; ifdirectionis not set, defaults to buyer (outgoing). May need backend to populatedirectionreliably 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.