Files
nick-doc/08 - Operations/Handoff - Telegram Mini App Debug - 2026-05-24.md
Siavash Sameni 873a57874e Update docs for TON proof backend, Mini App fixes, and EVM wallet stub
PRD - TON Wallet Ownership Proof.md:
- Status updated from ready-to-implement -> backend-implemented.
- Added Implementation Status section documenting what is complete
  (challenge endpoint, tonProofService.ts, User model fields, 15 tests)
  and what remains (frontend proof wiring, verified badge).
- Acceptance criteria updated: backend items checked, frontend pending.

Handoff - Telegram Mini App Debug - 2026-05-24.md:
- New Implemented sections for session 3:
  - TON Wallet Ownership Proof backend (full detail of tonProofService,
    userController changes, User model fields, 15 unit tests).
  - Telegram Mini App shell dir="ltr" + smart displayName fallback.
  - Socket status suppressed on /telegram paths.
  - EVM WalletConnect stub card (disabled until project ID configured).
- Known Issues: TON proof updated to "frontend wiring pending";
  EVM WalletConnect section added with activation steps.
- Current Git State updated to Session 3.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 20:21:29 +04:00

24 KiB
Raw Blame History

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<AddressFormData> 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<RequestTemplateSchemaType> 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:

cd backend
npm run typecheck --if-present

Result: passed.

Frontend focused tests:

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:

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=<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.tsxdir="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
  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:

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:

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.