Consolidate 3 separate applications (reports-app, data-entry-app, telegram-bot) into a unified
architecture with single backend and frontend:
Backend Changes:
- Unified FastAPI backend at backend/ with modular structure
- Modules: reports, data_entry, telegram in backend/modules/
- Centralized config.py and main.py with all routers registered
- Single worker mode (--workers 1) for Telegram bot compatibility
- Shared Oracle connection pool and JWT authentication
- Unified requirements.txt and environment configuration
Frontend Changes:
- Single Vue.js SPA with module-based routing
- Unified frontend at src/ with modules in src/modules/{reports,data-entry}/
- Shared components and stores in src/shared/
- Error boundaries for module isolation
- Dual API proxy in Vite for module communication
Infrastructure:
- New unified startup scripts: start-prod.sh, start-test.sh, start-backend.sh
- Environment templates: .env.dev.example, .env.test.example, .env.prod.example
- Updated deployment scripts for Windows IIS
- Simplified SSH tunnel management
Documentation:
- Comprehensive CLAUDE.md with architecture overview
- Module-specific docs in docs/{data-entry,telegram}/
- Architecture decision records in docs/ARCHITECTURE-DECISIONS.md
- Deployment guides consolidated in deployment/windows/docs/
This migration reduces complexity, improves maintainability, and enables easier
deployment while maintaining all existing functionality.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
24 KiB
ROA2WEB Ultrathin Monolith Architecture
Version: 1.0.0 Last Updated: 2025-12-29 Status: ✅ Active
🎯 Overview
ROA2WEB uses an ultrathin monolith architecture - a single unified backend and frontend application with modular organization. This architecture provides the simplicity of a monolith with the organizational benefits of microservices.
Key Characteristics
- Single Backend Process: One FastAPI application serving all modules
- Single Frontend Build: One Vue.js SPA with lazy-loaded modules
- Modular Organization: Business logic separated into distinct modules
- Shared Resources: Database pools, auth, cache shared across modules
- Independent Modules: Each module can be developed and tested independently
🏗️ Architecture Diagram
┌─────────────────────────────────────────────────────────────────────────────┐
│ 🌐 CLIENT BROWSER │
└────────────────────────────────┬────────────────────────────────────────────┘
│ HTTP/HTTPS Requests
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ 📦 UNIFIED VUE.JS FRONTEND │
│ Single-page application (SPA) served from /dist │
│ Port: 3000 (dev) / 80,443 (production) │
│ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ Frontend Modules (Lazy Loaded) │ │
│ │ │ │
│ │ • src/modules/reports/ - Reports module UI │ │
│ │ • src/modules/data-entry/ - Data entry module UI │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ Shared Frontend Components │ │
│ │ │ │
│ │ • src/shared/components/ - Reusable Vue components │ │
│ │ • src/shared/stores/ - Pinia stores │ │
│ │ • src/assets/css/ - Global CSS system │ │
│ │ • shared/frontend/ - Login, auth components │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
└────────────────────────────────┬────────────────────────────────────────────┘
│ API Calls (Axios)
│ Authorization: Bearer <JWT>
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ 🚀 UNIFIED FASTAPI BACKEND │
│ Single Python process running all modules │
│ Port: 8000 (dev) / 8001 (production) │
│ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ 🛡️ Global Middleware Layer │ │
│ │ │ │
│ │ • CORSMiddleware - CORS handling │ │
│ │ • AuthenticationMiddleware - JWT validation & user injection │ │
│ │ • Rate Limiting - 5 req/5 min per IP │ │
│ │ • Security Headers - XSS, CSP, Frame protection │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ 📊 Backend Modules (backend/modules/) │ │
│ │ │ │
│ │ reports/ │ │
│ │ ├── routers/ - API endpoints │ │
│ │ ├── services/ - Business logic with caching │ │
│ │ ├── models/ - Pydantic models │ │
│ │ └── cache/ - L1+L2 cache implementation │ │
│ │ │ │
│ │ data_entry/ │ │
│ │ ├── routers/ - API endpoints │ │
│ │ ├── services/ - Business logic │ │
│ │ ├── models/ - SQLModel ORM models │ │
│ │ └── db/ - SQLite database │ │
│ │ │ │
│ │ telegram/ │ │
│ │ ├── bot/ - Telegram bot handlers │ │
│ │ ├── api/ - Internal API for bot │ │
│ │ └── db/ - Bot session management │ │
│ │ │ │
│ │ data/ │ │
│ │ └── telegram_bot.db - Telegram bot SQLite database │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ 🔧 Shared Backend Components (shared/) │ │
│ │ │ │
│ │ database/ │ │
│ │ └── oracle_pool.py - Singleton Oracle connection pool │ │
│ │ │ │
│ │ auth/ │ │
│ │ ├── middleware.py - JWT authentication middleware │ │
│ │ ├── jwt_handler.py - Token creation/validation │ │
│ │ └── models.py - Auth data models │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
└────────────────────────────────┬────────────────────────────────────────────┘
│ Database Queries
│ (Oracle + SQLite)
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ 🗄️ DATABASE LAYER │
│ │
│ ┌─────────────────────────┐ ┌─────────────────────────┐ │
│ │ Oracle Database │ │ SQLite Databases │ │
│ │ (via SSH Tunnel) │ │ (Local Files) │ │
│ │ │ │ │ │
│ │ • CONTAFIN_ORACLE │ │ • data_entry.db │ │
│ │ • Financial schemas │ │ • telegram_bot.db │ │
│ │ • User management │ │ • cache.db │ │
│ │ │ │ │ │
│ │ Port: 1521 (remote) │ │ Path: backend/modules/ │ │
│ │ 1526 (tunnel) │ │ /data/ │ │
│ │ │ │ │ │
│ └─────────────────────────┘ └─────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────────┘
📁 Directory Structure
Backend Structure
backend/
├── main.py # FastAPI app entry point
├── config.py # Centralized configuration
├── .env # Environment variables
├── .env.dev # Development environment
├── .env.test # Test environment
├── .env.prod # Production environment
│
└── modules/ # Business logic modules
├── __init__.py
│
├── reports/ # Reports module (Oracle read-only)
│ ├── __init__.py
│ ├── routers/ # API endpoints
│ │ ├── dashboard.py
│ │ ├── invoices.py
│ │ └── treasury.py
│ ├── services/ # Business logic
│ │ ├── dashboard_service.py
│ │ └── invoice_service.py
│ ├── models/ # Pydantic models
│ ├── schemas/ # Response schemas
│ └── cache/ # Cache implementation
│ ├── decorators.py # @cached decorator
│ └── manager.py # L1+L2 cache manager
│
├── data_entry/ # Data entry module (SQLite + workflow)
│ ├── __init__.py
│ ├── routers/ # API endpoints
│ │ ├── receipts.py
│ │ └── entries.py
│ ├── services/ # Business logic
│ ├── models/ # SQLModel ORM models
│ │ ├── receipt.py
│ │ ├── attachment.py
│ │ └── accounting_entry.py
│ ├── db/ # Database
│ │ ├── session.py # SQLite session
│ │ └── migrations/ # Alembic migrations
│ └── utils/ # Helper functions
│
├── telegram/ # Telegram bot module
│ ├── __init__.py
│ ├── bot/ # Bot implementation
│ │ ├── handlers.py # Command handlers
│ │ ├── helpers.py # Helper functions
│ │ └── formatters.py # Message formatters
│ ├── api/ # Internal API
│ │ └── auth.py # Auth code management
│ ├── db/ # Bot database
│ │ └── session.py # Session management
│ └── bot_main.py # Bot entry point
│
└── data/ # Shared data
└── telegram_bot.db # Telegram bot database
Frontend Structure
src/
├── main.js # App entry point
├── App.vue # Root component
│
├── modules/ # Feature modules
│ ├── reports/ # Reports module
│ │ ├── views/ # Page components
│ │ │ ├── DashboardView.vue
│ │ │ ├── InvoicesView.vue
│ │ │ └── TreasuryView.vue
│ │ ├── components/ # Module-specific components
│ │ ├── stores/ # Module-specific Pinia stores
│ │ │ ├── dashboard.js
│ │ │ └── invoices.js
│ │ ├── services/ # API client
│ │ │ └── api.js
│ │ └── utils/ # Helpers
│ │
│ └── data-entry/ # Data entry module
│ ├── views/ # Page components
│ │ ├── ReceiptsView.vue
│ │ └── EntriesView.vue
│ ├── components/ # Module-specific components
│ ├── stores/ # Module-specific Pinia stores
│ │ └── receipts.js
│ └── services/ # API client
│ └── api.js
│
├── shared/ # Shared components
│ ├── components/ # Reusable Vue components
│ │ ├── ErrorBoundary.vue
│ │ ├── CompanySelector.vue
│ │ └── PeriodSelector.vue
│ └── stores/ # Shared Pinia stores
│ ├── auth.js
│ ├── companies.js
│ └── accountingPeriod.js
│
├── router/ # Vue Router
│ ├── index.js # Main router
│ ├── reports.js # Reports routes
│ └── data-entry.js # Data entry routes
│
├── assets/ # Global assets
│ ├── css/ # Global CSS system
│ │ ├── core/ # Design tokens
│ │ ├── components/ # Component styles
│ │ ├── patterns/ # UI patterns
│ │ ├── layout/ # Layout styles
│ │ ├── utilities/ # Utility classes
│ │ └── vendor/ # PrimeVue overrides
│ └── images/ # Images
│
└── views/ # Global views
└── LoginView.vue # Login page
🔄 Request Flow
1. User Authentication Flow
User Login Request
↓
Frontend (LoginView.vue)
↓ POST /api/auth/login
Backend (main.py)
↓
AuthenticationMiddleware (excluded for /login)
↓
Auth Router (/api/auth/login)
↓
Oracle Database (pack_drepturi.verificautilizator)
↓
JWT Token Generation
↓
Response with access_token + refresh_token
↓
Frontend stores token in localStorage
↓
Subsequent requests include: Authorization: Bearer <token>
2. Reports Data Flow (with Cache)
User Request (Dashboard data)
↓
Frontend (DashboardView.vue)
↓ GET /api/reports/dashboard
Backend Middleware
├─ CORS check ✓
├─ JWT validation ✓
└─ User injection into request.state
↓
Reports Router (/api/reports/dashboard)
↓
DashboardService.get_dashboard_data()
↓
@cached decorator checks cache
├─ L1 Cache (Memory) HIT? → Return cached data
├─ L2 Cache (SQLite) HIT? → Store in L1, return data
└─ MISS → Query Oracle
↓
Oracle Database (via connection pool)
↓
Process and cache result (L1 + L2)
↓
Return data
↓
Response with cache metadata headers
↓
Frontend updates Pinia store
↓
Vue component reactively updates UI
3. Data Entry Flow (with Workflow)
User Creates Receipt
↓
Frontend (ReceiptsView.vue)
↓ POST /api/data-entry/receipts
Backend Middleware (JWT validation)
↓
Data Entry Router
↓
ReceiptService.create_receipt()
↓
SQLModel ORM
↓
SQLite Database (data_entry.db)
├─ Insert Receipt (status: DRAFT)
├─ Insert Attachments
└─ Generate AccountingEntries
↓
Response with receipt ID
↓
Frontend updates Pinia store
↓
UI shows new receipt in DRAFT state
↓
User submits for approval
↓ POST /api/data-entry/receipts/{id}/submit
Backend updates status: DRAFT → PENDING
↓
Workflow continues (PENDING → APPROVED/REJECTED)
🚀 Module Independence
Benefits of Modular Monolith
-
Development:
- Each module can be developed independently
- Clear boundaries between features
- Easy to understand and navigate
-
Testing:
- Modules can be tested in isolation
- Shared components tested once
- Integration tests verify module interactions
-
Deployment:
- Single deployment process
- No service coordination complexity
- Atomic updates (all or nothing)
-
Performance:
- No network latency between modules
- Shared connection pools
- Efficient resource utilization
Module Communication
Within Backend:
- Modules can directly import from each other
- Use shared utilities from
shared/ - Share database connections and auth
Within Frontend:
- Modules use shared Pinia stores
- Shared components in
src/shared/ - Routing handles module navigation
🔧 Configuration Management
Environment-Based Configuration
The backend supports multiple environment configurations:
# Development
backend/.env.dev # Local development settings
PORT=8000
DEBUG=True
ORACLE_HOST=localhost
ORACLE_PORT=1526
# Testing
backend/.env.test # Testing environment
PORT=8001
DEBUG=False
ORACLE_HOST=10.0.20.121
# Production
backend/.env.prod # Production settings
PORT=8001
DEBUG=False
ORACLE_HOST=10.0.20.36
Module Toggle Configuration
Modules can be enabled/disabled via environment variables:
MODULE_REPORTS_ENABLED=true
MODULE_DATA_ENTRY_ENABLED=true
MODULE_TELEGRAM_ENABLED=true
📊 Shared Resources
1. Database Connection Pool
Oracle Pool (shared/database/oracle_pool.py):
- Singleton pattern
- Configured pool size (min=2, max=10)
- Automatic reconnection
- Connection health checks
- Used by Reports module
2. Authentication & Authorization
JWT Authentication (shared/auth/):
- Centralized token management
- Middleware auto-injection of user
- Rate limiting (5 req/5 min)
- Used by all modules
3. Cache System (Reports Module)
Two-Tier Cache:
- L1: In-memory (LRU, 1000 entries)
- L2: SQLite persistent cache
- Automatic TTL management
- Performance tracking
4. Frontend Shared Components
Shared UI (src/shared/ and shared/frontend/):
- Authentication components
- Company/Period selectors
- Error boundaries
- Global CSS system
🎯 Migration from Microservices
What Changed
Before (Microservices):
reports-app/backend/ → Port 8001
data-entry-app/backend/ → Port 8003
telegram-bot/ → Port 8002
After (Monolith):
backend/ → Single port 8000/8001
└── modules/
├── reports/
├── data_entry/
└── telegram/
Migration Benefits
- ✅ Simpler deployment (1 service instead of 3)
- ✅ Faster startup (no multi-service coordination)
- ✅ Easier debugging (single process)
- ✅ Shared connection pools (better resource utilization)
- ✅ No inter-service network latency
- ✅ Atomic deployments (all modules update together)
What Stayed the Same
- ✅ Module boundaries and organization
- ✅ Business logic and models
- ✅ Frontend structure
- ✅ Database schemas
- ✅ API contracts
- ✅ Authentication flow
🔒 Security Considerations
Middleware Stack
All requests pass through:
- CORS validation
- JWT authentication
- Rate limiting
- Security headers injection
Module Isolation
While modules share the same process:
- Each has its own routers
- Business logic is separated
- Database access is controlled
- Permissions are enforced at API level
📈 Scalability
Horizontal Scaling
The monolith can be scaled horizontally:
- Multiple instances behind load balancer
- Stateless design (JWT, no sessions)
- Shared database (Oracle)
- Redis for distributed cache (future)
Vertical Scaling
Optimize single instance:
- Increase worker processes
- Connection pool tuning
- Cache optimization
- Query optimization
Future: Microservices Migration
If needed, modules can be extracted:
- Each module already has clear boundaries
- Services are independent
- API contracts are defined
- Database can be split (if needed)
📚 Related Documentation
- Setup & Commands:
README.md - CSS Architecture:
docs/ONBOARDING_CSS.md - Data Entry Module:
docs/data-entry/ARCHITECTURE.md - Telegram Bot:
docs/telegram/README.md - Deployment:
deployment/windows/README.md(Windows) orDOKPLOY_DEPLOYMENT.md(Linux)
For questions about this architecture, consult the development team or open an issue in the repository.