# Handoff - Telegram Mini App Debug - 2026-05-24 ## Scope This handoff covers the work done after bringing the app up under the consolidated `https://amn.gg` URL and debugging the Telegram Mini App flow. Primary user-reported issues: - The red `N` badge in the Telegram webview was interpreted as backend/socket failure. - Telegram-created users without an existing Amanat account were blocked by the link/sign-in screen instead of being treated as buyer users. - Wallet connect did not support Telegram Wallet / TON. - Profile email updates for Telegram-created users did not persist and did not send confirmation email. - The page needed visible debug statistics to identify which subsystem is working. ## Repositories Touched Backend: - `backend/src/models/User.ts` - `backend/src/services/user/userController.ts` - `backend/src/services/user/userControllerRoutes.ts` - `backend/src/services/user/userRoutes.ts` Frontend: - `frontend/next.config.ts` - `frontend/package.json` - `frontend/yarn.lock` - `frontend/public/tonconnect-manifest.json` - `frontend/src/actions/account.ts` - `frontend/src/app/layout.tsx` - `frontend/src/auth/context/jwt/auth-provider.tsx` - `frontend/src/auth/types.ts` - `frontend/src/components/debug/telegram-debug-panel.tsx` - `frontend/src/lib/axios.ts` - `frontend/src/sections/account/account-general.tsx` - `frontend/src/sections/account/account-wallet-connection.tsx` - `frontend/src/types/user.ts` - `frontend/src/web3/tonconnect-provider.tsx` Vault: - This file. ## Implemented ### Debug Statistics Added `TelegramDebugPanel` to account/profile and wallet pages. It reports: - API URL - Socket URL - socket connected/disconnected state and socket id - auth state - user id, role, email, email verification state - Telegram Mini App detection, platform, version, and initData presence - saved wallet type/address - last frontend account/wallet action and result Visibility: - Always visible in development. - Visible inside Telegram Mini App. - Visible in production browser with `?debug=1` or `localStorage.setItem('amn-debug', '1')`. ### Red `N` Badge The red `N` indicator is the Next.js development indicator, not the backend/socket status. Change: - `frontend/next.config.ts` now sets `devIndicators: false`. The actual socket status should be read from the debug panel or the app socket status component. ### Telegram User / Buyer Flow Frontend auth mapping was changed so users without an email are not treated as email-unverified blockers: - `isEmailVerified` is treated as true when the user has no email. - If an email exists, normal verification state applies. This supports Telegram-created buyer accounts without forcing immediate email collection. ### Profile Email Update And Verification Backend profile update now accepts `email` and handles verification: - Normalizes email to lowercase. - Rejects duplicate email. - Stores a six-digit verification code on the user. - Sets `isEmailVerified=false` when email changes. - Attempts to send a confirmation email. - Returns `verificationEmailQueued`. New authenticated endpoints: - `POST /api/user/profile/email/resend-verification` - `POST /api/user/profile/email/verify` Frontend: - `updateUserProfile` now unwraps the backend `{ user, verificationEmailQueued }` response correctly. - Profile page shows a verification code input and resend/verify controls when a user has an unverified email. - Debug events are emitted for profile update/resend/verify actions. ### Telegram Wallet / TON Support Frontend: - Added `@tonconnect/ui-react` and `@ton/core`. - Added `TonWalletProvider` in the root layout. - Added `public/tonconnect-manifest.json`. - Wallet connection page now offers Telegram Wallet / TON connection inside Telegram Mini App. - Connected TON wallet can be saved as `walletType: "ton"` with provider metadata. Backend: - User profile schema now supports: - `profile.walletType: "evm" | "ton"` - `profile.walletProvider` - Current `/user/wallet-address` controller supports TON address validation. - Legacy `/users/wallet-address` route also accepts TON. - EVM still requires signature verification. - TON currently validates address format only and skips EVM signature. ### Frontend Typecheck — All Pre-Existing Errors Resolved All 13 pre-existing TypeScript errors in the frontend were fixed. `npx tsc --noEmit` now passes clean and can be used as a release gate. Fixes applied: - `src/web3/components/provider-payment.tsx` — changed invalid icon `solar:wallet-money-bold` to `solar:wallet-bold`. - `src/components/payment/shkeeper-payment-widget.tsx` — moved `sellerId` from `metadata` to top-level payload (matches `IPaymentIntentPayload`). - `src/sections/address/address-form.tsx` — added `as unknown as Resolver` double cast for Zod v4 + `@hookform/resolvers` v5 type mismatch. - `src/sections/address/address-new-form.tsx` — same resolver cast fix. - `src/sections/request-template/request-template-checkout-payment.tsx` — same resolver cast fix. - `src/sections/request-template/request-template-new-edit-form.tsx` — added explicit `useForm` generic and resolver cast. ### Backend Tests for Email Verification and Wallet Created `backend/__tests__/user-profile-email-wallet.test.ts` — 27 tests, all passing. Coverage: - Profile email update stores normalized email, sets `isEmailVerified=false`, returns `verificationEmailQueued`. - Duplicate email rejected with 409. - Resend verification: fails when no email, fails when already verified, succeeds otherwise. - Verify email code: rejects malformed, rejects expired/wrong, sets `isEmailVerified=true` on correct code. - TON wallet save: accepts valid friendly address, stores `walletType`, `walletAddress`, `walletProvider`. - TON wallet save: rejects malformed address. - EVM wallet save: rejects missing signature, rejects wrong signature. `emailService` is mocked — no Resend calls are made during tests. ### Email Delivery Confirmed Resend SMTP relay verified end-to-end. Configuration: port 465 SSL (`SMTP_SECURE=true`), sender `noreply@amn.gg`. Test email delivered successfully during session. ### Telegram Bot Command Handlers and Notification Foundation (Task 5.3) Created `backend/src/services/telegram/botService.ts` (~480 lines). Implemented: - `sendBotMessage(chatId, text, options)` — raw Telegram Bot API call with inline keyboard support. - `answerCallbackQuery(id, text?)` — acknowledges callback queries. - `sendTelegramNotification(telegramUserId, text, options)` — looks up active `TelegramLink`, sends message, detects 403 (bot blocked by user) and marks link as `status: 'blocked'` to prevent future sends. - `dispatchBotUpdate(update)` — routes incoming webhook updates to command handlers or callback handler. - Command handlers: `/start` (welcome + Mini App button), `/help`, `/link`, `/status`, `/requests`, `/offers`, `/payments`, `/settings`. - Per-chat rate limiter (10 messages per 10-second window) to prevent abuse. - Mini App buttons use `web_app` inline keyboard type pointing to `https://amn.gg/telegram/`. Modified `telegramService.ts`: - Expanded `TelegramWebhookUpdate` type to include `message.from`, `message.chat`, `callback_query.message`. - Wired `handleTelegramWebhook` to fire `dispatchBotUpdate` asynchronously (dynamic import) so Telegram always receives HTTP 200 immediately. Updated `index.ts`: - Exports: `sendTelegramNotification`, `sendBotMessage`, `NotificationDeliveryResult`, `BotSendOptions`, `InlineKeyboard`. Created `backend/__tests__/telegram-bot-service.test.ts` — 17 tests, all passing. Committed: "Implement Telegram bot command handlers and notification foundation (task 5.3)" — 4 files, 1092 insertions. ### Telegram Bot Commands Registered Registered bot commands with Telegram Bot API (`setMyCommands`): - `/start` — Open Amanat escrow marketplace - `/help` — Show help and command list - `/link` — Link your Amanat account - `/status` — Check your active escrow status - `/requests` — Browse service requests - `/offers` — View your offers - `/payments` — Check payment status - `/settings` — Account settings ### PRD — TON Wallet Ownership Proof Created `nick-doc/07 - Development/PRD - TON Wallet Ownership Proof.md`. Covers: challenge nonce endpoint, TonConnect proof request flow, backend ed25519 verification with `@ton/ton` + `tweetnacl`, new User model fields, frontend badge/CTA, migration notes, acceptance criteria, and tests. ### TON Wallet Ownership Proof — Backend Implemented Full backend implementation completed in session 3. New file: `backend/src/services/user/tonProofService.ts` - In-memory TTL challenge store keyed by `userId` (5-minute TTL). - `generateChallenge(userId)` — generates 32-byte hex nonce, returns `{ payload, domain, timestamp }`. - `verifyTonProof(userId, walletAddress, proof)` — full ed25519 verification: 1. Nonce match and expiry check. 2. Domain must equal `amn.gg`. 3. Timestamp within ±300 s of now. 4. `stateInit` required; its hash must match the claimed wallet address hash (anti-substitution). 5. Public key extracted from wallet data cell (skip 64-bit seqno+subwallet_id, read 32-byte pubkey — works for v3/v4/v5 standard wallets). 6. Signed message reconstructed: `ton-proof-item-v2/ + workChain (BE int32) + address.hash + domainLen (LE uint32) + domain + timestamp (LE int64) + payload (hex)`. 7. `sha256(0xff0xff + "ton-connect" + sha256(message))` — verified with `nacl.sign.detached.verify`. 8. Nonce cleared only on success (allows retry on failure within TTL). Modified `backend/src/services/user/userController.ts`: - `updateWalletAddress` extracts optional `tonProof` from body; calls `verifyTonProof` when present; sets `profile.walletProofVerified` and `profile.walletProofTimestamp`; returns `INVALID_TON_PROOF` on failure. - New `getTonProofChallenge` handler calls `generateChallenge(userId)` and returns the nonce object. Modified `backend/src/services/user/userControllerRoutes.ts`: - `POST /api/user/wallet-address/ton-proof/challenge` registered (authenticated). Modified `backend/src/models/User.ts`: - Added `walletProofVerified?: boolean` and `walletProofTimestamp?: Date` to both IUser interface and Mongoose schema. Added `@ton/ton@16.2.4`, `@ton/crypto@3.3.0`, `tweetnacl@1.0.3` to backend `package.json`. New file: `backend/__tests__/ton-proof.test.ts` — 15 tests, all passing: - Challenge generation (uniqueness, TTL invalidation). - Valid proof accepted, nonce cleared (replay rejected). - Rejection cases: no challenge, nonce mismatch, wrong domain, expired timestamp, missing stateInit, stateInit/address mismatch, bad signature, wrong keypair. - Nonce preserved on failure (allows retry). ### Telegram Mini App Shell — LTR Fix and Smart Display Name Modified `frontend/src/sections/telegram/telegram-mini-app-shell.tsx`: - Added `dir="ltr"` to all three Container states (linked, unlinked, unsupported) so English content does not inherit the page-level RTL direction. - Added smart `displayName` logic: falls back from Telegram name → auth user name → `"there"` if Telegram returns a generic or empty name (e.g., the literal string `"Telegram user"`). ### Socket Status — Suppressed Inside Telegram Mini App Modified `frontend/src/socket/components/socket-status.tsx`: - Added `usePathname` import; added path-guard `if (pathname?.startsWith('/telegram')) return null`. - The "قطع" (disconnected) chip that briefly appeared on Mini App load was caused by normal Socket.IO connection latency (~0.5 s before handshake). Suppressing it on `/telegram` routes eliminates the false alarm without hiding useful status on other pages. ### EVM WalletConnect Stub Card Telegram Wallet is TON-only. Request Network requires EVM. MetaMask is not available in Telegram; WalletConnect is the right approach but requires a project ID from `cloud.walletconnect.com`. Added `EvmWalletStubCard` to `frontend/src/sections/account/account-wallet-connection.tsx`: - Always rendered below the TON wallet card on the Account › Wallet page. - Shows WalletConnect logo, "به زودی" (coming soon) chip, and explanation. - Connect button is disabled when `NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID` is not set; tooltip tells developer what to configure. - Button activates automatically when the env var is added — wire the wagmi `walletConnect()` connector (already commented out in `src/web3/config.ts`) at that point. Rendered from `frontend/src/sections/account/view/account-wallet-view.tsx`. ## Verification Completed Backend: ```bash cd backend npm run typecheck --if-present ``` Result: passed. Frontend focused tests: ```bash cd frontend npm test -- __tests__/account-test/account-actions.test.ts __tests__/auth/telegram-auth-action.test.ts __tests__/sections/telegram/telegram-mini-app-shell.test.tsx --runInBand ``` Result: - 3 suites passed - 38 tests passed Diff hygiene: ```bash git diff --check ``` Result: passed in backend and frontend after whitespace cleanup. Public smoke checks completed during the session: - `https://amn.gg/` returned HTTP 200. - `https://amn.gg/tonconnect-manifest.json` returned HTTP 200 with JSON. - `https://amn.gg/socket.io/?EIO=4&transport=polling` returned HTTP 200 polling handshake. - `https://amn.gg/dashboard/account/wallet/` returned HTTP 200 after compilation. ## Known Issues Left ### TON Wallet Ownership Proof — Frontend Wiring Pending Backend is fully implemented and tested (see "Implemented" section above, and PRD `07 - Development/PRD - TON Wallet Ownership Proof.md` — status: `backend-implemented`). Remaining frontend work: 1. Add `getTonProofChallenge` action in `src/actions/account.ts` (calls `POST /api/user/wallet-address/ton-proof/challenge`). 2. In `handleConnectTelegramWallet` in `account-wallet-connection.tsx`: - Fetch challenge nonce before opening modal. - Call `tonConnectUI.setConnectRequestParameters({ state: 'ready', value: { tonProof: payload } })`. - After connection, read `tonWallet.connectItems?.tonProof?.proof` and send to `PATCH /api/user/wallet-address` with `tonProof` field. 3. Show "Verified ✅" badge when `walletProofVerified: true`; show "Verify ownership" CTA when wallet is saved but unverified. Until the frontend proof flow is wired, the backend accepts wallet saves without proof (legacy path — `walletProofVerified` will be absent/false). TON wallet addresses saved without proof must not be used for automatic payout routing. ### EVM Wallet (WalletConnect) Not Yet Functional A stub card is now rendered on the wallet page with a disabled connect button. To activate: 1. Register at `cloud.walletconnect.com` (free), get a project ID. 2. Add `NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID=` to `.env.local` (and server env). 3. Uncomment the `walletConnect()` connector in `src/web3/config.ts`. 4. Wire the connect handler in `EvmWalletStubCard` to open the WalletConnect modal. ### Profile Update UX Needs Manual Telegram Test The backend email verification endpoints are implemented and covered by tests. The UI flow in the actual Telegram Mini App has not been end-to-end verified manually: - Start with a Telegram-created buyer without email. - Add email in profile. - Confirm warning/verification controls appear. - Confirm Resend works. - Enter verification code. - Confirm session refresh shows verified state. ### Pangolin/Newt Routing Not Re-Verified The desired public shape is one URL: - Browser and Telegram app: `https://amn.gg` - Backend proxied by path under the same host. Expected route intent: - `/*` → frontend container/service - `/api/*` → backend container/service - `/socket.io/*` → backend container/service with WebSocket support - `/uploads/*` → backend container/service - `/health` → backend container/service If Telegram shows network errors, open `https://amn.gg/?debug=1` and check the debug panel API/Socket fields. ### Package Manager State The frontend project declares Yarn 1 as package manager and `yarn.lock` was updated for TON dependencies. `package-lock.json` was intentionally restored to avoid unrelated massive lockfile churn. Next agent should continue using Yarn for dependency changes unless the project standard changes. ### Dev Runtime Note During dependency installation, the mounted `node_modules` was temporarily broken by an Alpine/Yarn install attempt involving native packages. It was repaired on the host with dependency install and the public app recovered. If the container shows stale Next errors in logs, check for a later successful startup before treating them as current. ## Current Git State At Handoff (Updated 2026-05-24 Session 3) ### Backend — Session 3 Changes (Uncommitted) New files: - `src/services/user/tonProofService.ts` — full TON proof verification service - `__tests__/ton-proof.test.ts` — 15 unit tests (all passing) Modified files: - `src/models/User.ts` — added `walletProofVerified`, `walletProofTimestamp` fields - `src/services/user/userController.ts` — TON proof challenge handler + proof verification in wallet save - `src/services/user/userControllerRoutes.ts` — challenge endpoint registered - `package.json` / `package-lock.json` — `@ton/ton`, `@ton/crypto`, `tweetnacl` added Still uncommitted from earlier sessions: - `src/services/user/userRoutes.ts` - `__tests__/user-profile-email-wallet.test.ts` (27 tests) ### Frontend — Session 3 Changes (Uncommitted) Modified: - `src/sections/account/account-wallet-connection.tsx` — added `EvmWalletStubCard` component - `src/sections/account/view/account-wallet-view.tsx` — renders `EvmWalletStubCard` - `src/sections/telegram/telegram-mini-app-shell.tsx` — `dir="ltr"` on all containers, smart `displayName` fallback - `src/socket/components/socket-status.tsx` — suppressed on `/telegram` paths Other files still uncommitted from earlier sessions (listed in Session 2 handoff). ### Vault — Session 3 Changes (Uncommitted) - `07 - Development/PRD - TON Wallet Ownership Proof.md` — status updated to `backend-implemented`, acceptance criteria checked - `08 - Operations/Handoff - Telegram Mini App Debug - 2026-05-24.md` — this file ### Recommended Commit Split 1. Backend commit A — user/email/wallet: - `src/models/User.ts` - `src/services/user/userController.ts` - `src/services/user/userControllerRoutes.ts` - `src/services/user/userRoutes.ts` - `__tests__/user-profile-email-wallet.test.ts` 2. Frontend commit: - All frontend files above. 3. Vault commit: - All vault files above. Before committing, rerun: ```bash cd /Users/manwe/CascadeProjects/escrow/backend npm run typecheck --if-present npx jest --testPathPattern='user-profile-email-wallet|telegram-bot-service' --runInBand cd /Users/manwe/CascadeProjects/escrow/frontend npx tsc --noEmit -p tsconfig.json ``` Do not include secrets, local `.env` files, or regenerated `package-lock.json` churn. ## Suggested Next Steps 1. Implement TON wallet ownership proof per `07 - Development/PRD - TON Wallet Ownership Proof.md`. This is the only remaining security-critical backend item. 2. Manually test profile email update + verification flow in the Telegram Mini App. 3. Recheck Pangolin/Newt routing and confirm Mini App loads via `https://amn.gg/telegram/`. 4. Build Telegram Mini App shell for marketplace workflows (Taskmaster task 5.4). 5. Add frontend tests for `updateWalletAddress` and `TelegramDebugPanel`. 6. Rebuild/redeploy frontend container after dependency changes (`@tonconnect/ui-react`, `@ton/core`). 7. Commit pending vault changes (PRD file, updated handoff). ## Detailed Remaining Work ### 1. ~~Confirm Telegram Bot Web App URL~~ ✓ Done Bot commands registered via `setMyCommands`. Mini App buttons in `/start` and `/help` use `web_app` type pointing to `https://amn.gg/telegram/`. No BotFather URL change was needed for command dispatch. If the menu button URL still points to an old URL, update it via BotFather → Bot Settings → Menu Button. ### 2. Recheck Pangolin/Newt Routing Not touched this session. See "Known Issues Left" section above for routing checklist. ### 3. ~~Finish Email Verification Test Coverage~~ ✓ Done 27 tests in `backend/__tests__/user-profile-email-wallet.test.ts` cover all email verification cases. See "Implemented" section above. ### 4. ~~Finish Wallet Test Coverage~~ ✓ Done (format-only) Backend tests for TON format validation and EVM signature enforcement are in `user-profile-email-wallet.test.ts`. Ownership proof tests will be added when TonConnect proof verification is implemented (see item 5). Recommended frontend tests still pending: - `updateWalletAddress` sends legacy EVM payload unchanged when no options are passed. - `updateWalletAddress` sends TON payload without signature when `{ walletType: "ton" }` is passed. - `TelegramDebugPanel` renders socket/auth/TG fields when debug is enabled. - Account profile page renders email verification controls for an unverified email. ### 5. Implement TON Ownership Proof PRD written: `07 - Development/PRD - TON Wallet Ownership Proof.md`. Implementation not started. See PRD for full spec. Summary: - Add `yarn add @ton/ton @ton/crypto tweetnacl` to backend. - Add `POST /api/user/wallet-address/ton-proof/challenge` (generates TTL nonce). - Update `PATCH /api/user/wallet-address` to verify ed25519 proof when `tonProof` is present. - Add `profile.walletProofVerified` and `profile.walletProofTimestamp` to User model. - Frontend: request proof via `tonConnectUI.connectWallet({ tonProof: payload })`, send proof to backend. - Frontend: show "Verified" badge or "Verify ownership" CTA. ### 6. Check Profile Update UX in Telegram Backend and tests done. Manual Telegram Mini App test not yet done: - Start with a Telegram-created buyer without email. - Add email in profile, confirm page does not discard it. - Confirm warning/verification controls appear. - Confirm Resend works and email arrives from `noreply@amn.gg`. - Enter verification code, confirm `isEmailVerified=true`. ### 7. ~~Resolve Existing Typecheck Debt~~ ✓ Done All 13 pre-existing frontend TypeScript errors fixed. `npx tsc --noEmit` passes clean. Add it to the frontend verification gate. ### 8. Deployment/Container Follow-Up Because dependencies changed in `frontend/package.json` and `yarn.lock`, the deployed frontend image/container should be rebuilt from a clean dependency install. Recommended sequence: ```bash cd /Users/manwe/CascadeProjects/escrow/frontend yarn install --frozen-lockfile yarn test __tests__/account-test/account-actions.test.ts __tests__/auth/telegram-auth-action.test.ts __tests__/sections/telegram/telegram-mini-app-shell.test.tsx --runInBand cd /Users/manwe/CascadeProjects/escrow docker compose build frontend backend docker compose up -d frontend backend ``` If the existing compose setup relies on mounted `node_modules`, verify the mounted dependencies include `@tonconnect/ui-react` and `@ton/core`. ### 9. Spark Agent Status The user asked to use codex-spark agents. Earlier in this session, existing subagents were already active and a fresh spark verifier could not be spawned because the agent thread limit was reached. Next agent can continue with spark workers once capacity is available. Good isolated assignments: - Worker A: backend tests for profile email verification. - Worker B: backend tests for wallet address EVM/TON behavior. - Worker C: frontend tests for debug panel and TON wallet action payload. - Worker D: manual Telegram/Pangolin runtime verification report. ### 10. Safety Notes - Do not commit Telegram bot token, Resend API key, Pangolin/Newt secret, or any `.env` file. - Do not revert unrelated vault audit files; they predate this handoff and should be reviewed as separate documentation work. - Do not regenerate package locks casually. The frontend project declares Yarn 1 and `yarn.lock` is the relevant lockfile for this change. - Keep Trezor optional; this pass did not modify Trezor safekeeping behavior. - Payment adapter remains optional; this pass did not force SHKeeper or Request Network.