Cache System (Backend): - Implemented two-tier hybrid cache: L1 (in-memory) + L2 (SQLite) - L1 cache: Fast dictionary-based with 5-minute TTL for hot data - L2 cache: Persistent SQLite with 1-hour TTL for warm data - Cache decorator with automatic tier management and fallback - Cache key generation with per-user isolation - Event monitoring system for cache statistics - Cache benchmarking utilities for performance testing - Added cache management endpoints: /api/cache/stats, /api/cache/clear, /api/cache/benchmark - Cache configuration via environment variables (CACHE_ENABLED, CACHE_L1_TTL, etc.) Backend Services: - Updated dashboard_service to use @cached decorator with request context - Added cache support to invoice_service and treasury_service - Integrated cache manager into main.py with lifespan events - Added Request parameter to service methods for cache metadata Frontend Enhancements: - New CacheStatsView.vue for real-time cache monitoring dashboard - Cache store (cacheStore.js) for state management - Updated router to include /cache-stats route - Navigation updates in DashboardHeader and HamburgerMenu - Cache stats accessible from main navigation Telegram Bot Improvements: - Enhanced formatters with YTD comparison data - Improved menu navigation and button layout - Better error handling and user feedback - Bot startup improvements with graceful shutdown Auth & Middleware: - Enhanced middleware with cache metadata injection - Improved request state handling for cache source tracking Development: - Updated start-dev.sh with better error handling - Added TELEGRAM_EMAIL_AUTH_PLAN.md documentation - Updated requirements.txt with aiosqlite for async SQLite Performance: - L1 cache provides <1ms response for hot data - L2 cache provides ~5ms response for warm data - Database queries only for cold data or cache misses - Cache hit rates tracked and displayed in real-time 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com>
58 KiB
Plan: Autentificare Telegram Bot prin Email + Parolă (2FA)
Data: 2025-11-07 Autor: Claude Code Status: Planificat - Neîmplementat
🎯 Obiectiv
Implementare autentificare alternativă email + parolă pentru Telegram Bot, în paralel cu metoda actuală (cod din web app). Ambele metode vor fi disponibile pentru toți utilizatorii.
Cerințe cheie:
- ✅ Minimal invaziv - nu modifica logica existentă
- ✅ Ambele metode de autentificare în paralel
- ✅2FA real: email possession + parolă Oracle
- ✅ Simplu de testat cu un singur utilizator (mmarius28@gmail.com)
📊 Context: Sistemul Actual
Metoda Actuală de Autentificare (rămâne neschimbată)
1. User se autentifică în web app (username + parolă)
2. User cere linking Telegram → backend generează cod 8-char
3. Backend salvează cod în telegram-bot via POST /internal/save-code
4. User trimite /start ABC123XY în Telegram
5. Bot validează codul și auto-linkează (fără parolă din nou)
6. User autentificat în bot
Caracteristici:
- Nu necesită email
- Necesită acces la web app
- Auto-linking fără re-introducere parolă
- Cod expiră în 15 minute
🔄 Noul Flux de Autentificare (Email + Parolă)
Flow Complet
┌─────────────────────────────────────────────────────────────┐
│ 1. User: /login SAU apasă buton "🔐 Login cu Email" │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ 2. Bot: "📧 Introdu adresa ta de email Oracle:" │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ 3. User: mmarius28@gmail.com │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ 4. Bot: │
│ - Verifică email în Oracle UTILIZATORI table │
│ - Generează cod 6-digit random │
│ - Salvează în email_auth_codes (expiry 5 min) │
│ - Trimite email SMTP: "Codul tău: 123456" │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ 5. Bot: "✉️ Cod trimis pe email. Introdu codul (5 min):" │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ 6. User: 123456 │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ 7. Bot: │
│ - Validează cod în email_auth_codes │
│ - Verifică expiry (5 minute) │
│ - Marchează cod ca "used" │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ 8. Bot: "🔐 Introdu parola ta Oracle:" │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ 9. User: parola_mea (mesaj va fi șters automat) │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ 10. Bot → Backend: │
│ POST /api/telegram/auth/login-with-email │
│ { │
│ "email": "mmarius28@gmail.com", │
│ "password": "parola_mea", │
│ "telegram_user_id": 123456789 │
│ } │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ 11. Backend: │
│ - Găsește username din email în UTILIZATORI │
│ - Verifică parolă: pack_drepturi.verificautilizator() │
│ - Generează JWT tokens (access + refresh) │
│ - Returnează tokens + user data │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ 12. Bot: │
│ - Salvează JWT în telegram_users table │
│ - Linkează telegram_user_id cu oracle_username │
│ - Șterge mesajele cu parolă │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ 13. Bot: "✅ Autentificat cu succes! Folosește /help" │
└─────────────────────────────────────────────────────────────┘
Conversation States (ConversationHandler)
AWAITING_EMAIL = 1 # Așteaptă email de la user
AWAITING_CODE = 2 # Așteaptă cod din email
AWAITING_PASSWORD = 3 # Așteaptă parolă Oracle
📦 Componente Noi (Arhitectură)
1. Email Service (SMTP Client)
Fișier NOU: reports-app/telegram-bot/app/utils/email_service.py
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
import os
class EmailService:
def __init__(self):
self.smtp_host = os.getenv("SMTP_HOST", "mail.romfast.ro")
self.smtp_port = int(os.getenv("SMTP_PORT", "587"))
self.smtp_user = os.getenv("SMTP_USER", "ups@romfast.ro")
self.smtp_password = os.getenv("SMTP_PASSWORD", "#Ups2020#")
self.from_email = os.getenv("SMTP_FROM_EMAIL", "ups@romfast.ro")
self.from_name = os.getenv("SMTP_FROM_NAME", "ROA2WEB")
async def send_auth_code(self, to_email: str, code: str, username: str) -> bool:
"""
Trimite cod de autentificare pe email
Returns: True dacă email trimis cu succes
"""
subject = "Codul tău de autentificare ROA2WEB"
html_body = f"""
<html>
<body style="font-family: Arial, sans-serif;">
<h2>🔐 Autentificare Telegram Bot</h2>
<p>Salut <strong>{username}</strong>,</p>
<p>Codul tău de autentificare este:</p>
<h1 style="background-color: #f0f0f0; padding: 20px; text-align: center; letter-spacing: 5px;">
{code}
</h1>
<p><strong>Codul expiră în 5 minute.</strong></p>
<p>Dacă nu ai solicitat acest cod, te rugăm să ignori acest email.</p>
<hr>
<p style="color: #666; font-size: 12px;">
ROA2WEB - ERP Reports Application
</p>
</body>
</html>
"""
# Implementare SMTP cu error handling
Funcții:
send_auth_code(email, code, username)- trimite cod pe email_send_email(to, subject, html_body)- helper SMTP generic- Error handling cu retry logic (3 încercări)
2. Tabela SQLite Nouă: email_auth_codes
Locație: reports-app/telegram-bot/app/db/database.py
Schema SQL:
CREATE TABLE IF NOT EXISTS email_auth_codes (
code TEXT PRIMARY KEY, -- 6-digit numeric code (e.g., "123456")
email TEXT NOT NULL, -- Email utilizator din Oracle
oracle_username TEXT NOT NULL, -- Username Oracle asociat
telegram_user_id INTEGER NOT NULL, -- Telegram user ID care a solicitat
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
expires_at TIMESTAMP NOT NULL, -- Current time + 5 minute
used BOOLEAN DEFAULT 0, -- 0 = nefolosit, 1 = folosit
used_at TIMESTAMP, -- Timestamp când a fost folosit
-- Index pentru query performance
INDEX idx_email (email),
INDEX idx_expires_at (expires_at),
INDEX idx_telegram_user_id (telegram_user_id)
);
Operații CRUD (în app/db/operations.py):
async def create_email_auth_code(code: str, email: str, username: str, telegram_user_id: int) -> bool
async def get_email_auth_code(code: str) -> Optional[Dict]
async def mark_email_code_used(code: str) -> bool
async def delete_expired_email_codes() -> int
async def get_pending_email_code_for_user(telegram_user_id: int) -> Optional[Dict]
Caracteristici:
- Cod 6-digit random numeric (000000 - 999999)
- Expirare 5 minute
- One-time use (marcat ca
used=1) - Auto-cleanup de către job-ul existent (hourly)
3. Backend Endpoint NOU: POST /api/telegram/auth/login-with-email
Locație: reports-app/backend/app/routers/telegram.py
Request Schema:
class TelegramEmailLoginRequest(BaseModel):
email: EmailStr
password: str
telegram_user_id: int
class TelegramEmailLoginResponse(BaseModel):
success: bool
access_token: str
refresh_token: str
token_type: str = "bearer"
user_id: int
username: str
companies: List[CompanyInfo]
message: str
Endpoint Logic:
@router.post("/auth/login-with-email", response_model=TelegramEmailLoginResponse)
async def login_with_email(request: TelegramEmailLoginRequest):
"""
Autentificare Telegram prin email + parolă
Flow:
1. Caută username în Oracle UTILIZATORI by email
2. Verifică parolă prin pack_drepturi.verificautilizator(username, password)
3. Dacă valid: generează JWT tokens
4. Returnează tokens + user data
"""
async with oracle_pool.get_connection() as connection:
# 1. Find username by email
cursor = connection.cursor()
cursor.execute("""
SELECT ID_UTIL, UTILIZATOR
FROM CONTAFIN_ORACLE.UTILIZATORI
WHERE UPPER(EMAIL) = UPPER(:email)
""", {"email": request.email})
user_row = cursor.fetchone()
if not user_row:
raise HTTPException(status_code=404, detail="Email not found")
user_id, username = user_row
# 2. Verify password via stored procedure
cursor.execute("""
SELECT pack_drepturi.verificautilizator(:username, :password)
FROM DUAL
""", {"username": username, "password": request.password})
result = cursor.fetchone()[0]
if result == -1:
raise HTTPException(status_code=401, detail="Invalid password")
# 3. Get user companies
companies = get_user_companies(user_id, connection)
# 4. Generate JWT tokens
access_token = create_access_token(...)
refresh_token = create_refresh_token(...)
return TelegramEmailLoginResponse(
success=True,
access_token=access_token,
refresh_token=refresh_token,
user_id=user_id,
username=username,
companies=companies,
message="Authentication successful"
)
Securitate:
- Rate limiting: 5 requests / 5 minutes per telegram_user_id
- Password validation prin Oracle stored procedure (nu stocăm parole)
- HTTPS required în producție
- Logging pentru failed attempts
4. Bot Handlers NOI: /login + ConversationHandler
Fișier NOU: reports-app/telegram-bot/app/bot/email_handlers.py
Command: /login
from telegram import Update, InlineKeyboardButton, InlineKeyboardMarkup
from telegram.ext import ContextTypes, ConversationHandler, CommandHandler, MessageHandler, filters
# Conversation states
AWAITING_EMAIL, AWAITING_CODE, AWAITING_PASSWORD = range(3)
async def login_command(update: Update, context: ContextTypes.DEFAULT_TYPE):
"""
Handler pentru /login command
Inițiază conversation pentru email auth
"""
user = update.effective_user
# Check dacă e deja autentificat
if await is_user_authenticated(user.id):
await update.message.reply_text(
"✅ Ești deja autentificat!\n"
"Folosește /unlink pentru a te deautentifica."
)
return ConversationHandler.END
# Afișează metode de autentificare
keyboard = [
[InlineKeyboardButton("🔐 Login cu Email", callback_data="email_login")],
[InlineKeyboardButton("🌐 Login din Web App", callback_data="web_login")],
[InlineKeyboardButton("❌ Anulează", callback_data="cancel")]
]
reply_markup = InlineKeyboardMarkup(keyboard)
await update.message.reply_text(
"🔑 Alege metoda de autentificare:\n\n"
"📧 **Email + Parolă**: Primești cod pe email, apoi introduci parola\n"
"🌐 **Web App**: Generează cod din aplicația web",
reply_markup=reply_markup
)
return AWAITING_EMAIL
async def email_login_callback(update: Update, context: ContextTypes.DEFAULT_TYPE):
"""Callback pentru butonul 'Login cu Email'"""
query = update.callback_query
await query.answer()
await query.edit_message_text(
"📧 **Autentificare prin Email**\n\n"
"Te rugăm să introduci adresa ta de email Oracle:\n"
"(Exemplu: nume.prenume@companie.ro)"
)
return AWAITING_EMAIL
async def receive_email(update: Update, context: ContextTypes.DEFAULT_TYPE):
"""
Handler pentru primirea email-ului
"""
email = update.message.text.strip()
user_id = update.effective_user.id
# Validare format email
if not is_valid_email(email):
await update.message.reply_text(
"❌ Email invalid. Te rugăm să introduci o adresă de email validă."
)
return AWAITING_EMAIL
# Verifică email în Oracle + trimite cod
try:
# 1. Verifică email în Oracle UTILIZATORI
username = await verify_email_in_oracle(email)
if not username:
await update.message.reply_text(
"❌ Email-ul nu este înregistrat în sistem.\n"
"Contactează administratorul pentru a-ți adăuga email-ul."
)
return ConversationHandler.END
# 2. Generează cod 6-digit
code = generate_6digit_code()
# 3. Salvează în email_auth_codes
await save_email_auth_code(
code=code,
email=email,
username=username,
telegram_user_id=user_id
)
# 4. Trimite email
email_sent = await email_service.send_auth_code(email, code, username)
if not email_sent:
await update.message.reply_text(
"❌ Eroare la trimiterea email-ului. Te rugăm să încerci din nou."
)
return ConversationHandler.END
# 5. Salvează email în context
context.user_data['pending_email'] = email
context.user_data['pending_username'] = username
await update.message.reply_text(
f"✉️ **Cod trimis pe {email}**\n\n"
"Verifică inbox-ul (și spam) și introdu codul de 6 cifre.\n"
"⏱ Codul expiră în **5 minute**.\n\n"
"Scrie /cancel pentru a anula."
)
return AWAITING_CODE
except Exception as e:
logger.error(f"Email login error: {e}")
await update.message.reply_text(
"❌ Eroare internă. Te rugăm să încerci din nou mai târziu."
)
return ConversationHandler.END
async def receive_code(update: Update, context: ContextTypes.DEFAULT_TYPE):
"""
Handler pentru primirea codului din email
"""
code = update.message.text.strip()
user_id = update.effective_user.id
# Validare format cod (6 digits)
if not code.isdigit() or len(code) != 6:
await update.message.reply_text(
"❌ Cod invalid. Introdu cele 6 cifre din email."
)
return AWAITING_CODE
# Verifică cod în DB
try:
code_data = await get_email_auth_code(code)
if not code_data:
await update.message.reply_text(
"❌ Cod invalid sau expirat. Te rugăm să reîncepi cu /login"
)
return ConversationHandler.END
# Verificări
if code_data['used']:
await update.message.reply_text(
"❌ Cod deja folosit. Te rugăm să reîncepi cu /login"
)
return ConversationHandler.END
if code_data['telegram_user_id'] != user_id:
await update.message.reply_text(
"❌ Codul nu îți aparține."
)
return ConversationHandler.END
if datetime.now() > code_data['expires_at']:
await update.message.reply_text(
"❌ Codul a expirat. Te rugăm să reîncepi cu /login"
)
return ConversationHandler.END
# Marchează cod ca folosit
await mark_email_code_used(code)
# Salvează username în context
context.user_data['verified_username'] = code_data['oracle_username']
context.user_data['verified_email'] = code_data['email']
await update.message.reply_text(
"✅ **Cod validat cu succes!**\n\n"
"🔐 Acum introdu parola ta Oracle:\n"
"(Parola va fi ștearsă automat după verificare)"
)
return AWAITING_PASSWORD
except Exception as e:
logger.error(f"Code validation error: {e}")
await update.message.reply_text(
"❌ Eroare la validarea codului. Te rugăm să încerci din nou."
)
return ConversationHandler.END
async def receive_password(update: Update, context: ContextTypes.DEFAULT_TYPE):
"""
Handler pentru primirea parolei
"""
password = update.message.text.strip()
user_id = update.effective_user.id
# Șterge imediat mesajul cu parola
try:
await update.message.delete()
except:
pass
username = context.user_data.get('verified_username')
email = context.user_data.get('verified_email')
if not username or not email:
await update.effective_chat.send_message(
"❌ Sesiune expirată. Te rugăm să reîncepi cu /login"
)
return ConversationHandler.END
# Trimite loading message
loading_msg = await update.effective_chat.send_message(
"⏳ Verificare credențiale..."
)
try:
# Call backend endpoint
response = await backend_client.login_with_email(
email=email,
password=password,
telegram_user_id=user_id
)
if not response['success']:
await loading_msg.edit_text(
"❌ Parolă incorectă. Te rugăm să reîncepi cu /login"
)
return ConversationHandler.END
# Salvează user în telegram_users
await save_telegram_user(
telegram_user_id=user_id,
username=update.effective_user.username,
first_name=update.effective_user.first_name,
last_name=update.effective_user.last_name,
oracle_username=response['username'],
jwt_token=response['access_token'],
jwt_refresh_token=response['refresh_token']
)
# Success message
companies_list = "\n".join([f"• {c['name']}" for c in response['companies'][:5]])
await loading_msg.edit_text(
f"✅ **Autentificat cu succes!**\n\n"
f"👤 Utilizator: **{response['username']}**\n"
f"🏢 Companii disponibile: {len(response['companies'])}\n\n"
f"{companies_list}\n\n"
f"Folosește /help pentru comenzi disponibile."
)
# Clear context
context.user_data.clear()
return ConversationHandler.END
except Exception as e:
logger.error(f"Password verification error: {e}")
await loading_msg.edit_text(
"❌ Eroare la autentificare. Te rugăm să încerci din nou cu /login"
)
return ConversationHandler.END
async def cancel_login(update: Update, context: ContextTypes.DEFAULT_TYPE):
"""Cancel conversation"""
context.user_data.clear()
await update.message.reply_text("❌ Autentificare anulată.")
return ConversationHandler.END
# ConversationHandler setup
email_login_handler = ConversationHandler(
entry_points=[
CommandHandler('login', login_command),
CallbackQueryHandler(email_login_callback, pattern='^email_login$')
],
states={
AWAITING_EMAIL: [MessageHandler(filters.TEXT & ~filters.COMMAND, receive_email)],
AWAITING_CODE: [MessageHandler(filters.TEXT & ~filters.COMMAND, receive_code)],
AWAITING_PASSWORD: [MessageHandler(filters.TEXT & ~filters.COMMAND, receive_password)],
},
fallbacks=[
CommandHandler('cancel', cancel_login),
CallbackQueryHandler(cancel_login, pattern='^cancel$')
],
conversation_timeout=300 # 5 minute timeout
)
Handler Registration (în app/bot/handlers.py):
from app.bot.email_handlers import email_login_handler
def setup_handlers(application):
# ... existing handlers ...
# Email login handler
application.add_handler(email_login_handler)
5. Backend API Client Method
Locație: reports-app/telegram-bot/app/api/client.py
class BackendAPIClient:
# ... existing methods ...
async def login_with_email(
self,
email: str,
password: str,
telegram_user_id: int
) -> dict:
"""
Login via email + password
"""
try:
response = await self.client.post(
f"{self.base_url}/api/telegram/auth/login-with-email",
json={
"email": email,
"password": password,
"telegram_user_id": telegram_user_id
}
)
response.raise_for_status()
return response.json()
except httpx.HTTPError as e:
logger.error(f"Email login failed: {e}")
raise
🔧 Environment Variables
Backend .env (nu necesită modificări - doar pentru referință)
# Existente (nu modificăm)
ORACLE_USER=CONTAFIN_ORACLE
ORACLE_PASSWORD=your_password
ORACLE_HOST=localhost
ORACLE_PORT=1526
ORACLE_SID=ROA
JWT_SECRET_KEY=your_secret_key
JWT_ALGORITHM=HS256
JWT_EXPIRE_MINUTES=30
Telegram Bot .env (ADAUGĂ ACESTEA)
# Existing
TELEGRAM_BOT_TOKEN=your_bot_token
BACKEND_URL=http://localhost:8000
DATABASE_PATH=data/telegram_bot.db
# NEW: SMTP Configuration
SMTP_HOST=mail.romfast.ro
SMTP_PORT=587
SMTP_USER=ups@romfast.ro
SMTP_PASSWORD=#Ups2020#
SMTP_FROM_EMAIL=ups@romfast.ro
SMTP_FROM_NAME=ROA2WEB
SMTP_USE_TLS=true
# NEW: Email Auth Settings
EMAIL_CODE_EXPIRY_MINUTES=5
EMAIL_CODE_LENGTH=6
MAX_EMAIL_ATTEMPTS_PER_HOUR=3
🔒 Securitate & Validări
1. Email Validation
import re
def is_valid_email(email: str) -> bool:
"""Validare format email"""
pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
return bool(re.match(pattern, email))
async def verify_email_in_oracle(email: str) -> Optional[str]:
"""
Verifică dacă email există în Oracle UTILIZATORI
Returns: username dacă există, None altfel
"""
async with oracle_pool.get_connection() as connection:
cursor = connection.cursor()
cursor.execute("""
SELECT UTILIZATOR
FROM CONTAFIN_ORACLE.UTILIZATORI
WHERE UPPER(EMAIL) = UPPER(:email)
AND ACTIV = 1
""", {"email": email})
row = cursor.fetchone()
return row[0] if row else None
2. Code Generation & Storage
import random
import string
from datetime import datetime, timedelta
def generate_6digit_code() -> str:
"""Generează cod random 6-digit"""
return ''.join(random.choices(string.digits, k=6))
async def save_email_auth_code(
code: str,
email: str,
username: str,
telegram_user_id: int
) -> bool:
"""Salvează cod în DB cu expiry 5 minute"""
expires_at = datetime.now() + timedelta(minutes=5)
async with get_db_connection() as db:
await db.execute("""
INSERT INTO email_auth_codes
(code, email, oracle_username, telegram_user_id, expires_at)
VALUES (?, ?, ?, ?, ?)
""", (code, email, username, telegram_user_id, expires_at))
await db.commit()
return True
3. Rate Limiting
from collections import defaultdict
from datetime import datetime, timedelta
# In-memory rate limiter (sau Redis în producție)
email_attempts = defaultdict(list)
async def check_rate_limit(identifier: str, max_attempts: int = 3, window_minutes: int = 60) -> bool:
"""
Rate limiting pentru email requests
identifier poate fi: email sau telegram_user_id
"""
now = datetime.now()
cutoff = now - timedelta(minutes=window_minutes)
# Curăță attempts vechi
email_attempts[identifier] = [
attempt for attempt in email_attempts[identifier]
if attempt > cutoff
]
# Verifică limita
if len(email_attempts[identifier]) >= max_attempts:
return False # Rate limit exceeded
# Adaugă attempt nou
email_attempts[identifier].append(now)
return True # OK to proceed
4. Password Security
async def receive_password(update: Update, context: ContextTypes.DEFAULT_TYPE):
"""Handler cu securitate mărite pentru parolă"""
password = update.message.text.strip()
# 1. Șterge IMEDIAT mesajul cu parola
try:
await update.message.delete()
except Exception as e:
logger.warning(f"Could not delete password message: {e}")
# 2. NU loga parola niciodată
logger.info(f"Password received for user {update.effective_user.id}")
# 3. Verifică parola prin backend (Oracle)
# ... (vezi cod de mai sus)
# 4. Șterge parola din memorie
del password
5. Auto-Cleanup Job
async def cleanup_expired_codes():
"""Job periodic pentru curățarea codurilor expirate"""
while True:
try:
async with get_db_connection() as db:
# Șterge email codes expirate
await db.execute("""
DELETE FROM email_auth_codes
WHERE expires_at < ?
OR (used = 1 AND used_at < ?)
""", (
datetime.now(),
datetime.now() - timedelta(days=1) # Cleanup used codes după 1 zi
))
await db.commit()
deleted = db.total_changes
logger.info(f"Cleaned up {deleted} expired email auth codes")
except Exception as e:
logger.error(f"Cleanup job error: {e}")
# Run every hour
await asyncio.sleep(3600)
# Start cleanup job în main.py
asyncio.create_task(cleanup_expired_codes())
📝 Fișiere Modificate/Create
CREATE (6 fișiere noi):
-
reports-app/telegram-bot/app/utils/email_service.py- SMTP client pentru trimitere email-uri
- Funcție:
send_auth_code(email, code, username) - Error handling + retry logic
-
reports-app/telegram-bot/app/auth/email_auth.py- Logică autentificare email
- Funcții:
verify_email_in_oracle(),generate_6digit_code(),check_rate_limit()
-
reports-app/telegram-bot/app/bot/email_handlers.py- ConversationHandler pentru
/login - States: AWAITING_EMAIL → AWAITING_CODE → AWAITING_PASSWORD
- Handlers:
receive_email(),receive_code(),receive_password()
- ConversationHandler pentru
-
reports-app/backend/app/schemas/telegram_email_auth.py- Pydantic schemas pentru email auth
TelegramEmailLoginRequest,TelegramEmailLoginResponse
-
reports-app/telegram-bot/tests/test_email_auth.py- Unit tests pentru email auth flow
- Mock SMTP, Oracle, backend API
-
TELEGRAM_EMAIL_AUTH_PLAN.md- Acest document (plan detaliat)
MODIFY (6 fișiere existente):
-
reports-app/telegram-bot/app/db/database.py- Adaugă: Schema tabela
email_auth_codes - Linie: ~40-60 (în funcția
init_database())
- Adaugă: Schema tabela
-
reports-app/telegram-bot/app/db/operations.py- Adaugă: CRUD operations pentru
email_auth_codes - Funcții noi:
create_email_auth_code(),get_email_auth_code(),mark_email_code_used(), etc. - Linii: ~200-300 (la final de fișier)
- Adaugă: CRUD operations pentru
-
reports-app/telegram-bot/app/bot/handlers.py- Adaugă: Import și register
email_login_handler - Linie: ~10 (import), ~150 (register în
setup_handlers()) - Modificare: Update
/startmessage pentru a menționa/login
- Adaugă: Import și register
-
reports-app/backend/app/routers/telegram.py- Adaugă: Endpoint
POST /auth/login-with-email - Linii: ~200-300 (la final de fișier)
- Import: Adaugă schema
TelegramEmailLoginRequest/Response
- Adaugă: Endpoint
-
reports-app/telegram-bot/app/api/client.py- Adaugă: Method
login_with_email(email, password, telegram_user_id) - Linii: ~150-180 (în clasa
BackendAPIClient)
- Adaugă: Method
-
reports-app/telegram-bot/.env- Adaugă: SMTP configuration variables (vezi secțiunea Environment Variables)
NO TOUCH (rămân 100% neschimbate):
- ✅ Fluxul actual de linking (web app → cod → /start)
- ✅ Tabele existente:
telegram_users,telegram_auth_codes,telegram_sessions - ✅ Endpoint-uri existente:
/generate-code,/verify-user,/refresh-token - ✅ Handler-e existente:
/start [code],/companies,/dashboard,/facturi, etc. - ✅ Toate comenzile Telegram existente (funcționalitate păstrată 100%)
🧪 Testing Strategy
1. Unit Tests
Fișier: reports-app/telegram-bot/tests/test_email_auth.py
import pytest
from unittest.mock import AsyncMock, patch
from app.auth.email_auth import verify_email_in_oracle, generate_6digit_code, check_rate_limit
from app.utils.email_service import EmailService
@pytest.mark.asyncio
async def test_generate_6digit_code():
"""Test generare cod 6-digit"""
code = generate_6digit_code()
assert len(code) == 6
assert code.isdigit()
@pytest.mark.asyncio
async def test_verify_email_in_oracle_success():
"""Test verificare email valid în Oracle"""
with patch('app.auth.email_auth.oracle_pool') as mock_pool:
# Mock Oracle response
mock_cursor = AsyncMock()
mock_cursor.fetchone.return_value = ("test_user",)
username = await verify_email_in_oracle("test@example.com")
assert username == "test_user"
@pytest.mark.asyncio
async def test_verify_email_not_found():
"""Test email inexistent în Oracle"""
with patch('app.auth.email_auth.oracle_pool') as mock_pool:
mock_cursor = AsyncMock()
mock_cursor.fetchone.return_value = None
username = await verify_email_in_oracle("notfound@example.com")
assert username is None
@pytest.mark.asyncio
async def test_rate_limiting():
"""Test rate limiting pentru email requests"""
identifier = "test_user_123"
# First 3 attempts should pass
for i in range(3):
result = await check_rate_limit(identifier, max_attempts=3, window_minutes=60)
assert result is True
# 4th attempt should fail
result = await check_rate_limit(identifier, max_attempts=3, window_minutes=60)
assert result is False
@pytest.mark.asyncio
async def test_email_service_send_code():
"""Test trimitere email cu cod"""
email_service = EmailService()
with patch('app.utils.email_service.smtplib.SMTP') as mock_smtp:
result = await email_service.send_auth_code(
to_email="test@example.com",
code="123456",
username="test_user"
)
assert result is True
assert mock_smtp.called
2. Integration Tests
@pytest.mark.asyncio
async def test_full_email_auth_flow():
"""Test complet: email → cod → parolă → JWT"""
# 1. Request email code
email = "mmarius28@gmail.com"
telegram_user_id = 123456789
with patch('app.auth.email_auth.verify_email_in_oracle') as mock_verify:
mock_verify.return_value = "marius_user"
# Generate code
code = generate_6digit_code()
await save_email_auth_code(code, email, "marius_user", telegram_user_id)
# 2. Validate code
code_data = await get_email_auth_code(code)
assert code_data is not None
assert code_data['email'] == email
assert code_data['used'] is False
# 3. Mock backend login
with patch('app.api.client.BackendAPIClient.login_with_email') as mock_login:
mock_login.return_value = {
'success': True,
'access_token': 'test_jwt_token',
'refresh_token': 'test_refresh_token',
'username': 'marius_user',
'user_id': 42,
'companies': []
}
# Verify password
response = await backend_client.login_with_email(
email=email,
password="test_password",
telegram_user_id=telegram_user_id
)
assert response['success'] is True
assert 'access_token' in response
3. Manual Testing Checklist
Fișier: reports-app/telegram-bot/tests/MANUAL_EMAIL_AUTH_TESTING.md
# Manual Testing Checklist - Email Authentication
## Prerequisites
- [ ] Backend running on port 8000
- [ ] Telegram bot running
- [ ] SMTP credentials configured in .env
- [ ] Test email: mmarius28@gmail.com exists in Oracle UTILIZATORI table
## Test Cases
### 1. Successful Authentication Flow
- [ ] Start bot: `/start`
- [ ] Type: `/login`
- [ ] Select "🔐 Login cu Email"
- [ ] Enter email: `mmarius28@gmail.com`
- [ ] Verify email received with 6-digit code
- [ ] Enter code from email
- [ ] Enter Oracle password
- [ ] Verify success message with companies list
- [ ] Test command: `/companies` (should work)
### 2. Invalid Email
- [ ] `/login`
- [ ] Enter email: `nonexistent@example.com`
- [ ] Verify error message: "Email-ul nu este înregistrat"
### 3. Expired Code
- [ ] `/login` → enter valid email
- [ ] Wait 6 minutes (code expiry = 5 min)
- [ ] Enter code
- [ ] Verify error: "Cod expirat"
### 4. Wrong Code
- [ ] `/login` → enter valid email
- [ ] Enter wrong code: `999999`
- [ ] Verify error: "Cod invalid"
### 5. Wrong Password
- [ ] `/login` → enter email → enter valid code
- [ ] Enter wrong password
- [ ] Verify error: "Parolă incorectă"
### 6. Rate Limiting
- [ ] `/login` → enter email (attempt 1)
- [ ] `/cancel`
- [ ] `/login` → enter email (attempt 2)
- [ ] `/cancel`
- [ ] `/login` → enter email (attempt 3)
- [ ] `/cancel`
- [ ] `/login` → enter email (attempt 4)
- [ ] Verify error: "Prea multe încercări. Încearcă în 60 minute"
### 7. Password Message Deletion
- [ ] `/login` → enter email → enter code
- [ ] Enter password
- [ ] Verify password message is deleted immediately
- [ ] Check chat history - password should not be visible
### 8. Cancel Flow
- [ ] `/login`
- [ ] `/cancel` (should cancel and clear state)
### 9. Already Authenticated
- [ ] Complete successful login
- [ ] Type `/login` again
- [ ] Verify message: "Ești deja autentificat"
### 10. Parallel Method (Web App Linking) Still Works
- [ ] Login to web app: http://localhost:3000
- [ ] Generate Telegram linking code
- [ ] Use `/start ABC123XY` in Telegram
- [ ] Verify linking works as before (OLD method)
### 11. Database Cleanup
- [ ] Create expired codes (manually set expires_at in past)
- [ ] Wait for hourly cleanup job
- [ ] Verify expired codes deleted from `email_auth_codes` table
📊 Estimare Efort & Timeline
Breakdown Detaliat
| Componentă | Efort (ore) | Detalii |
|---|---|---|
| Backend | ||
→ Endpoint /login-with-email |
1.5h | Logic + Oracle queries + JWT |
| → Schema Pydantic | 0.5h | Request/Response models |
| → Rate limiting | 0.5h | Middleware sau decorator |
| → Testing backend | 0.5h | Unit tests endpoint |
| Telegram Bot | ||
| → Email service (SMTP) | 1.5h | Client SMTP + templates + retry |
| → DB schema + operations | 1h | Tabela nouă + CRUD |
| → Email auth logic | 1h | Verificare email, cod generation |
| → ConversationHandler | 2h | States + handlers + callbacks |
| → API client method | 0.5h | Method nou în BackendAPIClient |
| → Testing bot | 1h | Unit + integration tests |
| Integration | ||
| → End-to-end testing | 1h | Flow complet manual |
| → Bug fixes | 1h | Edge cases |
| Documentation | ||
| → Update README | 0.5h | Secțiune nouă pentru email auth |
| → Update TELEGRAM_COMMANDS.md | 0.5h | Documentare /login |
| TOTAL | ~13h | ~2 zile lucru (6-7h/zi) |
Timeline Recomandat
Ziua 1 (6-7h):
- Setup environment (SMTP config) - 0.5h
- Backend: Endpoint + schema - 2h
- Telegram Bot: Email service - 1.5h
- Telegram Bot: DB schema + operations - 1h
- Testing preliminar - 1h
Ziua 2 (6-7h):
- Telegram Bot: ConversationHandler - 2h
- Email auth logic - 1h
- Integration - 1h
- End-to-end testing - 1.5h
- Documentation - 0.5h
- Bug fixes - 1h
✅ Avantaje Plan
| Avantaj | Detalii |
|---|---|
| ✅ Minimal Invaziv | 0 modificări la logica existentă, doar adăugiri |
| ✅ Ambele Metode | Users pot alege: email+parolă SAU web app linking |
| ✅ Backward Compatible | Utilizatori fără email folosesc metoda actuală |
| ✅ 2FA Real | Email possession (cod) + parolă Oracle = 2 factori |
| ✅ Simplu de Testat | Un singur utilizator cu email (mmarius28@gmail.com) |
| ✅ Extensibil | Ușor de activat pentru alți useri când adaugi email-uri |
| ✅ Securitate Mărite | Rate limiting, code expiry, password verification în Oracle |
| ✅ Auto-Cleanup | Job existent curăță automat coduri expirate |
| ✅ User-Friendly | Conversation flow natural în Telegram |
| ✅ Error Handling | Mesaje clare pentru fiecare caz de eroare |
🚀 Ordine Implementare (Step-by-Step)
Step 1: Environment Setup (15 min)
- Adaugă SMTP credentials în
.env:
cd reports-app/telegram-bot/
echo "SMTP_HOST=mail.romfast.ro" >> .env
echo "SMTP_PORT=587" >> .env
echo "SMTP_USER=ups@romfast.ro" >> .env
echo "SMTP_PASSWORD=#Ups2020#" >> .env
echo "SMTP_FROM_EMAIL=ups@romfast.ro" >> .env
echo "SMTP_FROM_NAME=ROA2WEB" >> .env
- Install dependencies:
pip install aiosmtplib # Async SMTP client
Step 2: Backend - Endpoint (2h)
- Create schema:
backend/app/schemas/telegram_email_auth.py - Add endpoint în
backend/app/routers/telegram.py - Test cu Postman/curl
Step 3: Telegram Bot - Infrastructure (2.5h)
- Create
app/utils/email_service.py(SMTP client) - Update
app/db/database.py(addemail_auth_codestable) - Update
app/db/operations.py(CRUD operations) - Test DB operations
Step 4: Telegram Bot - Auth Logic (1h)
- Create
app/auth/email_auth.py - Implement:
verify_email_in_oracle(),generate_6digit_code(),check_rate_limit() - Unit tests
Step 5: Telegram Bot - Handlers (2h)
- Create
app/bot/email_handlers.py - Implement ConversationHandler
- Register în
app/bot/handlers.py
Step 6: Backend API Client (30 min)
- Add
login_with_email()method înapp/api/client.py
Step 7: Integration Testing (1h)
- Start backend + bot
- Test flow complet cu mmarius28@gmail.com
- Fix bugs
Step 8: Comprehensive Testing (1.5h)
- Run all test cases from checklist
- Test edge cases
- Verify both methods work in parallel
Step 9: Documentation (30 min)
- Update README.md
- Update TELEGRAM_COMMANDS.md
- Create MANUAL_EMAIL_AUTH_TESTING.md
🐛 Troubleshooting Guide
Issue: Email nu ajunge
Cauze posibile:
- SMTP credentials incorecte
- Port blocat (587)
- Email în spam
Debugging:
# Test SMTP connection
import smtplib
try:
server = smtplib.SMTP('mail.romfast.ro', 587)
server.starttls()
server.login('ups@romfast.ro', '#Ups2020#')
print("✅ SMTP connection OK")
server.quit()
except Exception as e:
print(f"❌ SMTP error: {e}")
Issue: Cod invalid/expirat
Debugging:
-- Check code in DB
SELECT * FROM email_auth_codes WHERE code = '123456';
-- Check expiry
SELECT code, expires_at,
datetime('now') as now,
(julianday(expires_at) - julianday('now')) * 24 * 60 as minutes_remaining
FROM email_auth_codes
WHERE code = '123456';
Issue: Parolă incorectă (dar știu că e corectă)
Cauze posibile:
- Username găsit greșit din email
- Oracle stored procedure error
Debugging:
# Test Oracle auth direct
async with oracle_pool.get_connection() as connection:
cursor = connection.cursor()
# 1. Check email → username mapping
cursor.execute("""
SELECT UTILIZATOR, EMAIL
FROM CONTAFIN_ORACLE.UTILIZATORI
WHERE UPPER(EMAIL) = UPPER('mmarius28@gmail.com')
""")
print(cursor.fetchone())
# 2. Test stored procedure
cursor.execute("""
SELECT pack_drepturi.verificautilizator('marius_user', 'parola_mea')
FROM DUAL
""")
result = cursor.fetchone()[0]
print(f"Auth result: {result}") # -1 = fail, user_id = success
Issue: Rate limiting prea restrictiv
Quick fix:
# În email_auth.py, increase limits
MAX_EMAIL_ATTEMPTS = 5 # was 3
RATE_LIMIT_WINDOW_MINUTES = 30 # was 60
📚 Additional Documentation
Email Template (HTML)
<!DOCTYPE html>
<html>
<head>
<style>
body { font-family: Arial, sans-serif; line-height: 1.6; color: #333; }
.container { max-width: 600px; margin: 0 auto; padding: 20px; }
.header { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 30px; text-align: center; border-radius: 10px 10px 0 0; }
.code-box { background-color: #f4f4f4; border: 2px solid #667eea; padding: 30px; margin: 20px 0; text-align: center; border-radius: 10px; }
.code { font-size: 36px; font-weight: bold; letter-spacing: 10px; color: #667eea; font-family: 'Courier New', monospace; }
.content { padding: 20px; background: white; }
.warning { background-color: #fff3cd; border-left: 4px solid #ffc107; padding: 15px; margin: 20px 0; }
.footer { text-align: center; color: #666; font-size: 12px; padding: 20px; border-top: 1px solid #ddd; }
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>🔐 ROA2WEB</h1>
<p>Autentificare Telegram Bot</p>
</div>
<div class="content">
<p>Salut <strong>{{username}}</strong>,</p>
<p>Ai solicitat autentificarea în aplicația ROA2WEB Telegram Bot.</p>
<div class="code-box">
<p style="margin: 0; font-size: 14px; color: #666;">Codul tău de autentificare:</p>
<p class="code">{{code}}</p>
</div>
<div class="warning">
<strong>⏱️ Important:</strong> Acest cod expiră în <strong>5 minute</strong>.
</div>
<p>Introdu acest cod în conversația cu Telegram Bot, apoi vei fi solicitat să introduci parola.</p>
<p style="margin-top: 30px; padding-top: 20px; border-top: 1px solid #ddd;">
<strong>Nu ai solicitat acest cod?</strong><br>
Dacă nu ai inițiat această autentificare, te rugăm să ignori acest email.
Nimeni nu va avea acces la contul tău fără parola ta.
</p>
</div>
<div class="footer">
<p><strong>ROA2WEB</strong> - ERP Reports Application</p>
<p>Acest email a fost trimis automat. Te rugăm să nu răspunzi.</p>
</div>
</div>
</body>
</html>
Command Reference Update
Adaugă în TELEGRAM_COMMANDS.md:
## /login
**Descriere**: Autentificare în Telegram Bot prin email + parolă (2FA)
**Sintaxă**: `/login`
**Flow**:
1. Selectezi metoda de autentificare (Email sau Web App)
2. Pentru Email:
- Introduci adresa de email Oracle
- Primești cod pe email (6 cifre)
- Introduci codul din email
- Introduci parola Oracle
- Primești confirmare și acces la comenzi
**Exemple**:
/login → Selectează "🔐 Login cu Email" → Introdu: mmarius28@gmail.com → Verifică email și introdu cod: 123456 → Introdu parola → ✅ Autentificat cu succes!
**Securitate**:
- Cod expiră în 5 minute
- Cod utilizabil o singură dată
- Parolă verificată în Oracle
- Mesajul cu parola este șters automat
- Rate limiting: max 3 încercări/oră
**Comandă alternativă**: Buton "🔐 Login cu Email" în meniu principal
🎓 Learning Points & Best Practices
1. De ce 6-digit code în loc de 8-char alphanumeric?
Răspuns:
- Mai ușor de tastat pe mobile
- Mai puțin prone la erori (0/O, 1/I confusion)
- Suficient de securizat pentru 5 minute expiry
- Standard în industrie (Google, GitHub, etc.)
2. De ce 5 minute expiry pentru cod?
Răspuns:
- Balans între security și UX
- Suficient timp pentru check email + type code
- Redus attack window pentru code guessing
- Similar cu alte aplicații 2FA
3. De ce șterge mesajul cu parola?
Răspuns:
- Securitate: parola nu rămâne în chat history
- Telegram API permite ștergerea mesajelor
- Best practice în bot-uri care cer credențiale
- Protecție dacă telefonul e compromis
4. De ce în-memory rate limiting și nu Redis?
Răspuns:
- Simplitate: Nu adaugă dependency nou
- Suficient pentru scale mic-mediu:
- In-memory e OK pentru <1000 users concurrent
- Planul curent: test cu 1 user, extend la 10-20 max
- Upgrade path clar: Dacă scală, migrăm la Redis
- Code unchanged: Interfața rămâne aceeași
5. De ce SQLite și nu PostgreSQL pentru bot DB?
Răspuns:
- Consistency: Sistemul actual folosește SQLite
- Zero infrastructure: No server setup needed
- Sufficient performance: Telegram bot = low traffic
- Easy backup: Single file (
telegram_bot.db) - Deployment simplicity: Works în Windows Service
🔗 Integrare cu Sistemul Existent
Flow Diagram - Ambele Metode
┌─────────────────────────────────┐
│ USER VREA SĂ SE AUTENTIFICE │
│ ÎN TELEGRAM BOT │
└─────────────┬───────────────────┘
│
▼
┌─────────────────────────────────┐
│ ALEGE METODA: │
│ [Email + Parolă] sau [Web App] │
└─────────┬───────────┬───────────┘
│ │
┌────────────┘ └────────────┐
│ │
▼ ▼
┌────────────────────────┐ ┌──────────────────────────┐
│ METODA NOUĂ │ │ METODA EXISTENTĂ │
│ Email + Parolă │ │ Web App Linking │
└────────────────────────┘ └──────────────────────────┘
│ │
▼ ▼
1. /login în Telegram 1. Login în web app (username+pass)
2. Introdu email 2. Click "Link Telegram"
3. Primești cod pe email 3. Backend generează cod 8-char
4. Introdu cod în Telegram 4. Backend → POST /internal/save-code → Bot
5. Introdu parolă 5. User: /start ABC123XY
6. Bot verifică în Oracle 6. Bot auto-link (fără parolă din nou)
│ │
└──────────────┬──────────────────────┘
│
▼
┌───────────────────────────────────┐
│ USER AUTENTIFICAT ÎN BOT │
│ JWT tokens saved în telegram_users│
└───────────────────────────────────┘
│
▼
┌───────────────────────────────────┐
│ COMENZI DISPONIBILE: │
│ /companies, /dashboard, │
│ /facturi, /trezorerie, etc. │
└───────────────────────────────────┘
Database Schema - Complete View
-- EXISTING TABLE (no changes)
CREATE TABLE telegram_users (
telegram_user_id INTEGER PRIMARY KEY,
username TEXT,
first_name TEXT,
last_name TEXT,
oracle_username TEXT,
jwt_token TEXT,
jwt_refresh_token TEXT,
token_expires_at TIMESTAMP,
linked_at TIMESTAMP,
last_active_at TIMESTAMP,
is_active BOOLEAN
);
-- EXISTING TABLE (no changes)
CREATE TABLE telegram_auth_codes (
code TEXT PRIMARY KEY, -- 8-char code from web app
telegram_user_id INTEGER,
oracle_username TEXT,
created_at TIMESTAMP,
expires_at TIMESTAMP,
used BOOLEAN DEFAULT 0,
used_at TIMESTAMP
);
-- NEW TABLE (for email auth)
CREATE TABLE email_auth_codes (
code TEXT PRIMARY KEY, -- 6-digit code sent via email
email TEXT NOT NULL,
oracle_username TEXT NOT NULL,
telegram_user_id INTEGER NOT NULL,
created_at TIMESTAMP,
expires_at TIMESTAMP,
used BOOLEAN DEFAULT 0,
used_at TIMESTAMP,
INDEX idx_email (email),
INDEX idx_telegram_user_id (telegram_user_id)
);
-- EXISTING TABLE (no changes)
CREATE TABLE telegram_sessions (
session_id TEXT PRIMARY KEY,
telegram_user_id INTEGER,
active_company_id INTEGER,
active_company_name TEXT,
conversation_state TEXT,
created_at TIMESTAMP,
updated_at TIMESTAMP,
expires_at TIMESTAMP
);
Observații:
telegram_auth_codes= pentru web app linking (EXISTING)email_auth_codes= pentru email auth (NEW)- Ambele tabele coexistă, fiecare pentru flow-ul propriu
telegram_users= comună pentru ambele metode (linked users)
🚦 Success Criteria
Implementarea e considerată SUCCESS dacă:
- ✅ User poate să facă
/loginîn Telegram - ✅ User poate introduce email și primește cod pe email
- ✅ User poate introduce cod din email (valid 5 min)
- ✅ User poate introduce parola Oracle
- ✅ Bot verifică credențialele în Oracle și generează JWT
- ✅ User e autentificat și poate folosi comenzi (/companies, /dashboard, etc.)
- ✅ Metoda veche (web app → /start cod) funcționează în continuare
- ✅ Ambele metode pot fi folosite de același user (switch între ele)
- ✅ Codurile expirate sunt auto-șterse
- ✅ Mesajul cu parola e șters automat din chat
- ✅ Rate limiting funcționează (max 3 emails/oră)
- ✅ Error handling: mesaje clare pentru fiecare caz de eroare
- ✅ Testare cu mmarius28@gmail.com funcționează end-to-end
📅 Next Steps După Implementare
Immediate (după deploy)
-
Testare cu user real (Marius)
- Verifică flow complet cu mmarius28@gmail.com
- Test ambele metode de autentificare
- Validează email delivery și formatting
-
Monitoring
- Watch logs pentru erori SMTP
- Monitor rate limiting triggers
- Check database growth (
email_auth_codestable)
Short-term (1-2 săptămâni)
-
Adaugă email pentru alți useri
- Identifică 5-10 useri pentru beta testing
- Adaugă email-uri în Oracle
UTILIZATORItable - Anunță disponibilitatea noii metode
-
Collect feedback
- UX pentru conversation flow
- Timing email delivery (sunt 5 min suficienți?)
- Edge cases descoperite
Long-term (1-3 luni)
-
Analytics
- Câți useri folosesc fiecare metodă?
- Success rate pentru fiecare flow
- Common error patterns
-
Optimizări
- Migrate rate limiting la Redis (dacă scală)
- Adaugă email templates multiple (română + engleză)
- Consider migration de la SQLite la PostgreSQL (dacă >1000 users)
-
Feature extensions
- Email verification pentru schimbare parolă
- Email notifications pentru events (reports ready, etc.)
- Multi-language support
📞 Contact & Support
Developer: Claude Code (Anthropic) Project: ROA2WEB - ERP Reports Application Date: 2025-11-07
Pentru întrebări despre acest plan:
- Review cod în
reports-app/telegram-bot/șireports-app/backend/ - Consultă
CLAUDE.mdpentru context general - Check
TELEGRAM_COMMANDS.mdpentru comenzi existente
Resurse utile:
- python-telegram-bot docs: https://docs.python-telegram-bot.org/
- FastAPI docs: https://fastapi.tiangolo.com/
- aiosmtplib docs: https://aiosmtplib.readthedocs.io/
🎉 Conclusion
Acest plan implementează autentificare email + parolă (2FA) pentru Telegram Bot în mod minimal invaziv, păstrând întreaga funcționalitate existentă.
Key highlights:
- ✅ 0 breaking changes - metoda veche funcționează în continuare
- ✅ Simplu de implementat - ~13h efort total
- ✅ Securizat - 2FA real cu rate limiting
- ✅ Extensibil - ușor de scalat pentru mai mulți useri
- ✅ User-friendly - conversation flow natural
Ready to implement! 🚀
Document generat: 2025-11-07 Versiune: 1.0 Status: Planning Phase - Ready for Implementation