diff --git a/README.md b/README.md index da2dcca..eda7cbc 100644 --- a/README.md +++ b/README.md @@ -88,7 +88,7 @@ This starts SSH tunnel, unified backend (port 8001), and frontend (port 3000). - **Shared Database Pool**: Singleton Oracle connection pool shared across all modules - **Two-Tier Cache System**: Hybrid L1 (Memory) + L2 (SQLite) for optimal performance - **JWT Authentication**: Secure token-based auth with middleware -- **Microservices**: Independent services with clear separation of concerns +- **Modular Architecture**: Independent modules with clear separation of concerns - **Oracle Integration**: Direct Oracle stored procedure calls with caching - **Responsive Design**: Mobile-friendly Vue.js interface - **Telegram Integration**: Alternative bot-based interface @@ -299,30 +299,27 @@ BACKEND_API_URL=http://localhost:8001 ### Quick Reference - **`CLAUDE.md`** - Development guide for AI/Claude Code (architecture, cache system, common tasks, troubleshooting) -- **`docs/ARCHITECTURE_SCHEMA.md`** - Architecture diagrams, cache system, and schemas -- `docs/MICROSERVICES_GUIDE.md` - Microservices architecture details -- `DEVELOPMENT_BLUEPRINT.md` - Detailed development plan +- **`docs/ARCHITECTURE-DECISIONS.md`** - Architecture Decision Records (ADRs) +- **`docs/MONOLITH_ARCHITECTURE.md`** - Ultrathin monolith architecture details -### Component-Specific -- `README.md` - Main application README -- `backend/ modules and CLAUDE.md` - Backend specifics -- `src/ and docs/MONOLITH_ARCHITECTURE.md` - Frontend guide -- `E2E testing guide in docs/` - Frontend testing -- `backend/modules/telegram/README.md` - Telegram bot guide -- `backend/modules/telegram/TELEGRAM_COMMANDS.md` - Bot commands +### Module Documentation +- `docs/data-entry/DATA-ENTRY-MODULE.md` - Data Entry module (SQLModel, workflow, OCR) +- `docs/telegram/README.md` - Telegram bot integration +- `docs/telegram/DEPLOYMENT.md` - Telegram single-worker requirement ### Frontend Styling & CSS - `docs/ONBOARDING_CSS.md` - CSS system onboarding guide (start here!) - `docs/CSS_PATTERNS.md` - Comprehensive CSS patterns library - `docs/DESIGN_TOKENS.md` - Design tokens reference (colors, spacing, typography) -- `docs/STYLING_GUIDELINES.md` - CSS best practices and conventions -- `docs/COMPONENT_STYLING.md` - Component-specific styling guide -- `docs/FORM_TEMPLATE.md` - Standardized form template and patterns +- `docs/MOBILE_PATTERNS.md` - Mobile UI patterns and components ### Deployment -- `DEPLOYMENT_GUIDE.md` - Production deployment (Linux & Windows) -- `deployment/windows/README.md` - Windows quick start -- `deployment/windows/docs/WINDOWS_DEPLOYMENT.md` - Complete Windows guide +- **`docs/DEPLOYMENT.md`** - Principal deployment guide (start here!) +- `deployment/linux/README.md` - Deploy from Linux/LXC +- `deployment/windows/README.md` - Deploy from Windows + +### Testing +- `tests/ocr-validation/README.md` - OCR validation tests --- diff --git a/deployment/linux/README.md b/deployment/linux/README.md index cbedf13..79eb8c5 100644 --- a/deployment/linux/README.md +++ b/deployment/linux/README.md @@ -210,6 +210,5 @@ scp test.txt roa2web-prod:C:/Temp/ ## Related Documentation -- [Windows Deployment](../windows/docs/WINDOWS_DEPLOYMENT.md) +- [Windows Deployment README](../windows/README.md) - [Two-Tier IIS Architecture](../windows/docs/TWO-TIER-IIS-DEPLOYMENT.md) -- [ROA2WEB Console](../windows/scripts/ROA2WEB-Console.ps1) diff --git a/deployment/windows/DEPLOY_PACKAGE.md b/deployment/windows/DEPLOY_PACKAGE.md deleted file mode 100644 index ab32d45..0000000 --- a/deployment/windows/DEPLOY_PACKAGE.md +++ /dev/null @@ -1,221 +0,0 @@ -# 📦 Deployment Package Generation - -This document explains how to generate deployment packages for ROA2WEB Windows deployment. - -## ⚠️ Important Note - -The `deploy-package/` directory is **NOT** committed to git. It contains build artifacts that are generated fresh each time you build. - -## 🔨 Generating Deployment Packages - -Use the unified build script **`Build-ROA2WEB.ps1`** to generate deployment packages: - -### Build Complete Package (Recommended) - -```powershell -cd deployment/windows/scripts -.\Build-ROA2WEB.ps1 -``` - -This generates a complete deployment package containing: -- ✅ Frontend (Vue.js built static files) -- ✅ Backend (FastAPI Python application) -- ✅ Shared modules (auth, database, utils) -- ✅ Telegram Bot application -- ✅ Configuration templates -- ✅ Deployment scripts - -**Output**: `deployment/windows/deploy-package/` - -### Build Specific Components - -```powershell -# Frontend + Backend only -.\Build-ROA2WEB.ps1 -Component Frontend - -# Backend only (no frontend build) -.\Build-ROA2WEB.ps1 -Component Backend - -# Telegram Bot only -.\Build-ROA2WEB.ps1 -Component TelegramBot -``` - -### Custom Output Path - -```powershell -# Build to custom location with date suffix -.\Build-ROA2WEB.ps1 -OutputPath "D:\deployments\roa2web-$(Get-Date -Format 'yyyyMMdd')" -``` - -## 📂 Package Structure - -After building, `deploy-package/` will contain: - -``` -deploy-package/ -├── backend/ # FastAPI application files -│ ├── app/ # Application code -│ ├── requirements.txt # Python dependencies -│ └── ... -├── frontend/ # Built Vue.js static files -│ ├── assets/ # JS, CSS, fonts -│ ├── index.html # Main HTML -│ └── ... -├── telegram-bot/ # Telegram bot application -│ ├── app/ # Bot code -│ ├── requirements.txt # Bot dependencies -│ └── .env.example # Configuration template -├── shared/ # Shared Python modules -│ ├── auth/ # Authentication -│ ├── database/ # Oracle connection pool -│ └── utils/ # Utilities -├── config/ # Configuration templates -│ ├── .env.production.windows -│ ├── .env.production.windows.telegram -│ └── web.config # IIS configuration -├── scripts/ # Deployment scripts -│ ├── Install-ROA2WEB.ps1 -│ ├── Install-TelegramBot.ps1 -│ ├── Deploy-ROA2WEB.ps1 -│ ├── Deploy-TelegramBot.ps1 -│ ├── Manage-ROA2WEB.ps1 -│ ├── Backup-TelegramDB.ps1 -│ ├── Setup-DailyBackup.ps1 -│ ├── Setup-ClaudeAuth.ps1 -│ └── Enable-HTTPS.ps1 -└── README.txt # Deployment instructions -``` - -## 🚀 Deployment Workflow - -### 1. Build Package (Development Machine) - -```powershell -# On WSL or development machine -cd deployment/windows/scripts -.\Build-ROA2WEB.ps1 -``` - -### 2. Transfer to Windows Server - -```powershell -# Via network share -Copy-Item -Path ./deploy-package -Destination \\SERVER\C$\Temp\roa2web-deploy -Recurse - -# Or via RDP (manual copy) -``` - -### 3. Install on Server (First Time) - -```powershell -# On Windows Server (as Administrator) -cd C:\Temp\roa2web-deploy\scripts - -# Install main application -.\Install-ROA2WEB.ps1 - -# Install Telegram bot -.\Install-TelegramBot.ps1 -``` - -### 4. Configure & Start - -```powershell -# Configure environment -notepad C:\inetpub\wwwroot\roa2web\backend\.env -notepad C:\inetpub\wwwroot\roa2web\telegram-bot\.env - -# Start services -.\Manage-ROA2WEB.ps1 -Action Start -``` - -### 5. Deploy Updates - -```powershell -# Stop services -.\Manage-ROA2WEB.ps1 -Action Stop - -# Deploy updates -.\Deploy-ROA2WEB.ps1 -.\Deploy-TelegramBot.ps1 - -# Start services -.\Manage-ROA2WEB.ps1 -Action Start -``` - -## 🔧 Requirements - -**Development Machine (for building):** -- Node.js 16+ (for Frontend builds) -- npm -- PowerShell 5.1+ - -**Windows Server (for deployment):** -- Windows Server 2016+ or Windows 10/11 -- IIS with URL Rewrite Module -- Python 3.11+ -- PowerShell 5.1+ (Administrator) - -## 📝 Notes - -- **Build artifacts are NOT version-controlled**: The `deploy-package/` directory is in `.gitignore` -- **Fresh builds recommended**: Always generate a fresh package before deploying -- **Virtual environments**: Not included in package (created automatically during installation) -- **.env files**: Not included in package (created from templates during installation) -- **Database files**: Excluded from package (SQLite for Telegram bot created on server) - -## ⚙️ Advanced Options - -### Transfer to Server Automatically - -```powershell -# Using network share (Windows) -.\Build-ROA2WEB.ps1 -ServerHost "10.0.20.36" -ServerPath "C:\Temp\roa2web-deploy" -``` - -### Clean Build - -The build script automatically cleans the output directory. To preserve existing output: - -```powershell -.\Build-ROA2WEB.ps1 -Clean $false -``` - -## 🐛 Troubleshooting - -### "Node.js not found" - -Install Node.js 16+ from https://nodejs.org/ - -### "deploy-package already exists" - -The script automatically cleans old builds. If you see errors, manually delete `deploy-package/` and retry. - -### Build fails with "locked files" - -Close VS Code, IDEs, and file explorers that might have files open in the source directories. - -## 📚 Documentation - -- **Complete Deployment Guide**: [`docs/WINDOWS_DEPLOYMENT.md`](docs/WINDOWS_DEPLOYMENT.md) -- **Script Reference**: [`scripts/README.md`](scripts/README.md) -- **Quick Start**: [`README.md`](README.md) -- **Project Documentation**: [`../../CLAUDE.md`](../../CLAUDE.md) - -## 🔄 Migration from Old Build Scripts - -If you were using the old build scripts, here's the mapping: - -| Old Script | New Script | Equivalent Command | -|------------|------------|-------------------| -| `Build-Frontend.ps1` | `Build-ROA2WEB.ps1` | `.\Build-ROA2WEB.ps1 -Component Frontend` | -| `Build-TelegramBot.ps1` | `Build-ROA2WEB.ps1` | `.\Build-ROA2WEB.ps1 -Component TelegramBot` | -| Both scripts together | `Build-ROA2WEB.ps1` | `.\Build-ROA2WEB.ps1` (default: All) | - -**Note**: Old scripts are marked as DEPRECATED and will be removed in a future version. - ---- - -**Generated by**: ROA2WEB Team -**Last Updated**: 2025-11-11 -**Version**: 2.0 (Unified Build System) diff --git a/deployment/windows/README.md b/deployment/windows/README.md index 904f32d..9126d93 100644 --- a/deployment/windows/README.md +++ b/deployment/windows/README.md @@ -1,492 +1,200 @@ -# ROA2WEB - Windows Deployment Package +# ROA2WEB - Windows Deployment -Complete deployment solution for ROA2WEB on Windows Server with IIS and Oracle Database. - -**Includes:** -- **Reports App** - Read-only Oracle reports (Port 8000) -- **Telegram Bot** - Telegram integration (Port 8002) -- **Data Entry App** - Receipt data entry with approval workflow (Port 8003) +**Arhitectură:** Ultrathin Monolith | **Serviciu:** `ROA2WEB-Backend` (port 8000) --- -## 📂 Package Contents +## Quick Start -``` -deployment/windows/ -├── config/ # Configuration files -│ ├── web.config # IIS config for Reports App -│ ├── web.config.data-entry # IIS config for Data Entry App -│ └── .env.production.windows # Environment variables template -│ -├── scripts/ # PowerShell automation scripts -│ ├── Build-ROA2WEB.ps1 # Build all components (interactive menu) -│ ├── ROA2WEB-Console.ps1 # Unified deployment & management console -│ ├── Install-ROA2WEB.ps1 # Initial Reports App installation -│ ├── Install-TelegramBot.ps1 # Telegram Bot installation -│ └── deploy-config.json # Deployment configuration -│ -├── docs/ # Documentation -│ └── WINDOWS_DEPLOYMENT.md # Complete deployment guide -│ -└── README.md # This file -``` - ---- - -## 🎯 Quick Start - -### Prerequisites - -- **Windows Server** 2016+ (or Windows 10/11 Pro) -- **IIS** installed -- **Oracle Database** (local or network-accessible) -- **PowerShell 5.1+** -- **Administrator privileges** - -### Installation Steps - -#### 1. Build Frontend (on development machine) - -```bash -# On WSL/Linux/Mac -cd roa2web/deployment/windows/scripts -./Build-Frontend.ps1 - -# This creates: ./deploy-package/ -``` - -#### 2. Transfer to Server - -Copy the entire project to Windows Server: -``` -C:\roa2web\deployment\windows\ -``` - -#### 3. Run Installation +### 1. Instalare Server Nou ```powershell -# On Windows Server (PowerShell as Administrator) -cd C:\roa2web\deployment\windows\scripts - -# Install everything +# Pe Windows Server (PowerShell Administrator) +cd C:\path\to\deployment\windows\scripts .\Install-ROA2WEB.ps1 ``` -This will: -- ✅ Install Python 3.11+ -- ✅ Install NSSM (service manager) -- ✅ Install IIS URL Rewrite and ARR -- ✅ Create directory structure -- ✅ Install Python dependencies -- ✅ Create Windows Service -- ✅ Configure IIS website - -#### 4. Configure Application +### 2. Configurare ```powershell -# Copy and edit environment file -Copy-Item C:\inetpub\wwwroot\roa2web\backend\config\.env.production.windows ` - C:\inetpub\wwwroot\roa2web\backend\.env - -# Edit with your values notepad C:\inetpub\wwwroot\roa2web\backend\.env + +# Module control: +MODULE_REPORTS_ENABLED=true +MODULE_DATA_ENTRY_ENABLED=true +MODULE_TELEGRAM_ENABLED=true ``` -**Required settings:** - -Configure these variables in `.env`: -- Database credentials (user, password, host, port, SID) -- JWT secret key for authentication -- Other application-specific settings - -Example structure: -```env -ORACLE_USER=CONTAFIN_ORACLE -ORACLE_HOST=localhost -ORACLE_PORT=1521 -ORACLE_SID=ROA -# Add password and JWT secret here -``` - -#### 5. Deploy Application Files +### 3. Start ```powershell -# Deploy frontend and backend -.\Deploy-ROA2WEB.ps1 -SourcePath "C:\path\to\deploy-package" +Start-Service ROA2WEB-Backend ``` -#### 6. Verify Installation +--- + +## Deployment (Actualizări) + +### Opțiunea A: Din Windows (Publish-And-Deploy.ps1) ```powershell -# Check service +# Pe mașina de dezvoltare Windows +cd deployment\windows\scripts +.\Publish-And-Deploy.ps1 + +# Non-interactiv: +.\Publish-And-Deploy.ps1 -NonInteractive -Action Build -Component All +``` + +### Opțiunea B: Din Linux/LXC (deploy.sh) + +```bash +# Pe mașina de dezvoltare Linux +cd deployment/linux +./deploy.sh # Full deploy (frontend + backend) +./deploy.sh frontend # Doar frontend +./deploy.sh backend # Doar backend +./deploy.sh test # Test conexiune SSH +``` + +**Ambele metode:** +1. Build frontend (npm) + copiere backend +2. Transfer la server (`C:\Temp\deploy-YYYYMMDD-HHmmss\`) +3. Server-ul auto-deploy în 5 minute (sau manual) + +--- + +## Management + +### Consolă Interactivă (Recomandat) + +```powershell +.\ROA2WEB-Console.ps1 +``` + +### Comenzi Rapide + +```powershell +# Service +Start-Service ROA2WEB-Backend +Stop-Service ROA2WEB-Backend +Restart-Service ROA2WEB-Backend Get-Service ROA2WEB-Backend -# Test backend +# Status & Health +.\ROA2WEB-Console.ps1 -NonInteractive -Action Status Invoke-WebRequest http://localhost:8000/health -# Open application -Start-Process "http://localhost" +# Logs +Get-Content C:\inetpub\wwwroot\roa2web\logs\backend-stdout.log -Tail 50 +Get-Content C:\inetpub\wwwroot\roa2web\logs\backend-stderr.log -Tail 20 + +# Deploy manual +.\ROA2WEB-Console.ps1 -NonInteractive -Action DeployAll -PackagePath "C:\Temp\deploy-XXXXXXXX" ``` --- -## 🔄 Update Workflow - -For deploying updates to existing installation: - -**1. Build on development machine:** -```bash -cd roa2web/deployment/windows/scripts -./Build-Frontend.ps1 -OutputPath "./deploy-$(date +%Y%m%d)" -``` - -**2. Transfer to server:** -```powershell -Copy-Item .\deploy-20250118 -Destination C:\Temp\roa2web-deploy -Recurse -``` - -**3. Deploy on server:** -```powershell -cd C:\inetpub\wwwroot\roa2web\deployment\windows\scripts -.\Deploy-ROA2WEB.ps1 -SourcePath "C:\Temp\roa2web-deploy" -``` - ---- - -## 🔧 Management Commands - -### Interactive Console (Recommended) - -```powershell -# Open unified management console -cd C:\inetpub\wwwroot\roa2web\deployment\windows\scripts -.\ROA2WEB-Console.ps1 - -# Menu options: -# [1] Deploy Components -# [2] Manage Services -# [3] Check Status -``` - -### Non-Interactive Commands - -```powershell -# Deploy all components -.\ROA2WEB-Console.ps1 -NonInteractive -Action DeployAll - -# Deploy specific component -.\ROA2WEB-Console.ps1 -NonInteractive -Action DeployBackend -.\ROA2WEB-Console.ps1 -NonInteractive -Action DeployTelegramBot -.\ROA2WEB-Console.ps1 -NonInteractive -Action DeployDataEntry - -# Service management -.\ROA2WEB-Console.ps1 -NonInteractive -Action StartAll -.\ROA2WEB-Console.ps1 -NonInteractive -Action StopAll -.\ROA2WEB-Console.ps1 -NonInteractive -Action RestartAll - -# Data Entry service management -.\ROA2WEB-Console.ps1 -NonInteractive -Action StartDataEntry -.\ROA2WEB-Console.ps1 -NonInteractive -Action StopDataEntry -.\ROA2WEB-Console.ps1 -NonInteractive -Action RestartDataEntry - -# Check status -.\ROA2WEB-Console.ps1 -NonInteractive -Action Status -``` - -### Direct Service Commands - -```powershell -# Check all ROA2WEB services -Get-Service ROA2WEB-* - -# View logs -Get-Content C:\inetpub\wwwroot\roa2web\logs\backend-stdout.log -Tail 50 -Wait -Get-Content C:\inetpub\wwwroot\roa2web\data-entry-backend\logs\stdout.log -Tail 50 -Wait - -# Check IIS -Get-Website | Where-Object { $_.Name -like "*roa2web*" -or $_.Name -like "*data-entry*" } -``` - ---- - -## 📊 Architecture - -### Components - -| Component | Type | Port | Purpose | -|-----------|------|------|---------| -| **Reports Frontend** | IIS Static Files | 80/443 | Vue.js SPA (Reports) | -| **Reports Backend** | Windows Service | 8000 | FastAPI API (Reports) | -| **Telegram Bot** | Windows Service | 8002 | Telegram integration | -| **Data Entry Frontend** | IIS Static Files | 80/443 | Vue.js SPA (Data Entry) | -| **Data Entry Backend** | Windows Service | 8003 | FastAPI API (Data Entry) | -| **Database** | Oracle | 1521 | Reports data (read-only) | -| **SQLite** | File | - | Data Entry local storage | - -### Network Flow - -``` -Client → IIS (port 80/443) - │ - ├─ /roa2web/api/* → Reports Backend (localhost:8000) → Oracle DB - │ - ├─ /roa2web/* → Reports Frontend (Vue.js) - │ - ├─ /data-entry/api/* → Data Entry Backend (localhost:8003) → SQLite - │ - └─ /data-entry/* → Data Entry Frontend (Vue.js) -``` - -### Windows Services - -| Service Name | Description | Port | -|-------------|-------------|------| -| ROA2WEB-Backend | Reports API | 8000 | -| ROA2WEB-TelegramBot | Telegram Bot | 8002 | -| ROA2WEB-DataEntry | Data Entry API | 8003 | - ---- - -## 📋 Directory Structure After Installation +## Structura Server ``` C:\inetpub\wwwroot\roa2web\ -│ -├── backend\ # Reports Backend (FastAPI) -│ ├── app\ -│ ├── requirements.txt -│ ├── venv\ -│ └── .env -│ -├── frontend\ # Reports Frontend (Vue.js) -│ ├── index.html -│ ├── assets\ -│ └── web.config -│ -├── telegram-bot\ # Telegram Bot -│ ├── app\ -│ ├── data\telegram_bot.db -│ ├── requirements.txt -│ ├── venv\ -│ └── .env -│ -├── data-entry-backend\ # Data Entry Backend (FastAPI) -│ ├── app\ -│ ├── migrations\ -│ ├── data\receipts.db # SQLite database -│ ├── data\uploads\ # Uploaded receipts -│ ├── requirements.txt -│ ├── venv\ -│ └── .env -│ -├── data-entry-frontend\ # Data Entry Frontend (Vue.js) -│ ├── index.html -│ ├── assets\ -│ └── web.config -│ -├── shared\ # Shared Python modules -│ ├── auth\ -│ ├── database\ -│ └── utils\ -│ -├── logs\ # Service logs -│ ├── backend-stdout.log -│ └── backend-stderr.log -│ -└── backups\ # Automatic backups - └── backup-YYYYMMDD-HHMMSS\ +├── backend\ # FastAPI (Reports, Data Entry, Telegram modules) +│ └── .env # Configurare (MODULE_*_ENABLED flags) +├── frontend\ # Vue.js SPA + web.config +├── shared\ # Module Python partajate (auth, db) +├── logs\ # backend-stdout.log, backend-stderr.log +└── backups\ # Backup-uri automate ``` --- -## 🆘 Troubleshooting +## Arhitectură -### Service won't start - -```powershell -# Check logs -Get-Content C:\inetpub\wwwroot\roa2web\logs\backend-stderr.log -Tail 50 - -# Test manually -cd C:\inetpub\wwwroot\roa2web\backend -python -m uvicorn app.main:app --host 127.0.0.1 --port 8000 +``` +Client → IIS (80/443) + │ + ├─ /roa2web/api/* → ROA2WEB-Backend (localhost:8000) + │ ├── Reports Module → Oracle DB + │ ├── Data Entry Module → SQLite + │ └── Telegram Module + │ + └─ /roa2web/* → Frontend (Vue.js SPA) ``` -### Frontend not loading +**Single Service:** `ROA2WEB-Backend` pe port 8000 +**Module Control:** Via `.env` flags (fără restart cod) -```powershell -# Restart IIS -iisreset +--- + +## Workflow Deployment -# Check website status -Get-Website ROA2WEB -Start-Website ROA2WEB ``` +DEV MACHINE WINDOWS SERVER +─────────── ────────────── -### API calls failing (502/504) - -```powershell -# Check backend service -Get-Service ROA2WEB-Backend -.\Restart-ROA2WEB.ps1 - -# Test backend directly -Invoke-WebRequest http://localhost:8000/health -``` - -### Database connection issues - -```powershell -# Test Oracle connection -sqlplus CONTAFIN_ORACLE/password@localhost:1521/ROA - -# Check Oracle service -Get-Service Oracle* - -# Check .env configuration -Get-Content C:\inetpub\wwwroot\roa2web\backend\.env | Select-String ORACLE +Publish-And-Deploy.ps1 + sau ───► C:\Temp\deploy-*\ +deploy.sh (Linux) │ + ▼ + Check-And-Deploy.ps1 + (scheduled task, 5 min) + │ + ▼ + ROA2WEB-Console.ps1 + ├── Stop Service + ├── Backup + ├── Deploy Files + ├── Start Service + └── Health Check + │ + ▼ + ✅ PRODUCTION RUNNING ``` --- -## 📖 Full Documentation +## Troubleshooting -For complete documentation, see: -- **[WINDOWS_DEPLOYMENT.md](docs/WINDOWS_DEPLOYMENT.md)** - Comprehensive deployment guide -- **[.env.production.windows](config/.env.production.windows)** - Configuration reference +| Problemă | Verificare | Soluție | +|----------|------------|---------| +| Service nu pornește | `Get-Content ...\backend-stderr.log -Tail 30` | Verifică .env, port 8000 | +| API 502/504 | `Invoke-WebRequest http://localhost:8000/health` | Restart service | +| Frontend nu se încarcă | `iisreset` | Verifică IIS, web.config | +| Auto-deploy nu merge | `Get-ScheduledTask ROA2WEB-AutoDeploy` | `.\Setup-AutoDeploy.ps1` | --- -## 🔑 Key Features +## Fișiere web.config -✅ **Simple Installation** - One PowerShell script installs everything -✅ **Minimal Dependencies** - Only Python + IIS (already on Windows Server) -✅ **Easy Replication** - Same scripts work on all servers -✅ **Automatic Backups** - Every deployment creates a backup -✅ **Windows Service** - Backend runs as service with auto-start/restart -✅ **Production Ready** - Optimized for performance and reliability +| Fișier | Scop | Când se folosește | +|--------|------|-------------------| +| `public/web.config` | Sub-aplicație IIS (/roa2web) | La fiecare deploy (via Vite) | +| `deployment/windows/config/web.config` | Server IIS complet | La instalare nouă | + +**Notă:** Ambele au configurat `no-cache` pentru API (backend gestionează cache-ul). --- -## 📊 System Requirements +## Documentație Detaliată -| Resource | Minimum | Recommended | -|----------|---------|-------------| -| **OS** | Windows Server 2016 | Windows Server 2019+ | -| **RAM** | 4 GB | 8 GB (16 GB if using OCR) | -| **CPU** | 2 cores | 4 cores | -| **Disk** | 10 GB free | 20 GB free | -| **Network** | 100 Mbps | 1 Gbps | +- **HTTPS Setup:** `docs/HTTPS_SETUP.md` +- **2-Tier IIS:** `docs/TWO-TIER-IIS-DEPLOYMENT.md` +- **Telegram Bot:** `docs/TELEGRAM-BOT-DEPLOYMENT.md` --- -## 🔍 OCR Dependencies (Data Entry App) +## Cerințe Sistem -Data Entry App foloseste OCR pentru extragerea automata a datelor din bonuri fiscale. Pe Windows trebuie instalate manual: - -### 1. Poppler (conversie PDF → imagini) - -```powershell -# Descarca de la: https://github.com/osborn/poppler-windows/releases -# Extrage in: C:\Program Files\poppler\ -# Adauga la System PATH: C:\Program Files\poppler\Library\bin - -# Verificare instalare: -pdfinfo --version -``` - -### 2. Tesseract OCR (engine OCR backup) - -```powershell -# Descarca installer: https://github.com/UB-Mannheim/tesseract/wiki -# Selecteaza limbile: English + Romanian -# Default path: C:\Program Files\Tesseract-OCR\ -# Adauga la System PATH - -# Verificare instalare: -tesseract --version -``` - -### 3. Python OCR Packages - -```powershell -cd C:\inetpub\wwwroot\roa2web\data-entry-backend -.\venv\Scripts\activate - -pip install paddlepaddle>=2.5.0 -pip install paddleocr>=2.7.0 -pip install opencv-python>=4.8.0 -pip install pytesseract>=0.3.10 -pip install pdf2image>=1.16.0 - -# Restart serviciu -nssm restart ROA2WEB-DataEntry -``` - -### Note importante -- **PaddleOCR** descarca modele (~200MB) la prima rulare -- **RAM**: PaddleOCR necesita ~2GB RAM disponibil -- **PATH**: Dupa modificari PATH, restart serviciul backend -- **Test OCR**: `curl http://localhost:8003/api/ocr/status` +| Resursă | Minim | Recomandat | +|---------|-------|------------| +| OS | Windows Server 2016 | Windows Server 2019+ | +| RAM | 4 GB | 8 GB (16 GB cu OCR) | +| CPU | 2 cores | 4 cores | +| Python | 3.11+ | 3.11+ | +| IIS | URL Rewrite + ARR | URL Rewrite + ARR | --- -## 🔐 Security Recommendations - -1. **Generate Strong JWT Secret:** - ```powershell - -join ((65..90) + (97..122) + (48..57) | Get-Random -Count 32 | % {[char]$_}) - ``` - -2. **Secure .env File:** - ```powershell - icacls C:\inetpub\wwwroot\roa2web\backend\.env /inheritance:r /grant:r Administrators:F - ``` - -3. **Enable HTTPS:** ⭐ **RECOMMENDED** - ```powershell - # Quick setup with automated script - cd C:\roa2web\deployment\windows\scripts - .\Enable-HTTPS.ps1 - - # For detailed instructions, see: - # docs/HTTPS_SETUP.md - ``` - - **What it does:** - - Creates/installs SSL certificate - - Configures HTTPS binding (port 443) - - Enables HTTP to HTTPS redirect - - Activates HSTS (Strict Transport Security) - - **Access your application securely:** - - `https://10.0.20.36/roa2web` (or your domain) - -4. **Regular Updates:** - - Keep Windows Server updated - - Update Python packages monthly - - Monitor security advisories - - Renew SSL certificates before expiry - ---- - -## 📞 Support - -For issues or questions: -1. Check logs: `C:\inetpub\wwwroot\roa2web\logs\` -2. Review [WINDOWS_DEPLOYMENT.md](docs/WINDOWS_DEPLOYMENT.md) -3. Contact: development-team@your-company.com - ---- - -## 📝 Version History - -| Version | Date | Changes | -|---------|------|---------| -| 2.1.0 | 2025-12-18 | Added Data Entry App deployment support | -| 2.0.0 | 2025-01-18 | Initial Windows deployment package | - ---- - -*ROA2WEB - Modern ERP Application (Reports + Data Entry)* -*Windows Server Deployment Package v2.1.0* +*ROA2WEB - Ultrathin Monolith Architecture* +*Last Updated: 2025-01-22* diff --git a/deployment/windows/config/README-WEB-CONFIG.md b/deployment/windows/config/README-WEB-CONFIG.md deleted file mode 100644 index 1f4b3cd..0000000 --- a/deployment/windows/config/README-WEB-CONFIG.md +++ /dev/null @@ -1,240 +0,0 @@ -# web.config Files - Which Goes Where? - -## ⚠️ IMPORTANT - Read Before Deployment! - -ROA2WEB uses a **2-tier IIS architecture** with **2 different web.config files** for **2 different servers**. - ---- - -## Architecture Overview - -``` -Internet - ↓ -Public Server (10.0.20.122) - roa2web.romfast.ro - ↓ HTTPS reverse proxy -Internal Server (10.0.20.36) - application host - ↓ API proxy to localhost -Backend Service (localhost:8000 on 10.0.20.36) -``` - ---- - -## File Mapping - -### File: `web.config.10.0.20.122-PUBLIC` - -**Server**: 10.0.20.122 (Public IIS - roa2web.romfast.ro) -**Role**: Public gateway, reverse proxy to internal server - -**Purpose**: -- Proxies ALL requests to `https://10.0.20.36/{REQUEST_PATH}` -- Sets forwarding headers (`X-Forwarded-Proto`, `X-Forwarded-Host`, `X-Real-IP`) -- Redirects root `/` to `/roa2web/` - -**Key Rule**: -```xml - - -``` - -**Deployment Location**: -``` -10.0.20.122: - C:\inetpub\wwwroot\[ROOT]\web.config -``` - ---- - -### File: `web.config.10.0.20.36-INTERNAL` - -**Server**: 10.0.20.36 (Internal IIS - application host) -**Role**: Serves frontend, proxies API to localhost backend - -**Purpose**: -- Serves Vue.js frontend static files -- Proxies `/roa2web/api/*` to `http://localhost:8000/api/*` -- Proxies `/roa2web/uploads/*` to `http://localhost:8000/uploads/*` -- SPA fallback for client-side routing - -**Key Rules**: -```xml - - - - - - - - -``` - -**Deployment Location**: -``` -10.0.20.36: - C:\inetpub\wwwroot\roa2web\web.config -``` - -**Note**: This file is also in `public/web.config` (repository root) and is automatically copied to `dist/` during Vite build. - ---- - -## Deployment Checklist - -### ✅ Public Server (10.0.20.122) - -```powershell -# Copy public server config -Copy-Item deployment/windows/config/web.config.10.0.20.122-PUBLIC ` - C:\inetpub\wwwroot\[ROOT]\web.config - -# Verify -Get-Content C:\inetpub\wwwroot\[ROOT]\web.config | Select-String "10.0.20.36" -``` - -**Expected**: Should see `url="https://10.0.20.36/{R:1}"` - -### ✅ Internal Server (10.0.20.36) - -**Option A: From built dist/ (recommended)**: -```powershell -# After building frontend with `npm run build` -# web.config is automatically in dist/ - -# Deploy entire dist/ folder -Copy-Item dist\* C:\inetpub\wwwroot\roa2web\ -Recurse -Force -``` - -**Option B: Manual copy**: -```powershell -# Copy internal server config -Copy-Item deployment/windows/config/web.config.10.0.20.36-INTERNAL ` - C:\inetpub\wwwroot\roa2web\web.config - -# Verify -Get-Content C:\inetpub\wwwroot\roa2web\web.config | Select-String "roa2web/api" -``` - -**Expected**: Should see `url="^roa2web/api/(.*)"` and `url="http://localhost:8000/api/{R:1}"` - ---- - -## Verification - -### Test Public Server (10.0.20.122) - -```powershell -# Should proxy to internal server -Invoke-WebRequest https://roa2web.romfast.ro/roa2web/ -UseBasicParsing - -# Check response headers -(Invoke-WebRequest https://roa2web.romfast.ro/roa2web/).Headers -``` - -**Expected**: Request should be proxied to 10.0.20.36 - -### Test Internal Server (10.0.20.36) - -```powershell -# Test backend directly -Invoke-WebRequest http://localhost:8000/health - -# Test through IIS proxy -Invoke-WebRequest https://localhost/roa2web/api/health - -# Test frontend -Invoke-WebRequest https://localhost/roa2web/ -``` - -**Expected**: All should return 200 OK - ---- - -## Common Mistakes ❌ - -### ❌ WRONG: Using internal config on public server - -```xml - - - -``` - -**Problem**: Public server doesn't have backend on localhost:8000 - -### ❌ WRONG: Using public config on internal server - -```xml - - - -``` - -**Problem**: Creates infinite redirect loop - -### ❌ WRONG: Missing /roa2web/ prefix on internal server - -```xml - - - -``` - -**Problem**: Requests come as `/roa2web/api/...` from public server, so `^api/` won't match - ---- - -## Troubleshooting - -### Issue: 404 on API calls - -**Symptom**: Frontend loads but API returns 404 - -**Check**: web.config on 10.0.20.36 - -```powershell -# On 10.0.20.36 -Get-Content C:\inetpub\wwwroot\roa2web\web.config | Select-String "roa2web/api" -``` - -**Fix**: Update to correct internal server config (see above) - -### Issue: Infinite redirect loop - -**Symptom**: Browser shows "Too many redirects" - -**Check**: Verify you didn't put public config on internal server - -### Issue: Backend not reachable - -**Symptom**: 502 Bad Gateway on API calls - -**Check**: Backend service on 10.0.20.36 - -```powershell -# On 10.0.20.36 -Get-Service ROA2WEB-Backend -Invoke-WebRequest http://localhost:8000/health -``` - ---- - -## Quick Reference - -| Server | IP | Config File | Key Pattern | Proxies To | -|--------|----|----|-------------|------------| -| **Public** | 10.0.20.122 | `web.config.10.0.20.122-PUBLIC` | `url="(.*)"` | `https://10.0.20.36/{R:1}` | -| **Internal** | 10.0.20.36 | `web.config.10.0.20.36-INTERNAL` | `url="^roa2web/api/(.*)"` | `http://localhost:8000/api/{R:1}` | - ---- - -## Documentation - -For complete architecture details, see: -- `deployment/windows/docs/TWO-TIER-IIS-DEPLOYMENT.md` -- `DIAGNOSIS-2025-12-30.md` - ---- - -*Last Updated: 2025-12-30* -*ROA2WEB Deployment Configuration Guide* diff --git a/deployment/windows/config/web.config b/deployment/windows/config/web.config index 3bb7936..863c72c 100644 --- a/deployment/windows/config/web.config +++ b/deployment/windows/config/web.config @@ -124,16 +124,27 @@ - + + + + + + + + + + + + diff --git a/deployment/windows/docs/DEPLOYMENT_AUTOMATION.md b/deployment/windows/docs/DEPLOYMENT_AUTOMATION.md index ad50452..02a00fd 100644 --- a/deployment/windows/docs/DEPLOYMENT_AUTOMATION.md +++ b/deployment/windows/docs/DEPLOYMENT_AUTOMATION.md @@ -422,8 +422,8 @@ Get-Content "C:\ROA2WEB-Scripts\last-deploy.json" | ConvertFrom-Json | Format-Li ### Check Service Status (Server) ```powershell -# After deployment, verify services -Get-Service -Name "ROA2WEB-Backend", "ROA2WEB-TelegramBot" +# After deployment, verify service +Get-Service -Name "ROA2WEB-Backend" # Or use ROA2WEB-Console.ps1 cd C:\inetpub\wwwroot\roa2web\scripts @@ -669,14 +669,13 @@ Get-Content "C:\Temp\ROA2WEB-Scripts\Logs\check-and-deploy.log" -Tail 30 ``` ```powershell -# Verify services are running: -Get-Service -Name "ROA2WEB-Backend", "ROA2WEB-TelegramBot" +# Verify service is running: +Get-Service -Name "ROA2WEB-Backend" # Expected output: # Status Name DisplayName # ------ ---- ----------- # Running ROA2WEB-Backend ROA2WEB Backend Service -# Running ROA2WEB-TelegramBot ROA2WEB Telegram Bot Service ``` #### Step 5: Verify Web Application diff --git a/deployment/windows/docs/TELEGRAM_BOT_DEPLOYMENT.md b/deployment/windows/docs/TELEGRAM_BOT_DEPLOYMENT.md deleted file mode 100644 index fe44cfa..0000000 --- a/deployment/windows/docs/TELEGRAM_BOT_DEPLOYMENT.md +++ /dev/null @@ -1,855 +0,0 @@ -# ROA2WEB Telegram Bot - Windows Server Deployment Guide - -> ⚠️ **DEPRECATED ARCHITECTURE** -> -> This documentation refers to the OLD microservices architecture where the Telegram bot -> ran as a separate service on port 8002. The current architecture is an **ultrathin monolith** -> where everything runs on a single port (8000/8001) via `backend/main.py`. -> -> **Current Architecture**: Telegram bot runs as a background task within the unified backend. -> Internal API endpoints are now at `/api/telegram/internal/*` on the main port. -> -> See `CLAUDE.md` and `QUICK-START.md` for the current architecture. - -**Target Server**: Windows Server (10.0.20.36) -**Deployment Method**: Windows Service (NSSM) - No Docker -**Service Name**: ROA2WEB-TelegramBot -**Internal API Port**: ~~8002~~ (DEPRECATED - now via main backend) -**Created**: 2025-10-22 -**Last Updated**: 2025-10-22 - ---- - -## Table of Contents - -1. [Overview](#overview) -2. [Prerequisites](#prerequisites) -3. [Deployment Architecture](#deployment-architecture) -4. [Installation Steps](#installation-steps) -5. [Configuration](#configuration) -6. [Service Management](#service-management) -7. [Database Backup](#database-backup) -8. [Monitoring & Troubleshooting](#monitoring--troubleshooting) -9. [Security Considerations](#security-considerations) -10. [Maintenance Procedures](#maintenance-procedures) - ---- - -## Overview - -The ROA2WEB Telegram Bot is deployed as a Windows Service on the same server as the backend (10.0.20.36). It provides an alternative conversational interface to ROA2WEB using Claude Agent SDK. - -### Key Features - -- **Conversational AI**: Claude Agent SDK with 5 custom tools -- **Account Linking**: Secure linking between Telegram and Oracle accounts -- **Real-time Queries**: Dashboard, invoices, treasury, exports -- **Database**: Standalone SQLite for Telegram-specific data -- **Internal API**: FastAPI endpoint for backend callbacks (port 8002) -- **Production Ready**: All components use real backend integration (no mocks) - -### Deployment Method - -- **Windows Service**: Runs via NSSM (Non-Sucking Service Manager) -- **No Docker**: Direct Windows deployment (same pattern as backend) -- **Auto-start**: Service starts automatically on server boot -- **Auto-recovery**: Service restarts automatically on failure - ---- - -## Prerequisites - -### Server Requirements - -- **Operating System**: Windows Server 2016+ or Windows 10/11 -- **Python**: 3.11 or higher -- **RAM**: Minimum 512 MB (dedicated to service) -- **Disk Space**: Minimum 500 MB -- **Network**: Access to localhost:8000 (backend API) - -### Required Credentials - -1. **Telegram Bot Token** - - Get from @BotFather on Telegram - - Command: `/newbot` or `/mybots` - - Example: `123456789:ABCdefGHIjklMNOpqrsTUVwxyz` - -2. **Claude Authentication** (Choose ONE method) - - **Method A: Claude Pro/Max Subscription** ⭐ **RECOMMENDED** - - ✅ **NO API key needed** - - ✅ **NO additional costs** (included in your subscription) - - ✅ Uses browser authentication - - See: [Claude Authentication Setup](#claude-authentication-setup) below - - **Method B: Claude API Key** (Alternative) - - Get from Anthropic Console: https://console.anthropic.com/settings/keys - - Example: `sk-ant-api03-XXXXXXXX...` - - ⚠️ Usage-based billing applies - - Takes precedence over Method A if both are configured - -3. **Backend Access** - - Backend should be running on http://localhost:8000 - - Verify: `Invoke-WebRequest http://localhost:8000/health` - -### Software Prerequisites - -- **PowerShell 5.1+**: Built into Windows Server -- **Python 3.11+**: Will be installed if missing (via Chocolatey) -- **NSSM**: Will be installed automatically by installation script - ---- - -## Deployment Architecture - -### Directory Structure - -``` -C:\inetpub\wwwroot\roa2web\telegram-bot\ -├── app\ # Application source code -│ ├── main.py # Entry point, Claude Agent wrapper -│ ├── bot\ # Telegram bot handlers -│ ├── agent\ # Claude Agent tools and sessions -│ ├── auth\ # Account linking logic -│ ├── db\ # SQLite database operations -│ ├── api\ # Backend API client -│ └── internal_api.py # FastAPI internal API -├── venv\ # Python virtual environment -├── data\ # SQLite database -│ └── telegram_bot.db # Main database file -├── logs\ # Application logs -│ ├── stdout.log # Service output -│ ├── stderr.log # Service errors -│ └── backup.log # Backup operations -├── backups\ # Database backups -├── temp\ # Temporary files -├── scripts\ # PowerShell management scripts -├── config\ # Configuration templates -├── requirements.txt # Python dependencies -└── .env # Environment configuration -``` - -### Service Integration - -``` -┌─────────────────────────────────────────────────────────────┐ -│ Windows Server 10.0.20.36 │ -│ │ -│ ┌──────────────────┐ ┌──────────────────┐ │ -│ │ IIS (Port 80) │ │ ROA2WEB-Backend │ │ -│ │ Frontend Static │ │ (Port 8000) │ │ -│ └──────────────────┘ └────────┬─────────┘ │ -│ │ │ -│ │ HTTP API Calls │ -│ │ │ -│ ┌─────────────────▼──────────────┐ │ -│ │ ROA2WEB-TelegramBot │ │ -│ │ (Port 8002 - Internal API) │ │ -│ │ - Telegram Bot Handlers │ │ -│ │ - Claude Agent SDK │ │ -│ │ - SQLite Database │ │ -│ └────────────────────────────────┘ │ -│ │ -└─────────────────────────────────────────────────────────────┘ - │ - │ Telegram Bot API - ▼ - ┌─────────────────┐ - │ Telegram │ - │ Cloud │ - └─────────────────┘ -``` - ---- - -## Installation Steps - -### Step 1: Build Deployment Package (Development Machine) - -On your development machine (WSL/Linux), run: - -```bash -cd /mnt/e/proiecte/roa2web/roa2web/deployment/windows/scripts -./Build-TelegramBot.ps1 -``` - -This creates the deployment package at: -``` -../deploy-package/telegram-bot/ -``` - -**Package Contents**: -- `app/` - Application source code -- `requirements.txt` - Python dependencies -- `.env.example` - Configuration template -- `scripts/` - PowerShell management scripts -- `config/` - Production config templates -- `README.txt` - Deployment instructions - -### Step 2: Transfer Package to Server - -**Option A: Network Share** (Recommended) -```powershell -# On development machine -Copy-Item -Path ./deploy-package/telegram-bot -Destination \\10.0.20.36\C$\Temp\telegram-bot-deploy -Recurse -``` - -**Option B: RDP** -1. Connect to server via RDP: `mstsc /v:10.0.20.36` -2. Manually copy deployment package to `C:\Temp\telegram-bot-deploy` - -### Step 3: Run Installation Script - -On Windows Server (10.0.20.36), open PowerShell as Administrator: - -```powershell -cd C:\Temp\telegram-bot-deploy\scripts -.\Install-TelegramBot.ps1 -``` - -**Installation Process**: -1. ✅ Checks Python 3.11+ installation -2. ✅ Installs NSSM (service manager) -3. ✅ Creates directory structure -4. ✅ Creates Python virtual environment -5. ✅ Installs Python dependencies -6. ✅ Creates Windows Service (ROA2WEB-TelegramBot) -7. ✅ Creates .env configuration template - -**Installation Output**: -``` -==================================================================== - ROA2WEB TELEGRAM BOT INSTALLATION COMPLETED -==================================================================== - -Installation Details: - Install Path: C:\inetpub\wwwroot\roa2web\telegram-bot - Service Name: ROA2WEB-TelegramBot - Internal API Port: 8002 - -Next Steps: - 1. Edit configuration: C:\inetpub\wwwroot\roa2web\telegram-bot\.env - 2. Start service: .\Start-TelegramBot.ps1 -``` - -### Step 4: Configure Environment - -Edit the `.env` file: - -```powershell -notepad C:\inetpub\wwwroot\roa2web\telegram-bot\.env -``` - -**Required Configuration**: -```env -# CRITICAL: Update this value -TELEGRAM_BOT_TOKEN=your_production_bot_token_from_@BotFather - -# Claude Authentication: Leave empty to use Claude Pro/Max subscription -CLAUDE_API_KEY= - -# Verify these are correct -BACKEND_URL=http://localhost:8000 -SQLITE_DB_PATH=C:\inetpub\wwwroot\roa2web\telegram-bot\data\telegram_bot.db -INTERNAL_API_PORT=8002 -LOG_LEVEL=INFO -ENVIRONMENT=production -``` - -**Get Bot Token**: -1. Open Telegram, search for `@BotFather` -2. Send `/newbot` or `/mybots` -3. Copy token to `TELEGRAM_BOT_TOKEN` - -### Step 4a: Claude Authentication Setup - -**Choose ONE authentication method:** - -#### **Method A: Claude Pro/Max Subscription** ⭐ **RECOMMENDED** - -If you have a Claude Pro or Claude Max subscription, use this method (NO API key needed!): - -```powershell -cd C:\inetpub\wwwroot\roa2web\telegram-bot\scripts -.\Setup-ClaudeAuth.ps1 -``` - -**What happens:** -1. Script installs `claude-code` CLI (if not already installed) -2. Opens your browser for authentication -3. Log in with your Claude Pro/Max account -4. Authorize the application -5. Credentials are saved to: `%APPDATA%\claude\credentials.json` - -**Expected Output:** -``` -==================================================================== - IMPORTANT: Browser Authentication Required -==================================================================== - - 1. A browser window will open - 2. Log in with your Claude Pro/Max account - 3. Authorize the application - 4. Return to this window after authentication - -==================================================================== - -[*] Opening browser for authentication... - [OK] Authentication successful! - [OK] Credentials file found and valid - [OK] .env will use Claude Pro subscription (browser login) - -==================================================================== - CLAUDE AUTHENTICATION SETUP COMPLETE -==================================================================== -``` - -**Alternative: Copy credentials from development machine** - -If the server doesn't have browser access, authenticate on your local machine and copy credentials: - -```powershell -# On local machine (with browser): -npm install -g @anthropic-ai/claude-code -claude-code login - -# Copy credentials file to server -Copy-Item "$env:APPDATA\claude\credentials.json" -Destination "\\10.0.20.36\C$\Temp\claude-credentials.json" - -# On server: -cd C:\inetpub\wwwroot\roa2web\telegram-bot\scripts -.\Setup-ClaudeAuth.ps1 -Method copy -CredentialsPath "C:\Temp\claude-credentials.json" -``` - -#### **Method B: Claude API Key** (Alternative) - -If you prefer to use an API key instead: - -1. Visit https://console.anthropic.com/settings/keys -2. Create new key -3. Edit `.env` and set `CLAUDE_API_KEY=sk-ant-api03-XXXXXXXX...` -4. ⚠️ Usage-based billing applies - -**Note:** API key takes precedence over browser login if both are configured. - -### Step 5: Start Service - -```powershell -cd C:\inetpub\wwwroot\roa2web\telegram-bot\scripts -.\Start-TelegramBot.ps1 -``` - -**Expected Output**: -``` -[*] Starting ROA2WEB Telegram Bot Service... - [*] Service start command issued - [*] Waiting for service to start... (5/30) - [OK] Service started successfully - [OK] Health check passed: healthy - [OK] Database: connected -``` - -### Step 6: Verify Installation - -**Check Service Status**: -```powershell -Get-Service ROA2WEB-TelegramBot -``` - -Expected: `Status = Running` - -**Check Health Endpoint**: -```powershell -Invoke-WebRequest http://localhost:8002/internal/health | ConvertFrom-Json -``` - -Expected Output: -```json -{ - "status": "healthy", - "timestamp": "2025-10-22T14:30:00", - "database": { - "status": "connected", - "users": 0, - "pending_codes": 0 - } -} -``` - -**Test Bot on Telegram**: -1. Open Telegram -2. Search for your bot (name from @BotFather) -3. Send `/start` -4. Expected: Welcome message with linking instructions - ---- - -## Configuration - -### Environment Variables Reference - -See `.env.production.windows.telegram` in `config/` directory for complete reference. - -**Key Settings**: - -| Variable | Default | Description | -|----------|---------|-------------| -| `TELEGRAM_BOT_TOKEN` | *required* | Bot token from @BotFather | -| `CLAUDE_API_KEY` | *required* | API key from Anthropic | -| `BACKEND_URL` | `http://localhost:8000` | Backend API URL | -| `SQLITE_DB_PATH` | `C:\...\telegram_bot.db` | Database file location | -| `INTERNAL_API_PORT` | `8002` | Internal API port | -| `LOG_LEVEL` | `INFO` | Logging level (DEBUG/INFO/WARN/ERROR) | -| `ENVIRONMENT` | `production` | Environment name | -| `AUTH_CODE_EXPIRY_MINUTES` | `15` | Linking code expiry time | -| `SESSION_TIMEOUT_MINUTES` | `60` | User session timeout | -| `MAX_CONVERSATION_HISTORY` | `20` | Max messages per session | - -### Applying Configuration Changes - -After editing `.env`: - -```powershell -cd C:\inetpub\wwwroot\roa2web\telegram-bot\scripts -.\Restart-TelegramBot.ps1 -``` - ---- - -## Service Management - -### Start Service - -```powershell -cd C:\inetpub\wwwroot\roa2web\telegram-bot\scripts -.\Start-TelegramBot.ps1 -``` - -### Stop Service - -```powershell -.\Stop-TelegramBot.ps1 -``` - -### Restart Service - -```powershell -.\Restart-TelegramBot.ps1 -``` - -### Check Service Status - -```powershell -Get-Service ROA2WEB-TelegramBot - -# Detailed info -Get-Service ROA2WEB-TelegramBot | Select-Object * -``` - -### View Logs - -**Real-time Logs** (tail -f equivalent): -```powershell -Get-Content C:\inetpub\wwwroot\roa2web\telegram-bot\logs\stdout.log -Tail 50 -Wait -``` - -**Error Logs**: -```powershell -Get-Content C:\inetpub\wwwroot\roa2web\telegram-bot\logs\stderr.log -Tail 100 -``` - -**Backup Logs**: -```powershell -Get-Content C:\inetpub\wwwroot\roa2web\telegram-bot\logs\backup.log -Tail 50 -``` - ---- - -## Database Backup - -### Manual Backup - -```powershell -cd C:\inetpub\wwwroot\roa2web\telegram-bot\scripts -.\Backup-TelegramDB.ps1 -``` - -**Output**: -- Backup file: `backups/telegram_bot_backup_YYYYMMDD-HHMMSS.db.zip` -- Compressed and timestamped -- Integrity tested automatically - -### Setup Automated Daily Backup - -```powershell -cd C:\inetpub\wwwroot\roa2web\telegram-bot\scripts -.\Setup-DailyBackup.ps1 -``` - -**Configuration**: -- Runs daily at 2:00 AM -- Keeps last 30 days of backups -- Runs as SYSTEM account -- Logs all operations - -**Verify Scheduled Task**: -```powershell -Get-ScheduledTask -TaskName "ROA2WEB-TelegramBot-Backup" -``` - -**Run Backup Manually** (via Task Scheduler): -```powershell -Start-ScheduledTask -TaskName "ROA2WEB-TelegramBot-Backup" -``` - -### Restore from Backup - -1. Stop service: - ```powershell - .\Stop-TelegramBot.ps1 - ``` - -2. Find backup file: - ```powershell - Get-ChildItem C:\inetpub\wwwroot\roa2web\telegram-bot\backups | Sort-Object LastWriteTime -Descending - ``` - -3. Extract backup (if compressed): - ```powershell - Expand-Archive -Path "backups\telegram_bot_backup_YYYYMMDD-HHMMSS.db.zip" -DestinationPath "temp\" - ``` - -4. Replace database: - ```powershell - Copy-Item -Path "temp\telegram_bot_backup_YYYYMMDD-HHMMSS.db" -Destination "data\telegram_bot.db" -Force - ``` - -5. Start service: - ```powershell - .\Start-TelegramBot.ps1 - ``` - ---- - -## Monitoring & Troubleshooting - -### Health Checks - -**Service Health**: -```powershell -Get-Service ROA2WEB-TelegramBot | Select-Object Name, Status, StartType -``` - -**API Health**: -```powershell -Invoke-WebRequest http://localhost:8002/internal/health -``` - -**Database Stats**: -```powershell -(Invoke-WebRequest http://localhost:8002/internal/stats).Content | ConvertFrom-Json -``` - -### Common Issues - -#### Service Won't Start - -**Symptoms**: Service shows "Stopped" or "Starting" forever - -**Diagnosis**: -```powershell -Get-Content C:\inetpub\wwwroot\roa2web\telegram-bot\logs\stderr.log -Tail 100 -``` - -**Common Causes**: -1. **Missing .env file** → Create from `.env.example` -2. **Invalid bot token** → Check `TELEGRAM_BOT_TOKEN` -3. **Invalid Claude API key** → Check `CLAUDE_API_KEY` -4. **Port 8002 already in use** → Change `INTERNAL_API_PORT` -5. **Backend not running** → Start ROA2WEB-Backend service - -**Solutions**: -```powershell -# Fix config -notepad C:\inetpub\wwwroot\roa2web\telegram-bot\.env - -# Check port availability -Get-NetTCPConnection -LocalPort 8002 - -# Restart service -.\Restart-TelegramBot.ps1 -``` - -#### Bot Not Responding on Telegram - -**Symptoms**: Bot doesn't reply to messages - -**Diagnosis**: -1. Check service status: - ```powershell - Get-Service ROA2WEB-TelegramBot - ``` -2. Check health endpoint: - ```powershell - Invoke-WebRequest http://localhost:8002/internal/health - ``` -3. Check logs for errors: - ```powershell - Get-Content logs\stderr.log -Tail 50 - ``` - -**Common Causes**: -1. **Service stopped** → Start service -2. **Invalid bot token** → Update `.env` -3. **Network issues** → Check internet connectivity -4. **Bot blocked by user** → User must /start bot again - -#### Account Linking Fails - -**Symptoms**: `/link CODE` returns error - -**Diagnosis**: -```powershell -# Check internal API -Invoke-WebRequest http://localhost:8002/internal/stats - -# Check backend connectivity -Invoke-WebRequest http://localhost:8000/health -``` - -**Common Causes**: -1. **Code expired** (15 min) → Generate new code -2. **Backend unreachable** → Check ROA2WEB-Backend service -3. **Database error** → Check SQLite file permissions - -#### Database Errors - -**Symptoms**: "Database locked" or "Cannot open database" - -**Diagnosis**: -```powershell -# Check database file -Test-Path C:\inetpub\wwwroot\roa2web\telegram-bot\data\telegram_bot.db - -# Check file permissions -icacls C:\inetpub\wwwroot\roa2web\telegram-bot\data\telegram_bot.db -``` - -**Solutions**: -```powershell -# Stop service -.\Stop-TelegramBot.ps1 - -# Fix permissions -icacls C:\inetpub\wwwroot\roa2web\telegram-bot\data /grant "SYSTEM:(OI)(CI)F" /T - -# Restart service -.\Start-TelegramBot.ps1 -``` - ---- - -## Security Considerations - -### Secrets Management - -**NEVER**: -- Commit `.env` to git -- Share bot token or API keys -- Log sensitive data - -**ALWAYS**: -- Keep backups of `.env` in secure location -- Rotate API keys periodically -- Use strong file permissions - -**File Permissions**: -```powershell -# Restrict .env to SYSTEM and Administrators only -icacls C:\inetpub\wwwroot\roa2web\telegram-bot\.env /grant "SYSTEM:F" /grant "Administrators:F" /inheritance:r -``` - -### Network Security - -- **Internal API (8002)**: Bind to 127.0.0.1 (localhost only) -- **Backend API (8000)**: Already on localhost -- **No Firewall Rules Needed**: All communication is local - -### Bot Security - -- **Account Linking**: 8-character codes, 15-minute expiry -- **JWT Tokens**: Signed and verified by backend -- **Rate Limiting**: Built into authentication middleware -- **Session Timeout**: 60 minutes of inactivity - ---- - -## Maintenance Procedures - -### Updates and Deployments - -1. **Build new deployment package** (dev machine): - ```bash - ./Build-TelegramBot.ps1 - ``` - -2. **Transfer to server**: - ```powershell - Copy-Item -Path ./deploy-package/telegram-bot -Destination \\10.0.20.36\C$\Temp\telegram-bot-update -Recurse - ``` - -3. **Deploy update** (server): - ```powershell - cd C:\Temp\telegram-bot-update\scripts - .\Deploy-TelegramBot.ps1 - ``` - -**Deployment Features**: -- ✅ Automatic backup before deployment -- ✅ Stops service, updates files, restarts service -- ✅ Preserves `.env` configuration -- ✅ Automatic rollback on failure -- ✅ Health check after deployment - -### Log Rotation - -Logs are automatically rotated by Python logging: -- **Max size**: 10 MB per file -- **Backups**: 5 old log files kept -- **Location**: `C:\inetpub\wwwroot\roa2web\telegram-bot\logs\` - -**Manual cleanup**: -```powershell -# Delete old logs (older than 30 days) -Get-ChildItem C:\inetpub\wwwroot\roa2web\telegram-bot\logs\*.log | - Where-Object { $_.LastWriteTime -lt (Get-Date).AddDays(-30) } | - Remove-Item -Force -``` - -### Database Maintenance - -**Cleanup expired data** (automatic via scheduled task): -- Expired auth codes (older than 15 minutes) -- Old sessions (inactive for 60+ minutes) -- Runs hourly automatically - -**Manual cleanup**: -```sql --- Connect to database -sqlite3 C:\inetpub\wwwroot\roa2web\telegram-bot\data\telegram_bot.db - --- Delete expired codes -DELETE FROM telegram_auth_codes WHERE created_at < datetime('now', '-15 minutes'); - --- Delete old sessions -DELETE FROM telegram_sessions WHERE updated_at < datetime('now', '-60 minutes'); -``` - -### Service Health Monitoring - -**Daily Checks** (manual or script): -```powershell -# Service status -Get-Service ROA2WEB-TelegramBot - -# Health endpoint -Invoke-WebRequest http://localhost:8002/internal/health - -# Check logs for errors -Get-Content logs\stderr.log -Tail 50 | Select-String "ERROR" - -# Check database size -(Get-Item data\telegram_bot.db).Length / 1MB -``` - -**Weekly Checks**: -- Review backup logs -- Check backup retention (30 days) -- Review disk space usage -- Check for Windows updates - ---- - -## Appendix - -### PowerShell Scripts Reference - -| Script | Purpose | -|--------|---------| -| `Install-TelegramBot.ps1` | Initial installation | -| `Deploy-TelegramBot.ps1` | Deploy updates | -| `Build-TelegramBot.ps1` | Build deployment package | -| `Start-TelegramBot.ps1` | Start service | -| `Stop-TelegramBot.ps1` | Stop service | -| `Restart-TelegramBot.ps1` | Restart service | -| `Backup-TelegramDB.ps1` | Manual database backup | -| `Setup-DailyBackup.ps1` | Configure automated backups | - -### API Endpoints - -| Endpoint | Method | Description | -|----------|--------|-------------| -| `/internal/health` | GET | Health check | -| `/internal/stats` | GET | Database statistics | -| `/internal/save-code` | POST | Save auth code (from backend) | -| `/internal/verify-code` | POST | Verify auth code | - -### Database Schema - -**telegram_users**: -```sql -CREATE TABLE telegram_users ( - telegram_user_id INTEGER PRIMARY KEY, - oracle_user_id INTEGER NOT NULL, - oracle_username TEXT NOT NULL, - jwt_token TEXT NOT NULL, - jwt_refresh_token TEXT, - created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP -); -``` - -**telegram_auth_codes**: -```sql -CREATE TABLE telegram_auth_codes ( - code TEXT PRIMARY KEY, - oracle_user_id INTEGER NOT NULL, - oracle_username TEXT NOT NULL, - created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - expires_at TIMESTAMP NOT NULL, - used INTEGER DEFAULT 0 -); -``` - -**telegram_sessions**: -```sql -CREATE TABLE telegram_sessions ( - telegram_user_id INTEGER PRIMARY KEY, - conversation_history TEXT, -- JSON - session_data TEXT, -- JSON - created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP -); -``` - ---- - -## Support - -**Documentation**: -- Project README: `/mnt/e/proiecte/roa2web/roa2web/backend/modules/telegram/README.md` -- Progress Tracker: `/mnt/e/proiecte/roa2web/roa2web/development/TELEGRAM_BOT_PROGRESS.md` -- Production Deployment Plan: `/mnt/e/proiecte/roa2web/roa2web/development/TELEGRAM_BOT_PRODUCTION_DEPLOYMENT.md` - -**Logs Location**: -- Service Output: `C:\inetpub\wwwroot\roa2web\telegram-bot\logs\stdout.log` -- Service Errors: `C:\inetpub\wwwroot\roa2web\telegram-bot\logs\stderr.log` -- Backups: `C:\inetpub\wwwroot\roa2web\telegram-bot\logs\backup.log` - -**Contact**: ROA2WEB Development Team - ---- - -**Document Version**: 1.0 -**Last Updated**: 2025-10-22 -**Status**: Production Ready diff --git a/deployment/windows/docs/TELEGRAM_BOT_TROUBLESHOOTING.md b/deployment/windows/docs/TELEGRAM_BOT_TROUBLESHOOTING.md deleted file mode 100644 index 20b642f..0000000 --- a/deployment/windows/docs/TELEGRAM_BOT_TROUBLESHOOTING.md +++ /dev/null @@ -1,546 +0,0 @@ -# ROA2WEB Telegram Bot - Windows Deployment Troubleshooting Guide - -> ⚠️ **DEPRECATED ARCHITECTURE** -> -> This documentation refers to the OLD microservices architecture (port 8002). -> The current architecture is an **ultrathin monolith** - everything on port 8000/8001. -> Telegram internal API is now at `/api/telegram/internal/*` on the main backend. - -This guide helps diagnose and fix common issues with Telegram bot integration on Windows Server deployments. - -## Problem: "Link invalid sau expirat" (Invalid or expired link) - -When users generate a linking code in the web frontend but the Telegram bot says the code is invalid or expired, this indicates a communication problem between the backend and telegram bot services. - -### Root Cause - -The backend cannot communicate with the Telegram bot's internal API to save the generated linking codes. - -### Diagnostic Steps - -Run these PowerShell commands on the Windows Server (10.0.20.36) to diagnose: - -#### 1. Check Telegram Bot Service Status - -```powershell -# Check if service is running -Get-Service ROA2WEB-TelegramBot - -# Expected output: -# Status Name DisplayName -# ------ ---- ----------- -# Running ROA2WEB-TelegramBot ROA2WEB Telegram Bot Service -``` - -If service is **not running**, start it: -```powershell -cd C:\inetpub\wwwroot\roa2web\telegram-bot\scripts -.\Start-TelegramBot.ps1 -``` - -#### 2. Check Internal API Port (8002) - -```powershell -# Check if port 8002 is listening -netstat -ano | findstr :8002 - -# Expected output (should show LISTENING): -# TCP 127.0.0.1:8002 0.0.0.0:0 LISTENING -``` - -If port is **not listening**, the telegram bot service may not have started correctly. Check logs: -```powershell -# View service logs -Get-Content C:\inetpub\wwwroot\roa2web\telegram-bot\logs\stdout.log -Tail 50 - -# View error logs -Get-Content C:\inetpub\wwwroot\roa2web\telegram-bot\logs\stderr.log -Tail 50 -``` - -#### 3. Test Internal API Health Endpoint - -```powershell -# Test if internal API responds -Invoke-WebRequest http://localhost:8002/internal/health - -# Expected output: -# StatusCode : 200 -# StatusDescription : OK -# Content : {"status":"healthy","timestamp":"2025-...","database_stats":{...}} -``` - -If this **fails**, the internal API is not running. Check telegram bot service logs. - -#### 4. Check Backend .env Configuration - -```powershell -# View backend .env file -notepad C:\inetpub\wwwroot\roa2web\backend\.env - -# Look for this line: -# TELEGRAM_BOT_INTERNAL_API=http://localhost:8002 -``` - -If the line is **missing or incorrect**, add/fix it: -``` -TELEGRAM_BOT_INTERNAL_API=http://localhost:8002 -``` - -Then restart backend service: -```powershell -Restart-Service ROA2WEB-Backend -``` - -#### 5. Check Telegram Bot .env Configuration - -```powershell -# View telegram bot .env file -notepad C:\inetpub\wwwroot\roa2web\telegram-bot\.env - -# Verify these settings: -# TELEGRAM_BOT_TOKEN= -# BACKEND_URL=http://localhost:8000 -# INTERNAL_API_PORT=8002 -# INTERNAL_API_HOST=127.0.0.1 -``` - -If TELEGRAM_BOT_TOKEN is wrong (e.g., still using DEV token), update it and restart: -```powershell -cd C:\inetpub\wwwroot\roa2web\telegram-bot\scripts -.\Restart-TelegramBot.ps1 -``` - -#### 6. Test Full Linking Flow - -```powershell -# 1. Test backend can reach telegram bot internal API -Invoke-WebRequest -Method POST -Uri http://localhost:8002/internal/save-code -Headers @{"Content-Type"="application/json"} -Body '{"code":"TEST1234","telegram_user_id":0,"oracle_username":"testuser","expires_in_minutes":15}' - -# Expected output: -# StatusCode: 201 (Created) -# Content: {"success":true,"code":"TEST1234","expires_at":"...","message":"..."} - -# 2. Verify code was saved -Invoke-WebRequest -Method POST -Uri http://localhost:8002/internal/verify-code -Headers @{"Content-Type"="application/json"} -Body '{"code":"TEST1234"}' - -# Expected output: -# StatusCode: 200 (OK) -# Content: {"valid":true,"oracle_username":"testuser","message":"Code is valid"} -``` - -If step 1 **fails**, there's a network/firewall issue blocking localhost:8002. - -### Solution Checklist - -Fix the issue by following this checklist in order: - -- [ ] **Telegram bot service is running** - ```powershell - Get-Service ROA2WEB-TelegramBot - # If stopped: cd C:\inetpub\wwwroot\roa2web\telegram-bot\scripts; .\Start-TelegramBot.ps1 - ``` - -- [ ] **Internal API port 8002 is listening** - ```powershell - netstat -ano | findstr :8002 - # Should show LISTENING on 127.0.0.1:8002 - ``` - -- [ ] **Internal API responds to health checks** - ```powershell - Invoke-WebRequest http://localhost:8002/internal/health - # Should return 200 OK with status "healthy" - ``` - -- [ ] **Backend .env has TELEGRAM_BOT_INTERNAL_API configured** - ```powershell - notepad C:\inetpub\wwwroot\roa2web\backend\.env - # Add: TELEGRAM_BOT_INTERNAL_API=http://localhost:8002 - ``` - -- [ ] **Backend service restarted after .env changes** - ```powershell - Restart-Service ROA2WEB-Backend - ``` - -- [ ] **Telegram bot .env has correct TELEGRAM_BOT_TOKEN** - ```powershell - notepad C:\inetpub\wwwroot\roa2web\telegram-bot\.env - # Should have ROA2WEBBot token, not ROA2WEBDEVBot token - ``` - -- [ ] **Test full linking flow from web frontend** - - Log in to web frontend (http://10.0.20.36) - - Generate linking code - - Send code to @ROA2WEBBot via `/start CODE12345` - - Should receive success message from bot - ---- - -## Problem: "Cannot connect to backend" / Connection Errors - -After successfully generating a linking code, the Telegram bot finds the code but fails to complete the linking with error messages like: - -- `httpcore.ConnectError: All connection attempts failed` -- `Cannot connect to backend at http://localhost:8000` -- `AttributeError: 'ConnectError' object has no attribute 'response'` (fixed in latest version) - -### Root Cause - -The Telegram bot cannot communicate with the FastAPI backend to verify the Oracle user and obtain a JWT token. This happens when: - -1. Backend service is not running -2. Backend is running on wrong port -3. BACKEND_URL in telegram bot .env is incorrect -4. Firewall blocking communication - -### Diagnostic Steps - -#### 1. Check Backend Service Status - -```powershell -# Check if backend service is running -Get-Service ROA2WEB-Backend - -# Expected output: -# Status Name DisplayName -# ------ ---- ----------- -# Running ROA2WEB-Backend ROA2WEB Backend Service -``` - -If service is **not running**, start it: -```powershell -cd C:\inetpub\wwwroot\roa2web\scripts -.\Start-ROA2WEB.ps1 -``` - -#### 2. Check Backend Port (8000) - -```powershell -# Check if port 8000 is listening -netstat -ano | findstr :8000 - -# Expected output (should show LISTENING): -# TCP 0.0.0.0:8000 0.0.0.0:0 LISTENING -``` - -If port is **not listening**, check backend logs: -```powershell -# View backend service logs -Get-Content C:\inetpub\wwwroot\roa2web\backend\logs\*.log -Tail 50 -``` - -#### 3. Test Backend Health Endpoint - -```powershell -# Test if backend API responds -Invoke-WebRequest http://localhost:8000/health - -# Expected output: -# StatusCode : 200 -# Content : {"status":"healthy",...} -``` - -If this **fails**, backend is not accessible. Check service logs. - -#### 4. Check Telegram Bot BACKEND_URL Configuration - -```powershell -# View telegram bot .env file -notepad C:\inetpub\wwwroot\roa2web\telegram-bot\.env - -# Verify this line exists and is correct: -# BACKEND_URL=http://localhost:8000 -``` - -**Common mistakes:** -- Using `http://localhost:8001` (dev port instead of production port 8000) -- Missing `http://` prefix -- Using IP address instead of localhost - -If BACKEND_URL is **incorrect**, fix it and restart: -```powershell -cd C:\inetpub\wwwroot\roa2web\telegram-bot\scripts -.\Restart-TelegramBot.ps1 -``` - -#### 5. Test Backend Verify-User Endpoint - -```powershell -# Test the specific endpoint telegram bot uses -Invoke-WebRequest -Method POST -Uri http://localhost:8000/api/telegram/auth/verify-user ` - -Headers @{"Content-Type"="application/json"} ` - -Body '{"linking_code":"TESTCODE","oracle_username":"testuser"}' - -# Expected output (will fail with 400/404 for test data, but confirms endpoint is reachable): -# StatusCode: 400 or 404 (NOT connection error) -``` - -If you get **connection error** instead of 400/404, backend is not running or port is wrong. - -### Solution Checklist - -Fix the issue by following this checklist: - -- [ ] **Backend service is running** - ```powershell - Get-Service ROA2WEB-Backend - # If stopped: cd C:\inetpub\wwwroot\roa2web\scripts; .\Start-ROA2WEB.ps1 - ``` - -- [ ] **Backend port 8000 is listening** - ```powershell - netstat -ano | findstr :8000 - # Should show LISTENING on 0.0.0.0:8000 - ``` - -- [ ] **Backend health check responds** - ```powershell - Invoke-WebRequest http://localhost:8000/health - # Should return 200 OK - ``` - -- [ ] **Telegram bot .env has correct BACKEND_URL** - ```powershell - notepad C:\inetpub\wwwroot\roa2web\telegram-bot\.env - # Must be: BACKEND_URL=http://localhost:8000 - ``` - -- [ ] **Telegram bot service restarted after .env changes** - ```powershell - cd C:\inetpub\wwwroot\roa2web\telegram-bot\scripts - .\Restart-TelegramBot.ps1 - ``` - -- [ ] **Test full linking flow** - - Generate code in web frontend - - Send code to @ROA2WEBBot: `/start CODE12345` - - Should receive success message (not connection error) - ---- - -### Common Issues - -#### Issue 1: Port 8002 Already in Use - -**Symptoms:** -- Telegram bot service fails to start -- Logs show "Address already in use" or "Port 8002 is already allocated" - -**Solution:** -```powershell -# Find process using port 8002 -netstat -ano | findstr :8002 - -# Kill the process (replace with actual process ID) -taskkill /PID /F - -# Restart telegram bot service -cd C:\inetpub\wwwroot\roa2web\telegram-bot\scripts -.\Restart-TelegramBot.ps1 -``` - -#### Issue 2: Firewall Blocking Localhost - -**Symptoms:** -- Backend cannot reach http://localhost:8002 -- Connection timeout errors in backend logs - -**Solution:** -```powershell -# Add firewall rule for port 8002 (localhost only) -New-NetFirewallRule -DisplayName "ROA2WEB Telegram Bot Internal API" -Direction Inbound -LocalPort 8002 -Protocol TCP -Action Allow -LocalAddress 127.0.0.1 -``` - -#### Issue 3: Wrong Bot Token - -**Symptoms:** -- Telegram bot service runs but doesn't respond to commands -- Logs show "Unauthorized" or "Invalid bot token" - -**Solution:** -```powershell -# Update .env with correct token from @BotFather -notepad C:\inetpub\wwwroot\roa2web\telegram-bot\.env - -# Change TELEGRAM_BOT_TOKEN to production bot token: -# TELEGRAM_BOT_TOKEN= - -# Restart service -cd C:\inetpub\wwwroot\roa2web\telegram-bot\scripts -.\Restart-TelegramBot.ps1 -``` - -#### Issue 4: SQLite Database Locked - -**Symptoms:** -- Telegram bot logs show "database is locked" errors -- Commands fail intermittently - -**Solution:** -```powershell -# Stop service -cd C:\inetpub\wwwroot\roa2web\telegram-bot\scripts -.\Stop-TelegramBot.ps1 - -# Wait 10 seconds for locks to release -Start-Sleep -Seconds 10 - -# Start service -.\Start-TelegramBot.ps1 -``` - -#### Issue 5: Backend Service Not Running - -**Symptoms:** -- Telegram bot logs show "Cannot connect to backend" errors -- `httpcore.ConnectError: All connection attempts failed` -- Linking codes are found but linking fails - -**Solution:** -```powershell -# Check backend service status -Get-Service ROA2WEB-Backend - -# If stopped, start it -cd C:\inetpub\wwwroot\roa2web\scripts -.\Start-ROA2WEB.ps1 - -# Verify backend is listening on port 8000 -netstat -ano | findstr :8000 - -# Test backend health -Invoke-WebRequest http://localhost:8000/health -``` - -**Check backend logs for startup errors:** -```powershell -Get-Content C:\inetpub\wwwroot\roa2web\backend\logs\*.log -Tail 50 -``` - -**Common backend startup issues:** -- Oracle database not accessible -- Missing environment variables in backend `.env` -- Port 8000 already in use by another process -- Python dependencies not installed - -#### Issue 6: Wrong Backend URL in Telegram Bot - -**Symptoms:** -- Connection errors to backend -- Logs show wrong URL (e.g., `http://localhost:8001` instead of `http://localhost:8000`) - -**Solution:** -```powershell -# Edit telegram bot .env -notepad C:\inetpub\wwwroot\roa2web\telegram-bot\.env - -# Ensure this line is correct: -# BACKEND_URL=http://localhost:8000 -# (Production uses port 8000, not 8001 which is dev port) - -# Restart telegram bot service -cd C:\inetpub\wwwroot\roa2web\telegram-bot\scripts -.\Restart-TelegramBot.ps1 -``` - -### Verification Steps - -After fixing, verify the complete flow works: - -1. **Backend can save codes to telegram bot:** - ```powershell - Invoke-WebRequest -Method POST -Uri http://localhost:8002/internal/save-code -Headers @{"Content-Type"="application/json"} -Body '{"code":"VERIFY01","telegram_user_id":0,"oracle_username":"testuser","expires_in_minutes":15}' - ``` - Expected: `201 Created` with success message - -2. **Telegram bot can verify codes:** - ```powershell - Invoke-WebRequest -Method POST -Uri http://localhost:8002/internal/verify-code -Headers @{"Content-Type"="application/json"} -Body '{"code":"VERIFY01"}' - ``` - Expected: `200 OK` with `"valid":true` - -3. **End-to-end test from web frontend:** - - Open web app: http://10.0.20.36 - - Login with Oracle credentials - - Click "Link Telegram Account" - - Copy the 8-character code - - Send to @ROA2WEBBot: `/start CODE12345` - - Should receive: "Contul tău Telegram a fost asociat cu succes!" - -### Getting Help - -If issues persist after following this guide: - -1. **Collect diagnostic information:** - ```powershell - # Service status - Get-Service ROA2WEB-TelegramBot | Format-List * - - # Port listening - netstat -ano | findstr :8002 - - # Recent logs (last 100 lines) - Get-Content C:\inetpub\wwwroot\roa2web\telegram-bot\logs\stdout.log -Tail 100 - Get-Content C:\inetpub\wwwroot\roa2web\telegram-bot\logs\stderr.log -Tail 100 - - # Backend logs - Get-Content C:\inetpub\wwwroot\roa2web\backend\logs\*.log -Tail 100 - ``` - -2. **Check configuration files:** - ```powershell - # Backend .env (sanitize sensitive data before sharing!) - Get-Content C:\inetpub\wwwroot\roa2web\backend\.env - - # Telegram bot .env (sanitize bot token before sharing!) - Get-Content C:\inetpub\wwwroot\roa2web\telegram-bot\.env - ``` - -3. **Contact support** with the collected diagnostic information. - ---- - -## Quick Reference Commands - -### Service Management -```powershell -# Check status -Get-Service ROA2WEB-TelegramBot - -# Start -cd C:\inetpub\wwwroot\roa2web\telegram-bot\scripts -.\Start-TelegramBot.ps1 - -# Stop -.\Stop-TelegramBot.ps1 - -# Restart -.\Restart-TelegramBot.ps1 -``` - -### Monitoring -```powershell -# Watch logs in real-time -Get-Content C:\inetpub\wwwroot\roa2web\telegram-bot\logs\stdout.log -Wait -Tail 50 - -# Check health -Invoke-WebRequest http://localhost:8002/internal/health - -# Check database stats -Invoke-WebRequest http://localhost:8002/internal/stats -``` - -### Configuration -```powershell -# Edit backend config -notepad C:\inetpub\wwwroot\roa2web\backend\.env - -# Edit telegram bot config -notepad C:\inetpub\wwwroot\roa2web\telegram-bot\.env - -# Restart after changes -Restart-Service ROA2WEB-Backend -cd C:\inetpub\wwwroot\roa2web\telegram-bot\scripts -.\Restart-TelegramBot.ps1 -``` diff --git a/deployment/windows/scripts/README-DEPLOYMENT-WORKFLOW.md b/deployment/windows/scripts/README-DEPLOYMENT-WORKFLOW.md deleted file mode 100644 index 8276244..0000000 --- a/deployment/windows/scripts/README-DEPLOYMENT-WORKFLOW.md +++ /dev/null @@ -1,623 +0,0 @@ -# ROA2WEB - Complete Deployment Workflow (Ultrathin Monolith) - -**Last Updated:** 2025-12-29 -**Architecture:** Ultrathin Monolith (Single Backend Service) - ---- - -## 📋 Overview - -ROA2WEB uses an **automated deployment pipeline** that transfers code from your development machine to the Windows Server and deploys automatically. - -### Architecture Summary - -**Before (Microservices - OBSOLETE):** -- 3 separate Windows services (ports 8000, 8002, 8003) -- Complex deployment with multiple scripts - -**After (Ultrathin Monolith - CURRENT):** -- ✅ **1 Windows service:** `ROA2WEB-Backend` (port 8000) -- ✅ **1 unified backend:** All modules (Reports, Data Entry, Telegram) -- ✅ **Module control:** Enable/disable via `.env` flags -- ✅ **Simplified deployment:** Single service management - ---- - -## 🔄 Complete Deployment Workflow - -``` -┌──────────────────────────────────────────────────────────────────┐ -│ STEP 1: BUILD & TRANSFER (Dev Machine) │ -├──────────────────────────────────────────────────────────────────┤ -│ │ -│ Developer runs: │ -│ .\Publish-And-Deploy.ps1 │ -│ │ │ -│ ├──> Calls Build-ROA2WEB.ps1 │ -│ │ ├── npm run build (Vue.js frontend) │ -│ │ ├── Copy backend/ (Python FastAPI) │ -│ │ ├── Copy shared/ (shared modules) │ -│ │ └── Create ../deploy-package/ │ -│ │ │ -│ └──> Transfer to server │ -│ ├── Try: Windows Share (\\10.0.20.36\Temp) │ -│ └── Fallback: SSH/SCP (port 22122) │ -│ │ -│ Result: deploy-YYYYMMDD-HHmmss/ on server at C:\Temp\ │ -│ │ -└──────────────────────────────────────────────────────────────────┘ - │ - │ Package on server - ▼ -┌──────────────────────────────────────────────────────────────────┐ -│ STEP 2: AUTO-DETECTION (Windows Server - Scheduled Task) │ -├──────────────────────────────────────────────────────────────────┤ -│ │ -│ Check-And-Deploy.ps1 (runs every 5 minutes) │ -│ │ │ -│ ├──> Scan C:\Temp for deploy-* folders │ -│ ├──> Compare with last deployed (in state file) │ -│ └──> If NEW package found: │ -│ Call ROA2WEB-Console.ps1 -Action DeployAll │ -│ │ -└──────────────────────────────────────────────────────────────────┘ - │ - │ New package detected - ▼ -┌──────────────────────────────────────────────────────────────────┐ -│ STEP 3: DEPLOYMENT EXECUTION (ROA2WEB-Console.ps1) │ -├──────────────────────────────────────────────────────────────────┤ -│ │ -│ 1. STOP SERVICE │ -│ └─> Stop-Service ROA2WEB-Backend │ -│ │ -│ 2. BACKUP │ -│ ├─> Backup backend/ → backups/backup-All-TIMESTAMP/ │ -│ ├─> Backup shared/ │ -│ └─> Backup frontend/ │ -│ │ -│ 3. DEPLOY BACKEND │ -│ ├─> Copy backend/ files │ -│ ├─> Copy shared/ files │ -│ └─> Preserve .env file (MODULE flags!) │ -│ │ -│ 4. DEPLOY FRONTEND │ -│ ├─> Copy frontend/ to IIS path │ -│ └─> Copy web.config │ -│ │ -│ 5. START SERVICE │ -│ ├─> Start-Service ROA2WEB-Backend │ -│ ├─> Wait for initialization (5 sec) │ -│ └─> Test health endpoint (http://localhost:8000/health) │ -│ │ -│ 6. VERIFY │ -│ └─> Check service status + module health │ -│ │ -└──────────────────────────────────────────────────────────────────┘ - │ - │ Deployment complete - ▼ - ✅ PRODUCTION RUNNING -``` - ---- - -## 📁 Script Descriptions - -### Development Machine Scripts - -#### **1. Build-ROA2WEB.ps1** -**Purpose:** Create deployment package locally - -**Usage:** -```powershell -# Interactive menu -.\Build-ROA2WEB.ps1 - -# Non-interactive -.\Build-ROA2WEB.ps1 -Component All -OutputPath "D:\deploy-pkg" -``` - -**Components:** -- `All` - Backend + Frontend (recommended) -- `Frontend` - Frontend + Backend (same as All for monolith) -- `Backend` - Backend only (includes all modules) - -**Output:** `../deploy-package/` with: -``` -deploy-package/ -├── backend/ # Unified backend (Reports, Data Entry, Telegram) -├── frontend/ # Unified Vue.js SPA -├── shared/ # Shared Python modules -├── config/ # web.config, .env.example -├── scripts/ # Deployment scripts -└── README.txt # Deployment instructions -``` - ---- - -#### **2. Publish-And-Deploy.ps1** -**Purpose:** Build + Transfer to server - -**Usage:** -```powershell -# Interactive menu (recommended) -.\Publish-And-Deploy.ps1 - -# Non-interactive (for CI/CD) -.\Publish-And-Deploy.ps1 -NonInteractive -Action Build -Component All - -# Force specific transfer method -.\Publish-And-Deploy.ps1 -NonInteractive -Action Build -Component All -TransferMethod SSH -``` - -**Transfer Methods:** -- **Auto** (default) - Try Windows Share, fallback to SSH -- **WindowsShare** - Fast LAN transfer (`\\10.0.20.36\Temp`) -- **SSH** - Secure remote transfer (port 22122) - -**What it does:** -1. Calls `Build-ROA2WEB.ps1` internally -2. Transfers package to server `C:\Temp\deploy-YYYYMMDD-HHmmss\` -3. Server auto-deploys within 5 minutes - ---- - -### Server-Side Scripts - -#### **3. Check-And-Deploy.ps1** ⏰ -**Purpose:** Auto-deploy monitor (scheduled task) - -**Scheduled Task:** Runs every 5 minutes automatically - -**Manual Usage:** -```powershell -# Interactive mode -.\Check-And-Deploy.ps1 -Interactive - -# Check only (no deploy) -.\Check-And-Deploy.ps1 -CheckOnly - -# Non-interactive (as scheduled task) -.\Check-And-Deploy.ps1 -``` - -**What it does:** -1. Scans `C:\Temp` for `deploy-*` folders -2. Checks state file: `C:\Temp\ROA2WEB-Scripts\last-deploy.json` -3. If NEW package found → calls `ROA2WEB-Console.ps1 -Action DeployAll` -4. Saves deployment history - -**State File Location:** `C:\Temp\ROA2WEB-Scripts\last-deploy.json` -**Log File:** `C:\Temp\ROA2WEB-Scripts\Logs\check-and-deploy.log` - ---- - -#### **4. ROA2WEB-Console.ps1** ⚙️ -**Purpose:** Unified management console for monolith - -**Interactive Mode:** -```powershell -.\ROA2WEB-Console.ps1 - -# Menu options: -[1] Deploy Backend -[2] Deploy Frontend -[3] Deploy All (Backend + Frontend) -[4] Start Service -[5] Stop Service -[6] Restart Service -[7] View Status -[8] View Logs -[Q] Quit -``` - -**Non-Interactive Mode:** -```powershell -# Deploy all -.\ROA2WEB-Console.ps1 -NonInteractive -Action DeployAll -PackagePath "C:\Temp\deploy-20250129-120000" - -# Deploy backend only -.\ROA2WEB-Console.ps1 -NonInteractive -Action DeployBackend -PackagePath "C:\Temp\deploy-20250129-120000" - -# Service management -.\ROA2WEB-Console.ps1 -NonInteractive -Action RestartService -.\ROA2WEB-Console.ps1 -NonInteractive -Action Status -.\ROA2WEB-Console.ps1 -NonInteractive -Action ViewLogs -``` - -**Actions:** -- `DeployBackend` - Deploy backend + shared (stops/starts service) -- `DeployFrontend` - Deploy frontend to IIS -- `DeployAll` - Full deployment (backend + frontend) -- `StartService` - Start ROA2WEB-Backend -- `StopService` - Stop ROA2WEB-Backend -- `RestartService` - Restart ROA2WEB-Backend -- `Status` - Show service status + health check -- `ViewLogs` - Display recent logs - -**Service Configuration:** -- Service Name: `ROA2WEB-Backend` -- Port: `8000` -- Health Check: `http://localhost:8000/health` - -**Paths:** -- Install Root: `C:\inetpub\wwwroot\roa2web\` -- Backend: `C:\inetpub\wwwroot\roa2web\backend\` -- Frontend: `C:\inetpub\wwwroot\roa2web\frontend\` -- Shared: `C:\inetpub\wwwroot\roa2web\shared\` -- Logs: `C:\inetpub\wwwroot\roa2web\logs\` -- Backups: `C:\inetpub\wwwroot\roa2web\backups\` - ---- - -#### **5. Setup-AutoDeploy.ps1** 🔧 -**Purpose:** Configure scheduled task for auto-deployment - -**Usage (run once on server):** -```powershell -.\Setup-AutoDeploy.ps1 -``` - -**What it does:** -- Creates scheduled task: `ROA2WEB-AutoDeploy` -- Runs `Check-And-Deploy.ps1` every 5 minutes -- Runs as SYSTEM account with highest privileges - -**To verify:** -```powershell -Get-ScheduledTask -TaskName "ROA2WEB-AutoDeploy" -``` - ---- - -#### **6. Install-ROA2WEB.ps1** 🆕 -**Purpose:** First-time installation (creates Windows service) - -**Usage (run once during initial setup):** -```powershell -.\Install-ROA2WEB.ps1 -``` - -**What it does:** -- Creates `ROA2WEB-Backend` Windows service (NSSM) -- Configures Python virtual environment -- Sets up IIS application -- Creates necessary directories - ---- - -## 🎯 Common Scenarios - -### Scenario 1: Normal Development Workflow - -**On Dev Machine:** -```powershell -# Make your code changes, then: -.\Publish-And-Deploy.ps1 -# Select [1] All Components -# Select [1] Auto-detect transfer method -``` - -**On Server:** -- Wait 5 minutes (auto-deploy via scheduled task) -- OR manually: `.\Check-And-Deploy.ps1 -Interactive` → `[2] Check and Deploy Now` - -**Verify:** -- Check health: `http://10.0.20.36:8000/health` -- Check logs: `C:\inetpub\wwwroot\roa2web\logs\backend-stdout.log` - ---- - -### Scenario 2: Backend-Only Deployment (Faster) - -**Dev Machine:** -```powershell -.\Publish-And-Deploy.ps1 -NonInteractive -Action Build -Component Backend -``` - -**Server (manual):** -```powershell -.\ROA2WEB-Console.ps1 -NonInteractive -Action DeployBackend -PackagePath "C:\Temp\deploy-YYYYMMDD-HHmmss" -``` - ---- - -### Scenario 3: Emergency Rollback - -**Option A: Restore from backup** -```powershell -cd C:\inetpub\wwwroot\roa2web\backups -dir # Find latest backup - -Stop-Service ROA2WEB-Backend -Copy-Item backup-All-YYYYMMDD-HHmmss\backend\* C:\inetpub\wwwroot\roa2web\backend\ -Recurse -Force -Copy-Item backup-All-YYYYMMDD-HHmmss\shared\* C:\inetpub\wwwroot\roa2web\shared\ -Recurse -Force -Start-Service ROA2WEB-Backend -``` - -**Option B: Re-deploy previous package** -```powershell -cd C:\Temp -dir deploy-* # Find previous package - -.\scripts\ROA2WEB-Console.ps1 -NonInteractive -Action DeployAll -PackagePath "C:\Temp\deploy-PREVIOUS" -``` - ---- - -### Scenario 4: Module Control (Enable/Disable Modules) - -**Edit .env file:** -```powershell -notepad C:\inetpub\wwwroot\roa2web\backend\.env - -# Change flags: -MODULE_REPORTS_ENABLED=true # Enable Reports -MODULE_DATA_ENTRY_ENABLED=false # Disable Data Entry -MODULE_TELEGRAM_ENABLED=true # Enable Telegram -``` - -**Restart service:** -```powershell -.\ROA2WEB-Console.ps1 -NonInteractive -Action RestartService -``` - -**Verify:** -```powershell -.\ROA2WEB-Console.ps1 -NonInteractive -Action Status -# Shows which modules are enabled/disabled -``` - ---- - -## 🔍 Monitoring & Troubleshooting - -### Check Service Status -```powershell -# Via Console (recommended) -.\ROA2WEB-Console.ps1 -NonInteractive -Action Status - -# Via Windows Services -Get-Service ROA2WEB-Backend - -# Detailed status -Get-Service ROA2WEB-Backend | Format-List * -``` - -### View Logs -```powershell -# Via Console (recommended - last 30 lines) -.\ROA2WEB-Console.ps1 -NonInteractive -Action ViewLogs - -# Manual log access -Get-Content C:\inetpub\wwwroot\roa2web\logs\backend-stdout.log -Tail 50 -Get-Content C:\inetpub\wwwroot\roa2web\logs\backend-stderr.log -Tail 20 -``` - -### Check Deployment History -```powershell -# View state file -Get-Content C:\Temp\ROA2WEB-Scripts\last-deploy.json | ConvertFrom-Json | Format-List - -# View auto-deploy log -Get-Content C:\Temp\ROA2WEB-Scripts\Logs\check-and-deploy.log -Tail 100 -``` - -### Test Health Endpoint -```powershell -Invoke-WebRequest http://localhost:8000/health -Invoke-WebRequest http://localhost:8000/docs -``` - ---- - -## 🚨 Common Issues - -### Issue 1: Service Won't Start - -**Symptoms:** -```powershell -Get-Service ROA2WEB-Backend -# Status: Stopped -``` - -**Check:** -```powershell -# View error logs -Get-Content C:\inetpub\wwwroot\roa2web\logs\backend-stderr.log -Tail 30 - -# Common causes: -# - Port 8000 already in use -# - .env file missing/invalid -# - Python venv issues -# - Oracle connection issues -``` - -**Fix:** -```powershell -# Check port -netstat -ano | findstr :8000 - -# Verify .env file -Test-Path C:\inetpub\wwwroot\roa2web\backend\.env - -# Restart service -.\ROA2WEB-Console.ps1 -NonInteractive -Action RestartService -``` - ---- - -### Issue 2: Auto-Deploy Not Working - -**Check scheduled task:** -```powershell -Get-ScheduledTask -TaskName "ROA2WEB-AutoDeploy" | Format-List * -Get-ScheduledTaskInfo -TaskName "ROA2WEB-AutoDeploy" -``` - -**Check logs:** -```powershell -Get-Content C:\Temp\ROA2WEB-Scripts\Logs\check-and-deploy.log -Tail 50 -``` - -**Manual trigger:** -```powershell -Start-ScheduledTask -TaskName "ROA2WEB-AutoDeploy" -``` - -**Re-setup scheduled task:** -```powershell -.\Setup-AutoDeploy.ps1 -``` - ---- - -### Issue 3: Transfer Fails (Publish-And-Deploy) - -**Windows Share not accessible:** -```powershell -# Test share access -Test-Path \\10.0.20.36\Temp - -# If fails, use SSH -.\Publish-And-Deploy.ps1 -NonInteractive -Action Build -Component All -TransferMethod SSH -``` - -**SSH connection fails:** -```powershell -# Test SSH -.\Publish-And-Deploy.ps1 -NonInteractive -Action TestConnections - -# Check SSH key -Test-Path ~/.ssh/id_ed25519 -``` - ---- - -## 📊 Deployment Verification Checklist - -After deployment, verify: - -- [ ] **Service Status** - ```powershell - Get-Service ROA2WEB-Backend - # Status: Running - ``` - -- [ ] **Health Check** - ```powershell - Invoke-WebRequest http://localhost:8000/health - # StatusCode: 200 - ``` - -- [ ] **API Docs** - ```powershell - Invoke-WebRequest http://localhost:8000/docs - # Should show Swagger UI - ``` - -- [ ] **Module Status** - ```powershell - .\ROA2WEB-Console.ps1 -NonInteractive -Action Status - # Check all enabled modules - ``` - -- [ ] **Frontend Access** - - Open browser: `http://10.0.20.36/roa2web` - - Verify login page loads - -- [ ] **No Errors in Logs** - ```powershell - Get-Content C:\inetpub\wwwroot\roa2web\logs\backend-stderr.log -Tail 10 - # Should be empty or only INFO/WARNING - ``` - ---- - -## 🔄 Complete Workflow Diagram - -``` -DEV MACHINE NETWORK WINDOWS SERVER -───────────── ──────── ────────────── - -Code Changes - │ - ├─► Build-ROA2WEB.ps1 - │ │ - │ ├── npm build - │ ├── copy files - │ └── ../deploy-package/ - │ - ├─► Publish-And-Deploy.ps1 - │ │ - │ ├── calls Build-ROA2WEB.ps1 - │ └─► Transfer ───────────────────────► C:\Temp\deploy-*\ - │ - │ - ┌─────────▼──────────┐ - │ Scheduled Task │ - │ (every 5 minutes) │ - └────────┬───────────┘ - │ - Check-And-Deploy.ps1 - │ - ├─ Scan C:\Temp - ├─ Check state - └─ If NEW: - │ - ROA2WEB-Console.ps1 - │ - ┌─────────▼──────────┐ - │ 1. Stop Service │ - │ 2. Backup │ - │ 3. Deploy Backend │ - │ 4. Deploy Frontend │ - │ 5. Start Service │ - │ 6. Health Check │ - └─────────┬──────────┘ - │ - ▼ - ✅ DEPLOYMENT COMPLETE - - ROA2WEB-Backend - ├── Reports Module - ├── Data Entry Module - └── Telegram Module - (Port 8000) -``` - ---- - -## 📚 Additional Resources - -- **Main Documentation:** `/deployment/windows/docs/WINDOWS_DEPLOYMENT.md` -- **Architecture Guide:** `/CLAUDE.md` -- **Troubleshooting:** `/deployment/windows/docs/TELEGRAM_BOT_TROUBLESHOOTING.md` -- **Obsolete Scripts:** `/deployment/windows/scripts/obsolete/` (old microservices setup) - ---- - -## ✅ Summary - -**Ultrathin Monolith Benefits:** -- ✅ **1 service** instead of 3 (simpler management) -- ✅ **Shared resources** (Oracle pool, auth, cache) -- ✅ **Faster deployment** (single service restart) -- ✅ **Module control** via .env flags (no code changes needed) -- ✅ **Automated workflow** (5-minute auto-deploy) -- ✅ **Automatic backups** (last 5 kept) -- ✅ **Rollback capability** (restore from backup) - -**Key Scripts:** -1. `Publish-And-Deploy.ps1` - Dev machine (build + transfer) -2. `Check-And-Deploy.ps1` - Server (auto-deploy monitor) -3. `ROA2WEB-Console.ps1` - Server (deployment execution + management) - -**Normal Workflow:** -1. Make code changes -2. Run `Publish-And-Deploy.ps1` -3. Wait 5 minutes (auto-deploy) -4. Verify deployment - -That's it! 🎉 diff --git a/deployment/windows/scripts/README.md b/deployment/windows/scripts/README.md deleted file mode 100644 index 6016f82..0000000 --- a/deployment/windows/scripts/README.md +++ /dev/null @@ -1,491 +0,0 @@ -# 🛠️ ROA2WEB Windows Deployment Scripts - -Complete reference for ROA2WEB Windows deployment PowerShell scripts (v2.0 - Unified System). - -## 📋 Script Overview - -### ⭐ Unified Scripts (Recommended) - -#### **Build-ROA2WEB.ps1** - Unified Build System -**Purpose**: Build deployment packages for all components with interactive menu - -**Usage**: -```powershell -# Interactive mode - shows menu -.\Build-ROA2WEB.ps1 - -# Non-interactive mode - specific component -.\Build-ROA2WEB.ps1 -Component All # Complete package -.\Build-ROA2WEB.ps1 -Component Frontend # Frontend + Backend -.\Build-ROA2WEB.ps1 -Component Backend # Backend only -.\Build-ROA2WEB.ps1 -Component TelegramBot # Telegram Bot only - -# Custom output path -.\Build-ROA2WEB.ps1 -Component All -OutputPath "D:\builds\roa2web-$(Get-Date -Format 'yyyyMMdd')" -``` - -**Interactive Menu**: -``` -[1] All Components (Frontend + Backend + Telegram Bot) -[2] Frontend + Backend (Vue.js build + FastAPI backend) -[3] Backend Only (FastAPI backend + shared modules) -[4] Telegram Bot Only (Standalone package) -[Q] Quit -``` - -**Parameters**: -- `-Component` All|Frontend|Backend|TelegramBot (optional - shows menu if not specified) -- `-OutputPath` (default: `./deploy-package`) -- `-Clean` $true|$false (default: $true) - -**Features**: -- ✅ Interactive menu for component selection -- ✅ Isolated temp directory for frontend builds (doesn't corrupt WSL node_modules) -- ✅ Automatic dependency installation (including devDependencies) -- ✅ Auto-cleanup after build -- ✅ Generates deployment README - -**Output**: Creates `deploy-package/` with complete deployment files - ---- - -#### **ROA2WEB-Console.ps1** - Unified Deployment & Management Console -**Purpose**: All-in-one console for deploying and managing ROA2WEB services - -**Usage**: -```powershell -# Interactive mode - shows main menu -.\ROA2WEB-Console.ps1 - -# Non-interactive mode - specific actions -.\ROA2WEB-Console.ps1 -NonInteractive -Action DeployAll -.\ROA2WEB-Console.ps1 -NonInteractive -Action DeployBackend -.\ROA2WEB-Console.ps1 -NonInteractive -Action DeployTelegramBot -.\ROA2WEB-Console.ps1 -NonInteractive -Action StartAll -.\ROA2WEB-Console.ps1 -NonInteractive -Action StopAll -.\ROA2WEB-Console.ps1 -NonInteractive -Action RestartAll -.\ROA2WEB-Console.ps1 -NonInteractive -Action Status -``` - -**Interactive Main Menu**: -``` -[1] Deploy Components - - Deploy Backend + Frontend - - Deploy Telegram Bot - - Deploy All Components - -[2] Manage Services - - Start/Stop/Restart All - - Start/Stop/Restart Backend - - Start/Stop/Restart Telegram Bot - -[3] Check Status - - Service status - - Health checks - -[Q] Quit -``` - -**Parameters**: -- `-NonInteractive` Switch to enable non-interactive mode -- `-Action` DeployBackend|DeployTelegramBot|DeployAll|StartAll|StopAll|RestartAll|Status - -**Features**: -- ✅ Unified interface for deploy + management -- ✅ Interactive menus with easy navigation -- ✅ Automatic backups before deployment -- ✅ Smart dependency updates (only if requirements.txt changed) -- ✅ Health checks after operations -- ✅ Color-coded status output -- ✅ Both interactive and non-interactive modes -- ✅ Preserves .env configuration files - -**Replaces**: -- ❌ `Deploy-ROA2WEB.ps1` (removed) -- ❌ `Deploy-TelegramBot.ps1` (removed) -- ❌ `Manage-ROA2WEB.ps1` (removed) - ---- - -### 🚀 Installation Scripts (First-Time Setup) - -#### **Install-ROA2WEB.ps1** -**Purpose**: First-time installation of Backend + Frontend - -**Usage**: -```powershell -.\Install-ROA2WEB.ps1 - -# Custom parameters -.\Install-ROA2WEB.ps1 -InstallPath "C:\Apps\roa2web" -ServicePort 8000 -``` - -**What it does**: -1. Installs Chocolatey, Python 3.11+, NSSM -2. Installs IIS URL Rewrite & ARR modules -3. Creates directory structure -4. Creates Python virtual environment -5. Installs Python dependencies -6. Creates Windows Service (ROA2WEB-Backend) -7. Configures IIS website & application - -**Parameters**: -- `-InstallPath` (default: `C:\inetpub\wwwroot\roa2web`) -- `-ServicePort` (default: 8000) -- `-IISSiteName`, `-IISAppName` -- `-CreateNewSite`, `-SkipPython`, `-SkipIIS` - ---- - -#### **Install-TelegramBot.ps1** -**Purpose**: First-time installation of Telegram Bot - -**Usage**: -```powershell -.\Install-TelegramBot.ps1 - -# Custom parameters -.\Install-TelegramBot.ps1 -InstallPath "C:\Apps\telegram-bot" -ServicePort 8002 -``` - -**What it does**: -1. Validates Python 3.11+ installation -2. Installs NSSM (if needed) -3. Creates directory structure (data/, logs/, backups/) -4. Creates Python virtual environment -5. Installs Python dependencies -6. Creates Windows Service (ROA2WEB-TelegramBot) -7. Creates .env template - -**Parameters**: -- `-InstallPath` (default: `C:\inetpub\wwwroot\roa2web\telegram-bot`) -- `-ServicePort` (default: 8002) -- `-SourcePath` (auto-detected) - ---- - -### 🛠️ Utility Scripts - -#### **Backup-TelegramDB.ps1** -**Purpose**: Backup Telegram bot SQLite database - -**Usage**: -```powershell -# Basic backup -.\Backup-TelegramDB.ps1 - -# Compressed backup -.\Backup-TelegramDB.ps1 -Compress $true - -# Keep more backups -.\Backup-TelegramDB.ps1 -RetentionCount 20 -``` - -**What it does**: -1. Stops bot service gracefully -2. Creates timestamped backup of `telegram_bot.db` -3. Optionally compresses backup -4. Restarts service -5. Cleans old backups (configurable retention) - ---- - -#### **Setup-DailyBackup.ps1** -**Purpose**: Schedule automated daily database backups - -**Usage**: -```powershell -# Setup daily backup at 2 AM -.\Setup-DailyBackup.ps1 - -# Custom time and retention -.\Setup-DailyBackup.ps1 -Time "03:00" -RetentionDays 30 -``` - -**What it does**: -1. Creates Windows Scheduled Task -2. Runs `Backup-TelegramDB.ps1` daily at specified time -3. Configurable time, retention, and compression - ---- - -#### **Setup-ClaudeAuth.ps1** -**Purpose**: Setup Claude API authentication for Telegram bot - -**Usage**: -```powershell -.\Setup-ClaudeAuth.ps1 -``` - -**What it does**: -1. **Method 1 (Recommended)**: Browser-based Claude Pro/Max login - - Runs `claude-code login` if available - - Copies credentials to bot installation directory -2. **Method 2**: Manual API key entry -3. Validates credentials -4. Updates .env file -5. Restarts bot service - -**Features**: -- ✅ Supports both Claude Pro/Max and API key -- ✅ Auto-detects credentials location -- ✅ Validates authentication before applying - ---- - -#### **Enable-HTTPS.ps1** -**Purpose**: Enable HTTPS for IIS website - -**Usage**: -```powershell -# Create self-signed certificate -.\Enable-HTTPS.ps1 - -# Use existing certificate -.\Enable-HTTPS.ps1 -CertPath "C:\Certs\roa2web.pfx" -CertPassword "password" -``` - -**What it does**: -1. Creates/imports SSL certificate -2. Configures HTTPS binding (port 443) -3. Enables HTTP to HTTPS redirect -4. Activates HSTS (HTTP Strict Transport Security) - ---- - -## 🚀 Quick Reference Guide - -### 📦 First-Time Deployment Workflow - -```powershell -# ======================================== -# STEP 1: Build on Development Machine (WSL/Linux) -# ======================================== -cd deployment/windows/scripts -.\Build-ROA2WEB.ps1 -# Select [1] All Components from menu - -# ======================================== -# STEP 2: Transfer Package to Windows Server -# ======================================== -# Transfer deploy-package/ to server (e.g., C:\Deploy\roa2web-package) - -# ======================================== -# STEP 3: Install on Windows Server (as Administrator) -# ======================================== -cd C:\Deploy\roa2web-package\scripts - -# Install Backend + Frontend -.\Install-ROA2WEB.ps1 - -# Install Telegram Bot -.\Install-TelegramBot.ps1 - -# ======================================== -# STEP 4: Configure -# ======================================== -notepad C:\inetpub\wwwroot\roa2web\backend\.env -notepad C:\inetpub\wwwroot\roa2web\telegram-bot\.env - -# ======================================== -# STEP 5: Start Services via Console -# ======================================== -.\ROA2WEB-Console.ps1 -# Select [2] Manage Services -> [1] Start All Services -``` - ---- - -### 🔄 Deploy Updates Workflow - -```powershell -# ======================================== -# STEP 1: Build New Package on Development Machine -# ======================================== -cd deployment/windows/scripts -.\Build-ROA2WEB.ps1 -# Select component to update from menu - -# ======================================== -# STEP 2: Transfer to Windows Server -# ======================================== -# Transfer new deploy-package/ to server - -# ======================================== -# STEP 3: Deploy via Console (as Administrator) -# ======================================== -cd C:\Deploy\new-package\scripts -.\ROA2WEB-Console.ps1 - -# Option A: Interactive Menu -# [1] Deploy Components -> Select what to deploy - -# Option B: Non-Interactive -.\ROA2WEB-Console.ps1 -NonInteractive -Action DeployAll -``` - ---- - -### 🎛️ Daily Operations via Console - -```powershell -# Launch console -.\ROA2WEB-Console.ps1 - -# Main Menu Navigation: -# [1] Deploy Components -> Deploy/update application files -# [2] Manage Services -> Start/Stop/Restart services -# [3] Check Status -> View service status and health -# [Q] Quit - -# Non-Interactive Quick Commands: -.\ROA2WEB-Console.ps1 -NonInteractive -Action Status -.\ROA2WEB-Console.ps1 -NonInteractive -Action RestartAll -``` - ---- - -### 📊 Utility Operations - -```powershell -# Backup database -.\Backup-TelegramDB.ps1 - -# Setup automated daily backups -.\Setup-DailyBackup.ps1 -Time "02:00" -RetentionDays 14 - -# Configure Claude API -.\Setup-ClaudeAuth.ps1 - -# Enable HTTPS -.\Enable-HTTPS.ps1 -``` - ---- - -## 📊 Script Comparison: v1.0 vs v2.0 - -| Capability | v1.0 (Old) | v2.0 (Unified) | -|-----------|-----------|----------------| -| **Build Scripts** | 3 separate | 1 unified (`Build-ROA2WEB.ps1`) | -| **Deploy Scripts** | 2 separate | 1 unified console (`ROA2WEB-Console.ps1`) | -| **Manage Scripts** | 1 basic | Integrated in console | -| **Total Scripts** | 13 scripts | 8 scripts | -| **Interactive Menus** | ❌ No | ✅ Yes | -| **Non-Interactive Mode** | ⚠️ Partial | ✅ Full support | -| **Health Checks** | ⚠️ Basic | ✅ Comprehensive | -| **Backup Management** | ⚠️ Manual | ✅ Automatic | -| **Dependency Updates** | ⚠️ Always reinstall | ✅ Smart (only if changed) | -| **WSL Compatibility** | ❌ Corrupts node_modules | ✅ Isolated builds | - ---- - -## 🗂️ Complete Script List (v2.0) - -### Core Scripts (2) -1. ⭐ **Build-ROA2WEB.ps1** - Unified build system with menu -2. ⭐ **ROA2WEB-Console.ps1** - Unified deployment & management console - -### Installation Scripts (2) -3. **Install-ROA2WEB.ps1** - First-time Backend + Frontend setup -4. **Install-TelegramBot.ps1** - First-time Telegram Bot setup - -### Utility Scripts (4) -5. **Backup-TelegramDB.ps1** - Database backup -6. **Setup-DailyBackup.ps1** - Automated backup scheduling -7. **Setup-ClaudeAuth.ps1** - Claude API configuration -8. **Enable-HTTPS.ps1** - HTTPS setup for IIS - -### Removed Scripts (5) -- ❌ `Build-Frontend.ps1` → Use `Build-ROA2WEB.ps1 -Component Frontend` -- ❌ `Build-TelegramBot.ps1` → Use `Build-ROA2WEB.ps1 -Component TelegramBot` -- ❌ `Deploy-ROA2WEB.ps1` → Use `ROA2WEB-Console.ps1` menu option [1] Deploy -- ❌ `Deploy-TelegramBot.ps1` → Use `ROA2WEB-Console.ps1` menu option [1] Deploy -- ❌ `Manage-ROA2WEB.ps1` → Use `ROA2WEB-Console.ps1` menu option [2] Manage - ---- - -## 💡 Best Practices - -### Development Machine (WSL/Linux) -```powershell -# Always use Build-ROA2WEB.ps1 for building -# It isolates npm builds to prevent WSL corruption -.\Build-ROA2WEB.ps1 -``` - -### Windows Server -```powershell -# Use ROA2WEB-Console.ps1 for all operations -# Interactive mode for manual operations -.\ROA2WEB-Console.ps1 - -# Non-interactive mode for automation/scripts -.\ROA2WEB-Console.ps1 -NonInteractive -Action DeployAll -``` - -### Configuration Management -- ✅ `.env` files are NEVER overwritten during deployment -- ✅ Backups are created automatically before any deployment -- ✅ Old backups are auto-cleaned (keeps last 10) -- ✅ Dependencies only reinstalled if `requirements.txt` changes - -### Service Management -- ✅ Always use ROA2WEB-Console for service operations -- ✅ Health checks are automatic after service starts -- ✅ Color-coded output makes status clear -- ✅ Services can be managed individually or together - ---- - -## 🐛 Troubleshooting - -### Script Execution Policy Error -```powershell -Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser -``` - -### Build Fails on WSL -- Ensure Node.js 16+ is installed: `node -v` -- Close all IDEs (file locks prevent builds) -- Run as Administrator in PowerShell - -### Service Won't Start -```powershell -# Check status via console -.\ROA2WEB-Console.ps1 -NonInteractive -Action Status - -# View backend logs -Get-Content C:\inetpub\wwwroot\roa2web\logs\backend-stderr.log -Tail 50 - -# View Telegram bot logs -Get-Content C:\inetpub\wwwroot\roa2web\telegram-bot\logs\stderr.log -Tail 50 -``` - -### Deployment Fails -```powershell -# ROA2WEB-Console.ps1 creates automatic backups -# Check backup location if rollback needed -Get-ChildItem C:\inetpub\wwwroot\roa2web\backups\ | Sort-Object Name -Descending -``` - -### Frontend Build Corrupts WSL node_modules -- ✅ **Fixed in v2.0!** Build-ROA2WEB.ps1 uses isolated temp directory -- The temp directory is automatically cleaned after build - ---- - -## 📚 Documentation - -- **Quick Start**: [`../README.md`](../README.md) -- **Complete Deployment Guide**: [`../docs/WINDOWS_DEPLOYMENT.md`](../docs/WINDOWS_DEPLOYMENT.md) -- **Deployment Package Guide**: [`../DEPLOY_PACKAGE.md`](../DEPLOY_PACKAGE.md) -- **Telegram Bot Troubleshooting**: [`../docs/TELEGRAM_BOT_TROUBLESHOOTING.md`](../docs/TELEGRAM_BOT_TROUBLESHOOTING.md) -- **HTTPS Setup**: [`../docs/HTTPS_SETUP.md`](../docs/HTTPS_SETUP.md) -- **Project Documentation**: [`../../../CLAUDE.md`](../../../CLAUDE.md) - ---- - -**Version**: 2.0 (Unified System) -**Last Updated**: 2025-11-12 -**Author**: ROA2WEB Team diff --git a/docs/DEPLOYMENT.md b/docs/DEPLOYMENT.md new file mode 100644 index 0000000..1c4d730 --- /dev/null +++ b/docs/DEPLOYMENT.md @@ -0,0 +1,192 @@ +# ROA2WEB Deployment Guide + +**Arhitectură:** Ultrathin Monolith | **Serviciu:** `ROA2WEB-Backend` (port 8000) + +--- + +## Overview + +ROA2WEB folosește o arhitectură **ultrathin monolith** - un singur serviciu backend care gestionează toate modulele: + +| Modul | Descriere | Control | +|-------|-----------|---------| +| Reports | Rapoarte read-only din Oracle | `MODULE_REPORTS_ENABLED` | +| Data Entry | Input date cu workflow aprobare | `MODULE_DATA_ENTRY_ENABLED` | +| Telegram | Bot Telegram integrat | `MODULE_TELEGRAM_ENABLED` | + +**Avantaje:** +- Single Windows/Linux service de gestionat +- Shared database connection pool +- Deployment simplificat +- Consum redus de memorie + +--- + +## Quick Deploy + +### Din Linux/LXC (Recomandat) + +```bash +cd deployment/linux +./deploy.sh # Full deploy (frontend + backend) +./deploy.sh frontend # Doar frontend +./deploy.sh backend # Doar backend +./deploy.sh test # Test conexiune SSH +``` + +**Detalii:** [deployment/linux/README.md](../deployment/linux/README.md) + +### Din Windows + +```powershell +cd deployment\windows\scripts +.\Publish-And-Deploy.ps1 + +# Non-interactiv: +.\Publish-And-Deploy.ps1 -NonInteractive -Action Build -Component All +``` + +**Detalii:** [deployment/windows/README.md](../deployment/windows/README.md) + +--- + +## Deployment Flow + +``` +DEV MACHINE WINDOWS SERVER +─────────── ────────────── + +deploy.sh (Linux) + sau ───► C:\Temp\deploy-*\ +Publish-And-Deploy.ps1 │ + ▼ + Check-And-Deploy.ps1 + (scheduled task, 5 min) + │ + ▼ + ROA2WEB-Console.ps1 + ├── Stop Service + ├── Backup + ├── Deploy Files + ├── Start Service + └── Health Check + │ + ▼ + ✅ PRODUCTION RUNNING +``` + +--- + +## Server Configuration + +### Structura pe Server + +``` +C:\inetpub\wwwroot\roa2web\ +├── backend\ # FastAPI (toate modulele) +│ └── .env # MODULE_*_ENABLED flags +├── frontend\ # Vue.js SPA + web.config +├── shared\ # Module Python partajate +├── logs\ # backend-stdout.log, backend-stderr.log +└── backups\ # Backup-uri automate +``` + +### Configurare Modul (.env) + +```bash +# Module enable/disable +MODULE_REPORTS_ENABLED=true +MODULE_DATA_ENTRY_ENABLED=true +MODULE_TELEGRAM_ENABLED=true + +# Database +ORACLE_DSN=localhost:1521/ORCL +ORACLE_USER=contafin +ORACLE_PASSWORD=*** + +# Auth +JWT_SECRET_KEY=your-secret-key +``` + +--- + +## Architecture + +``` +Client → IIS (80/443) + │ + ├─ /roa2web/api/* → ROA2WEB-Backend (localhost:8000) + │ ├── Reports Module → Oracle DB + │ ├── Data Entry Module → SQLite + │ └── Telegram Module (background task) + │ + └─ /roa2web/* → Frontend (Vue.js SPA) +``` + +### Single Worker Requirement + +**IMPORTANT:** Backend-ul TREBUIE rulat cu `--workers 1` pentru: +- Telegram bot (un singur bot instance permis) +- SQLite cache (evită conflicte de locking) + +**Detalii:** [docs/telegram/DEPLOYMENT.md](./telegram/DEPLOYMENT.md) + +--- + +## Platform-Specific Guides + +| Platform | Guide | Scop | +|----------|-------|------| +| **Linux/LXC** | [deployment/linux/README.md](../deployment/linux/README.md) | Deploy din container Linux | +| **Windows** | [deployment/windows/README.md](../deployment/windows/README.md) | IIS setup, Windows service | +| **HTTPS** | [deployment/windows/docs/HTTPS_SETUP.md](../deployment/windows/docs/HTTPS_SETUP.md) | SSL certificate setup | +| **2-Tier IIS** | [deployment/windows/docs/TWO-TIER-IIS-DEPLOYMENT.md](../deployment/windows/docs/TWO-TIER-IIS-DEPLOYMENT.md) | Public → Internal architecture | +| **Auto-Deploy** | [deployment/windows/docs/DEPLOYMENT_AUTOMATION.md](../deployment/windows/docs/DEPLOYMENT_AUTOMATION.md) | Scheduled task automation | + +--- + +## web.config Files + +| Fișier | Scop | Când se folosește | +|--------|------|-------------------| +| `public/web.config` | Sub-aplicație IIS (/roa2web) | La fiecare deploy (via Vite) | +| `deployment/windows/config/web.config` | Server IIS complet | La instalare nouă | + +**Notă:** Ambele au configurat `no-cache` pentru API (backend gestionează cache-ul). + +--- + +## Troubleshooting + +| Problemă | Verificare | Soluție | +|----------|------------|---------| +| Service nu pornește | Logs: `backend-stderr.log` | Verifică `.env`, port 8000 | +| API 502/504 | `curl http://localhost:8000/health` | Restart service | +| Frontend nu se încarcă | `iisreset` | Verifică IIS, web.config | +| Auto-deploy nu merge | `Get-ScheduledTask ROA2WEB-AutoDeploy` | Re-run setup script | +| Telegram conflicts | Logs: "terminated by other getUpdates" | Ensure `--workers 1` | + +--- + +## System Requirements + +| Resursă | Minim | Recomandat | +|---------|-------|------------| +| OS | Windows Server 2016 / Ubuntu 20.04 | Windows Server 2019+ | +| RAM | 4 GB | 8 GB (16 GB cu OCR) | +| CPU | 2 cores | 4 cores | +| Python | 3.11+ | 3.11+ | +| IIS | URL Rewrite + ARR | URL Rewrite + ARR | + +--- + +## Related Documentation + +- [ARCHITECTURE-DECISIONS.md](./ARCHITECTURE-DECISIONS.md) - ADR-uri importante +- [MONOLITH_ARCHITECTURE.md](./MONOLITH_ARCHITECTURE.md) - Arhitectura detaliată +- [telegram/DEPLOYMENT.md](./telegram/DEPLOYMENT.md) - Single worker requirement + +--- + +*ROA2WEB - Ultrathin Monolith Architecture* +*Last Updated: 2026-01-22* diff --git a/docs/data-entry/README.md b/docs/data-entry/README.md deleted file mode 100644 index 113e877..0000000 --- a/docs/data-entry/README.md +++ /dev/null @@ -1,382 +0,0 @@ -# Data Entry App - Bonuri Fiscale - -Aplicatie pentru introducere bonuri fiscale cu workflow de aprobare si extragere automata date prin OCR. - -## Quick Start - -### Prerequisites - -- Python 3.10+ -- Node.js 18+ -- (Optional) SSH tunnel pentru Oracle nomenclatoare - -### Using Start Script (Recommended) - -```bash -# Start all services -./start-data-entry.sh - -# Or individual commands: -./start-data-entry.sh start # Start all -./start-data-entry.sh stop # Stop all -./start-data-entry.sh status # Check status -./start-data-entry.sh restart backend # Restart backend only -``` - -**Services:** -- Backend: http://localhost:8003 -- Frontend: http://localhost:3010 -- API Docs: http://localhost:8003/docs - -### Manual Setup - -#### Backend Setup - -```bash -cd backend/modules/data_entry/backend - -# Create virtual environment -python -m venv venv -source venv/bin/activate # Linux/Mac -# sau: venv\Scripts\activate # Windows - -# Install dependencies -pip install -r requirements.txt - -# Create .env file -cp .env.example .env -# Edit .env with your settings - -# Run migrations -alembic upgrade head - -# Start server -uvicorn app.main:app --reload --port 8003 -``` - -#### Frontend Setup - -```bash -cd backend/modules/data_entry/frontend - -# Install dependencies -npm install - -# Start dev server -npm run dev -- --port 3010 -``` - -## Features - -### Pentru Utilizatori -- **OCR Automat** - Extragere automata date din poza bonului (suma, data, furnizor, CUI) -- Upload poze bonuri fiscale -- Completare date bon (suma, data, furnizor) -- Selectie tip cheltuiala -- Trimitere spre aprobare - -### Pentru Contabili -- Vizualizare bonuri in asteptare -- Editare note contabile propuse -- Aprobare/Respingere bonuri -- Aprobare in masa - -## OCR Feature - -### Cum functioneaza - -1. **Upload imagine** - Trage sau selecteaza poza bonului -2. **Procesare OCR** - Click pe "Proceseaza cu OCR" -3. **Previzualizare** - Datele extrase sunt afisate cu indicatori de incredere -4. **Aplicare** - Click "Aplica datele in formular" pentru auto-fill - -### Campuri extrase automat - -| Camp | Acuratete estimata | -|------|-------------------| -| Suma (TOTAL) | 90-95% | -| Data | 85-90% | -| Numar bon | 80-85% | -| Furnizor | 70-80% | -| CUI | 85-90% | -| Tip document | 95%+ | - -### OCR System Dependencies (Linux/Docker) - -Pentru functionarea OCR trebuie instalate: - -```bash -# Ubuntu/Debian -apt-get install -y \ - tesseract-ocr \ - tesseract-ocr-ron \ - tesseract-ocr-eng \ - poppler-utils \ - libgl1-mesa-glx \ - libglib2.0-0 - -# Fedora/RHEL -dnf install -y \ - tesseract \ - tesseract-langpack-ron \ - tesseract-langpack-eng \ - poppler-utils -``` - -**Note:** PaddleOCR (engine principal) se instaleaza automat cu pip. Tesseract este folosit ca fallback. - -### OCR System Dependencies (Windows) - -Pe Windows Server trebuie instalate manual urmatoarele componente: - -#### 1. Poppler (pentru conversie PDF → imagini) - -```powershell -# Descarca Poppler pentru Windows -# https://github.com/osborn/poppler-windows/releases -# sau https://github.com/bblanchon/pdfium-binaries - -# Extrage in C:\Program Files\poppler\ -# Adauga la PATH: C:\Program Files\poppler\Library\bin -``` - -#### 2. Tesseract OCR (engine OCR backup) - -```powershell -# Descarca installer de la: -# https://github.com/UB-Mannheim/tesseract/wiki - -# Instaleaza cu limbile: English + Romanian -# Default path: C:\Program Files\Tesseract-OCR\ -# Adauga la PATH -``` - -#### 3. Python OCR Dependencies (in venv) - -```powershell -cd C:\inetpub\wwwroot\roa2web\data-entry-backend -.\venv\Scripts\activate - -# Instaleaza dependentele OCR -pip install paddlepaddle>=2.5.0 -pip install paddleocr>=2.7.0 -pip install opencv-python>=4.8.0 -pip install pytesseract>=0.3.10 -pip install pdf2image>=1.16.0 - -# Sau din requirements.txt -pip install -r requirements.txt -``` - -#### 4. Restart serviciu - -```powershell -nssm restart ROA2WEB-DataEntry -``` - -**Note importante Windows:** -- Prima rulare PaddleOCR descarca modele (~200MB) - poate dura cateva minute -- PaddleOCR necesita ~2GB RAM disponibil -- Verifica PATH-ul pentru Poppler si Tesseract dupa instalare -- Restart serviciul backend dupa orice modificare PATH - -### OCR API Endpoints - -| Method | Endpoint | Description | -|--------|----------|-------------| -| GET | /api/ocr/status | Check OCR service status | -| POST | /api/ocr/extract | Extract data from uploaded image | -| POST | /api/ocr/extract-attachment/{id} | Re-process existing attachment | - -### Test OCR - -```bash -# Check OCR status -curl http://localhost:8003/api/ocr/status - -# Extract from image -curl -X POST -F "file=@bon.jpg" http://localhost:8003/api/ocr/extract -``` - -## Workflow - -``` -DRAFT → PENDING_REVIEW → APPROVED/REJECTED → (SYNCED in Oracle) -``` - -1. **DRAFT**: Utilizator completeaza datele (manual sau via OCR) -2. **PENDING_REVIEW**: Sistemul genereaza note contabile automat -3. **APPROVED**: Contabil a aprobat bonul -4. **REJECTED**: Contabil a respins (utilizatorul poate corecta) - -## Project Structure - -``` -backend/modules/data_entry/ -├── backend/ -│ ├── app/ -│ │ ├── main.py # FastAPI entry point -│ │ ├── config.py # Settings -│ │ ├── db/ -│ │ │ ├── database.py # SQLite engine -│ │ │ ├── models/ # SQLModel models -│ │ │ └── crud/ # CRUD operations -│ │ ├── schemas/ # Pydantic schemas -│ │ │ └── ocr.py # OCR response schemas -│ │ ├── services/ -│ │ │ ├── receipt_service.py -│ │ │ ├── ocr_service.py # OCR orchestration -│ │ │ ├── ocr_engine.py # PaddleOCR/Tesseract -│ │ │ ├── ocr_extractor.py # Regex patterns RO -│ │ │ └── image_preprocessor.py # OpenCV pipeline -│ │ └── routers/ -│ │ ├── receipts.py -│ │ └── ocr.py # OCR endpoints -│ ├── migrations/ # Alembic migrations -│ ├── data/ -│ │ ├── receipts.db # SQLite database -│ │ └── uploads/ # Uploaded files -│ └── requirements.txt -│ -├── frontend/ -│ ├── src/ -│ │ ├── views/receipts/ # Page components -│ │ ├── components/ -│ │ │ ├── receipts/ # Receipt components -│ │ │ └── ocr/ # OCR components -│ │ │ ├── OCRUploadZone.vue -│ │ │ ├── OCRPreview.vue -│ │ │ └── OCRConfidenceIndicator.vue -│ │ ├── stores/ # Pinia stores -│ │ └── router/ # Vue Router -│ ├── package.json -│ └── vite.config.js -│ -└── docs/ # Documentation -``` - -## Environment Variables - -### Backend (.env) - -```bash -# SQLite -SQLITE_DATABASE_PATH=data/receipts.db - -# File uploads -UPLOAD_PATH=data/uploads -MAX_UPLOAD_SIZE_MB=10 - -# Oracle (for nomenclatures) -ORACLE_USER=CONTAFIN_ORACLE -ORACLE_PASSWORD=your_password -ORACLE_HOST=localhost -ORACLE_PORT=1526 -ORACLE_SID=ROA - -# JWT (shared with Reports module) -JWT_SECRET_KEY=your_secret_key -JWT_ALGORITHM=HS256 -``` - -## Development - -### Create new migration - -```bash -cd backend -alembic revision --autogenerate -m "Add new field" -alembic upgrade head -``` - -### Run tests - -```bash -# Backend -cd backend && pytest - -# Frontend -cd frontend && npm run test -``` - -## API Documentation - -Full API documentation available at http://localhost:8003/docs when backend is running. - -### Key Endpoints - -| Method | Endpoint | Description | -|--------|----------|-------------| -| POST | /api/receipts/ | Create receipt | -| GET | /api/receipts/ | List receipts | -| GET | /api/receipts/{id} | Get receipt details | -| POST | /api/receipts/{id}/submit | Submit for review | -| POST | /api/receipts/{id}/approve | Approve receipt | -| POST | /api/receipts/{id}/reject | Reject receipt | -| POST | /api/receipts/{id}/attachments | Upload attachment | -| GET | /api/ocr/status | OCR service status | -| POST | /api/ocr/extract | OCR image extraction | - -## Troubleshooting - -### OCR not working - -1. Check OCR status: `curl http://localhost:8003/api/ocr/status` -2. Install system dependencies (tesseract, poppler) -3. Verify PaddleOCR installed: `python -c "from paddleocr import PaddleOCR"` - -### OCR Windows - "poppler not in PATH" - -```powershell -# Eroare: "Unable to get page count. Is poppler installed and in PATH?" - -# Solutie 1: Adauga Poppler la PATH -# System Properties → Environment Variables → System variables → Path → New -# Adauga: C:\Program Files\poppler\Library\bin - -# Solutie 2: Restart serviciul dupa modificarea PATH -nssm restart ROA2WEB-DataEntry - -# Verificare: -pdfinfo --version -``` - -### OCR Windows - "tesseract not found" - -```powershell -# Eroare: "tesseract is not installed or it's not in your PATH" - -# Solutie: Adauga Tesseract la PATH -# C:\Program Files\Tesseract-OCR\ - -# Verificare: -tesseract --version -tesseract --list-langs # Trebuie sa arate 'ron' si 'eng' -``` - -### OCR Windows - PaddleOCR import error - -```powershell -# Eroare: "No module named 'paddleocr'" - -cd C:\inetpub\wwwroot\roa2web\data-entry-backend -.\venv\Scripts\activate -pip install paddlepaddle>=2.5.0 -pip install paddleocr>=2.7.0 - -# Restart serviciu -nssm restart ROA2WEB-DataEntry -``` - -### Low OCR accuracy - -- Ensure good lighting when taking receipt photos -- Keep receipt flat (no folds/wrinkles) -- Try PDF instead of JPG for scanned documents -- Check if text is in focus - -## Phase 2 (Future) - -- Oracle sync for approved receipts -- Integration with pack_contafin procedures -- Automatic posting to ACT/RUL tables diff --git a/deployment/windows/docs/TELEGRAM-BOT-DEPLOYMENT.md b/docs/telegram/DEPLOYMENT.md similarity index 100% rename from deployment/windows/docs/TELEGRAM-BOT-DEPLOYMENT.md rename to docs/telegram/DEPLOYMENT.md diff --git a/docs/telegram/README.md b/docs/telegram/README.md index 4dba540..9cf01a6 100644 --- a/docs/telegram/README.md +++ b/docs/telegram/README.md @@ -1,11 +1,7 @@ # ROA2WEB Telegram Bot -> ⚠️ **ARCHITECTURE NOTE** -> -> This documentation partially references the old standalone bot architecture. -> The current architecture is an **ultrathin monolith** where the Telegram bot runs -> as a background task within the main backend (`backend/main.py`) on port 8000/8001. -> The `INTERNAL_API_PORT` variable is no longer used - internal API is at `/api/telegram/internal/*`. +> **Architecture:** Ultrathin Monolith - Telegram bot runs as a background task within the unified backend on port 8000. +> See `docs/telegram/DEPLOYMENT.md` for single-worker requirement. > **Telegram Frontend for ROA2WEB ERP System** with Direct Command Interface @@ -71,78 +67,45 @@ The bot uses a standalone SQLite database for: - **telegram_auth_codes**: Temporary 8-character linking codes (15 min expiry) - **telegram_sessions**: Active company selection and session state -## Installation & Setup +## Setup & Configuration ### Prerequisites -- Python 3.11+ -- Telegram account -- ROA2WEB backend API running (default: http://localhost:8001) +- ROA2WEB backend running (the bot runs as part of the unified backend) +- Telegram Bot Token (from @BotFather) -### Step 1: Create Telegram Bot +### Step 1: Create Telegram Bot (One-time) 1. Open Telegram and search for `@BotFather` 2. Send `/newbot` command 3. Follow prompts to create bot 4. Save the bot token provided -### Step 2: Install Dependencies +### Step 2: Configure Environment + +Add to `backend/.env`: ```bash -# Navigate to telegram-bot directory -cd backend/modules/telegram - -# Create virtual environment -python3 -m venv venv - -# Activate virtual environment -source venv/bin/activate # Linux/Mac -# or -venv\Scripts\activate # Windows - -# Install dependencies -pip install -r requirements.txt -``` - -### Step 3: Configure Environment - -```bash -# Copy environment template -cp .env.example .env - -# Edit .env file with your configuration -nano .env -``` - -Required configuration in `.env`: - -```bash -# Required +# Telegram Bot Configuration +MODULE_TELEGRAM_ENABLED=true TELEGRAM_BOT_TOKEN=your_bot_token_from_botfather -BACKEND_URL=http://localhost:8001 - -# Database -SQLITE_DB_PATH=./data/telegram_bot.db - -# Internal API - DEPRECATED (now served via main backend at /api/telegram/internal/*) -# INTERNAL_API_PORT=8002 - -# Optional -LOG_LEVEL=INFO -SENTRY_DSN=https://your-sentry-dsn -ENVIRONMENT=production ``` -### Step 4: Run the Bot +### Step 3: Start the Application ```bash -# Make sure backend is running first -# Backend should be at http://localhost:8001 (or configured BACKEND_URL) +# From project root - starts backend with Telegram bot integrated +./start-prod.sh -# Run the bot -python -m app.main +# Or for testing: +./start-test.sh ``` +The bot starts automatically as a background task when `MODULE_TELEGRAM_ENABLED=true`. + +> **Important:** Backend must run with `--workers 1` for Telegram bot to work correctly. +> See `docs/telegram/DEPLOYMENT.md` for details. + ## Usage ### Available Commands diff --git a/docs/telegram/TELEGRAM_BUTTON_INTERFACE_PLAN.md b/docs/telegram/TELEGRAM_BUTTON_INTERFACE_PLAN.md deleted file mode 100644 index eb30240..0000000 --- a/docs/telegram/TELEGRAM_BUTTON_INTERFACE_PLAN.md +++ /dev/null @@ -1,1928 +0,0 @@ -# Plan Implementare Interfață Telegram cu Butoane Interactive - -**Data creării:** 2025-10-23 -**Scop:** Implementare interfață interactivă cu butoane pentru Telegram bot, similar BotFather -**Structură:** 3 niveluri de navigare, layout 2 coloane - -**⚠️ IMPORTANT: NO EMOJI/ICONS** -**TOATE butoanele și textele trebuie să fie FĂRĂ emoji sau iconuri. Doar text simplu.** - ---- - -## 📋 Context General - -### Obiectiv -Transformarea Telegram bot ROA2WEB dintr-o interfață bazată pe comenzi text în una cu **butoane interactive** organizate pe 3 niveluri: -- **Nivel 1:** Meniu principal cu opțiuni financiare -- **Nivel 2:** Liste detaliate (clienți/furnizori cu solduri) -- **Nivel 3:** Detalii facturi - -### Cerințe Utilizator -1. ✅ Meniu principal la `/start` (pentru useri linked) și `/menu` -2. ✅ Layout 2 coloane (similar BotFather) -3. ✅ Butoane acțiuni în TOATE răspunsurile (Refresh, Export, Back) -4. ✅ Selecție companie la început + posibilitate schimbare -5. ✅ Opțiuni financiare: - - Sold (dashboard general) - - Trezorerie Casa (numerar) - - Trezorerie Banca (conturi bancare) - - Sold Clienți (în termen/restant) - - Sold Furnizori (în termen/restant) - - Evoluție Încasări/Plăți - -### Endpoint-uri Backend Existente ✅ -**NU sunt necesare modificări backend - toate endpoint-urile există:** -- `/api/dashboard/summary` - Sold general -- `/api/dashboard/treasury-breakdown` - Trezorerie (casă + bancă) -- `/api/dashboard/detailed-data?data_type=clients` - Listă clienți -- `/api/dashboard/detailed-data?data_type=suppliers` - Listă furnizori -- `/api/dashboard/maturity?period=all` - Scadențe (în termen/restanță) -- `/api/dashboard/performance` - Performance încasări/plăți -- `/api/dashboard/monthly-flows` - Evoluție lunară -- `/api/invoices/?company={id}&partner_type=CLIENTI` - Facturi clienți -- `/api/invoices/?company={id}&partner_type=FURNIZORI` - Facturi furnizori - ---- - -## 🏗️ Arhitectură Soluție - -### Structură Fișiere Noi/Modificate - -``` -roa2web/backend/modules/telegram/ -├── app/ -│ ├── bot/ -│ │ ├── menus.py ⭐ NOU - Builders pentru tastaturi butoane -│ │ ├── handlers.py ✏️ MODIFICAT - Adaugă comenzi noi + callbacks -│ │ ├── helpers.py ✏️ MODIFICAT - Noi helper functions -│ │ ├── formatters.py ✏️ MODIFICAT - Noi formatteri pentru date -│ ├── main.py ✏️ MODIFICAT - Înregistrare noi handlers -├── tests/ -│ ├── test_menus.py ⭐ NOU - Teste pentru menus.py -│ ├── test_handlers_extended.py ⭐ NOU - Teste pentru noi handlers -├── docs/ -│ └── TELEGRAM_BUTTON_INTERFACE_PLAN.md ⭐ ACEST FIȘIER -``` - -### Flow Navigare Complet - -``` -┌─────────────────────────────────────────────────────────────┐ -│ /start (linked user) sau /menu │ -│ → Main Menu (Nivel 1) │ -└────────────────┬────────────────────────────────────────────┘ - │ - ┌────────────┴────────────┐ - │ Main Menu (Nivel 1) │ - │ ┌────────────────────┐ │ - │ │ 📊 Selectare Co. │ │ (full width) - │ ├─────────┬──────────┤ │ - │ │ 💰 Sold │ 💵 Casa │ │ - │ ├─────────┼──────────┤ │ - │ │ 🏦 Banca│ 👥 Clien │ │ - │ ├─────────┼──────────┤ │ - │ │ 🏢 Furn │ 📈 Evol │ │ - │ └─────────┴──────────┘ │ - └────────────┬────────────┘ - │ - ├─► Click "💰 Sold" → Dashboard cu butoane [Refresh][🏠 Menu] - │ - ├─► Click "👥 Clienți" → Nivel 2 - │ │ - │ ▼ - │ ┌────────────────────┐ - │ │ Nivel 2: Clienți │ - │ │ • Client A - 15k │──► Click Client A → Nivel 3 - │ │ • Client B - 8.5k │ │ - │ │ [⬅️ Înapoi][Refresh]│ ▼ - │ └────────────────────┘ ┌────────────────┐ - │ │ Nivel 3: Fact. │ - ├─► Click "🏢 Furnizori" │ • FV001 - 5k │ - │ │ │ • FV002 - 3.5k │ - │ ▼ │ [⬅️][📄 Export]│ - │ Similar cu Clienți └────────────────┘ - │ - └─► Alte opțiuni: Casa, Bancă, Evoluție - │ - ▼ - Date + Butoane Acțiuni -``` - ---- - -## 📝 FAZA 1: Creare Modul Meniuri (`menus.py`) ✅ COMPLETATĂ - -**Status**: ✅ COMPLETATĂ (2025-10-23) -**Teste**: 22/22 PASSED -**Important**: ⚠️ Toate butoanele sunt FĂRĂ emoji/iconuri - doar text simplu - -### 🎯 Obiectiv -Creare modul dedicat pentru construirea tastaturelor cu butoane (InlineKeyboardMarkup). - -### 📁 Fișier: `app/bot/menus.py` - -**Funcții de implementat:** - -1. **`create_main_menu(company_name: Optional[str] = None) -> InlineKeyboardMarkup`** - - Creează meniul principal (Nivel 1) - - Layout 2 coloane - - Rând 1: Selecție companie (full width) sau Companie activă + schimbare - - Rânduri 2-4: Grid 2x3 cu opțiuni financiare - - Rând final: Help - - Callback data: `menu:sold`, `menu:casa`, `menu:banca`, `menu:clienti`, `menu:furnizori`, `menu:evolutie` - -2. **`create_action_buttons(current_view: str, show_export: bool = True) -> InlineKeyboardMarkup`** - - Creează butoane de acțiuni pentru răspunsuri - - Layout: [🔄 Refresh][📄 Export] - - [🏠 Menu] (full width) - - Parametri: - - `current_view`: string pentru callback refresh (ex: "sold", "clienti") - - `show_export`: dacă să arate butonul Export - - Callback data: `action:refresh:{view}`, `action:export:{view}`, `action:menu` - -3. **`create_client_list_keyboard(clients: List[Dict], max_items: int = 10) -> InlineKeyboardMarkup`** - - Creează listă clienți cu butoane (Nivel 2) - - Un buton per client: "Client Name - 15,000 RON" - - Layout: 1 coloană pentru clienți, 2 coloane pentru acțiuni - - Callback data: `details:client:{client_id}` - - Footer: [⬅️ Înapoi][🔄 Refresh] - -4. **`create_supplier_list_keyboard(suppliers: List[Dict], max_items: int = 10) -> InlineKeyboardMarkup`** - - Similar cu `create_client_list_keyboard` - - Callback data: `details:supplier:{supplier_id}` - -5. **`create_invoice_list_keyboard(invoices: List[Dict], partner_type: str, max_items: int = 10) -> InlineKeyboardMarkup`** - - Creează listă facturi (Nivel 3) - - Layout: 1 coloană pentru facturi, 2 coloane pentru acțiuni - - Callback data: `invoice:{partner_type}:{invoice_id}` - - Footer: [⬅️ Înapoi][📄 Export] - -6. **`create_navigation_buttons(back_to: str) -> InlineKeyboardMarkup`** - - Creează butoane simple de navigare - - Layout: [⬅️ Înapoi la {back_to}] - - Callback data: `nav:back:{back_to}` - -### 📋 Checklist Implementare - -```python -# menus.py - Structură Minimă -from telegram import InlineKeyboardButton, InlineKeyboardMarkup -from typing import List, Dict, Optional - -def create_main_menu(company_name: Optional[str] = None) -> InlineKeyboardMarkup: - """Creează meniul principal (Nivel 1)""" - # TODO: Implementare - pass - -def create_action_buttons(current_view: str, show_export: bool = True) -> InlineKeyboardMarkup: - """Creează butoane acțiuni pentru răspunsuri""" - # TODO: Implementare - pass - -def create_client_list_keyboard(clients: List[Dict], max_items: int = 10) -> InlineKeyboardMarkup: - """Creează listă clienți cu butoane (Nivel 2)""" - # TODO: Implementare - pass - -def create_supplier_list_keyboard(suppliers: List[Dict], max_items: int = 10) -> InlineKeyboardMarkup: - """Creează listă furnizori cu butoane""" - # TODO: Implementare - pass - -def create_invoice_list_keyboard(invoices: List[Dict], partner_type: str, max_items: int = 10) -> InlineKeyboardMarkup: - """Creează listă facturi (Nivel 3)""" - # TODO: Implementare - pass - -def create_navigation_buttons(back_to: str) -> InlineKeyboardMarkup: - """Creează butoane navigare simple""" - # TODO: Implementare - pass -``` - -### ✅ Teste FAZA 1 - -**Fișier:** `tests/test_menus.py` - -```python -import pytest -from app.bot.menus import ( - create_main_menu, - create_action_buttons, - create_client_list_keyboard, - create_supplier_list_keyboard, - create_invoice_list_keyboard, - create_navigation_buttons -) - -def test_create_main_menu_without_company(): - """Test main menu când nu e selectată companie""" - keyboard = create_main_menu() - assert keyboard is not None - assert len(keyboard.inline_keyboard) >= 5 # Minim 5 rânduri - # Verifică că primul rând e pentru selecție companie - assert "compan" in keyboard.inline_keyboard[0][0].text.lower() - -def test_create_main_menu_with_company(): - """Test main menu cu companie activă""" - keyboard = create_main_menu(company_name="ACME SRL") - assert keyboard is not None - # Verifică că arată compania activă - first_row = keyboard.inline_keyboard[0][0].text - assert "ACME SRL" in first_row or "Selectare" in first_row - -def test_main_menu_has_6_financial_buttons(): - """Test că meniul are 6 butoane financiare""" - keyboard = create_main_menu("Test Co") - buttons_text = [] - for row in keyboard.inline_keyboard[1:-1]: # Exclude primul și ultimul rând - for button in row: - buttons_text.append(button.text) - - # Verifică că avem butoanele așteptate - expected = ["Sold", "Casa", "Banca", "Client", "Furniz", "Evol"] - found = [any(exp.lower() in btn.lower() for btn in buttons_text) for exp in expected] - assert all(found), f"Missing buttons. Found: {buttons_text}" - -def test_main_menu_callback_data_format(): - """Test că callback data e corect formatat""" - keyboard = create_main_menu("Test Co") - for row in keyboard.inline_keyboard: - for button in row: - if button.callback_data and button.callback_data.startswith("menu:"): - # Verifică format: menu:action - parts = button.callback_data.split(":") - assert len(parts) == 2 - assert parts[0] == "menu" - assert parts[1] in ["sold", "casa", "banca", "clienti", "furnizori", "evolutie", "select_company"] - -def test_create_action_buttons_with_export(): - """Test butoane acțiuni cu export""" - keyboard = create_action_buttons("sold", show_export=True) - assert len(keyboard.inline_keyboard) == 2 # 2 rânduri - assert len(keyboard.inline_keyboard[0]) == 2 # Primul rând: 2 butoane - - # Verifică text butoane - row1_text = [btn.text for btn in keyboard.inline_keyboard[0]] - assert any("Refresh" in txt or "🔄" in txt for txt in row1_text) - assert any("Export" in txt or "📄" in txt for txt in row1_text) - -def test_create_action_buttons_without_export(): - """Test butoane acțiuni fără export""" - keyboard = create_action_buttons("sold", show_export=False) - all_text = " ".join([btn.text for row in keyboard.inline_keyboard for btn in row]) - assert "Export" not in all_text and "📄" not in all_text - -def test_action_buttons_callback_format(): - """Test format callback pentru butoane acțiuni""" - keyboard = create_action_buttons("sold") - for row in keyboard.inline_keyboard: - for button in row: - if "refresh" in button.text.lower() or "🔄" in button.text: - assert button.callback_data.startswith("action:refresh:") - elif "menu" in button.text.lower() or "🏠" in button.text: - assert button.callback_data == "action:menu" - elif "export" in button.text.lower() or "📄" in button.text: - assert button.callback_data.startswith("action:export:") - -def test_create_client_list_keyboard(): - """Test listă clienți""" - clients = [ - {"id": 1, "name": "Client A", "balance": 15000}, - {"id": 2, "name": "Client B", "balance": 8500} - ] - keyboard = create_client_list_keyboard(clients) - - # Verifică că avem 2 clienți + 1 rând de navigare - assert len(keyboard.inline_keyboard) >= 3 - - # Verifică că primele 2 rânduri sunt pentru clienți - assert "Client A" in keyboard.inline_keyboard[0][0].text - assert "15" in keyboard.inline_keyboard[0][0].text # Suma - - # Verifică callback data - assert keyboard.inline_keyboard[0][0].callback_data == "details:client:1" - -def test_create_supplier_list_keyboard(): - """Test listă furnizori""" - suppliers = [ - {"id": 1, "name": "Supplier A", "balance": 5000} - ] - keyboard = create_supplier_list_keyboard(suppliers) - assert "Supplier A" in keyboard.inline_keyboard[0][0].text - assert "details:supplier:1" in keyboard.inline_keyboard[0][0].callback_data - -def test_client_list_max_items(): - """Test limitare număr clienți afișați""" - clients = [{"id": i, "name": f"Client {i}", "balance": 1000} for i in range(20)] - keyboard = create_client_list_keyboard(clients, max_items=5) - - # Număr rânduri = 5 clienți + 1 rând navigare (+ eventual 1 overflow indicator) - assert len(keyboard.inline_keyboard) <= 7 - -def test_create_invoice_list_keyboard(): - """Test listă facturi""" - invoices = [ - {"id": 1, "number": "FV001", "amount": 5000, "status": "unpaid"}, - {"id": 2, "number": "FV002", "amount": 3500, "status": "paid"} - ] - keyboard = create_invoice_list_keyboard(invoices, partner_type="CLIENTI") - - # Verifică că avem facturi + navigare - assert len(keyboard.inline_keyboard) >= 3 - assert "FV001" in keyboard.inline_keyboard[0][0].text - assert "invoice:CLIENTI:1" in keyboard.inline_keyboard[0][0].callback_data - -def test_create_navigation_buttons(): - """Test butoane navigare""" - keyboard = create_navigation_buttons("menu") - assert len(keyboard.inline_keyboard) == 1 - assert "Înapoi" in keyboard.inline_keyboard[0][0].text or "⬅️" in keyboard.inline_keyboard[0][0].text - assert keyboard.inline_keyboard[0][0].callback_data == "nav:back:menu" -``` - -**Rulare teste FAZA 1:** -```bash -cd /mnt/e/proiecte/roa2web/roa2web/backend/modules/telegram -source venv/bin/activate -pytest tests/test_menus.py -v -``` - -### 📦 Deliverables FAZA 1 -- ✅ Fișier `app/bot/menus.py` cu toate funcțiile implementate (269 linii) - - ✅ `create_main_menu()` - Meniu principal cu 6 opțiuni financiare - - ✅ `create_action_buttons()` - Butoane acțiuni (Refresh, Export, Menu) - - ✅ `create_client_list_keyboard()` - Listă clienți cu navigare - - ✅ `create_supplier_list_keyboard()` - Listă furnizori cu navigare - - ✅ `create_invoice_list_keyboard()` - Listă facturi cu navigare - - ✅ `create_navigation_buttons()` - Butoane navigare simplă -- ✅ Fișier `tests/test_menus.py` cu toate testele passing (22 teste, 414 linii) - - ✅ 22/22 teste passed în 2.23s - - ✅ Coverage: main menu, action buttons, lists, navigation, edge cases -- ✅ Documentație inline (docstrings) pentru fiecare funcție - -### 🔄 Context Handover pentru FAZA 2 -``` -FAZA 1 COMPLETATĂ ✅ - -Fișiere create: -- app/bot/menus.py (builders pentru tastaturi butoane) -- tests/test_menus.py (toate testele passing) - -Următoarea fază: FAZA 2 - Extindere Formatters și Helpers -- Adaugă formatteri noi în formatters.py -- Adaugă helper functions în helpers.py - -Citește FAZA 2 din acest document pentru detalii. -``` - ---- - -## 📝 FAZA 2: Extindere Formatters și Helpers ✅ COMPLETATĂ - -**Status**: ✅ COMPLETATĂ (2025-10-23) -**Teste**: 31/31 PASSED (17 formatters + 14 helpers) - -### 🎯 Obiectiv -Adăugare funcții noi în `formatters.py` și `helpers.py` pentru suport date noi. - -### 📁 Fișier: `app/bot/formatters.py` (EXTINDERE) - -**Funcții noi de adăugat:** - -1. **`format_treasury_casa_response(data: Dict, company_name: str) -> str`** - - Formatează date trezorerie CASH - - Folosește `data['treasury_breakdown']` filtrat pentru tipul "Casa" - - Include: Sold total cash, conturi de casă, ultimele mișcări - -2. **`format_treasury_banca_response(data: Dict, company_name: str) -> str`** - - Formatează date trezorerie BANCĂ - - Folosește `data['treasury_breakdown']` filtrat pentru tipul "Banca" - - Include: Sold total bancă, conturi bancare, ultimele mișcări - -3. **`format_clients_balance_response(clients: List[Dict], maturity_data: Dict, company_name: str) -> str`** - - Formatează sold clienți cu defalcare în termen/restant - - Combină date de la `/detailed-data` și `/maturity` - - Include: Total sold, în termen, restant, top 5 clienți - -4. **`format_suppliers_balance_response(suppliers: List[Dict], maturity_data: Dict, company_name: str) -> str`** - - Similar cu `format_clients_balance_response` dar pentru furnizori - -5. **`format_cashflow_evolution_response(performance_data: Dict, monthly_data: Dict, company_name: str) -> str`** - - Formatează evoluție încasări/plăți - - Combină date de la `/performance` și `/monthly-flows` - - Include: Grafic text ASCII (simplificat), tendințe, comparații - -6. **`format_client_detail_response(client: Dict, invoices: List[Dict], company_name: str) -> str`** - - Formatează detalii client + facturile lui (Nivel 2 → 3) - -7. **`format_supplier_detail_response(supplier: Dict, invoices: List[Dict], company_name: str) -> str`** - - Similar pentru furnizor - -### 📋 Exemplu Format Treasury Casa - -```python -def format_treasury_casa_response(data: Dict, company_name: str) -> str: - """ - Formatează date trezorerie CASH pentru Telegram. - - Args: - data: Dict cu treasury_breakdown de la API - company_name: Numele companiei - - Returns: - String formatat Markdown pentru Telegram - """ - text = "💵 **Trezorerie Casa**\n\n" - - # Filtrează doar conturile de tip "Casa" - casa_accounts = [ - acc for acc in data.get('accounts', []) - if acc.get('type') == 'Casa' or 'casa' in acc.get('name', '').lower() - ] - - # Calculează sold total cash - total_cash = sum(acc.get('balance', 0) for acc in casa_accounts) - text += f"💰 **Sold Total Cash:** {total_cash:,.2f} RON\n\n" - - # Liste conturi - if casa_accounts: - text += "📋 **Conturi de Casă:**\n" - for acc in casa_accounts[:5]: # Max 5 - name = acc.get('name', 'N/A') - balance = acc.get('balance', 0) - text += f" • {name}: {balance:,.2f} RON\n" - else: - text += "ℹ️ Nu există conturi de casă configurate.\n" - - # Footer cu context - from app.bot.helpers import format_company_context_footer - text += format_company_context_footer(company_name) - - return text -``` - -### 📁 Fișier: `app/bot/helpers.py` (EXTINDERE) - -**Funcții noi de adăugat:** - -1. **`async def get_treasury_breakdown_split(company_id: int, jwt_token: str) -> Dict[str, Any]`** - - Apelează `/api/dashboard/treasury-breakdown` - - Returnează dict cu 2 chei: `casa` și `banca` - - Fiecare cheie conține conturi filtrate și sold total - -2. **`async def get_clients_with_maturity(company_id: int, jwt_token: str) -> Dict[str, Any]`** - - Combină date de la `/detailed-data?data_type=clients` și `/maturity?period=all` - - Returnează dict cu clienți și defalcare în termen/restant - -3. **`async def get_suppliers_with_maturity(company_id: int, jwt_token: str) -> Dict[str, Any]`** - - Similar pentru furnizori - -4. **`async def get_cashflow_evolution_data(company_id: int, jwt_token: str, period: str = "12m") -> Dict[str, Any]`** - - Combină `/performance` și `/monthly-flows` - - Returnează date pentru evoluție - -5. **`async def get_client_invoices(company_id: int, client_id: int, jwt_token: str) -> List[Dict]`** - - Apelează `/api/invoices/?company={id}&partner_type=CLIENTI&partner_name={client_name}` - - Returnează lista de facturi pentru client - -6. **`async def get_supplier_invoices(company_id: int, supplier_id: int, jwt_token: str) -> List[Dict]`** - - Similar pentru furnizor - -### ✅ Teste FAZA 2 - -**Fișier:** `tests/test_formatters_extended.py` - -```python -import pytest -from app.bot.formatters import ( - format_treasury_casa_response, - format_treasury_banca_response, - format_clients_balance_response, - format_suppliers_balance_response, - format_cashflow_evolution_response -) - -def test_format_treasury_casa_response(): - """Test formatare trezorerie casa""" - data = { - 'accounts': [ - {'name': 'Casa Ron', 'type': 'Casa', 'balance': 5000}, - {'name': 'Casa Valuta', 'type': 'Casa', 'balance': 2000}, - {'name': 'BCR', 'type': 'Banca', 'balance': 10000} # Exclus - ] - } - result = format_treasury_casa_response(data, "Test Co") - - assert "Casa" in result - assert "7,000" in result or "7000" in result # Total: 5000 + 2000 - assert "Casa Ron" in result - assert "BCR" not in result # Contul bancar nu trebuie să apară - -def test_format_treasury_banca_response(): - """Test formatare trezorerie banca""" - data = { - 'accounts': [ - {'name': 'BCR', 'type': 'Banca', 'balance': 10000}, - {'name': 'BRD', 'type': 'Banca', 'balance': 5000}, - {'name': 'Casa Ron', 'type': 'Casa', 'balance': 2000} # Exclus - ] - } - result = format_treasury_banca_response(data, "Test Co") - - assert "Bancă" in result or "Banca" in result - assert "15,000" in result or "15000" in result - assert "BCR" in result - assert "Casa" not in result - -def test_format_clients_balance_with_maturity(): - """Test formatare sold clienți cu scadențe""" - clients = [ - {'id': 1, 'name': 'Client A', 'balance': 15000}, - {'id': 2, 'name': 'Client B', 'balance': 8500} - ] - maturity_data = { - 'in_term': 18000, - 'overdue': 5500, - 'total': 23500 - } - - result = format_clients_balance_response(clients, maturity_data, "Test Co") - - assert "Client" in result - assert "23,500" in result or "23500" in result # Total - assert "18,000" in result or "18000" in result # În termen - assert "5,500" in result or "5500" in result # Restant - assert "Client A" in result - -def test_format_suppliers_balance(): - """Test formatare sold furnizori""" - suppliers = [ - {'id': 1, 'name': 'Supplier A', 'balance': 5000} - ] - maturity_data = { - 'in_term': 4000, - 'overdue': 1000, - 'total': 5000 - } - - result = format_suppliers_balance_response(suppliers, maturity_data, "Test Co") - - assert "Furniz" in result - assert "5,000" in result or "5000" in result - assert "Supplier A" in result - -def test_format_cashflow_evolution(): - """Test formatare evoluție cash flow""" - performance = { - 'incasari_total': 100000, - 'plati_total': 80000, - 'net': 20000 - } - monthly = { - 'months': ['Ian', 'Feb', 'Mar'], - 'incasari': [30000, 35000, 35000], - 'plati': [25000, 27000, 28000] - } - - result = format_cashflow_evolution_response(performance, monthly, "Test Co") - - assert "Evoluție" in result or "Încasări" in result - assert "100,000" in result or "100000" in result - assert "Ian" in result or "Feb" in result # Cel puțin o lună -``` - -**Fișier:** `tests/test_helpers_extended.py` - -```python -import pytest -from unittest.mock import AsyncMock, patch -from app.bot.helpers import ( - get_treasury_breakdown_split, - get_clients_with_maturity, - get_suppliers_with_maturity -) - -@pytest.mark.asyncio -async def test_get_treasury_breakdown_split(): - """Test split trezorerie în casa/banca""" - mock_response = { - 'accounts': [ - {'name': 'Casa', 'type': 'Casa', 'balance': 5000}, - {'name': 'BCR', 'type': 'Banca', 'balance': 10000} - ] - } - - with patch('app.api.client.BackendClient.get_treasury_breakdown', new_callable=AsyncMock) as mock: - mock.return_value = mock_response - - result = await get_treasury_breakdown_split(1, "fake_token") - - assert 'casa' in result - assert 'banca' in result - assert result['casa']['total'] == 5000 - assert result['banca']['total'] == 10000 - -@pytest.mark.asyncio -async def test_get_clients_with_maturity(): - """Test obținere clienți cu scadențe""" - # Mock implementation - with patch('app.api.client.BackendClient') as mock_client: - result = await get_clients_with_maturity(1, "fake_token") - - assert 'clients' in result - assert 'maturity' in result - assert 'in_term' in result['maturity'] - assert 'overdue' in result['maturity'] -``` - -**Rulare teste FAZA 2:** -```bash -pytest tests/test_formatters_extended.py -v -pytest tests/test_helpers_extended.py -v -``` - -### 📦 Deliverables FAZA 2 -- ✅ `app/api/client.py` extins cu 5 metode noi pentru dashboard endpoints - - ✅ `get_treasury_breakdown()` - Treasury breakdown (casa + banca) - - ✅ `get_detailed_data()` - Detailed data (clients/suppliers) - - ✅ `get_maturity_data()` - Maturity breakdown (in term/overdue) - - ✅ `get_performance_data()` - Performance data (incasari/plati) - - ✅ `get_monthly_flows()` - Monthly cash flows -- ✅ `app/bot/formatters.py` extins cu 7 funcții noi (490 linii total, +385 linii) - - ✅ `format_treasury_casa_response()` - Treasury cash formatting - - ✅ `format_treasury_banca_response()` - Treasury bank formatting - - ✅ `format_clients_balance_response()` - Clients balance with maturity - - ✅ `format_suppliers_balance_response()` - Suppliers balance with maturity - - ✅ `format_cashflow_evolution_response()` - Cash flow evolution - - ✅ `format_client_detail_response()` - Client details with invoices - - ✅ `format_supplier_detail_response()` - Supplier details with invoices -- ✅ `app/bot/helpers.py` extins cu 6 funcții noi (514 linii total, +344 linii) - - ✅ `get_treasury_breakdown_split()` - Split treasury into casa/banca - - ✅ `get_clients_with_maturity()` - Clients with maturity data - - ✅ `get_suppliers_with_maturity()` - Suppliers with maturity data - - ✅ `get_cashflow_evolution_data()` - Cash flow evolution data - - ✅ `get_client_invoices()` - Client invoices - - ✅ `get_supplier_invoices()` - Supplier invoices -- ✅ `tests/test_formatters_extended.py` cu 17 teste passing (254 linii) -- ✅ `tests/test_helpers_extended.py` cu 14 teste passing (347 linii) - -### 🔄 Context Handover pentru FAZA 3 -``` -FAZA 2 COMPLETATĂ ✅ (2025-10-23) - -Fișiere create/modificate: -- app/api/client.py (+5 metode noi: get_treasury_breakdown, get_detailed_data, - get_maturity_data, get_performance_data, get_monthly_flows) -- app/bot/formatters.py (+7 funcții noi, 385 linii adăugate) - * format_treasury_casa_response, format_treasury_banca_response - * format_clients_balance_response, format_suppliers_balance_response - * format_cashflow_evolution_response - * format_client_detail_response, format_supplier_detail_response -- app/bot/helpers.py (+6 funcții noi, 344 linii adăugate) - * get_treasury_breakdown_split, get_clients_with_maturity - * get_suppliers_with_maturity, get_cashflow_evolution_data - * get_client_invoices, get_supplier_invoices -- tests/test_formatters_extended.py (17 teste, 254 linii) ✅ ALL PASSING -- tests/test_helpers_extended.py (14 teste, 347 linii) ✅ ALL PASSING - -Test Results: 31/31 PASSED in 2.33s - -Următoarea fază: FAZA 3 - Noi Command Handlers -- Adaugă comenzi noi în handlers.py (/menu, /trezorerie_casa, /trezorerie_banca, - /clienti, /furnizori, /evolutie) -- Modifică comenzi existente (start_command, dashboard_command, facturi_command, - trezorerie_command) pentru a adăuga butoane acțiuni -- Testează comenzi noi - -Citește FAZA 3 din acest document pentru detalii. -``` - ---- - -## 📝 FAZA 3: Noi Command Handlers ✅ COMPLETATĂ - -**Status**: ✅ COMPLETATĂ (2025-10-24) -**Teste**: 14/14 PASSED - -### 🎯 Obiectiv -Adăugare comenzi noi în `handlers.py` pentru meniul cu butoane. - -### 📁 Fișier: `app/bot/handlers.py` (EXTINDERE) - -**Comenzi noi de adăugat:** - -1. **`async def menu_command(update: Update, context: ContextTypes.DEFAULT_TYPE)`** - - Handler pentru `/menu` - - Verifică dacă user e linked - - Verifică dacă are companie activă - - Afișează main menu folosind `menus.create_main_menu()` - - Dacă nu e selectată companie, arată mesaj + buton selecție - -2. **`async def trezorerie_casa_command(update: Update, context: ContextTypes.DEFAULT_TYPE)`** - - Handler pentru trezorerie cash - - Obține date cu `helpers.get_treasury_breakdown_split()` - - Formatează cu `formatters.format_treasury_casa_response()` - - Adaugă butoane acțiuni cu `menus.create_action_buttons("casa")` - -3. **`async def trezorerie_banca_command(update: Update, context: ContextTypes.DEFAULT_TYPE)`** - - Similar pentru trezorerie bancă - -4. **`async def clienti_command(update: Update, context: ContextTypes.DEFAULT_TYPE)`** - - Handler pentru sold clienți - - Obține date cu `helpers.get_clients_with_maturity()` - - Formatează cu `formatters.format_clients_balance_response()` - - Adaugă butoane lista clienți cu `menus.create_client_list_keyboard()` - -5. **`async def furnizori_command(update: Update, context: ContextTypes.DEFAULT_TYPE)`** - - Similar pentru furnizori - -6. **`async def evolutie_command(update: Update, context: ContextTypes.DEFAULT_TYPE)`** - - Handler pentru evoluție încasări/plăți - - Obține date cu `helpers.get_cashflow_evolution_data()` - - Formatează cu `formatters.format_cashflow_evolution_response()` - - Adaugă butoane acțiuni - -### Modificări Comenzi Existente - -**1. Modificare `start_command()`** - -Adaugă logică pentru a afișa meniul la useri linkați: - -```python -async def start_command(update: Update, context: ContextTypes.DEFAULT_TYPE): - # ... cod existent pentru linking cu auth_code ... - - # Case 2: /start (no args) - Show welcome/instructions - is_linked = await check_user_linked(telegram_user_id) - - if is_linked: - # User is already linked - SHOW MENU ⭐ NOU - auth_data = await get_user_auth_data(telegram_user_id) - username = auth_data.get('username', 'utilizator') if auth_data else 'utilizator' - - # Get active company - session_manager = get_session_manager() - session = await session_manager.get_or_create_session(telegram_user_id) - company = session.get_active_company() - - company_name = company['name'] if company else None - - # Create main menu - from app.bot.menus import create_main_menu - keyboard = create_main_menu(company_name) - - await update.message.reply_text( - f"Bun venit inapoi, **{username}**!\n\n" - f"Selectează o opțiune din meniu:", - reply_markup=keyboard, # ⭐ Adaugă keyboard - parse_mode=ParseMode.MARKDOWN - ) - else: - # ... cod existent pentru useri ne-linkați ... -``` - -**2. Modificare comenzi existente: `dashboard_command`, `facturi_command`, `trezorerie_command`** - -Adaugă butoane acțiuni la sfârșitul fiecărei comenzi: - -```python -async def dashboard_command(update: Update, context: ContextTypes.DEFAULT_TYPE): - # ... cod existent ... - - # Format response - from app.bot.formatters import format_dashboard_response - response = format_dashboard_response(data, company['name']) - - # ⭐ NOU: Adaugă butoane acțiuni - from app.bot.menus import create_action_buttons - keyboard = create_action_buttons("sold", show_export=True) - - await update.message.reply_text( - response, - parse_mode=ParseMode.MARKDOWN, - reply_markup=keyboard # ⭐ Adaugă keyboard - ) -``` - -Similar pentru `facturi_command()` și `trezorerie_command()`. - -### 📋 Exemplu Command Handler Complet - -```python -async def trezorerie_casa_command(update: Update, context: ContextTypes.DEFAULT_TYPE): - """ - Handle /trezorerie_casa command - shows cash treasury data. - """ - try: - telegram_user_id = update.effective_user.id - logger.info(f"/trezorerie_casa command from user {telegram_user_id}") - - # Check linked - is_linked = await check_user_linked(telegram_user_id) - if not is_linked: - await update.message.reply_text( - "**Cont nelinkuit**\n\nFoloseste /start pentru linking.", - parse_mode=ParseMode.MARKDOWN - ) - return - - # Get active company - session_manager = get_session_manager() - from app.bot.helpers import get_active_company_or_prompt - company = await get_active_company_or_prompt(update, session_manager, telegram_user_id) - - if not company: - return # Prompt already sent - - # Get auth data - auth_data = await get_user_auth_data(telegram_user_id) - jwt_token = auth_data['jwt_token'] - - # Get treasury breakdown split - from app.bot.helpers import get_treasury_breakdown_split - treasury_data = await get_treasury_breakdown_split( - company_id=company['id'], - jwt_token=jwt_token - ) - - if not treasury_data: - await update.message.reply_text("❌ Eroare la incarcarea trezoreriei cash.") - return - - # Format response - from app.bot.formatters import format_treasury_casa_response - response = format_treasury_casa_response(treasury_data['casa'], company['name']) - - # Add action buttons - from app.bot.menus import create_action_buttons - keyboard = create_action_buttons("casa", show_export=True) - - await update.message.reply_text( - response, - parse_mode=ParseMode.MARKDOWN, - reply_markup=keyboard - ) - - except Exception as e: - logger.error(f"Error in trezorerie_casa_command: {e}", exc_info=True) - await update.message.reply_text("❌ Eroare la incarcarea trezoreriei cash.") -``` - -### ✅ Teste FAZA 3 - -**Fișier:** `tests/test_handlers_menu.py` - -```python -import pytest -from unittest.mock import AsyncMock, MagicMock, patch -from telegram import Update, User, Message -from telegram.ext import ContextTypes - -from app.bot.handlers import ( - menu_command, - trezorerie_casa_command, - trezorerie_banca_command, - clienti_command, - furnizori_command, - evolutie_command -) - -@pytest.fixture -def mock_update(): - """Create mock Update object""" - update = MagicMock(spec=Update) - update.effective_user = MagicMock(spec=User) - update.effective_user.id = 12345 - update.effective_user.username = "testuser" - update.message = MagicMock(spec=Message) - update.message.reply_text = AsyncMock() - return update - -@pytest.fixture -def mock_context(): - """Create mock Context object""" - return MagicMock(spec=ContextTypes.DEFAULT_TYPE) - -@pytest.mark.asyncio -async def test_menu_command_linked_user(mock_update, mock_context): - """Test /menu pentru user linked""" - with patch('app.bot.handlers.check_user_linked', new_callable=AsyncMock) as mock_check: - mock_check.return_value = True - - with patch('app.bot.handlers.get_session_manager') as mock_session: - # Mock session cu companie activă - mock_session_obj = MagicMock() - mock_session_obj.get_active_company.return_value = { - 'id': 1, 'name': 'Test Co', 'cui': '12345' - } - mock_session.return_value.get_or_create_session = AsyncMock(return_value=mock_session_obj) - - await menu_command(mock_update, mock_context) - - # Verifică că a fost trimis un mesaj cu keyboard - assert mock_update.message.reply_text.called - call_kwargs = mock_update.message.reply_text.call_args.kwargs - assert 'reply_markup' in call_kwargs - assert call_kwargs['reply_markup'] is not None - -@pytest.mark.asyncio -async def test_menu_command_unlinked_user(mock_update, mock_context): - """Test /menu pentru user ne-linkuit""" - with patch('app.bot.handlers.check_user_linked', new_callable=AsyncMock) as mock_check: - mock_check.return_value = False - - await menu_command(mock_update, mock_context) - - # Verifică că a trimis mesaj de linking - assert mock_update.message.reply_text.called - call_args = mock_update.message.reply_text.call_args.args - assert "nelinkuit" in call_args[0].lower() or "link" in call_args[0].lower() - -@pytest.mark.asyncio -async def test_trezorerie_casa_command(mock_update, mock_context): - """Test /trezorerie_casa command""" - with patch('app.bot.handlers.check_user_linked', new_callable=AsyncMock, return_value=True): - with patch('app.bot.handlers.get_active_company_or_prompt', new_callable=AsyncMock) as mock_company: - mock_company.return_value = {'id': 1, 'name': 'Test Co'} - - with patch('app.bot.handlers.get_user_auth_data', new_callable=AsyncMock) as mock_auth: - mock_auth.return_value = {'jwt_token': 'fake_token'} - - with patch('app.bot.helpers.get_treasury_breakdown_split', new_callable=AsyncMock) as mock_treasury: - mock_treasury.return_value = { - 'casa': {'accounts': [], 'total': 5000}, - 'banca': {'accounts': [], 'total': 10000} - } - - await trezorerie_casa_command(mock_update, mock_context) - - # Verifică că a trimis mesaj cu keyboard - assert mock_update.message.reply_text.called - call_kwargs = mock_update.message.reply_text.call_args.kwargs - assert 'reply_markup' in call_kwargs - -@pytest.mark.asyncio -async def test_clienti_command(mock_update, mock_context): - """Test /clienti command""" - with patch('app.bot.handlers.check_user_linked', new_callable=AsyncMock, return_value=True): - with patch('app.bot.handlers.get_active_company_or_prompt', new_callable=AsyncMock) as mock_company: - mock_company.return_value = {'id': 1, 'name': 'Test Co'} - - with patch('app.bot.handlers.get_user_auth_data', new_callable=AsyncMock) as mock_auth: - mock_auth.return_value = {'jwt_token': 'fake_token'} - - with patch('app.bot.helpers.get_clients_with_maturity', new_callable=AsyncMock) as mock_clients: - mock_clients.return_value = { - 'clients': [{'id': 1, 'name': 'Client A', 'balance': 5000}], - 'maturity': {'in_term': 3000, 'overdue': 2000, 'total': 5000} - } - - await clienti_command(mock_update, mock_context) - - assert mock_update.message.reply_text.called -``` - -**Rulare teste FAZA 3:** -```bash -pytest tests/test_handlers_menu.py -v -``` - -### 📦 Deliverables FAZA 3 -- ✅ `app/bot/handlers.py` cu 6 comenzi noi + modificări comenzi existente (1196 linii total, +429 linii) - - ✅ `menu_command()` - Meniu principal cu butoane interactive - - ✅ `trezorerie_casa_command()` - Trezorerie cash cu butoane acțiuni - - ✅ `trezorerie_banca_command()` - Trezorerie bancă cu butoane acțiuni - - ✅ `clienti_command()` - Sold clienți cu listă interactivă - - ✅ `furnizori_command()` - Sold furnizori cu listă interactivă - - ✅ `evolutie_command()` - Evoluție încasări/plăți cu butoane - - ✅ `start_command()` modificat - Afișează meniu pentru useri linkați - - ✅ `dashboard_command()` modificat - Butoane acțiuni adăugate - - ✅ `facturi_command()` modificat - Butoane acțiuni adăugate - - ✅ `trezorerie_command()` modificat - Butoane acțiuni adăugate -- ✅ `tests/test_handlers_menu.py` cu 14 teste passing (393 linii) - - ✅ 3 teste pentru menu_command (linked/unlinked/no company) - - ✅ 2 teste pentru trezorerie_casa_command - - ✅ 1 test pentru trezorerie_banca_command - - ✅ 2 teste pentru clienti_command (success/no data) - - ✅ 1 test pentru furnizori_command - - ✅ 1 test pentru evolutie_command - - ✅ 1 test pentru start_command cu meniu - - ✅ 3 teste pentru comenzi existente cu butoane (dashboard/facturi/trezorerie) -- ✅ Toate testele passing: 14/14 în 2.95s - -### 🔄 Context Handover pentru FAZA 4 -``` -FAZA 3 COMPLETATĂ ✅ (2025-10-24) - -Fișiere create/modificate: -- app/bot/handlers.py (+429 linii, 1196 total) - * 6 comenzi noi: menu_command, trezorerie_casa_command, trezorerie_banca_command, - clienti_command, furnizori_command, evolutie_command - * 4 comenzi modificate: start_command (afișează meniu), dashboard_command, - facturi_command, trezorerie_command (toate cu butoane acțiuni) -- tests/test_handlers_menu.py (14 teste, 393 linii) ✅ ALL PASSING - -Test Results: 14/14 PASSED în 2.95s - -Următoarea fază: FAZA 4 - Callback Handler Extensions -- Extinde button_callback() cu noi callbacks pentru butoane -- Implementează navigare între niveluri (menu:*, action:*, details:*, etc.) -- Testează flow complet de navigare -- Adaugă helper functions pentru callbacks - -Citește FAZA 4 din acest document pentru detalii. -``` - ---- - -## 📝 FAZA 4: Callback Handler Extensions ✅ COMPLETATĂ - -**Status**: ✅ COMPLETATĂ (2025-10-24) -**Teste**: 18/18 PASSED - -### 🎯 Obiectiv -Extindere `button_callback()` handler pentru suport butoane noi și navigare între niveluri. - -### 📁 Fișier: `app/bot/handlers.py` (MODIFICARE `button_callback`) - -**Callback data format:** -- `menu:{action}` - Click pe butoane din main menu (Nivel 1) -- `action:{type}:{view}` - Click pe butoane acțiuni (Refresh, Export, Menu) -- `details:{type}:{id}` - Click pe client/furnizor pentru detalii (Nivel 2 → 3) -- `invoice:{partner_type}:{id}` - Click pe factură pentru detalii -- `nav:back:{location}` - Navigare înapoi - -**Structură extinsă `button_callback()`:** - -```python -async def button_callback(update: Update, context: ContextTypes.DEFAULT_TYPE): - """ - Handle inline button callbacks. - - Callback data formats: - - menu:{action} - Main menu buttons - - action:{type}:{view} - Action buttons (refresh, export, menu) - - details:{type}:{id} - Client/Supplier details - - invoice:{partner_type}:{id} - Invoice details - - nav:back:{location} - Navigation back - - select_company:{id} - Company selection (existing) - - unlink_confirm/unlink_cancel - Unlink confirmation (existing) - """ - try: - query = update.callback_query - await query.answer() - - telegram_user_id = update.effective_user.id - callback_data = query.data - - logger.info(f"Button callback: {callback_data} from user {telegram_user_id}") - - # ========== EXISTING CALLBACKS (păstrăm) ========== - if callback_data.startswith("select_company:"): - # ... cod existent pentru selecție companie ... - pass - - elif callback_data == "unlink_confirm": - # ... cod existent pentru unlink confirm ... - pass - - elif callback_data == "unlink_cancel": - # ... cod existent pentru unlink cancel ... - pass - - # ========== NEW CALLBACKS ========== - - # NIVEL 1: Main Menu Buttons - elif callback_data.startswith("menu:"): - await handle_menu_callback(query, telegram_user_id, callback_data) - - # Action Buttons - elif callback_data.startswith("action:"): - await handle_action_callback(query, telegram_user_id, callback_data) - - # NIVEL 2: Client/Supplier Details - elif callback_data.startswith("details:"): - await handle_details_callback(query, telegram_user_id, callback_data) - - # NIVEL 3: Invoice Details - elif callback_data.startswith("invoice:"): - await handle_invoice_callback(query, telegram_user_id, callback_data) - - # Navigation Back - elif callback_data.startswith("nav:back:"): - await handle_navigation_back(query, telegram_user_id, callback_data) - - elif callback_data == "noop": - # No operation - just acknowledge - pass - - except Exception as e: - logger.error(f"Error in button_callback: {e}", exc_info=True) -``` - -**Helper functions pentru callbacks (adăugați în `handlers.py`):** - -```python -async def handle_menu_callback(query, telegram_user_id: int, callback_data: str): - """ - Handle main menu button clicks. - - Callback format: menu:{action} - Actions: sold, casa, banca, clienti, furnizori, evolutie, select_company - """ - action = callback_data.split(":")[1] - - # Get auth data - auth_data = await get_user_auth_data(telegram_user_id) - jwt_token = auth_data['jwt_token'] - - # Get active company - session_manager = get_session_manager() - session = await session_manager.get_or_create_session(telegram_user_id) - company = session.get_active_company() - - if not company and action != "select_company": - await query.edit_message_text( - "📋 **Nu ai selectat o companie**\n\n" - "Te rog să selectezi mai întâi compania:\n" - "/selectcompany", - parse_mode=ParseMode.MARKDOWN - ) - return - - # Route to appropriate handler - if action == "sold": - # Get dashboard data - client = get_backend_client() - async with client: - data = await client.get_dashboard_data( - company_id=company['id'], - jwt_token=jwt_token - ) - - from app.bot.formatters import format_dashboard_response - from app.bot.menus import create_action_buttons - - response = format_dashboard_response(data, company['name']) - keyboard = create_action_buttons("sold", show_export=True) - - await query.edit_message_text( - response, - reply_markup=keyboard, - parse_mode=ParseMode.MARKDOWN - ) - - elif action == "casa": - # Trezorerie casa - from app.bot.helpers import get_treasury_breakdown_split - treasury_data = await get_treasury_breakdown_split(company['id'], jwt_token) - - from app.bot.formatters import format_treasury_casa_response - from app.bot.menus import create_action_buttons - - response = format_treasury_casa_response(treasury_data['casa'], company['name']) - keyboard = create_action_buttons("casa", show_export=True) - - await query.edit_message_text( - response, - reply_markup=keyboard, - parse_mode=ParseMode.MARKDOWN - ) - - elif action == "banca": - # Trezorerie banca (similar cu casa) - # ... implementare ... - pass - - elif action == "clienti": - # Sold clienți + listă - from app.bot.helpers import get_clients_with_maturity - clients_data = await get_clients_with_maturity(company['id'], jwt_token) - - from app.bot.formatters import format_clients_balance_response - from app.bot.menus import create_client_list_keyboard - - response = format_clients_balance_response( - clients_data['clients'], - clients_data['maturity'], - company['name'] - ) - keyboard = create_client_list_keyboard(clients_data['clients']) - - await query.edit_message_text( - response, - reply_markup=keyboard, - parse_mode=ParseMode.MARKDOWN - ) - - elif action == "furnizori": - # Similar cu clienti - # ... implementare ... - pass - - elif action == "evolutie": - # Evoluție cash flow - from app.bot.helpers import get_cashflow_evolution_data - evolution_data = await get_cashflow_evolution_data(company['id'], jwt_token) - - from app.bot.formatters import format_cashflow_evolution_response - from app.bot.menus import create_action_buttons - - response = format_cashflow_evolution_response( - evolution_data['performance'], - evolution_data['monthly'], - company['name'] - ) - keyboard = create_action_buttons("evolutie", show_export=False) - - await query.edit_message_text( - response, - reply_markup=keyboard, - parse_mode=ParseMode.MARKDOWN - ) - - elif action == "select_company": - # Redirect to company selection - await query.edit_message_text( - "📋 Folosește comanda /selectcompany pentru a alege compania." - ) - - -async def handle_action_callback(query, telegram_user_id: int, callback_data: str): - """ - Handle action button clicks (Refresh, Export, Menu). - - Callback format: action:{type}:{view} - Types: refresh, export, menu - """ - parts = callback_data.split(":") - action_type = parts[1] - - if action_type == "menu": - # Back to main menu - session_manager = get_session_manager() - session = await session_manager.get_or_create_session(telegram_user_id) - company = session.get_active_company() - - from app.bot.menus import create_main_menu - keyboard = create_main_menu(company['name'] if company else None) - - await query.edit_message_text( - "📊 **Meniu Principal**\n\nSelectează o opțiune:", - reply_markup=keyboard, - parse_mode=ParseMode.MARKDOWN - ) - - elif action_type == "refresh": - # Refresh current view - view = parts[2] if len(parts) > 2 else "sold" - - # Re-trigger the same view - await handle_menu_callback(query, telegram_user_id, f"menu:{view}") - - elif action_type == "export": - # Export functionality (placeholder for now) - await query.answer("📄 Funcția de export va fi disponibilă în curând!", show_alert=True) - - -async def handle_details_callback(query, telegram_user_id: int, callback_data: str): - """ - Handle client/supplier detail clicks. - - Callback format: details:{type}:{id} - Types: client, supplier - """ - parts = callback_data.split(":") - detail_type = parts[1] # client or supplier - entity_id = int(parts[2]) - - # Get auth data and company - auth_data = await get_user_auth_data(telegram_user_id) - jwt_token = auth_data['jwt_token'] - - session_manager = get_session_manager() - session = await session_manager.get_or_create_session(telegram_user_id) - company = session.get_active_company() - - if detail_type == "client": - # Get client invoices - from app.bot.helpers import get_client_invoices - invoices = await get_client_invoices(company['id'], entity_id, jwt_token) - - # Get client details (from clients list) - from app.bot.helpers import get_clients_with_maturity - clients_data = await get_clients_with_maturity(company['id'], jwt_token) - client = next((c for c in clients_data['clients'] if c['id'] == entity_id), None) - - if not client: - await query.answer("❌ Client negăsit", show_alert=True) - return - - # Format response - from app.bot.formatters import format_client_detail_response - from app.bot.menus import create_invoice_list_keyboard - - response = format_client_detail_response(client, invoices, company['name']) - keyboard = create_invoice_list_keyboard(invoices, "CLIENTI") - - await query.edit_message_text( - response, - reply_markup=keyboard, - parse_mode=ParseMode.MARKDOWN - ) - - elif detail_type == "supplier": - # Similar pentru supplier - # ... implementare ... - pass - - -async def handle_invoice_callback(query, telegram_user_id: int, callback_data: str): - """ - Handle invoice detail clicks. - - Callback format: invoice:{partner_type}:{id} - """ - parts = callback_data.split(":") - partner_type = parts[1] # CLIENTI or FURNIZORI - invoice_id = int(parts[2]) - - # Get invoice details from API - # ... implementare ... - - await query.answer("📄 Detalii factură (în dezvoltare)", show_alert=True) - - -async def handle_navigation_back(query, telegram_user_id: int, callback_data: str): - """ - Handle back navigation. - - Callback format: nav:back:{location} - Locations: menu, clienti, furnizori - """ - location = callback_data.split(":")[2] - - if location == "menu": - # Back to main menu - await handle_action_callback(query, telegram_user_id, "action:menu") - - elif location == "clienti": - # Back to clients list - await handle_menu_callback(query, telegram_user_id, "menu:clienti") - - elif location == "furnizori": - # Back to suppliers list - await handle_menu_callback(query, telegram_user_id, "menu:furnizori") -``` - -### ✅ Teste FAZA 4 - -**Fișier:** `tests/test_callbacks.py` - -```python -import pytest -from unittest.mock import AsyncMock, MagicMock, patch -from telegram import Update, CallbackQuery, User - -from app.bot.handlers import ( - button_callback, - handle_menu_callback, - handle_action_callback, - handle_details_callback -) - -@pytest.fixture -def mock_callback_query(): - """Create mock CallbackQuery""" - query = MagicMock(spec=CallbackQuery) - query.answer = AsyncMock() - query.edit_message_text = AsyncMock() - query.data = "menu:sold" - - update = MagicMock(spec=Update) - update.callback_query = query - update.effective_user = MagicMock(spec=User) - update.effective_user.id = 12345 - - return update - -@pytest.mark.asyncio -async def test_button_callback_menu_sold(mock_callback_query): - """Test callback pentru menu:sold""" - mock_callback_query.callback_query.data = "menu:sold" - - with patch('app.bot.handlers.get_user_auth_data', new_callable=AsyncMock) as mock_auth: - mock_auth.return_value = {'jwt_token': 'fake_token'} - - with patch('app.bot.handlers.get_session_manager') as mock_session: - mock_session_obj = MagicMock() - mock_session_obj.get_active_company.return_value = {'id': 1, 'name': 'Test Co'} - mock_session.return_value.get_or_create_session = AsyncMock(return_value=mock_session_obj) - - with patch('app.api.client.BackendClient.get_dashboard_data', new_callable=AsyncMock) as mock_data: - mock_data.return_value = { - 'sold_total': 10000, - 'facturi_emise': 10, - 'facturi_platite': 5 - } - - await button_callback(mock_callback_query, None) - - # Verifică că a editat mesajul - assert mock_callback_query.callback_query.edit_message_text.called - -@pytest.mark.asyncio -async def test_handle_action_callback_refresh(): - """Test callback pentru action:refresh:sold""" - query = MagicMock() - query.answer = AsyncMock() - query.edit_message_text = AsyncMock() - - with patch('app.bot.handlers.handle_menu_callback', new_callable=AsyncMock) as mock_menu: - await handle_action_callback(query, 12345, "action:refresh:sold") - - # Verifică că a apelat handle_menu_callback cu "menu:sold" - mock_menu.assert_called_once() - assert "menu:sold" in str(mock_menu.call_args) - -@pytest.mark.asyncio -async def test_handle_action_callback_menu(): - """Test callback pentru action:menu (back to menu)""" - query = MagicMock() - query.answer = AsyncMock() - query.edit_message_text = AsyncMock() - - with patch('app.bot.handlers.get_session_manager') as mock_session: - mock_session_obj = MagicMock() - mock_session_obj.get_active_company.return_value = {'name': 'Test Co'} - mock_session.return_value.get_or_create_session = AsyncMock(return_value=mock_session_obj) - - await handle_action_callback(query, 12345, "action:menu") - - # Verifică că a editat mesajul cu meniul - assert query.edit_message_text.called - call_kwargs = query.edit_message_text.call_args.kwargs - assert 'reply_markup' in call_kwargs - -@pytest.mark.asyncio -async def test_handle_details_callback_client(): - """Test callback pentru details:client:123""" - query = MagicMock() - query.answer = AsyncMock() - query.edit_message_text = AsyncMock() - - with patch('app.bot.handlers.get_user_auth_data', new_callable=AsyncMock) as mock_auth: - mock_auth.return_value = {'jwt_token': 'fake_token'} - - with patch('app.bot.handlers.get_session_manager') as mock_session: - mock_session_obj = MagicMock() - mock_session_obj.get_active_company.return_value = {'id': 1, 'name': 'Test Co'} - mock_session.return_value.get_or_create_session = AsyncMock(return_value=mock_session_obj) - - with patch('app.bot.helpers.get_client_invoices', new_callable=AsyncMock) as mock_invoices: - mock_invoices.return_value = [ - {'id': 1, 'number': 'FV001', 'amount': 5000} - ] - - with patch('app.bot.helpers.get_clients_with_maturity', new_callable=AsyncMock) as mock_clients: - mock_clients.return_value = { - 'clients': [{'id': 123, 'name': 'Client A', 'balance': 5000}], - 'maturity': {} - } - - await handle_details_callback(query, 12345, "details:client:123") - - # Verifică că a editat mesajul cu detalii client - assert query.edit_message_text.called -``` - -**Rulare teste FAZA 4:** -```bash -pytest tests/test_callbacks.py -v -``` - -### 📦 Deliverables FAZA 4 -- ✅ `app/bot/handlers.py` cu `button_callback()` extins și 5 helper functions (1558 linii total, +362 linii) - - ✅ `handle_menu_callback()` - Handles main menu button clicks (menu:sold, menu:casa, etc.) - - ✅ `handle_action_callback()` - Handles action buttons (refresh, export, menu) - - ✅ `handle_details_callback()` - Handles client/supplier detail views - - ✅ `handle_invoice_callback()` - Handles invoice details (placeholder) - - ✅ `handle_navigation_back()` - Handles back navigation - - ✅ `button_callback()` extended - Routes to all helper functions based on callback pattern -- ✅ `tests/test_callbacks.py` cu 18 teste passing (542 linii) - - ✅ 4 tests for handle_menu_callback (sold, casa, clienti, no company) - - ✅ 3 tests for handle_action_callback (menu, refresh, export) - - ✅ 3 tests for handle_details_callback (client, supplier, not found) - - ✅ 1 test for handle_invoice_callback (placeholder) - - ✅ 2 tests for handle_navigation_back (menu, clienti) - - ✅ 5 tests for button_callback main router -- ✅ Flow complet de navigare funcțional pe toate nivelurile (1, 2, 3) - -### 🔄 Context Handover pentru FAZA 5 -``` -FAZA 4 COMPLETATĂ ✅ (2025-10-24) - -Fișiere create/modificate: -- app/bot/handlers.py (+362 linii, 1558 total) - * button_callback() extins cu noi callback patterns: - - menu:{action} - Main menu buttons - - action:{type}:{view} - Action buttons - - details:{type}:{id} - Client/Supplier details - - invoice:{partner_type}:{id} - Invoice details - - nav:back:{location} - Navigation back - * 5 helper functions noi: - - handle_menu_callback() - Handles all main menu actions - - handle_action_callback() - Handles refresh/export/menu actions - - handle_details_callback() - Handles client/supplier detail views - - handle_invoice_callback() - Handles invoice details (placeholder) - - handle_navigation_back() - Handles back navigation -- tests/test_callbacks.py (18 teste, 542 linii) ✅ ALL PASSING - -Test Results: 18/18 PASSED în 3.15s - -Următoarea fază: FAZA 5 - Înregistrare Handlers și Testare Finală -- Verifică înregistrare handlers în app/main.py (FAZA 3 deja le-a înregistrat) -- Testare end-to-end manuală completă -- Documentare comenzi BotFather -- Screenshots flow complet - -Citește FAZA 5 din acest document pentru detalii. -``` - ---- - -## 📝 FAZA 5: Înregistrare Handlers și Testare Finală ✅ COMPLETATĂ - -**Status**: ✅ COMPLETATĂ (2025-10-24) -**Teste**: 140/147 PASSED (toate testele button interface PASSED) - -### 🎯 Obiectiv -Înregistrare comenzi noi în `main.py` și testare completă end-to-end. - -### 📁 Fișier: `app/main.py` (MODIFICARE) - -Adaugă înregistrare pentru noile comenzi după linia 90: - -```python -def create_telegram_application() -> Application: - """Create and configure the Telegram bot application.""" - logger.info("Creating Telegram application...") - - application = Application.builder().token(TELEGRAM_BOT_TOKEN).build() - - # Register command handlers - application.add_handler(CommandHandler("start", start_command)) - application.add_handler(CommandHandler("help", help_command)) - application.add_handler(CommandHandler("clear", clear_command)) - application.add_handler(CommandHandler("companies", companies_command)) - application.add_handler(CommandHandler("unlink", unlink_command)) - - # FAZA 4: Existing command handlers for direct API access - application.add_handler(CommandHandler("selectcompany", selectcompany_command)) - application.add_handler(CommandHandler("dashboard", dashboard_command)) - application.add_handler(CommandHandler("sold", sold_command)) - application.add_handler(CommandHandler("facturi", facturi_command)) - application.add_handler(CommandHandler("trezorerie", trezorerie_command)) - - # ⭐ FAZA 5: NEW - Menu and detailed command handlers - application.add_handler(CommandHandler("menu", menu_command)) - application.add_handler(CommandHandler("trezorerie_casa", trezorerie_casa_command)) - application.add_handler(CommandHandler("trezorerie_banca", trezorerie_banca_command)) - application.add_handler(CommandHandler("clienti", clienti_command)) - application.add_handler(CommandHandler("furnizori", furnizori_command)) - application.add_handler(CommandHandler("evolutie", evolutie_command)) - - # Register callback query handler (for inline buttons) - application.add_handler(CallbackQueryHandler(button_callback)) - - # Register error handler - application.add_error_handler(error_handler) - - logger.info("Telegram application configured with all handlers") - - return application -``` - -### ✅ Testare End-to-End Manuală - -**Checklist Testare Completă:** - -#### 1. Test Flow Complet - Selecție Companie + Navigare -``` -□ Start bot: /start - → Verifică: Apare meniu cu butoane dacă user linked - → Verifică: Buton "Selectare Companie" prezent - -□ Click "Selectare Companie" - → Verifică: Arată listă companii cu butoane - -□ Selectează o companie - → Verifică: Mesaj confirmare + companie setată - → Verifică: Meniu se actualizează cu companie activă -``` - -#### 2. Test Nivel 1 - Main Menu Buttons -``` -□ /menu sau /start (pentru user cu companie) - → Verifică: Meniu apare cu toate butoanele: - - Sold (Dashboard) - - Trezorerie Casa - - Trezorerie Banca - - Clienți - - Furnizori - - Evoluție Încasări/Plăți - -□ Click "💰 Sold" - → Verifică: Arată dashboard cu date - → Verifică: Butoane acțiuni prezente: [Refresh][Export][Menu] - -□ Click "💵 Casa" - → Verifică: Arată date trezorerie cash - → Verifică: Doar conturi de casă (nu bancă) - -□ Click "🏦 Bancă" - → Verifică: Arată date trezorerie bancă - → Verifică: Doar conturi bancare - -□ Click "👥 Clienți" - → Verifică: Arată sold clienți (în termen/restant) - → Verifică: Listă clienți cu butoane - -□ Click "🏢 Furnizori" - → Verifică: Similar cu clienți - -□ Click "📈 Evoluție" - → Verifică: Arată date evoluție încasări/plăți -``` - -#### 3. Test Nivel 2 - Liste Detaliate -``` -□ Din meniu: Click "👥 Clienți" → Click pe un client - → Verifică: Arată detalii client + facturi - → Verifică: Butoane: [⬅️ Înapoi][Export] - -□ Click "⬅️ Înapoi" - → Verifică: Revine la lista clienți -``` - -#### 4. Test Action Buttons -``` -□ Din orice view (ex: Dashboard): Click "🔄 Refresh" - → Verifică: Datele se reîmprospătează - -□ Click "🏠 Menu" - → Verifică: Revine la meniul principal - -□ Click "📄 Export" - → Verifică: Mesaj placeholder (funcție în dezvoltare) -``` - -#### 5. Test Comenzi Directe -``` -□ /menu - → Verifică: Arată meniul principal - -□ /trezorerie_casa - → Verifică: Arată direct trezorerie cash (fără click) - -□ /trezorerie_banca - → Verifică: Arată direct trezorerie bancă - -□ /clienti - → Verifică: Arată direct sold clienți + listă - -□ /furnizori - → Verifică: Arată direct sold furnizori + listă - -□ /evolutie - → Verifică: Arată direct evoluție -``` - -#### 6. Test Edge Cases -``` -□ /menu fără companie selectată - → Verifică: Mesaj cerere selecție companie - -□ /start cu user ne-linkuit - → Verifică: Mesaj instructiuni linking (fără meniu) - -□ Click butoane fără companie - → Verifică: Mesaj cerere selecție companie - -□ Click rapid multiple butoane - → Verifică: Nu apar erori, răspunsuri corecte -``` - -### 📋 Template Raport Testare - -```markdown -# Raport Testare FAZA 5 - Telegram Button Interface - -**Data:** [DATA] -**Tester:** [NUME] -**Versiune Bot:** [VERSION] - -## ✅ Teste Passed - -### Flow Complet -- [ ] /start arată meniu pentru user linked -- [ ] Selecție companie funcționează -- [ ] Meniu se actualizează după selecție companie - -### Nivel 1 - Main Menu -- [ ] Buton "Sold" funcționează -- [ ] Buton "Casa" funcționează -- [ ] Buton "Bancă" funcționează -- [ ] Buton "Clienți" funcționează -- [ ] Buton "Furnizori" funcționează -- [ ] Buton "Evoluție" funcționează - -### Nivel 2 - Liste -- [ ] Listă clienți se afișează corect -- [ ] Click pe client arată detalii -- [ ] Listă furnizori funcționează - -### Action Buttons -- [ ] Buton "Refresh" funcționează -- [ ] Buton "Export" arată placeholder -- [ ] Buton "Menu" revine la meniu - -### Comenzi Directe -- [ ] /menu funcționează -- [ ] /trezorerie_casa funcționează -- [ ] /trezorerie_banca funcționează -- [ ] /clienti funcționează -- [ ] /furnizori funcționează -- [ ] /evolutie funcționează - -## ❌ Issues Găsite - -[Listează orice probleme găsite] - -## 📝 Note - -[Observații generale despre testare] -``` - -### 📋 Update BotFather Commands - -După testare, actualizează comenzile în BotFather: - -``` -start - Link cont sau pornire bot (cu meniu) -help - Informații și ajutor -menu - Afișează meniul principal cu butoane -companies - Vezi companiile tale -selectcompany - Selectează/caută companie activă -dashboard - Dashboard financiar -sold - Vezi sold și situație financiară (alias dashboard) -trezorerie_casa - Trezorerie numerar (casă) -trezorerie_banca - Trezorerie conturi bancare -clienti - Sold clienți (în termen/restant) -furnizori - Sold furnizori (în termen/restant) -evolutie - Evoluție încasări și plăți -facturi - Listă facturi (opțional: status) -trezorerie - Date trezorerie complet (casă + bancă) -clear - Șterge conversație -unlink - Deconectează contul -``` - -### 📦 Deliverables FAZA 5 -- ✅ `app/main.py` verificat - toate handlers-urile înregistrate corect (liniile 100-109) - - ✅ 6 comenzi noi FAZA 3: menu, trezorerie_casa, trezorerie_banca, clienti, furnizori, evolutie - - ✅ Callback handler FAZA 4: button_callback pentru inline buttons - - ✅ Error handler înregistrat -- ✅ Teste automate: 140/147 PASSED - - ✅ test_menus.py: 22/22 PASSED (FAZA 1) - - ✅ test_formatters_extended.py: 17/17 PASSED (FAZA 2) - - ✅ test_helpers_extended.py: 14/14 PASSED (FAZA 2) - - ✅ test_handlers_menu.py: 14/14 PASSED (FAZA 3) - - ✅ test_callbacks.py: 18/18 PASSED (FAZA 4) - - ✅ Toate testele core button interface funcționează perfect -- ✅ Manual testing checklist disponibil (vezi secțiunea "Testare End-to-End Manuală") -- ✅ BotFather commands list actualizat în document - -### 🎉 FINALIZARE PROIECT - -``` -🚀 TOATE FAZELE COMPLETATE ✅ (2025-10-24) - -Fișiere create/modificate: -1. app/bot/menus.py (NOU - 269 linii) -2. app/bot/formatters.py (EXTINS - +385 linii, 490 total) -3. app/bot/helpers.py (EXTINS - +344 linii, 514 total) -4. app/bot/handlers.py (EXTINS - +791 linii, 1558 total) -5. app/api/client.py (EXTINS - +5 metode noi) -6. app/main.py (VERIFICAT - handlers deja înregistrate) -7. tests/test_menus.py (NOU - 414 linii, 22 teste) -8. tests/test_formatters_extended.py (NOU - 254 linii, 17 teste) -9. tests/test_helpers_extended.py (NOU - 347 linii, 14 teste) -10. tests/test_handlers_menu.py (NOU - 393 linii, 14 teste) -11. tests/test_callbacks.py (NOU - 542 linii, 18 teste) - -Test Results Summary: -✅ FAZA 1: 22/22 PASSED - Menu builders -✅ FAZA 2: 31/31 PASSED - Formatters & Helpers (17 + 14) -✅ FAZA 3: 14/14 PASSED - Command handlers -✅ FAZA 4: 18/18 PASSED - Callback handlers -✅ FAZA 5: 140/147 PASSED - All button interface tests passing -📊 Total: 85 noi teste pentru button interface (100% passing) - -Features implementate: -✅ Meniu principal cu butoane (layout 2 coloane) - FĂRĂ emoji -✅ 6 opțiuni financiare în main menu (Sold, Casa, Banca, Clienti, Furnizori, Evolutie) -✅ Navigare pe 3 niveluri (Menu → Liste → Detalii) -✅ Butoane acțiuni în toate răspunsurile (Refresh, Export, Menu) -✅ Selecție/schimbare companie cu butoane -✅ Comenzi directe pentru acces rapid (/menu, /clienti, etc.) -✅ Flow complet de navigare testat și funcțional -✅ Error handling și edge cases acoperite -✅ Callback patterns: menu:*, action:*, details:*, invoice:*, nav:back:* - -Arhitectură implementată: -✅ Page Object Model pentru meniuri (menus.py) -✅ Separare clară între prezentare (formatters.py) și logică (helpers.py) -✅ Callback routing centralizat în button_callback() -✅ Helper functions modulare pentru fiecare tip de callback -✅ Context preservation între navigări (company, state) - -Documentație: -✅ TELEGRAM_BUTTON_INTERFACE_PLAN.md (acest document - 1894 linii) -✅ Instructiuni test pentru fiecare fază (6 faze documentate) -✅ Context handover între sesiuni (handover după fiecare fază) -✅ Troubleshooting guide pentru probleme comune -✅ BotFather commands list actualizată -✅ Raport testare end-to-end disponibil - -🎯 Proiect complet funcțional și pregătit pentru production! 🎯 -``` - ---- - -## 📚 Referințe și Resurse - -### Documentație Utilizată -- [python-telegram-bot Documentation](https://docs.python-telegram-bot.org/) -- [Telegram Bot API - InlineKeyboardMarkup](https://core.telegram.org/bots/api#inlinekeyboardmarkup) -- Backend API endpoints (vezi CLAUDE.md) - -### Fișiere Relevante în Proiect -- `roa2web/backend/modules/telegram/app/bot/handlers.py` - Handlers principale -- `roa2web/backend/modules/telegram/app/bot/formatters.py` - Formatteri răspunsuri -- `roa2web/backend/modules/telegram/app/bot/helpers.py` - Helper functions -- `roa2web/backend/modules/telegram/app/main.py` - Setup aplicație -- `roa2web/backend/modules/telegram/TELEGRAM_COMMANDS.md` - Documentație comenzi - -### Screenshots Pentru Referință -- BotFather interface (screenshot.jpg în root) - Model pentru layout butoane - ---- - -## 🔧 Troubleshooting - -### Probleme Comune și Soluții - -#### 1. Butoanele nu apar în Telegram -**Cauză:** `reply_markup` nu e trimis sau e None -**Soluție:** Verifică că toate comenzile și callbacks trimit `reply_markup=keyboard` - -#### 2. Callback data invalid -**Cauză:** Format incorect sau depășește limita de 64 bytes -**Soluție:** Verifică format `level:action:id` și limitează lungimea ID-urilor - -#### 3. Butoane nu răspund la click -**Cauză:** `button_callback` nu handle-uiește callback data -**Soluție:** Verifică că toate pattern-urile de callback sunt acoperite în `button_callback()` - -#### 4. Teste failing -**Cauză:** Mock-uri incomplete sau async/await lipsă -**Soluție:** Verifică că toate funcțiile async sunt patched cu `new_callable=AsyncMock` - -#### 5. Meniu nu se actualizează după selecție companie -**Cauză:** Session nu se salvează sau nu se reîmprospătează -**Soluție:** Verifică `await session_manager.save_session()` și `.get_active_company()` - ---- - -## 📝 Notițe pentru Dezvoltare Viitoare - -### Features care pot fi adăugate: -1. **Export Real:** Implementare export Excel/PDF pentru toate view-urile -2. **Paginare:** Pentru liste lungi de clienți/furnizori/facturi -3. **Search Inline:** Buton de search în liste pentru filtrare rapidă -4. **Notificări:** Alerte automate pentru scadențe importante -5. **Grafice:** Imagini grafice pentru evoluție (Chart.js → PNG) -6. **Setări User:** Preferințe utilizator (limbă, format dată, etc.) - -### Optimizări Posibile: -1. **Cache:** Cache API responses pentru reducere latență -2. **Async Parallel:** Fetch multiple endpoint-uri în paralel -3. **Lazy Loading:** Load date doar când user navighează la nivel 2/3 -4. **Batch Updates:** Update multiple mesaje odată pentru performanță - ---- - -**Acest document este ghidul complet pentru implementarea interfeței cu butoane interactive pentru Telegram bot ROA2WEB. Urmează fazele în ordine, testează după fiecare fază, și predă contextul între sesiuni folosind secțiunile "Context Handover".** - -**Succes la implementare! 🚀** diff --git a/docs/telegram/testing/DOCKER_TESTING_GUIDE.md b/docs/telegram/testing/DOCKER_TESTING_GUIDE.md deleted file mode 100644 index d634157..0000000 --- a/docs/telegram/testing/DOCKER_TESTING_GUIDE.md +++ /dev/null @@ -1,502 +0,0 @@ -# 🐳 Docker Testing Guide - ROA2WEB Telegram Bot - -> ⚠️ **DEPRECATED ARCHITECTURE** -> -> This guide references the OLD microservices architecture (separate Telegram container on port 8002). -> The current architecture is an **ultrathin monolith** where the Telegram bot runs as a background -> task within the main backend (port 8000/8001). No separate Docker container needed for Telegram. - -This guide provides instructions for testing the Telegram bot Docker deployment. - -## 📋 Prerequisites - -Before testing Docker deployment: - -- [ ] Docker Engine installed (version 20.10+) -- [ ] Docker Compose installed (version 2.0+) -- [ ] At least 2GB RAM available for containers -- [ ] At least 10GB disk space available - -## 🔍 Pre-Build Verification - -### 1. Check Dockerfile Syntax - -```bash -cd /path/to/roa2web/backend/modules/telegram - -# Verify Dockerfile exists and is valid -cat Dockerfile - -# Check for common issues -grep -n "COPY\|RUN\|ENV" Dockerfile -``` - -**Expected**: -- Multi-stage build with `builder` and `production` stages -- Non-root user `telegrambot` created -- All required dependencies installed -- Tini init system configured -- Health check defined - -### 2. Verify Required Files - -```bash -# Check all required files exist -ls -la app/ -ls -la requirements.txt -ls -la .env.example -ls -la Dockerfile -``` - -**Required files**: -- ✅ `Dockerfile` -- ✅ `requirements.txt` -- ✅ `.env.example` -- ✅ `app/` directory with all modules -- ✅ `.dockerignore` (optional but recommended) - -### 3. Check .dockerignore - -```bash -cat .dockerignore -``` - -**Should exclude**: -- `venv/` -- `__pycache__/` -- `*.pyc` -- `.env` -- `data/*.db` -- `.git/` -- `tests/` - ---- - -## 🏗️ Build Tests - -### Test 1: Build Telegram Bot Image - -```bash -cd /path/to/roa2web/backend/modules/telegram - -# Build the image -docker build -t roa2web/telegram-bot:test --target production . -``` - -**Expected**: -- ✅ Build completes without errors -- ✅ Both stages (builder + production) execute -- ✅ Final image size < 500MB (typically ~300-400MB) -- ✅ No security warnings in output - -**Troubleshooting**: -- If build fails at requirements install → check `requirements.txt` syntax -- If permission errors → ensure Dockerfile uses correct user -- If large image size → verify multi-stage build is working - -### Test 2: Inspect Built Image - -```bash -# Check image size -docker images roa2web/telegram-bot:test - -# Inspect image details -docker inspect roa2web/telegram-bot:test - -# Check layers -docker history roa2web/telegram-bot:test -``` - -**Expected**: -- Image size: 300-450 MB -- Base: `python:3.11-slim` -- User: `telegrambot` (not root) -- Working dir: `/app` -- Health check configured - -### Test 3: Build with Docker Compose - -```bash -cd /path/to/roa2web - -# Build telegram-bot service -docker-compose build roa-telegram-bot -``` - -**Expected**: -- ✅ Service builds successfully -- ✅ Image tagged as `roa2web/telegram-bot:latest` -- ✅ No errors or warnings - ---- - -## 🚀 Runtime Tests - -### Test 4: Run Standalone Container (Without Backend) - -```bash -# Create test .env file -cat > .env.test < -CLAUDE_API_KEY= -BACKEND_URL=http://roa-backend:8000 -SQLITE_DB_PATH=/app/data/telegram_bot.db -INTERNAL_API_PORT=8002 -``` - -### Test 9: Network Connectivity - -```bash -# Test bot can reach backend -docker exec roa-telegram-bot curl -v http://roa-backend:8000/health - -# Test backend can reach bot internal API -docker exec roa-backend curl -v http://roa-telegram-bot:8002/internal/health -``` - -**Expected**: -- ✅ Both services can communicate via `roa-network` -- ✅ DNS resolution works (service names resolve) -- ✅ Health endpoints return 200 OK - -### Test 10: Logs and Monitoring - -```bash -# View real-time logs -docker-compose logs -f roa-telegram-bot - -# View last 100 lines -docker-compose logs --tail=100 roa-telegram-bot - -# Search for errors -docker-compose logs roa-telegram-bot | grep -i error -``` - -**Expected**: -- ✅ Logs are readable and structured -- ✅ No critical errors -- ✅ Log level respects `LOG_LEVEL` env var - ---- - -## 🔒 Security Tests - -### Test 11: User Permissions - -```bash -# Check container is not running as root -docker exec roa-telegram-bot whoami -# Expected: telegrambot - -# Check file permissions -docker exec roa-telegram-bot ls -la /app/ -# Expected: All files owned by telegrambot:telegrambot -``` - -### Test 12: Port Exposure - -```bash -# Check exposed ports -docker port roa-telegram-bot - -# Should only show: -# 8002/tcp -> 0.0.0.0:8002 -``` - -**Expected**: -- ✅ Only internal API port (8002) exposed -- ✅ No unnecessary ports open - -### Test 13: Volume Mounts - -```bash -# Check volumes -docker volume inspect roa2web_telegram-bot-data - -# Check mount point -docker inspect roa-telegram-bot | grep -A 10 Mounts -``` - -**Expected**: -- ✅ Only `/app/data` is mounted -- ✅ Volume is named `telegram-bot-data` -- ✅ No sensitive files mounted - ---- - -## 🧪 Integration Tests - -### Test 14: Full Stack Integration - -```bash -# Start all services -cd /path/to/roa2web -docker-compose up -d - -# Wait for all services to be healthy -docker-compose ps - -# Test complete flow: -# 1. Backend generates auth code -# 2. Bot verifies code -# 3. User links account -# 4. Bot queries backend API -``` - -**Test Steps**: - -1. **Generate Auth Code via Backend**: -```bash -curl -X POST http://localhost:8000/api/telegram/auth/generate-code \ - -H "Authorization: Bearer " \ - -H "Content-Type: application/json" \ - -d '{"telegram_user_id": 123456}' -``` - -2. **Verify Code in Bot Database**: -```bash -docker exec roa-telegram-bot sqlite3 /app/data/telegram_bot.db \ - "SELECT * FROM telegram_auth_codes WHERE telegram_user_id = 123456;" -``` - -3. **Link via Telegram Bot**: -- Send code to bot via Telegram app -- Verify linking succeeds - -4. **Query Dashboard**: -- Ask bot: "Show dashboard for company 1" -- Verify data is retrieved from backend - ---- - -## 🛑 Cleanup - -### Remove Test Containers - -```bash -# Stop and remove containers -docker-compose down - -# Remove volumes (WARNING: deletes data) -docker-compose down -v - -# Remove images -docker rmi roa2web/telegram-bot:test -docker rmi roa2web/telegram-bot:latest -``` - -### Clean Build Cache - -```bash -# Remove build cache -docker builder prune -a - -# Remove unused images -docker image prune -a -``` - ---- - -## 📊 Test Results Checklist - -| Test ID | Description | Status | Notes | -|---------|-------------|--------|-------| -| 1 | Build telegram-bot image | ⬜ | | -| 2 | Inspect image | ⬜ | | -| 3 | Build with docker-compose | ⬜ | | -| 4 | Run standalone container | ⬜ | | -| 5 | Run with docker-compose | ⬜ | | -| 6 | Health check | ⬜ | | -| 7 | Database persistence | ⬜ | | -| 8 | Environment variables | ⬜ | | -| 9 | Network connectivity | ⬜ | | -| 10 | Logs and monitoring | ⬜ | | -| 11 | User permissions | ⬜ | | -| 12 | Port exposure | ⬜ | | -| 13 | Volume mounts | ⬜ | | -| 14 | Full stack integration | ⬜ | | - -**Overall Result**: ⬜ PASS ⬜ FAIL - ---- - -## 🐛 Common Issues & Solutions - -### Issue 1: Build Fails - "requirements.txt not found" -**Solution**: Ensure you're in the correct directory (`telegram-bot/`) when building - -### Issue 2: Permission Denied Errors -**Solution**: Check Dockerfile uses correct user and permissions are set with `chown` - -### Issue 3: Health Check Fails -**Solution**: -- Check internal API is starting on port 8002 -- Verify httpx is installed in requirements.txt -- Check logs: `docker logs roa-telegram-bot` - -### Issue 4: Can't Connect to Backend -**Solution**: -- Ensure both containers are on `roa-network` -- Check backend is healthy before starting bot -- Use service name `roa-backend` not `localhost` - -### Issue 5: Database Not Persisting -**Solution**: -- Verify volume is mounted: `docker inspect roa-telegram-bot` -- Check volume exists: `docker volume ls | grep telegram-bot-data` -- Ensure `/app/data` has write permissions - ---- - -## ✅ Success Criteria - -For Docker deployment to be considered successful: - -- ✅ Image builds without errors -- ✅ Container starts and runs stably -- ✅ Health checks pass -- ✅ Bot connects to Telegram API -- ✅ Bot connects to backend API -- ✅ Database persists across restarts -- ✅ No security warnings or vulnerabilities -- ✅ Logs are clean (no critical errors) -- ✅ All network connectivity works -- ✅ Full stack integration succeeds - ---- - -**Last Updated**: 2025-10-21 diff --git a/docs/telegram/testing/MANUAL_TESTING_CHECKLIST.md b/docs/telegram/testing/MANUAL_TESTING_CHECKLIST.md index 574cd01..1ae6a16 100644 --- a/docs/telegram/testing/MANUAL_TESTING_CHECKLIST.md +++ b/docs/telegram/testing/MANUAL_TESTING_CHECKLIST.md @@ -6,29 +6,32 @@ This checklist guides you through manual testing of the Telegram bot functionali Before starting manual tests: -- [ ] Backend API is running (`http://localhost:8001`) -- [ ] SSH tunnel to Oracle DB is active -- [ ] Telegram bot is running (`python -m app.main`) -- [ ] TELEGRAM_BOT_TOKEN is configured in `.env` -- [ ] CLAUDE_API_KEY is configured in `.env` (if using real Claude SDK) -- [ ] SQLite database is initialized (`data/telegram_bot.db` exists) +- [ ] Backend API is running (`http://localhost:8000` or `8001`) +- [ ] SSH tunnel to Oracle DB is active (Linux dev only) +- [ ] `MODULE_TELEGRAM_ENABLED=true` in `.env` +- [ ] `TELEGRAM_BOT_TOKEN` is configured in `.env` +- [ ] SQLite database is initialized (auto-created on first run) + +> **Note:** In the **ultrathin monolith** architecture, the Telegram bot runs as a background task +> within the unified backend. There's no separate bot process to start. ## 📱 Test Environment Setup ### Start Services ```bash -# Terminal 1: Start backend API (from roa2web/) -cd backend -source venv/bin/activate -uvicorn app.main:app --reload --port 8001 +# From project root - starts everything (SSH tunnel + backend + frontend) +./start-prod.sh -# Terminal 2: Start Telegram bot -cd backend/modules/telegram -source venv/bin/activate -python -m app.main +# Or for testing mode: +./start-test.sh + +# Check status +./status.sh ``` +The bot starts automatically with the backend when `MODULE_TELEGRAM_ENABLED=true`. + ### Test User Setup - [ ] Create test Oracle user account in Oracle database (if needed) diff --git a/public/web.config b/public/web.config index c931172..57073f6 100644 --- a/public/web.config +++ b/public/web.config @@ -4,7 +4,7 @@ ROA2WEB - IIS Sub-Application Configuration ==================================================================== - ⚠️ CRITICAL - For IIS Sub-Application Deployment! ⚠️ + CRITICAL - For IIS Sub-Application Deployment! This web.config is for when IIS is configured as SUB-APPLICATION: - IIS Application Path: /roa2web @@ -19,11 +19,11 @@ **Production Architecture (2-Tier IIS)**: Public Server (10.0.20.122 - roa2web.romfast.ro) - └─ Proxies ALL to → https://10.0.20.36/{REQUEST_PATH} + - Proxies ALL to -> https://10.0.20.36/{REQUEST_PATH} Internal Server (10.0.20.36) - └─ IIS Sub-App: /roa2web → Physical: C:\inetpub\wwwroot\roa2web\frontend - └─ This web.config proxies /api/* to localhost:8000 + - IIS Sub-App: /roa2web -> Physical: C:\inetpub\wwwroot\roa2web\frontend + - This web.config proxies /api/* to localhost:8000 See: deployment/windows/docs/TWO-TIER-IIS-DEPLOYMENT.md @@ -56,6 +56,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + @@ -68,12 +92,5 @@ - - - - - - - diff --git a/docs/data-entry/Lidl papetarie 604 fara TVA. nu are cod fiscal.pdf b/tests/fixtures/ocr-samples/Lidl papetarie 604 fara TVA. nu are cod fiscal.pdf similarity index 100% rename from docs/data-entry/Lidl papetarie 604 fara TVA. nu are cod fiscal.pdf rename to tests/fixtures/ocr-samples/Lidl papetarie 604 fara TVA. nu are cod fiscal.pdf diff --git a/docs/data-entry/Lidl personal 4 ianuarie .pdf b/tests/fixtures/ocr-samples/Lidl personal 4 ianuarie .pdf similarity index 100% rename from docs/data-entry/Lidl personal 4 ianuarie .pdf rename to tests/fixtures/ocr-samples/Lidl personal 4 ianuarie .pdf diff --git a/docs/data-entry/abonament kineterra.pdf b/tests/fixtures/ocr-samples/abonament kineterra.pdf similarity index 100% rename from docs/data-entry/abonament kineterra.pdf rename to tests/fixtures/ocr-samples/abonament kineterra.pdf diff --git a/docs/data-entry/benzina 07 aug. 2024.pdf b/tests/fixtures/ocr-samples/benzina 07 aug. 2024.pdf similarity index 100% rename from docs/data-entry/benzina 07 aug. 2024.pdf rename to tests/fixtures/ocr-samples/benzina 07 aug. 2024.pdf diff --git a/docs/data-entry/benzina 10 mai 2025.pdf b/tests/fixtures/ocr-samples/benzina 10 mai 2025.pdf similarity index 100% rename from docs/data-entry/benzina 10 mai 2025.pdf rename to tests/fixtures/ocr-samples/benzina 10 mai 2025.pdf diff --git a/docs/data-entry/benzina 13 iulie.pdf b/tests/fixtures/ocr-samples/benzina 13 iulie.pdf similarity index 100% rename from docs/data-entry/benzina 13 iulie.pdf rename to tests/fixtures/ocr-samples/benzina 13 iulie.pdf diff --git a/docs/data-entry/benzina 13 septembrie .pdf b/tests/fixtures/ocr-samples/benzina 13 septembrie .pdf similarity index 100% rename from docs/data-entry/benzina 13 septembrie .pdf rename to tests/fixtures/ocr-samples/benzina 13 septembrie .pdf diff --git a/docs/data-entry/benzina 14 august.pdf b/tests/fixtures/ocr-samples/benzina 14 august.pdf similarity index 100% rename from docs/data-entry/benzina 14 august.pdf rename to tests/fixtures/ocr-samples/benzina 14 august.pdf diff --git a/docs/data-entry/benzina 20 dec.pdf b/tests/fixtures/ocr-samples/benzina 20 dec.pdf similarity index 100% rename from docs/data-entry/benzina 20 dec.pdf rename to tests/fixtures/ocr-samples/benzina 20 dec.pdf diff --git a/docs/data-entry/benzina 27 octombrie .pdf b/tests/fixtures/ocr-samples/benzina 27 octombrie .pdf similarity index 100% rename from docs/data-entry/benzina 27 octombrie .pdf rename to tests/fixtures/ocr-samples/benzina 27 octombrie .pdf diff --git a/docs/data-entry/best print stampila .pdf b/tests/fixtures/ocr-samples/best print stampila .pdf similarity index 100% rename from docs/data-entry/best print stampila .pdf rename to tests/fixtures/ocr-samples/best print stampila .pdf diff --git a/docs/data-entry/bon fiscal Dedeman - efactura.pdf b/tests/fixtures/ocr-samples/bon fiscal Dedeman - efactura.pdf similarity index 100% rename from docs/data-entry/bon fiscal Dedeman - efactura.pdf rename to tests/fixtures/ocr-samples/bon fiscal Dedeman - efactura.pdf diff --git a/docs/data-entry/brick consumabil 604 50% deductibil 22 dec.pdf b/tests/fixtures/ocr-samples/brick consumabil 604 50% deductibil 22 dec.pdf similarity index 100% rename from docs/data-entry/brick consumabil 604 50% deductibil 22 dec.pdf rename to tests/fixtures/ocr-samples/brick consumabil 604 50% deductibil 22 dec.pdf diff --git a/docs/data-entry/brick consumabile 604 22 dec.pdf b/tests/fixtures/ocr-samples/brick consumabile 604 22 dec.pdf similarity index 100% rename from docs/data-entry/brick consumabile 604 22 dec.pdf rename to tests/fixtures/ocr-samples/brick consumabile 604 22 dec.pdf diff --git a/docs/data-entry/brick igiena 1 sept.pdf b/tests/fixtures/ocr-samples/brick igiena 1 sept.pdf similarity index 100% rename from docs/data-entry/brick igiena 1 sept.pdf rename to tests/fixtures/ocr-samples/brick igiena 1 sept.pdf diff --git a/docs/data-entry/brick igiena 604.pdf b/tests/fixtures/ocr-samples/brick igiena 604.pdf similarity index 100% rename from docs/data-entry/brick igiena 604.pdf rename to tests/fixtures/ocr-samples/brick igiena 604.pdf diff --git a/docs/data-entry/brick igiena 8 octombrie 98.95 lei card.pdf b/tests/fixtures/ocr-samples/brick igiena 8 octombrie 98.95 lei card.pdf similarity index 100% rename from docs/data-entry/brick igiena 8 octombrie 98.95 lei card.pdf rename to tests/fixtures/ocr-samples/brick igiena 8 octombrie 98.95 lei card.pdf diff --git a/docs/data-entry/brick igiena, electrice consumabile 604.pdf b/tests/fixtures/ocr-samples/brick igiena, electrice consumabile 604.pdf similarity index 100% rename from docs/data-entry/brick igiena, electrice consumabile 604.pdf rename to tests/fixtures/ocr-samples/brick igiena, electrice consumabile 604.pdf diff --git a/docs/data-entry/electrobering igiena iulie 604.pdf b/tests/fixtures/ocr-samples/electrobering igiena iulie 604.pdf similarity index 100% rename from docs/data-entry/electrobering igiena iulie 604.pdf rename to tests/fixtures/ocr-samples/electrobering igiena iulie 604.pdf diff --git a/docs/data-entry/electrobering telecomanda.pdf b/tests/fixtures/ocr-samples/electrobering telecomanda.pdf similarity index 100% rename from docs/data-entry/electrobering telecomanda.pdf rename to tests/fixtures/ocr-samples/electrobering telecomanda.pdf diff --git a/docs/data-entry/factura 70005116259 20.09.2025 Dedeman.pdf b/tests/fixtures/ocr-samples/factura 70005116259 20.09.2025 Dedeman.pdf similarity index 100% rename from docs/data-entry/factura 70005116259 20.09.2025 Dedeman.pdf rename to tests/fixtures/ocr-samples/factura 70005116259 20.09.2025 Dedeman.pdf diff --git a/docs/data-entry/gama ink refill toner imprimanta 17 sept 2024.pdf b/tests/fixtures/ocr-samples/gama ink refill toner imprimanta 17 sept 2024.pdf similarity index 100% rename from docs/data-entry/gama ink refill toner imprimanta 17 sept 2024.pdf rename to tests/fixtures/ocr-samples/gama ink refill toner imprimanta 17 sept 2024.pdf diff --git a/docs/data-entry/igiena 11 octombrie .pdf b/tests/fixtures/ocr-samples/igiena 11 octombrie .pdf similarity index 100% rename from docs/data-entry/igiena 11 octombrie .pdf rename to tests/fixtures/ocr-samples/igiena 11 octombrie .pdf diff --git a/docs/data-entry/igiena 14 decembrie five-holding.pdf b/tests/fixtures/ocr-samples/igiena 14 decembrie five-holding.pdf similarity index 100% rename from docs/data-entry/igiena 14 decembrie five-holding.pdf rename to tests/fixtures/ocr-samples/igiena 14 decembrie five-holding.pdf diff --git a/docs/data-entry/kineterra abonament terapie august 2024.pdf b/tests/fixtures/ocr-samples/kineterra abonament terapie august 2024.pdf similarity index 100% rename from docs/data-entry/kineterra abonament terapie august 2024.pdf rename to tests/fixtures/ocr-samples/kineterra abonament terapie august 2024.pdf diff --git a/docs/data-entry/kineterra fizioterapie 9 sept.pdf b/tests/fixtures/ocr-samples/kineterra fizioterapie 9 sept.pdf similarity index 100% rename from docs/data-entry/kineterra fizioterapie 9 sept.pdf rename to tests/fixtures/ocr-samples/kineterra fizioterapie 9 sept.pdf diff --git a/docs/data-entry/rechizite 12 decembrie pictus.pdf b/tests/fixtures/ocr-samples/rechizite 12 decembrie pictus.pdf similarity index 100% rename from docs/data-entry/rechizite 12 decembrie pictus.pdf rename to tests/fixtures/ocr-samples/rechizite 12 decembrie pictus.pdf diff --git a/docs/data-entry/stepout-bon1-5.jpg b/tests/fixtures/ocr-samples/stepout-bon1-5.jpg similarity index 100% rename from docs/data-entry/stepout-bon1-5.jpg rename to tests/fixtures/ocr-samples/stepout-bon1-5.jpg diff --git a/docs/data-entry/stepout-bon2-5.jpg b/tests/fixtures/ocr-samples/stepout-bon2-5.jpg similarity index 100% rename from docs/data-entry/stepout-bon2-5.jpg rename to tests/fixtures/ocr-samples/stepout-bon2-5.jpg diff --git a/docs/data-entry/unlimited duplicat chei 23 mai.pdf b/tests/fixtures/ocr-samples/unlimited duplicat chei 23 mai.pdf similarity index 100% rename from docs/data-entry/unlimited duplicat chei 23 mai.pdf rename to tests/fixtures/ocr-samples/unlimited duplicat chei 23 mai.pdf diff --git a/tests/ocr-validation/README.md b/tests/ocr-validation/README.md new file mode 100644 index 0000000..7a5e2b8 --- /dev/null +++ b/tests/ocr-validation/README.md @@ -0,0 +1,158 @@ +# OCR Validation Tests + +Teste pentru validarea acurateții extragerii OCR din bonuri fiscale. + +--- + +## Prerequisites + +1. **Backend-ul trebuie să ruleze** pe `http://localhost:8000` +2. **Modulul Data Entry activat** în `.env`: `MODULE_DATA_ENTRY_ENABLED=true` +3. **JWT_SECRET_KEY** setat (sau folosește default-ul de test) + +```bash +# Pornește backend-ul +cd /workspace/roa2web +./start-prod.sh +# sau +./start-test.sh +``` + +--- + +## Test Files + +| Fișier | Scop | +|--------|------| +| `expected_receipts.json` | Expected values pentru fiecare bon (ground truth) | +| `ocr-direct-validation.py` | Test individual cu comparare detaliată | +| `test_receipts_sequential.py` | Rulează toate bonurile secvențial | +| `test_receipts_parallel.py` | Rulează toate bonurile în paralel (performance test) | +| `test_receipts_parallel_windows.py` | Versiune Windows cu memory tracking | +| `get_raw_ocr_text.py` | Debug tool - afișează raw OCR text | + +**Fixtures:** `tests/fixtures/ocr-samples/` - 30 PDF-uri de bonuri fiscale + +--- + +## Cum să rulezi testele + +### 1. Test Individual (Recomandat pentru debug) + +```bash +cd /workspace/roa2web + +# Test toate bonurile cu engine doctr_plus +python tests/ocr-validation/ocr-direct-validation.py + +# Test cu engine specific +python tests/ocr-validation/ocr-direct-validation.py --engine doctr_plus +python tests/ocr-validation/ocr-direct-validation.py --engine tesseract + +# Test doar un bon specific +python tests/ocr-validation/ocr-direct-validation.py --receipt receipt_01 + +# Include și bonuri multi-page +python tests/ocr-validation/ocr-direct-validation.py --include-multipage +``` + +### 2. Test Secvențial (Toate bonurile, unul câte unul) + +```bash +python tests/ocr-validation/test_receipts_sequential.py +``` + +Output: +``` +Processing: abonament kineterra.pdf + ✓ Total: MATCH (1900.0 = 1900.0) + ✓ Date: MATCH (2025-11-10) + ✗ CUI: MISMATCH (expected: 31180432, got: 3118043) +``` + +### 3. Test Paralel (Performance benchmark) + +```bash +python tests/ocr-validation/test_receipts_parallel.py +``` + +Output: +``` +PARALLEL TEST: 26 receipts +Phase 1: Submitting all jobs... +Submitted 26 jobs in 2.3s +Phase 2: Waiting for results... + OK: abonament kineterra.pdf 12.3s conf=95% + OK: benzina 14 august.pdf 8.7s conf=92% +TOTAL TIME: 45.2s +``` + +### 4. Debug Raw OCR Text + +```bash +# Vezi textul raw extras de OCR +python tests/ocr-validation/get_raw_ocr_text.py + +# Sau pentru un fișier specific +python tests/ocr-validation/get_raw_ocr_text.py tests/fixtures/ocr-samples/benzina\ 14\ august.pdf +``` + +--- + +## Expected Receipts Format + +`expected_receipts.json` conține ground truth pentru fiecare bon: + +```json +{ + "receipts": [ + { + "id": "receipt_01", + "filename": "abonament kineterra.pdf", + "furnizor": "KINETERRA CONCEPT SRL", + "cui_furnizor": "31180432", + "total": 1900.0, + "tva_details": [], + "total_tva": 0.0, + "data_bon": "2025-11-10", + "notes": "Neplatitor TVA - abonament terapie" + } + ] +} +``` + +--- + +## Adaugă bonuri noi pentru testare + +1. Pune PDF-ul în `tests/fixtures/ocr-samples/` +2. Adaugă entry în `expected_receipts.json` cu valorile corecte +3. Rulează testul: + ```bash + python tests/ocr-validation/ocr-direct-validation.py --receipt receipt_XX + ``` + +--- + +## Troubleshooting + +### "Connection refused" sau "Failed to connect" +- Backend-ul nu rulează. Pornește cu `./start-prod.sh` + +### "401 Unauthorized" +- JWT token invalid. Verifică `JWT_SECRET_KEY` în `.env` + +### "File not found" +- Verifică că PDF-urile sunt în `tests/fixtures/ocr-samples/` + +### Rezultate incorecte +- Folosește `get_raw_ocr_text.py` pentru a vedea ce text extrage OCR +- Verifică dacă bonul e lizibil și de calitate bună + +--- + +## Performance Notes + +- **doctr_plus** engine: ~8-15 secunde per bon (GPU accelerated) +- **tesseract** engine: ~3-5 secunde per bon (CPU only) +- Testul paralel poate procesa ~26 bonuri în ~45 secunde (vs ~5 minute secvențial) diff --git a/tests/ocr-validation/get_raw_ocr_text.py b/tests/ocr-validation/get_raw_ocr_text.py index 3aafc3a..48c5968 100644 --- a/tests/ocr-validation/get_raw_ocr_text.py +++ b/tests/ocr-validation/get_raw_ocr_text.py @@ -113,10 +113,11 @@ if __name__ == "__main__": print(f"Using JWT token for authentication") if len(sys.argv) < 2: - # Default: process the two receipts user wants to see + # Default: process sample receipts from fixtures + fixtures_dir = Path(__file__).parent.parent / "fixtures" / "ocr-samples" receipts = [ - "/mnt/e/proiecte/ab-worktrees/doctr-ocr-metrics/docs/data-entry/brick igiena 1 sept.pdf", - "/mnt/e/proiecte/ab-worktrees/doctr-ocr-metrics/docs/data-entry/brick igiena, electrice consumabile 604.pdf" + str(fixtures_dir / "brick igiena 1 sept.pdf"), + str(fixtures_dir / "brick igiena, electrice consumabile 604.pdf") ] else: receipts = sys.argv[1:] diff --git a/tests/ocr-validation/ocr-direct-validation.py b/tests/ocr-validation/ocr-direct-validation.py index 1b6e95d..7bf8372 100644 --- a/tests/ocr-validation/ocr-direct-validation.py +++ b/tests/ocr-validation/ocr-direct-validation.py @@ -193,7 +193,7 @@ def main(): # Paths script_dir = Path(__file__).parent expected_path = script_dir / 'expected_receipts.json' - pdf_base_path = script_dir.parent.parent / 'docs' / 'data-entry' + pdf_base_path = script_dir.parent.parent / 'tests' / 'fixtures' / 'ocr-samples' # JWT secret from environment or default jwt_secret = os.getenv('JWT_SECRET_KEY', 'generate_with_secrets_token_urlsafe_32') diff --git a/tests/ocr-validation/test_receipts_parallel.py b/tests/ocr-validation/test_receipts_parallel.py index 82dce2b..a0ed17a 100644 --- a/tests/ocr-validation/test_receipts_parallel.py +++ b/tests/ocr-validation/test_receipts_parallel.py @@ -10,8 +10,13 @@ from datetime import datetime, timedelta from jose import jwt API_BASE = "http://localhost:8000" -PDF_FOLDER = "/mnt/e/proiecte/ab-worktrees/doctr-ocr-metrics/docs/data-entry" -EXPECTED_FILE = "/mnt/e/proiecte/ab-worktrees/doctr-ocr-metrics/tests/ocr-validation/expected_receipts.json" + +# Paths - relative to project root +from pathlib import Path +SCRIPT_DIR = Path(__file__).parent +PROJECT_ROOT = SCRIPT_DIR.parent.parent +PDF_FOLDER = str(PROJECT_ROOT / "tests" / "fixtures" / "ocr-samples") +EXPECTED_FILE = str(SCRIPT_DIR / "expected_receipts.json") def get_jwt_token(): secret_key = os.getenv('JWT_SECRET_KEY', 'generate_with_secrets_token_urlsafe_32') diff --git a/tests/ocr-validation/test_receipts_parallel_windows.py b/tests/ocr-validation/test_receipts_parallel_windows.py index 6d5f601..8f27e96 100644 --- a/tests/ocr-validation/test_receipts_parallel_windows.py +++ b/tests/ocr-validation/test_receipts_parallel_windows.py @@ -27,7 +27,7 @@ except ImportError: # Paths - relative to backend directory SCRIPT_DIR = Path(__file__).parent BACKEND_DIR = SCRIPT_DIR.parent.parent / "backend" -PDF_FOLDER = SCRIPT_DIR.parent.parent / "docs" / "data-entry" +PDF_FOLDER = SCRIPT_DIR.parent.parent / "tests" / "fixtures" / "ocr-samples" EXPECTED_FILE = SCRIPT_DIR / "expected_receipts.json" diff --git a/tests/ocr-validation/test_receipts_sequential.py b/tests/ocr-validation/test_receipts_sequential.py index 9402c11..265a38e 100644 --- a/tests/ocr-validation/test_receipts_sequential.py +++ b/tests/ocr-validation/test_receipts_sequential.py @@ -10,8 +10,13 @@ from datetime import datetime, timedelta from jose import jwt API_BASE = "http://localhost:8000" -PDF_FOLDER = "/mnt/e/proiecte/ab-worktrees/doctr-ocr-metrics/docs/data-entry" -EXPECTED_FILE = "/mnt/e/proiecte/ab-worktrees/doctr-ocr-metrics/tests/ocr-validation/expected_receipts.json" + +# Paths - relative to project root +from pathlib import Path +SCRIPT_DIR = Path(__file__).parent +PROJECT_ROOT = SCRIPT_DIR.parent.parent +PDF_FOLDER = str(PROJECT_ROOT / "tests" / "fixtures" / "ocr-samples") +EXPECTED_FILE = str(SCRIPT_DIR / "expected_receipts.json") def get_jwt_token(): """Create a test JWT token for API authentication."""