feat(api): add Redis session cache to reduce Appwrite API calls by ~90%

- Add SessionCacheService with 5-minute TTL Redis cache
- Cache validated sessions to avoid redundant Appwrite calls
- Add /api/v1/auth/me endpoint for retrieving current user
- Invalidate cache on logout and password reset
- Add session_cache config to auth section (Redis db 2)
- Fix Docker Redis hostname (localhost -> redis)
- Handle timezone-aware datetime comparisons

Security: tokens hashed before use as cache keys, explicit
invalidation on logout/password change, graceful degradation
when Redis unavailable.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-11-25 22:01:14 -06:00
parent a0635499a7
commit 8675f9bf75
7 changed files with 462 additions and 7 deletions

View File

@@ -86,6 +86,14 @@ class RateLimitingConfig:
tiers: Dict[str, RateLimitTier] = field(default_factory=dict)
@dataclass
class SessionCacheConfig:
"""Session cache configuration for reducing Appwrite API calls."""
enabled: bool = True
ttl_seconds: int = 300 # 5 minutes
redis_db: int = 2 # Separate from RQ (db 0) and rate limiting (db 1)
@dataclass
class AuthConfig:
"""Authentication configuration."""
@@ -104,6 +112,7 @@ class AuthConfig:
name_min_length: int
name_max_length: int
email_max_length: int
session_cache: SessionCacheConfig = field(default_factory=SessionCacheConfig)
@dataclass
@@ -229,7 +238,11 @@ class Config:
tiers=rate_limit_tiers
)
auth_config = AuthConfig(**config_data['auth'])
# Parse auth config with nested session_cache
auth_data = config_data['auth'].copy()
session_cache_data = auth_data.pop('session_cache', {})
session_cache_config = SessionCacheConfig(**session_cache_data) if session_cache_data else SessionCacheConfig()
auth_config = AuthConfig(**auth_data, session_cache=session_cache_config)
session_config = SessionConfig(**config_data['session'])
marketplace_config = MarketplaceConfig(**config_data['marketplace'])
cors_config = CORSConfig(**config_data['cors'])