---
paths: {reports-app,data-entry-app}/backend/**/*.py
---

# Backend Patterns

## Router Factory Pattern
Use shared router factories instead of custom implementations:
```python
from shared.routes.companies import create_companies_router
from shared.routes.calendar import create_calendar_router

companies_router = create_companies_router(oracle_pool, cache_decorator=cached)
app.include_router(companies_router, prefix="/api/companies")
```

## Database Queries
- All queries use parameterized Oracle queries (no SQL injection)
- Schema lookup: `SELECT SCHEMA FROM CONTAFIN_ORACLE.V_NOM_FIRME`
- Company access: Join V_NOM_FIRME with VDEF_UTIL_FIRME

## Caching (reports-app)
- Use `@cached` decorator from `app/cache/decorators`
- Place logic in services, not routers
- Cache schema lookups (24h TTL)
- Cache user data (10-30 min TTL)

## Error Handling
```python
try:
    # Business logic
except HTTPException:
    raise  # Re-raise HTTP exceptions
except Exception as e:
    logger.error(...)
    raise HTTPException(500, "Internal error")
```

## Oracle Pool Pattern
```python
async with oracle_pool.get_connection() as connection:
    with connection.cursor() as cursor:
        cursor.execute(query, params)
```
