docs: Restructure styling documentation and add theme toggle docs
- Simplify CLAUDE.md from ~460 to ~145 lines with imports - Add Theme System section to css-design-system.md (3 modes: auto/light/dark) - Document theme toggle UI, localStorage persistence, CSS priority order - Add paths: frontmatter to authentication.md and company-period.md - Update DESIGN_TOKENS.md Dark Mode section with toggle documentation - Clean auto-build-memory.md header (remove non-existent auto-sync reference) - Remove non-existent plugin from settings.json 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,3 +1,7 @@
|
|||||||
|
---
|
||||||
|
paths: "{backend,shared}/**/*.py,src/**/*.{js,vue}"
|
||||||
|
---
|
||||||
|
|
||||||
# Authentication Rules
|
# Authentication Rules
|
||||||
|
|
||||||
## JWT Token Structure (IMMUTABLE)
|
## JWT Token Structure (IMMUTABLE)
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
# Auto-Build Learned Patterns & Gotchas
|
# Learned Patterns & Gotchas
|
||||||
|
|
||||||
**Last updated**: 2025-12-24T00:10:00Z
|
**Last updated**: 2025-12-24
|
||||||
**Source**: `.auto-build/memory/*.json` (auto-synced)
|
**Maintained**: Manually (add new patterns/gotchas as discovered)
|
||||||
|
|
||||||
This file is automatically loaded by Claude Code and contains insights learned during feature implementations using the Auto-Build system.
|
This file contains insights learned during feature implementations. Claude Code auto-loads this file to prevent repeating past mistakes.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,7 @@
|
|||||||
|
---
|
||||||
|
paths: "{backend,shared}/**/*.py,src/**/*.{js,vue}"
|
||||||
|
---
|
||||||
|
|
||||||
# Company & Period Selection Rules
|
# Company & Period Selection Rules
|
||||||
|
|
||||||
## Store Factories (MANDATORY)
|
## Store Factories (MANDATORY)
|
||||||
|
|||||||
@@ -14,20 +14,36 @@ paths: src/modules/**/*.{vue,css}
|
|||||||
- Check `CSS_PATTERNS.md` BEFORE writing any CSS
|
- Check `CSS_PATTERNS.md` BEFORE writing any CSS
|
||||||
- Import shared styles from `shared/frontend/styles/`
|
- Import shared styles from `shared/frontend/styles/`
|
||||||
|
|
||||||
## Dark Mode Support (CRITICAL)
|
## Theme System (3 Modes) - CRITICAL
|
||||||
Dark mode is ACTIVE via `@media (prefers-color-scheme: dark)`.
|
|
||||||
|
|
||||||
**Use semantic surface tokens for backgrounds:**
|
ROA2WEB are **theme toggle în header**: auto → light → dark
|
||||||
|
|
||||||
|
| Mode | Comportament | CSS Selector |
|
||||||
|
|------|--------------|--------------|
|
||||||
|
| `auto` | Urmează preferința OS | `@media (prefers-color-scheme: dark)` |
|
||||||
|
| `light` | Forțează light mode | `[data-theme="light"]` pe `<html>` |
|
||||||
|
| `dark` | Forțează dark mode | `[data-theme="dark"]` pe `<html>` |
|
||||||
|
|
||||||
|
**Detalii implementare:**
|
||||||
|
- **Toggle:** `AppHeader.vue` (lines 137-175)
|
||||||
|
- **Persistență:** `localStorage['user-theme']` (valori: 'light', 'dark', sau absent=auto)
|
||||||
|
- **CSS Priority:** `[data-theme]` > `@media (prefers-color-scheme)` > default light
|
||||||
|
|
||||||
|
**Testare OBLIGATORIE:**
|
||||||
|
1. Click buton temă în header (ciclează auto→light→dark)
|
||||||
|
2. DevTools → Rendering → Emulate CSS media → prefers-color-scheme: dark
|
||||||
|
|
||||||
|
**Semantic surface tokens (funcționează în TOATE modurile):**
|
||||||
| Token | Light | Dark | Use For |
|
| Token | Light | Dark | Use For |
|
||||||
|-------|-------|------|---------|
|
|-------|-------|------|---------|
|
||||||
| `--surface-card` | white | dark | Card/container backgrounds |
|
| `--surface-card` | white | #1e293b | Card/container backgrounds |
|
||||||
| `--surface-ground` | light gray | darker | Page background |
|
| `--surface-ground` | #f8fafc | #0f172a | Page background |
|
||||||
| `--surface-hover` | hover gray | dark hover | Hover states |
|
| `--surface-hover` | #f1f5f9 | #334155 | Hover states |
|
||||||
| `--surface-border` | light border | dark border | Borders |
|
| `--surface-border` | #e2e8f0 | #475569 | Borders |
|
||||||
| `--text-color` | dark | light | Primary text |
|
| `--text-color` | #111827 | #f9fafb | Primary text |
|
||||||
| `--text-color-secondary` | gray | light gray | Secondary text |
|
| `--text-color-secondary` | #6b7280 | #d1d5db | Secondary text |
|
||||||
|
|
||||||
**For status colors, use scales:**
|
**Status colors (scales 50-900):**
|
||||||
- Success: `--green-50` to `--green-900` (bg: 50/100, text: 500/600)
|
- Success: `--green-50` to `--green-900` (bg: 50/100, text: 500/600)
|
||||||
- Warning: `--yellow-50` to `--yellow-900`
|
- Warning: `--yellow-50` to `--yellow-900`
|
||||||
- Error: `--red-50` to `--red-900`
|
- Error: `--red-50` to `--red-900`
|
||||||
@@ -79,4 +95,4 @@ color: var(--red-600); /* Error text */
|
|||||||
- Use hardcoded colors like `#2563eb` (use `var(--color-primary)`)
|
- Use hardcoded colors like `#2563eb` (use `var(--color-primary)`)
|
||||||
- Use hardcoded backgrounds like `#ffffff` or `white` (use `var(--surface-card)`)
|
- Use hardcoded backgrounds like `#ffffff` or `white` (use `var(--surface-card)`)
|
||||||
- Create scoped CSS for patterns that already exist in shared files
|
- Create scoped CSS for patterns that already exist in shared files
|
||||||
- Forget dark mode - always test with `prefers-color-scheme: dark`
|
- **Skip theme testing** - ALWAYS test cu toggle (auto/light/dark) + DevTools dark mode
|
||||||
|
|||||||
@@ -1,7 +1,4 @@
|
|||||||
{
|
{
|
||||||
"enabledPlugins": {
|
|
||||||
"ab@roa2web-tools": true
|
|
||||||
},
|
|
||||||
"statusLine": {
|
"statusLine": {
|
||||||
"type": "command",
|
"type": "command",
|
||||||
"command": "input=$(cat); model=$(echo \"$input\" | jq -r '.model.display_name // \"Unknown\"'); usage=$(echo \"$input\" | jq '.context_window.current_usage'); if [ \"$usage\" != \"null\" ]; then current=$(echo \"$usage\" | jq '.input_tokens + .cache_creation_input_tokens + .cache_read_input_tokens'); size=$(echo \"$input\" | jq '.context_window.context_window_size'); pct=$((current * 100 / size)); ctx=$(printf '%d%% ctx' \"$pct\"); else ctx='0% ctx'; fi; branch=$(git -c core.useBuiltinFSMonitor=false branch --show-current 2>/dev/null || echo 'no-git'); cwd=$(basename \"$(pwd)\"); printf '\\033[36m%s\\033[0m | \\033[33m%s\\033[0m | \\033[32m%s\\033[0m | \\033[35m%s\\033[0m' \"$model\" \"$ctx\" \"$branch\" \"$cwd\""
|
"command": "input=$(cat); model=$(echo \"$input\" | jq -r '.model.display_name // \"Unknown\"'); usage=$(echo \"$input\" | jq '.context_window.current_usage'); if [ \"$usage\" != \"null\" ]; then current=$(echo \"$usage\" | jq '.input_tokens + .cache_creation_input_tokens + .cache_read_input_tokens'); size=$(echo \"$input\" | jq '.context_window.context_window_size'); pct=$((current * 100 / size)); ctx=$(printf '%d%% ctx' \"$pct\"); else ctx='0% ctx'; fi; branch=$(git -c core.useBuiltinFSMonitor=false branch --show-current 2>/dev/null || echo 'no-git'); cwd=$(basename \"$(pwd)\"); printf '\\033[36m%s\\033[0m | \\033[33m%s\\033[0m | \\033[32m%s\\033[0m | \\033[35m%s\\033[0m' \"$model\" \"$ctx\" \"$branch\" \"$cwd\""
|
||||||
|
|||||||
464
CLAUDE.md
464
CLAUDE.md
@@ -1,437 +1,119 @@
|
|||||||
# CLAUDE.md
|
# CLAUDE.md
|
||||||
|
|
||||||
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
This file provides guidance to Claude Code when working with code in this repository.
|
||||||
|
|
||||||
## 🚀 Project Overview
|
## Project Overview
|
||||||
|
|
||||||
**ROA2WEB** - Modern ERP Application with ultrathin monolith architecture:
|
**ROA2WEB** - Modern ERP Application with ultrathin monolith architecture:
|
||||||
1. **Reports Module** (`backend/modules/reports/`) - Read-only reports from Oracle (raportări)
|
- **Reports Module** (`backend/modules/reports/`) - Read-only reports from Oracle
|
||||||
2. **Data Entry Module** (`backend/modules/data_entry/`) - Data input with approval workflow (introduceri date)
|
- **Data Entry Module** (`backend/modules/data_entry/`) - Data input with approval workflow
|
||||||
3. **Telegram Bot Module** (`backend/modules/telegram/`) - Telegram bot integration
|
- **Telegram Bot Module** (`backend/modules/telegram/`) - Telegram bot integration
|
||||||
|
|
||||||
**Main Branch**: `main` (use for PRs)
|
**Main Branch**: `main` | **Setup & Commands**: See `README.md`
|
||||||
**Working Directory**: Repository root
|
|
||||||
|
|
||||||
**Quick Reference**: See `README.md` for complete setup, commands, deployment, and testing instructions.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 📁 Module-Specific Instructions
|
## Module-Specific Instructions
|
||||||
|
|
||||||
> **IMPORTANT**: When working on a specific module, read its documentation first!
|
> **IMPORTANT**: Read module documentation FIRST before working on a module!
|
||||||
|
|
||||||
| Module | Documentation Location | Description |
|
| Module | Documentation | Key Points |
|
||||||
|--------|----------------------|-------------|
|
|--------|--------------|------------|
|
||||||
| **Data Entry** | `docs/data-entry/DATA-ENTRY-MODULE.md` | Bonuri fiscale, chitanțe, workflow aprobare |
|
| **Data Entry** | `docs/data-entry/DATA-ENTRY-MODULE.md` | SQLModel, SQLite, workflow states |
|
||||||
| **Reports** | This file (below) | Rapoarte Oracle read-only |
|
| **Reports** | This file + `README.md` | Oracle read-only, caching |
|
||||||
| **Telegram Bot** | `docs/telegram/README.md` | Bot Telegram |
|
| **Telegram** | `docs/telegram/README.md` | Bot commands, formatting |
|
||||||
|
|
||||||
### 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
|
## Quick Reference
|
||||||
|
|
||||||
> **Important Architecture Decisions:** See `docs/ARCHITECTURE-DECISIONS.md` for critical decisions about:
|
### Architecture
|
||||||
> - Why single worker (`--workers 1`) is required for Telegram bot
|
See `docs/ARCHITECTURE-DECISIONS.md` for:
|
||||||
> - Ultrathin monolith vs microservices rationale
|
- Single worker (`--workers 1`) - required for Telegram bot
|
||||||
> - IIS sub-application deployment strategy
|
- Ultrathin monolith rationale
|
||||||
> - Performance characteristics and scaling considerations
|
- IIS deployment strategy
|
||||||
|
|
||||||
### 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
|
### Starting Services
|
||||||
|
|
||||||
**Quick Start** (Unified backend + frontend):
|
|
||||||
```bash
|
```bash
|
||||||
./start-prod.sh # Prod env: Backend :8001, Frontend :3000
|
./start-prod.sh # Backend :8001 + Frontend :3000
|
||||||
./start-test.sh # Test env: Backend :8001, Frontend :3000
|
./ssh-tunnel-prod.sh # Oracle DB tunnel (REQUIRED on Linux)
|
||||||
|
./status.sh # Check services
|
||||||
```
|
```
|
||||||
|
|
||||||
**Individual Service Control**:
|
### Database
|
||||||
```bash
|
- **Schema**: `CONTAFIN_ORACLE`
|
||||||
./start-frontend.sh restart # Restart frontend only (~7s - fastest!)
|
- **Connection**: SSH tunnel required (Linux dev)
|
||||||
./start-backend.sh # Start unified backend :8000 or :8001
|
- **Env**: `backend/.env` (see `backend/ENV-SETUP.md`)
|
||||||
./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
|
## Key Rules (ALWAYS FOLLOW)
|
||||||
|
|
||||||
**Schema**: `CONTAFIN_ORACLE` (authentication and user management)
|
### Frontend Development
|
||||||
**Connection**: SSH tunnel required (Oracle on remote network)
|
**Before writing CSS**: Read `docs/ONBOARDING_CSS.md` (5 min)
|
||||||
|
|
||||||
### SSH Tunnel (Development/Linux)
|
- Use design tokens: `var(--color-primary)` not `#2563eb`
|
||||||
```bash
|
- Use shared CSS from `src/assets/css/` - NEVER duplicate
|
||||||
./ssh-tunnel-prod.sh start # localhost:1526 → remote:1521
|
- Check `docs/CSS_PATTERNS.md` for existing patterns
|
||||||
./ssh-tunnel-prod.sh status # Check tunnel
|
- **Theme toggle**: App has 3 modes (auto/light/dark) - test BOTH themes!
|
||||||
./ssh-tunnel-prod.sh stop # Stop tunnel
|
|
||||||
```
|
|
||||||
|
|
||||||
**IMPORTANT**: Always ensure SSH tunnel is running before starting backend services.
|
**Tables**:
|
||||||
|
- Use separate columns (Debit | Credit, not stacked)
|
||||||
|
- Filter buttons on separate row below filters
|
||||||
|
- Export ALL data, not just current page
|
||||||
|
|
||||||
### Environment Variables (`backend/.env`)
|
### Backend Development
|
||||||
```bash
|
- Place logic in **services**, not routers
|
||||||
# Oracle Database (through SSH tunnel)
|
- Use `@cached` decorator for ALL database queries
|
||||||
ORACLE_USER=CONTAFIN_ORACLE
|
- Cache schema lookups separately (24h TTL)
|
||||||
ORACLE_PASSWORD=your_password
|
|
||||||
ORACLE_HOST=localhost
|
|
||||||
ORACLE_PORT=1526
|
|
||||||
ORACLE_SID=ROA
|
|
||||||
|
|
||||||
# JWT Authentication
|
**Service pattern**:
|
||||||
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
|
```python
|
||||||
# app/services/your_service.py
|
|
||||||
from app.cache.decorators import cached
|
from app.cache.decorators import cached
|
||||||
from database.oracle_pool import oracle_pool
|
|
||||||
|
|
||||||
class YourService:
|
class YourService:
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@cached(cache_type='schema', key_params=['company_id'])
|
@cached(cache_type='your_data', key_params=['company_id', 'username'])
|
||||||
async def _get_schema(company_id: int) -> str:
|
async def get_data(company_id: int, username: str):
|
||||||
"""Get schema for company (CACHED 24h)"""
|
# Query Oracle here
|
||||||
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):
|
### Authentication
|
||||||
```python
|
- JWT structure: `username`, `user_id`, `companies[]`, `permissions[]`, `exp`, `iat`, `type`
|
||||||
# app/routers/your_router.py
|
- Middleware: `shared/auth/middleware.py` (auto-injects `request.state.user`)
|
||||||
from app.services.your_service import YourService
|
- Rate limiting: 5 req/5 min for `/auth/*`
|
||||||
|
|
||||||
@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 `<Column>` 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 `<button>` for filter actions** (use PrimeVue `<Button>`)
|
|
||||||
- ❌ **Never put action buttons on same row as filters** (separate row!)
|
|
||||||
- ❌ **Never export only current page** (must fetch all data for export)
|
|
||||||
- 📖 **See**: `CSS_PATTERNS.md` → Table Patterns → Unified Table Column Structure & Filter/Action Buttons
|
|
||||||
|
|
||||||
### Adding a New Telegram Bot Command
|
|
||||||
**IMPORTANT**: Follow established command patterns and formatting.
|
|
||||||
|
|
||||||
**Before coding**: Read **`docs/telegram/TELEGRAM_BUTTON_INTERFACE_PLAN.md`** for command patterns → See "Documentation Index" for complete guides.
|
|
||||||
|
|
||||||
**Standard Pattern** (add handler in `app/bot/handlers.py`):
|
|
||||||
```python
|
|
||||||
async def your_command(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
|
|
||||||
telegram_id = update.effective_user.id
|
|
||||||
|
|
||||||
# 1. Check authentication (use helpers.py)
|
|
||||||
user = await get_user_by_telegram_id(telegram_id)
|
|
||||||
if not user:
|
|
||||||
await update.message.reply_text("⚠️ Account not linked. Use /start with code.")
|
|
||||||
return
|
|
||||||
|
|
||||||
# 2. Check active company (use session.py)
|
|
||||||
active_company = await get_active_company(telegram_id)
|
|
||||||
if not active_company:
|
|
||||||
await update.message.reply_text("⚠️ Select company first: /selectcompany")
|
|
||||||
return
|
|
||||||
|
|
||||||
# 3. Call backend API (use api/client.py)
|
|
||||||
# 4. Format response (use formatters.py)
|
|
||||||
# 5. Add tests + update MANUAL_TESTING_CHECKLIST.md
|
|
||||||
```
|
|
||||||
|
|
||||||
### Adding Shared Functionality
|
|
||||||
1. Place in `shared/{database|auth|utils}/`
|
|
||||||
2. Import using `sys.path.append()` pattern (see `backend/app/main.py:21`)
|
|
||||||
3. Add tests in `shared/tests/`
|
|
||||||
|
|
||||||
### Frontend API Integration
|
|
||||||
```javascript
|
|
||||||
// Store pattern (src/stores/yourStore.js)
|
|
||||||
import axios from 'axios';
|
|
||||||
|
|
||||||
const api = axios.create({
|
|
||||||
baseURL: 'http://localhost:8001/api',
|
|
||||||
headers: { 'Authorization': `Bearer ${token}` }
|
|
||||||
});
|
|
||||||
|
|
||||||
const response = await api.get('/endpoint');
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 🔒 Security
|
## Documentation Index
|
||||||
|
|
||||||
- **Git Hooks**: Security scanning in `security/install_hooks.sh`
|
| Topic | File | Description |
|
||||||
- **Environment Files**: Never commit `.env` (use `.env.example` as template)
|
|-------|------|-------------|
|
||||||
- **SSH Keys**: In `ssh-tunnel/secrets/` (gitignored)
|
| **Setup** | `README.md` | Commands, testing, deployment |
|
||||||
- **JWT Secrets**: Generate strong secrets for production
|
| **Architecture** | `docs/ARCHITECTURE-DECISIONS.md` | Critical decisions |
|
||||||
- **Rate Limiting**: Built into auth middleware (5 requests per 5 minutes)
|
| **CSS Quick Start** | `docs/ONBOARDING_CSS.md` | START HERE for frontend |
|
||||||
|
| **CSS Patterns** | `docs/CSS_PATTERNS.md` | Cards, forms, buttons, tables |
|
||||||
|
| **Design Tokens** | `docs/DESIGN_TOKENS.md` | Colors, spacing, dark mode |
|
||||||
|
| **Data Entry** | `docs/data-entry/DATA-ENTRY-MODULE.md` | SQLModel, workflow |
|
||||||
|
| **Telegram** | `docs/telegram/README.md` | Bot development |
|
||||||
|
| **Deployment** | `deployment/linux/README.md` | Deploy from LXC |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 📚 Documentation Index
|
## Learned Patterns & Known Issues
|
||||||
|
|
||||||
### Quick Start & Commands
|
> **Patterns/Gotchas from previous sessions**: Auto-loaded from `.claude/rules/auto-build-memory.md`
|
||||||
→ **`README.md`** - Project overview, setup, development commands, testing, deployment
|
|
||||||
|
|
||||||
### Data Entry App (Bonuri Fiscale)
|
|
||||||
- **`docs/data-entry/CLAUDE.md`** - ⚠️ **READ FIRST** when working on data-entry
|
|
||||||
- `docs/data-entry/README.md` - Quick start guide
|
|
||||||
- `docs/data-entry/REQUIREMENTS.md` - Functional requirements
|
|
||||||
- `docs/data-entry/ARCHITECTURE.md` - Technical architecture (SQLModel, workflow)
|
|
||||||
|
|
||||||
### Architecture & Planning
|
|
||||||
- `DEVELOPMENT_BLUEPRINT.md` - Detailed development plan
|
|
||||||
|
|
||||||
### Frontend Development
|
|
||||||
- **`docs/ONBOARDING_CSS.md`** - CSS system quick start (START HERE for new components)
|
|
||||||
- **`docs/CSS_PATTERNS.md`** - Complete CSS patterns library (cards, forms, buttons, etc.)
|
|
||||||
- **`docs/DESIGN_TOKENS.md`** - Design tokens (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
|
|
||||||
- `Frontend module documentation in src/modules/` - Frontend architecture and setup
|
|
||||||
- `Playwright E2E testing (see tests/ directory)` - Playwright E2E testing guide
|
|
||||||
|
|
||||||
### Backend Development
|
|
||||||
- `Backend module documentation in backend/modules/` - Backend architecture and API details
|
|
||||||
- API endpoints documented in `README.md` (Authentication, Companies, Dashboard, Invoices, Treasury, Telegram)
|
|
||||||
|
|
||||||
### Telegram Bot Development
|
|
||||||
- **`docs/telegram/README.md`** - Complete bot architecture and development guide (START HERE)
|
|
||||||
- **`docs/telegram/TELEGRAM_BUTTON_INTERFACE_PLAN.md`** - Command reference and patterns
|
|
||||||
- `tests/MANUAL_TESTING_CHECKLIST.md` - Manual testing procedures
|
|
||||||
|
|
||||||
### Deployment
|
|
||||||
|
|
||||||
**🚀 Quick Deploy from Claude-Agent LXC:**
|
|
||||||
```bash
|
|
||||||
# Din orice director ROA2WEB (main, worktree, branch):
|
|
||||||
./deployment/linux/deploy.sh # Full deploy (frontend + backend)
|
|
||||||
./deployment/linux/deploy.sh frontend # Frontend only
|
|
||||||
./deployment/linux/deploy.sh backend # Backend only
|
|
||||||
./deployment/linux/deploy.sh test # Test SSH connection
|
|
||||||
```
|
|
||||||
→ Server auto-deploys within 5 minutes (scheduled task)
|
|
||||||
|
|
||||||
- **`deployment/linux/README.md`** - ⚠️ **DEPLOY FROM LXC** - Linux to Windows deployment guide
|
|
||||||
- `deployment/windows/README.md` - Windows deployment quick start
|
|
||||||
- `deployment/windows/docs/WINDOWS_DEPLOYMENT.md` - Complete Windows guide
|
|
||||||
- **`deployment/windows/docs/TWO-TIER-IIS-DEPLOYMENT.md`** - ⚠️ **PRODUCTION ARCHITECTURE** - 2-tier IIS setup with public gateway
|
|
||||||
- `deployment/windows/docs/TELEGRAM_BOT_TROUBLESHOOTING.md` - Bot troubleshooting
|
|
||||||
|
|
||||||
### Troubleshooting
|
|
||||||
→ **`README.md`** - Common issues (SSH tunnel, backend, frontend, database)
|
|
||||||
→ **Backend**: Check `.env`, SSH tunnel status, port 8001 availability
|
|
||||||
→ **Frontend**: Clear node_modules, check Node.js version (16+), Vite auto-ports
|
|
||||||
→ **Database**: Verify SSH tunnel, Oracle listener, credentials, test `/health`
|
|
||||||
|
|
||||||
### Known Issues & Fixes
|
### Known Issues & Fixes
|
||||||
|
|
||||||
#### Mobile File Upload ERR_NETWORK (Android/iOS)
|
#### Mobile File Upload ERR_NETWORK (Android/iOS)
|
||||||
**Problem**: File uploads (OCR, attachments) fail with `ERR_NETWORK` (status 0) on mobile browsers, but work on desktop.
|
**Problem**: File uploads fail with `ERR_NETWORK` (status 0) on mobile browsers.
|
||||||
|
|
||||||
**Cause**: Android/iOS browsers invalidate File object references after accessing properties (`file.name`, `file.size`, `file.type`) due to **SnapshotState** in the W3C File API. See [Chromium Bug #40703873](https://issues.chromium.org/40703873).
|
**Cause**: Android/iOS browsers invalidate File object references after accessing properties due to SnapshotState in W3C File API. See [Chromium Bug #40703873](https://issues.chromium.org/40703873).
|
||||||
|
|
||||||
**Solution**: Clone the file into memory immediately after selection, before accessing any properties:
|
**Solution**: Clone the file into memory immediately after selection:
|
||||||
```javascript
|
```javascript
|
||||||
const handleFile = async (file) => {
|
const handleFile = async (file) => {
|
||||||
// Validations first...
|
|
||||||
|
|
||||||
// FIX: Clone file to memory to avoid SnapshotState invalidation
|
// FIX: Clone file to memory to avoid SnapshotState invalidation
|
||||||
const arrayBuffer = await file.arrayBuffer()
|
const arrayBuffer = await file.arrayBuffer()
|
||||||
const clonedFile = new File([arrayBuffer], file.name, {
|
const clonedFile = new File([arrayBuffer], file.name, {
|
||||||
@@ -446,13 +128,17 @@ const handleFile = async (file) => {
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 🔧 Tech Stack
|
## Security
|
||||||
|
|
||||||
**Backend**: FastAPI, python-oracledb, JWT (PyJWT), Pydantic, pytest
|
- Never commit `.env` files
|
||||||
**Frontend**: Vue.js 3 (Composition API), PrimeVue, Pinia, Vite, Axios, Chart.js, Playwright
|
- SSH keys in `ssh-tunnel/secrets/` (gitignored)
|
||||||
**Telegram Bot**: python-telegram-bot, SQLite + aiosqlite, httpx, FastAPI (internal), pytest
|
- Rate limiting in auth middleware
|
||||||
**Infrastructure**: Oracle Database, SSH Tunnel, Nginx (Linux prod), Docker (Linux prod), IIS + NSSM (Windows prod)
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
**For detailed information on any topic, always check the Documentation Index above first.**
|
## Tech Stack
|
||||||
|
|
||||||
|
**Backend**: FastAPI, python-oracledb, JWT, Pydantic
|
||||||
|
**Frontend**: Vue.js 3, PrimeVue, Pinia, Vite
|
||||||
|
**Telegram**: python-telegram-bot, SQLite, httpx
|
||||||
|
**Infra**: Oracle DB, SSH Tunnel, IIS (Windows prod)
|
||||||
|
|||||||
@@ -483,20 +483,52 @@ For backwards compatibility with existing code:
|
|||||||
|
|
||||||
## Dark Mode (ACTIVE)
|
## Dark Mode (ACTIVE)
|
||||||
|
|
||||||
Dark mode is fully supported via `@media (prefers-color-scheme: dark)` in `variables.css`. All tokens automatically switch to dark variants.
|
ROA2WEB folosește un **sistem two-tier** pentru teme cu toggle manual în header.
|
||||||
|
|
||||||
|
### Theme Toggle UI
|
||||||
|
|
||||||
|
Butonul de temă din header ciclează prin 3 moduri:
|
||||||
|
|
||||||
|
| Mode | Icon | Label | Comportament |
|
||||||
|
|------|------|-------|--------------|
|
||||||
|
| `auto` | 🖥️ `pi-desktop` | "Tema: Auto (sistem)" | Urmează preferința OS |
|
||||||
|
| `light` | ☀️ `pi-sun` | "Tema: Light" | Forțează light mode |
|
||||||
|
| `dark` | 🌙 `pi-moon` | "Tema: Dark" | Forțează dark mode |
|
||||||
|
|
||||||
|
**Implementare:** `src/shared/components/layout/AppHeader.vue` (lines 137-175)
|
||||||
|
|
||||||
|
### Persistență
|
||||||
|
|
||||||
|
- **Key:** `localStorage['user-theme']`
|
||||||
|
- **Values:** `'light'`, `'dark'`, sau absent (= auto)
|
||||||
|
- **Init:** La mount, aplică tema salvată
|
||||||
|
|
||||||
|
### CSS Priority Order
|
||||||
|
|
||||||
|
```
|
||||||
|
1. [data-theme="dark/light"] → Manual override (highest)
|
||||||
|
2. @media (prefers-color-scheme) → System preference (fallback)
|
||||||
|
3. :root (light) → Default
|
||||||
|
```
|
||||||
|
|
||||||
### How It Works
|
### How It Works
|
||||||
|
|
||||||
```css
|
```css
|
||||||
/* Light mode (default) */
|
/* 1. Default light mode */
|
||||||
:root {
|
:root {
|
||||||
--surface-card: #ffffff;
|
--surface-card: #ffffff;
|
||||||
--text-color: #111827;
|
--text-color: #111827;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Dark mode (automatic) */
|
/* 2. Manual dark override (user clicks toggle) */
|
||||||
|
[data-theme="dark"] {
|
||||||
|
--surface-card: #1e293b;
|
||||||
|
--text-color: #f9fafb;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 3. Auto-detect (when mode=auto + OS dark) */
|
||||||
@media (prefers-color-scheme: dark) {
|
@media (prefers-color-scheme: dark) {
|
||||||
:root {
|
:root:not([data-theme]) {
|
||||||
--surface-card: #1e293b;
|
--surface-card: #1e293b;
|
||||||
--text-color: #f9fafb;
|
--text-color: #f9fafb;
|
||||||
}
|
}
|
||||||
@@ -509,6 +541,7 @@ Dark mode is fully supported via `@media (prefers-color-scheme: dark)` in `varia
|
|||||||
|-------|-------|------|---------|
|
|-------|-------|------|---------|
|
||||||
| `--surface-card` | #ffffff | #1e293b | Card/container backgrounds |
|
| `--surface-card` | #ffffff | #1e293b | Card/container backgrounds |
|
||||||
| `--surface-ground` | #f8fafc | #0f172a | Page background |
|
| `--surface-ground` | #f8fafc | #0f172a | Page background |
|
||||||
|
| `--surface-hover` | #f1f5f9 | #334155 | Hover states |
|
||||||
| `--surface-border` | #e2e8f0 | #475569 | Borders |
|
| `--surface-border` | #e2e8f0 | #475569 | Borders |
|
||||||
| `--text-color` | #111827 | #f9fafb | Primary text |
|
| `--text-color` | #111827 | #f9fafb | Primary text |
|
||||||
| `--text-color-secondary` | #6b7280 | #d1d5db | Secondary text |
|
| `--text-color-secondary` | #6b7280 | #d1d5db | Secondary text |
|
||||||
@@ -528,9 +561,12 @@ Each color has a full scale (50-900) that inverts appropriately in dark mode:
|
|||||||
|
|
||||||
### Testing Dark Mode
|
### Testing Dark Mode
|
||||||
|
|
||||||
1. In browser DevTools: Set `prefers-color-scheme: dark`
|
**IMPORTANT:** Testează întotdeauna ambele scenarii!
|
||||||
2. In Playwright: `await page.emulateMedia({ colorScheme: 'dark' })`
|
|
||||||
3. System preference: Change OS dark mode setting
|
1. **Toggle manual:** Click buton temă în header (ciclează auto→light→dark)
|
||||||
|
2. **DevTools:** Rendering → Emulate CSS media → `prefers-color-scheme: dark`
|
||||||
|
3. **Playwright:** `await page.emulateMedia({ colorScheme: 'dark' })`
|
||||||
|
4. **System:** Change OS dark mode setting
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user