Files
app_umbrix/TRIAL-USERNAME-FIX.md

9.8 KiB
Raw Permalink Blame History

🔒 Исправление: Имена user_... при trial подписке

📋 Описание проблемы

При оформлении trial (пробной) подписки username генерировался в формате user_1770605873419 (timestamp) вместо реального имени пользователя.

🔍 Причина

Это НЕ баг кода! Telegram WebApp API не передает данные пользователя (tgUser.id, tgUser.username, tgUser.first_name) когда:

  1. Приложение открыто в браузере напрямую (не через Telegram бота)
  2. Telegram WebApp не инициализирован (например, в dev режиме)
  3. Недостаточно прав доступа к Telegram API

Старое поведение (до фикса):

// app/page.tsx (handleActivateTrial)
telegramId: tgUser?.id || Date.now(),  // ❌ Fallback на timestamp!

Результат: Если tgUser?.id = undefined → username = user_1770605873419 (таймстамп)

Решение

Добавлена обязательная валидация Telegram ID на всех уровнях:

1. Frontend - app/page.tsx (Trial кнопка)

const tgUser = telegramWebApp?.initDataUnsafe?.user;

// 🔍 DEBUG логирование
console.log('🎁 TRIAL ACTIVATION - Telegram data:', {
  hasWebApp: !!telegramWebApp,
  hasUser: !!tgUser,
  userId: tgUser?.id,
  username: tgUser?.username,
  firstName: tgUser?.first_name
});

// ⚠️ БЛОКИРУЕМ создание без Telegram ID
if (!tgUser?.id) {
  console.error('❌ TRIAL BLOCKED: No Telegram user data!');
  showToastNotification('❌ Откройте приложение через Telegram бота');
  return;
}

// Теперь tgUser.id 100% есть
const response = await fetch('/api/create-user', {
  body: JSON.stringify({
    planType: 'trial',
    telegramId: tgUser.id,  // ✅ Без fallback!
    telegramUsername: tgUser?.username,
    firstName: tgUser?.first_name,
  })
});

2. Frontend - app/plans/page.tsx (3-step flow)

async function createUser(planType, period, locationIds) {
  const user = telegramWebApp?.initDataUnsafe?.user;

  // ⚠️ БЛОКИРУЕМ без user.id
  if (!user?.id) {
    console.error('❌ USER CREATION BLOCKED: No Telegram user ID!');
    alert('❌ Откройте приложение через Telegram бота\n\nПриложение должно быть открыто в Telegram Mini App.');
    return;
  }

  const requestBody = {
    telegramId: user.id,  // ✅ 100% существует
    telegramUsername: user?.username || null,
    firstName: user?.first_name || null,
  };
}

3. Backend - app/api/create-user/route.ts

export async function POST(request: NextRequest) {
  const { telegramId, telegramUsername, firstName } = await request.json();

  // ⚠️ СЕРВЕРНАЯ ВАЛИДАЦИЯ
  if (!telegramId) {
    logger.error('❌ VALIDATION FAILED: No telegramId provided');
    return NextResponse.json(
      { 
        success: false, 
        error: 'Telegram ID is required. Please open the app through Telegram bot.' 
      },
      { status: 400 }
    );
  }

  // Генерация username с приоритетами
  let username: string;
  if (telegramUsername) {
    username = telegramUsername.toLowerCase().replace(/[^a-z0-9_]/g, '_');
  } else if (firstName && telegramId) {
    username = `${firstName.toLowerCase().replace(/[^a-z0-9]/g, '_')}_${telegramId}`;
  } else {
    username = `user_${telegramId}`;  // ✅ Используем реальный ID, не timestamp
  }
}

📊 Результат

До фикса:

  • user_1770605873419 (timestamp) - когда Telegram не передает данные
  • Создается подписка даже без Telegram ID
  • Невозможно отследить пользователя

После фикса:

  • БЛОКИРОВКА создания если нет tgUser.id
  • Понятное сообщение: "Откройте приложение через Telegram бота"
  • Debug логи показывают причину блокировки
  • Все имена генерируются из реальных Telegram данных

