Files
roa2web-service-auto/backend/modules/reports/cache/keys.py
Marius Mutu c5e051ad80 feat: Migrate to ultrathin monolith architecture
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>
2025-12-29 23:48:14 +02:00

151 lines
4.1 KiB
Python

"""
Cache key generation utilities
"""
import hashlib
import json
from typing import Any, List, Optional
def generate_cache_key(cache_type: str, key_params: Optional[List[str]], args: tuple, kwargs: dict) -> str:
"""
Generate cache key from function parameters
Format: "{cache_type}:{param1_value}:{param2_value}:..."
Args:
cache_type: Type of cache (e.g., 'dashboard_summary', 'invoices')
key_params: List of parameter names to include in key
args: Positional arguments from function call
kwargs: Keyword arguments from function call
Returns:
Cache key string
Examples:
generate_cache_key('schema', ['company_id'], (123,), {})
-> "schema:123"
generate_cache_key('dashboard_summary', ['company', 'username'], (), {'company': '123', 'username': 'john'})
-> "dashboard_summary:123:john"
generate_cache_key('invoices', ['company', 'invoice_type', 'status'], (123, 'CLIENTI', 'neplatite'), {})
-> "invoices:123:CLIENTI:neplatite"
"""
key_parts = [cache_type]
if not key_params:
# No specific params - use all args/kwargs (fallback)
if args:
key_parts.extend([str(arg) for arg in args])
if kwargs:
# Sort kwargs for consistent key generation
sorted_kwargs = sorted(kwargs.items())
key_parts.extend([f"{k}={v}" for k, v in sorted_kwargs])
else:
# Extract specific params
for i, param_name in enumerate(key_params):
# Try to get from kwargs first
if param_name in kwargs:
value = kwargs[param_name]
# Then try positional args
elif i < len(args):
value = args[i]
else:
# Parameter not found - use placeholder
value = "none"
key_parts.append(str(value))
return ":".join(key_parts)
def generate_key_pattern(cache_type: str, company_id: Optional[int] = None) -> str:
"""
Generate cache key pattern for matching multiple keys
Used for invalidation by type or company
Args:
cache_type: Type of cache
company_id: Optional company ID to filter by
Returns:
Pattern string (prefix)
Examples:
generate_key_pattern('dashboard_summary')
-> "dashboard_summary:"
generate_key_pattern('dashboard_summary', 123)
-> "dashboard_summary:123"
"""
if company_id is not None:
return f"{cache_type}:{company_id}"
return f"{cache_type}:"
def hash_complex_params(params: dict) -> str:
"""
Generate hash for complex parameters (e.g., filters, queries)
Used when cache key would be too long with full param values
Args:
params: Dictionary of parameters to hash
Returns:
8-character hash string
Example:
filters = {'status': 'neplatite', 'date_from': '2024-01-01', 'date_to': '2024-12-31'}
hash_complex_params(filters)
-> "a3f8b2c1"
"""
# Sort keys for consistent hashing
sorted_params = json.dumps(params, sort_keys=True)
hash_obj = hashlib.sha256(sorted_params.encode())
# Return first 8 characters of hex digest
return hash_obj.hexdigest()[:8]
def extract_company_id_from_key(cache_key: str) -> Optional[int]:
"""
Extract company_id from cache key
Assumes format: "cache_type:company_id:..."
Args:
cache_key: Cache key string
Returns:
Company ID or None if not found
Example:
extract_company_id_from_key("dashboard_summary:123:john")
-> 123
"""
parts = cache_key.split(":")
if len(parts) >= 2:
try:
return int(parts[1])
except (ValueError, TypeError):
pass
return None
def extract_cache_type_from_key(cache_key: str) -> str:
"""
Extract cache_type from cache key
Args:
cache_key: Cache key string
Returns:
Cache type (first part before colon)
Example:
extract_cache_type_from_key("dashboard_summary:123:john")
-> "dashboard_summary"
"""
return cache_key.split(":")[0]