# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## πŸš€ Project Overview **ROA2WEB** - Modern ERP Application with ultrathin monolith architecture: 1. **Reports Module** (`backend/modules/reports/`) - Read-only reports from Oracle (raportΔƒri) 2. **Data Entry Module** (`backend/modules/data_entry/`) - Data input with approval workflow (introduceri date) 3. **Telegram Bot Module** (`backend/modules/telegram/`) - Telegram bot integration **Main Branch**: `main` (use for PRs) **Working Directory**: Repository root **Quick Reference**: See `README.md` for complete setup, commands, deployment, and testing instructions. --- ## πŸ“ Module-Specific Instructions > **IMPORTANT**: When working on a specific module, read its documentation first! | Module | Documentation Location | Description | |--------|----------------------|-------------| | **Data Entry** | `docs/data-entry/DATA-ENTRY-MODULE.md` | Bonuri fiscale, chitanΘ›e, workflow aprobare | | **Reports** | This file (below) | Rapoarte Oracle read-only | | **Telegram Bot** | `docs/telegram/README.md` | Bot Telegram | ### When to Use Which Instructions **Working on Data Entry** (`backend/modules/data_entry/` or `src/modules/data-entry/`): β†’ **FIRST read `docs/data-entry/DATA-ENTRY-MODULE.md`** for: - SQLModel + Alembic patterns (NOT Oracle) - SQLite database (NOT Oracle pool) - Workflow states (DRAFT β†’ PENDING β†’ APPROVED) - Receipt/Attachment/AccountingEntry models - Expense types and auto-generation logic - Oracle nomenclatures integration **Working on Reports Module** (`backend/modules/reports/` or `src/modules/reports/`): β†’ Use instructions from this file (below) **Working on shared components** (`shared/auth/`, `shared/database/`, `shared/frontend/`): β†’ These are used by ALL modules - be careful with changes! β†’ `shared/frontend/` contains: LoginView.vue, auth store factory, login styles --- ## πŸ—οΈ Architecture > **Important Architecture Decisions:** See `docs/ARCHITECTURE-DECISIONS.md` for critical decisions about: > - Why single worker (`--workers 1`) is required for Telegram bot > - Ultrathin monolith vs microservices rationale > - IIS sub-application deployment strategy > - Performance characteristics and scaling considerations ### Ultrathin Monolith Structure ``` . β”œβ”€β”€ backend/ # Unified FastAPI backend (port 8000/8001) β”‚ β”œβ”€β”€ modules/ # Business logic modules β”‚ β”‚ β”œβ”€β”€ reports/ # Reports module (Oracle read-only) β”‚ β”‚ β”œβ”€β”€ data_entry/ # Data entry module (SQLite + workflow) β”‚ β”‚ β”œβ”€β”€ telegram/ # Telegram bot module β”‚ β”‚ └── data/ # Shared data (telegram_bot.db) β”‚ β”œβ”€β”€ config.py # Centralized configuration β”‚ └── main.py # FastAPI app entry point β”‚ β”œβ”€β”€ src/ # Unified Vue.js 3 frontend β”‚ β”œβ”€β”€ modules/ # Feature modules β”‚ β”‚ β”œβ”€β”€ reports/ # Reports frontend β”‚ β”‚ └── data-entry/ # Data entry frontend β”‚ β”œβ”€β”€ shared/ # Shared frontend components β”‚ β”‚ β”œβ”€β”€ components/ # Reusable Vue components β”‚ β”‚ └── stores/ # Pinia stores β”‚ β”œβ”€β”€ assets/ # Global CSS, images β”‚ β”œβ”€β”€ router/ # Vue Router β”‚ └── App.vue # Root component β”‚ β”œβ”€β”€ shared/ # Shared backend components β”‚ β”œβ”€β”€ database/ # Oracle pool β”‚ β”œβ”€β”€ auth/ # JWT auth & middleware β”‚ └── frontend/ # Shared frontend assets β”‚ β”œβ”€β”€ components/ # LoginView.vue β”‚ β”œβ”€β”€ stores/ # Auth store factory β”‚ └── styles/ # Login CSS β”‚ β”œβ”€β”€ docs/ # Architecture & style guides β”œβ”€β”€ deployment/ # Production deployment scripts └── ssh-tunnel/ # SSH tunnel for Oracle DB access ``` ### Starting Services **Quick Start** (Unified backend + frontend): ```bash ./start-prod.sh # Prod env: Backend :8001, Frontend :3000 ./start-test.sh # Test env: Backend :8001, Frontend :3000 ``` **Individual Service Control**: ```bash ./start-frontend.sh restart # Restart frontend only (~7s - fastest!) ./start-backend.sh # Start unified backend :8000 or :8001 ./status.sh # Show services status + health checks ``` **Infrastructure**: ```bash ./ssh-tunnel-prod.sh start # Oracle DB tunnel (production: 10.0.20.36) ./ssh-tunnel-test.sh start # Oracle TEST tunnel (LXC: 10.0.20.121) ``` **Benefits**: - **Single backend process**: All modules in one FastAPI app - **Faster startup**: No multi-service coordination overhead - **Easier debugging**: Single process to monitor - **Shared resources**: Connection pools, cache, and middleware ### Key Architectural Decisions **Core Architecture:** - **Ultrathin Monolith**: Single backend process with modular structure (`backend/modules/`) - **Single Worker Mode**: `--workers 1` (required for Telegram bot - see ADR-002 in `docs/ARCHITECTURE-DECISIONS.md`) - **Shared Database Pool**: Singleton `OraclePool` in `shared/database/oracle_pool.py` (python-oracledb with connection pooling) - **Centralized Auth**: JWT-based auth in `shared/auth/` with middleware auto-injecting `request.state.user` **Module-Specific:** - **Module-Based Cache**: Each module can have its own cache strategy (Reports uses L1+L2 hybrid cache) - **Telegram Bot**: Integrated module with SQLite database (`backend/modules/data/telegram_bot.db`) - **FastAPI Structure**: Modules in `backend/modules/*/`, each with services, routers, models/schemas **Infrastructure:** - **SSH Tunnel**: Required for Oracle DB connections (development/Linux) - see Database Setup - **IIS Sub-Application**: Deployed at `/roa2web` path, not root (production) > **For detailed rationale and trade-offs**, see `docs/ARCHITECTURE-DECISIONS.md` --- ## πŸ—„οΈ Database Setup **Schema**: `CONTAFIN_ORACLE` (authentication and user management) **Connection**: SSH tunnel required (Oracle on remote network) ### SSH Tunnel (Development/Linux) ```bash ./ssh-tunnel-prod.sh start # localhost:1526 β†’ remote:1521 ./ssh-tunnel-prod.sh status # Check tunnel ./ssh-tunnel-prod.sh stop # Stop tunnel ``` **IMPORTANT**: Always ensure SSH tunnel is running before starting backend services. ### Environment Variables (`backend/.env`) ```bash # Oracle Database (through SSH tunnel) ORACLE_USER=CONTAFIN_ORACLE ORACLE_PASSWORD=your_password ORACLE_HOST=localhost ORACLE_PORT=1526 ORACLE_SID=ROA # JWT Authentication JWT_SECRET_KEY=your_secret_key JWT_ALGORITHM=HS256 JWT_EXPIRE_MINUTES=30 # Module Configuration MODULE_REPORTS_ENABLED=true MODULE_DATA_ENTRY_ENABLED=true MODULE_TELEGRAM_ENABLED=true ``` **Windows Production**: Direct Oracle connection, no SSH tunnel required. **Environment Files**: Multiple .env files available (.env.dev, .env.test, .env.prod) - see `backend/ENV-SETUP.md` for details. --- ## πŸ”‘ Authentication Flow 1. **Login**: `POST /api/auth/login` β†’ calls `pack_drepturi.verificautilizator(username, password)` 2. **Token**: JWT includes `username`, `user_id`, `companies[]`, `permissions[]`, `exp`, `iat`, `type` 3. **Middleware**: `AuthenticationMiddleware` in `shared/auth/middleware.py` validates tokens, injects user 4. **Protected Routes**: All routes except `excluded_paths` require valid JWT **Key Files**: - `shared/auth/middleware.py` - FastAPI middleware with rate limiting (5 req/5 min) - `shared/auth/jwt_handler.py` - Token creation/validation - `backend/main.py` - Main FastAPI app with auth router registration --- ## πŸ“ Common Development Tasks ### Adding a New API Endpoint **IMPORTANT**: Always use the cache system for database queries to improve performance. 1. Create **service** in `backend/modules/reports/services/your_service.py` (NOT in router!) 2. Define Pydantic schemas in `modules/*/schemas/` or `modules/*/models/` 3. **Add caching** using `@cached` decorator in service methods 4. Create router in `backend/modules/reports/routers/your_router.py` (calls service) 5. Register router in `app/main.py`: `app.include_router(your_router, prefix="/api/your_prefix")` **Service Example with Caching** (RECOMMENDED): ```python # app/services/your_service.py from app.cache.decorators import cached from database.oracle_pool import oracle_pool class YourService: @staticmethod @cached(cache_type='schema', key_params=['company_id']) async def _get_schema(company_id: int) -> str: """Get schema for company (CACHED 24h)""" async with oracle_pool.get_connection() as connection: with connection.cursor() as cursor: cursor.execute(""" SELECT schema FROM CONTAFIN_ORACLE.v_nom_firme WHERE id_firma = :company_id """, {'company_id': company_id}) result = cursor.fetchone() return result[0] if result else None @staticmethod @cached(cache_type='your_data', key_params=['filter_params', 'username']) async def get_your_data(filter_params: YourFilter, username: str) -> YourResponse: """ Get your data from Oracle (CACHED 10 min) Cache automatically: - Generates unique key from filter_params + username - Stores in L1 (memory) + L2 (SQLite) - Returns cached data on subsequent calls - Tracks performance metrics """ schema = await YourService._get_schema(filter_params.company_id) async with oracle_pool.get_connection() as connection: with connection.cursor() as cursor: cursor.execute(f""" SELECT * FROM {schema}.your_table WHERE your_condition = :param """, {'param': filter_params.param}) rows = cursor.fetchall() # Process results... return YourResponse(data=processed_data) ``` **Router Example** (calls service): ```python # app/routers/your_router.py from app.services.your_service import YourService @router.get("/", response_model=YourResponse) async def get_your_data( filter_params: YourFilter = Depends(), current_user: CurrentUser = Depends(get_current_user) ): """Get your data - delegated to service with caching""" return await YourService.get_your_data(filter_params, current_user.username) ``` **Cache Configuration** (add to `app/cache/config.py` if new cache type): ```python # Add TTL for your cache type ttl_your_data: int = int(os.getenv('CACHE_TTL_YOUR_DATA', '600')) # 10 min default # Add to get_ttl_for_type() method: 'your_data': self.ttl_your_data, ``` **Cache Best Practices**: - βœ… Use `@cached` decorator for ALL database queries - βœ… Place logic in services (NOT routers) - βœ… Cache schema lookups separately (long TTL: 24h) - βœ… Choose appropriate TTL (frequently changing data: 5-10 min, static data: 30 min - 24h) - βœ… Include `username` in `key_params` for user-specific data - βœ… Include filter parameters in `key_params` for query variations - ❌ Don't query Oracle directly in routers (use services with caching) - ❌ Don't skip caching for performance-critical endpoints ### Adding a New Frontend Page/Component **IMPORTANT**: Follow the established CSS architecture and design system. **Before writing ANY CSS**: Read **`docs/ONBOARDING_CSS.md`** (5-minute quick start) β†’ See "Documentation Index" below for complete guide list. **Golden Rules**: - βœ… Use global patterns first (`.roa-card`, `.roa-metric`, `.roa-badge-*`) - check `CSS_PATTERNS.md` - βœ… Use design tokens (`var(--color-primary)`) not hardcoded values (`#2563eb`) - βœ… **Use shared CSS** from `src/assets/css/` - NEVER create new CSS when shared classes exist - βœ… For inline stats/totals use `.summary-stats-inline`, `.stat-item`, `.stat-label`, `.stat-value` from `stats.css` - ❌ Never use `:deep()` in components (use `src/assets/css/vendor/` for PrimeVue overrides) - ❌ Never duplicate CSS (write once, use everywhere) - ❌ Never add new scoped CSS for patterns that already exist in shared CSS files **Tables - Unified Column Structure & Filter Buttons**: - βœ… **ALWAYS use separate columns** for related data (Debit | Credit, not Debit+Credit stacked) - βœ… **Use PrimeVue DataTable** with one value per `` component - βœ… **Add filter/action buttons** (clear, export Excel, export PDF, refresh) **on separate row below filters** - βœ… **PrimeVue Button** components with **icon + label** (not icon-only!) - βœ… **Export ALL data** from backend (page_size: 999999), not just current page - ❌ **Never group multiple values** vertically in a single column - ❌ **Never use HTML `