🧪 Тестирование

Правильный путь (через Telegram бота):

  1. Открыть Telegram бот @Chat_8n8_bot
  2. Нажать "Открыть приложение" / Start
  3. Telegram WebApp передаст: { id: 123456789, username: "john_doe", first_name: "John" }
  4. Username: john_doe

Неправильный путь (в браузере напрямую):

  1. Открыть https://app.umbrix.net в Chrome
  2. Telegram WebApp недоступен: window.Telegram?.WebApp = undefined
  3. Попытка создать trial → БЛОКИРОВКА
  4. Сообщение: "Откройте приложение через Telegram бота"

📝 Debug логи

При попытке создать trial без Telegram данных в консоли браузера:

🎁 TRIAL ACTIVATION - Telegram data: {
  hasWebApp: false,
  hasInitData: false,
  hasUser: false,
  userId: undefined,
  username: undefined,
  firstName: undefined,
  fullData: undefined
}
❌ TRIAL BLOCKED: No Telegram user data!

🚀 Production деплой

Изменения задеплоены:

  • Локальный билд: PASSED
  • Production билд: PASSED
  • PM2 перезапущен: pid 48353
  • Git коммит: 806b668

🔑 Ключевые файлы

💡 Важно!

Если пользователь видит имена user_... - это означает, что:

  1. Приложение открыто не через Telegram бота
  2. Telegram WebApp не инициализирован
  3. Нужно переоткрыть через @Chat_8n8_bot → "Открыть приложение"

Теперь система автоматически блокирует такие попытки!


🔓 UPDATE: Исключение для n8n переходов (5677b48)

Проблема после первого фикса:

После блокировки создания без Telegram ID - перестали работать переходы из n8n!

n8n workflow отправляет пользователей по прямой ссылке (открывается в браузере), где window.Telegram?.WebApp недоступен.

Решение:

Добавлены URL параметры-исключения для n8n переходов:

// Проверяем источник перехода
const urlParams = new URLSearchParams(window.location.search);
const source = urlParams.get('source') || urlParams.get('utm_source');
const fromN8n = source === 'n8n' || source === 'chat' || urlParams.has('from_n8n');

// Блокируем ТОЛЬКО если нет Telegram ID И это НЕ n8n переход
if (!tgUser?.id && !fromN8n) {
  showToastNotification('❌ Откройте приложение через Telegram бота');
  return;
}

// Для n8n переходов генерируем временный ID
const userId = tgUser?.id || Date.now();

Поддерживаемые параметры:

  1. ?source=n8n - рекомендуемый
  2. ?utm_source=n8n - для аналитики
  3. ?utm_source=chat - альтернативный вариант
  4. ?from_n8n=true - явное указание

Примеры ссылок из n8n:

✅ https://app.umbrix.net/?source=n8n
✅ https://app.umbrix.net/plans?utm_source=chat
✅ https://app.umbrix.net/?from_n8n=true&ref=user123
❌ https://app.umbrix.net/ (без параметров - блокируется)

Итоговая логика:

Способ входа Telegram ID URL параметры Результат
Telegram Mini App Есть Любые Создается с реальным ID
n8n workflow Нет ?source=n8n Создается с временным ID
Прямая ссылка Нет Нет параметров БЛОКИРОВКА

Backend поддержка:

// app/api/create-user/route.ts
const { telegramId, source } = await request.json();

// Разрешаем n8n переходы
const fromN8n = source === 'n8n' || source === 'chat';

if (!telegramId && !fromN8n) {
  return NextResponse.json(
    { success: false, error: 'Telegram ID required' },
    { status: 400 }
  );
}

Проверка в production:

# 1. Переход через n8n (должен работать)
curl -X POST https://app.umbrix.net/api/create-user \
  -H "Content-Type: application/json" \
  -d '{"planType":"trial","source":"n8n"}'

# 2. Переход без параметров (должен блокироваться)
curl -X POST https://app.umbrix.net/api/create-user \
  -H "Content-Type: application/json" \
  -d '{"planType":"trial"}'

Деплой: PM2 перезапущен (pid 50711), коммит 5677b48