# Changelog

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.3.11] - 2026-02-18

### Changed
- **Configurable Redis TTL**: `redis_access_cache_ttl` and `redis_expression_cache_ttl` are now `Optional[int]`
  - Set to `None` to disable time-based expiry entirely (keys only cleared by event-based invalidation)
  - Default behavior unchanged: `redis_access_cache_ttl=3600` (1 hour), `redis_expression_cache_ttl=600` (10 minutes)

### Added
- **`LibraryConfig._parse_optional_int()`** helper for parsing optional integer env vars
- **Env var support**: `REDIS_ACCESS_CACHE_TTL=0` and `REDIS_EXPRESSION_CACHE_TTL=0` now disable TTL (previously ignored)

### Usage
```python
# Disable TTL entirely (event-based invalidation only)
config = LibraryConfig(
    redis_access_cache_ttl=None,
    redis_expression_cache_ttl=None,
)

# Or via env vars
REDIS_ACCESS_CACHE_TTL=0       # 0 = no expiry
REDIS_EXPRESSION_CACHE_TTL=0   # 0 = no expiry
```

### Migration Notes
- **No Breaking Changes**: Default values unchanged
- **`redis_client.py`**: Already handled `None` TTL correctly — no changes needed

## [0.3.10] - 2026-02-12

### Fixed
- **CRITICAL: Redis Event Loop Shutdown Error**: Fixed "Event loop is closed" errors during application shutdown
  - Added `_is_event_loop_running()` check before all Redis operations
  - Graceful handling of RuntimeError when event loop is closing
  - Added `_shutting_down` flag to prevent operations during shutdown
  - Cross-platform support (Windows ProactorEventLoop and Unix SelectorEventLoop)
  - Redis operations now check event loop status and skip gracefully during shutdown
  - Changes in `medha_one_access/core/redis_client.py`:
    - Lines 73-97: Added `_is_event_loop_running()` helper method
    - Lines 195-215: Enhanced `delete()` with event loop checks and shutdown handling
    - Lines 227-254: Enhanced `delete_pattern()` with event loop checks
    - Lines 256-278: Enhanced `close()` with graceful shutdown handling

- **CRITICAL: Sync Methods Missing Redis Cache Invalidation**: Fixed 7 sync controller methods that were NOT clearing Redis cache before recalculation
  - **Impact**: Stale permissions served to users for 100-500ms until background recalculation completed
  - **Root Cause**: Sync methods only called `_trigger_auto_recalculation()` but skipped `_mark_summaries_stale()` which clears Redis
  - **Fixed Methods**:
    - `create_user()` (line 2125-2129): Now clears Redis cache for affected users
    - `update_user()` (line 2188-2192): Now clears Redis cache for affected users
    - `delete_user()` (line 2221-2225): Now clears Redis cache for affected users
    - `create_artifact()` (line 2301-2305): Now clears Redis cache for affected users
    - `delete_artifact()` (line 3198-3202): Now clears Redis cache for affected users
    - `create_access_rule()` (line 2365-2369): Now clears Redis cache for affected users
    - `delete_access_rule()` (line 3060-3063): Now clears Redis cache for affected users
  - **Already Correct**: `update_access_rule()` and `update_artifact()` already had proper cache invalidation
  - **Consistency**: All sync methods now match async versions' cache invalidation behavior

### Changed
- Redis client now performs comprehensive event loop checks before async operations
- All sync CRUD methods now follow two-phase invalidation pattern (Redis DELETE + PostgreSQL UPDATE)
- Improved error logging: "Event loop is closed" now logged as DEBUG instead of WARNING during shutdown
- Enhanced shutdown sequence to set flag before closing connections

### Documentation
- Added `SYNC_REDIS_CACHE_FIX.md` - Complete documentation of sync method cache invalidation fixes
- Updated `REDIS_CACHE_INVALIDATION_SUMMARY.md` - Comprehensive reference of all cache invalidation points

### Technical Details
- **Event Loop Fix**:
  - Checks `loop.is_closed()` (works on all platforms)
  - Checks `loop.is_closing()` when available (Unix only)
  - Catches `RuntimeError` and checks for "Event loop is closed" message
  - Prevents new operations when `_shutting_down=True`
- **Cache Invalidation Fix**:
  - All sync methods now call `_mark_summaries_stale()` before `_trigger_auto_recalculation()`
  - Ensures Redis cache deleted immediately (1-10ms)
  - Ensures PostgreSQL marked stale for durability (30-50ms)
  - Prevents stale cache data during recalculation window

### Migration Notes
- **No Breaking Changes**: These are bug fixes with no API changes
- **Performance Impact**: None - actually prevents error log spam during shutdown
- **Recommended Action**: Update immediately to fix shutdown errors and cache consistency issues
- **Backward Compatible**: Works with all existing code without modifications

## [0.3.9] - 2026-02-12

### Fixed
- **Critical Fix**: Fixed sync controller Redis initialization to work with running event loops
  - Changed `_init_redis_sync()` to use `_run_async_redis()` helper for ping test
  - Fixes `RuntimeWarning: coroutine 'RedisClient.ping' was never awaited`
  - Redis now properly initializes in FastAPI/Uvicorn async environments
  - Resolves issue where Redis was being disabled in production

## [0.3.8] - 2026-02-12

### Fixed
- **Critical Bug Fix**: Added missing `_mark_summaries_stale()` call in sync `AccessController.update_access_rule()`
  - Redis cache invalidation now works properly when access rules are updated via sync controller
  - Ensures cache consistency between Redis L1 and PostgreSQL L2
  - Fixes issue where stale cache entries were not cleared on rule updates

### Changed
- Sync controller now properly invalidates Redis cache on all CRUD operations
- Improved cache invalidation logging for better debugging

## [0.3.7] - 2026-02-12

### Added
- **Full Redis Support in Sync Controller**: The sync `AccessController` now has complete Redis caching support
  - Hybrid L1 (Redis) + L2 (PostgreSQL) caching strategy
  - Dual-write to both Redis and PostgreSQL for data durability
  - Two-phase cache invalidation (fast Redis DELETE + durable PostgreSQL UPDATE)
  - Automatic async-to-sync wrapper for Redis operations (`_run_async_redis()`)
  - Graceful fallback to PostgreSQL when Redis is unavailable
  - Redis backfill from PostgreSQL on L1 cache miss

### Changed
- Both sync and async controllers now have feature parity for Redis caching
- `mount_access_control_routes()` now benefits from Redis performance improvements
- Improved error handling for Redis operations in sync context

## [0.3.6] - 2026-02-12

### Added
- **Redis Integration**: Full hybrid Redis + PostgreSQL caching architecture
  - Azure Redis Cache support with SSL/TLS on port 6380
  - Two-tier caching: Redis L1 (1-3ms) + PostgreSQL L2 (10-30ms)
  - Expression caching for user and resource group resolution
  - Dual-write strategy for cache consistency
  - Fast two-phase cache invalidation (Redis DELETE + PostgreSQL UPDATE)
  - Automatic fallback to PostgreSQL when Redis unavailable
  - Backward compatible - works without Redis configuration

- **New Configuration Parameters**:
  - `redis_host` - Redis server hostname (optional, enables Redis when set)
  - `redis_port` - Redis server port (default: 6379)
  - `redis_password` - Redis authentication password
  - `redis_ssl` - Enable SSL/TLS for Azure Redis (default: False)
  - `redis_decode_responses` - Auto-decode Redis responses to strings (default: True)
  - `redis_db` - Redis database number (default: 0)
  - `redis_socket_timeout` - Socket timeout in seconds (default: 5)
  - `redis_socket_connect_timeout` - Connection timeout in seconds (default: 5)
  - `redis_max_connections` - Connection pool size (default: 10)
  - `redis_access_cache_ttl` - TTL for access summaries in seconds (default: 3600)
  - `redis_expression_cache_ttl` - TTL for expression resolution in seconds (default: 600)

- **New Components**:
  - `RedisClient` class in `medha_one_access.core.redis_client` - Async Redis wrapper with graceful error handling
  - `ExpressionCache` class in `medha_one_access.core.controller` - Expression resolution caching

### Changed
- **Performance Improvements**:
  - Access checks: 10x faster (10-30ms → 1-3ms with Redis L1 cache hit)
  - Cache invalidation: 20x faster (50-200ms → 5-10ms)
  - Expression resolution: 10-15x faster with caching
  - Bulk artifact updates: 10x faster (2-5s → 200-500ms for 1000 users)

- Updated `_get_cached_user_access()` to check Redis L1 cache first, then PostgreSQL L2
- Updated `_store_user_access_cache()` to write to both Redis and PostgreSQL
- Updated `_mark_summaries_stale()` for fast two-phase invalidation
- Updated all affected user methods to use expression caching
- Added cache invalidation to CRUD operations for user/resource groups

### Dependencies
- Added `redis[hiredis]>=5.0.0` for high-performance Redis operations with hiredis C parser

### Documentation
- Added comprehensive `REDIS_OPTIMIZATION_PLAN.md` with architecture details
- Updated package description to mention Redis caching capability

### Migration Guide: 0.3.5 → 0.3.6

#### For Existing Users (No Redis)
No changes required! The library works exactly as before. Simply upgrade:

```bash
pip install --upgrade medha-one-access
```

#### For New Redis Users
1. Install/upgrade the package:
```bash
pip install --upgrade medha-one-access
```

2. Add Redis configuration to your `LibraryConfig`:
```python
from medha_one_access import LibraryConfig

config = LibraryConfig(
    database_url="postgresql://...",
    secret_key="your-secret-key",
    # Add these Redis parameters
    redis_host="your-redis-host.redis.cache.windows.net",
    redis_port=6380,
    redis_password="your-redis-password",
    redis_ssl=True,  # For Azure Redis
    redis_db=0,
)
```

3. Initialize controller as usual:
```python
controller = AsyncAccessController(config)
await controller.initialize()
# Should see: "INFO: Redis cache enabled - your-redis-host:6380"
```

#### Performance Expectations
With Redis enabled:
- **Access checks**: 10x faster (1-3ms vs 10-30ms)
- **Cache invalidation**: 20x faster (5-10ms vs 50-200ms)
- **Expression resolution**: 10-15x cached speedup
- **Bulk operations**: 10x faster for large user sets

#### Troubleshooting
If you see `INFO: Redis not configured`, check:
1. `redis_host` parameter is set (not None)
2. Package version is 0.3.6: `pip show medha-one-access`
3. Application restarted after upgrade

If you see `WARNING: Redis connection failed`, check:
1. Redis server is accessible
2. Credentials are correct
3. Firewall allows connection to Redis port
4. SSL is enabled for Azure Redis (`redis_ssl=True`)

Library will automatically fall back to PostgreSQL-only caching.

### Notes
- Redis is **optional** - library works exactly as before if `redis_host` is not configured
- All Redis operations have graceful error handling and automatic fallback
- Recommended for production workloads with >1000 users or frequent access checks
- Azure Redis Cache fully supported with SSL/TLS

## [0.3.5] - 2026-02-09

### Fixed
- **CRITICAL: Silent Exception in Background Recalculation**: Fixed silent exception handling in `_get_affected_users_for_artifact_change()` that prevented background recalculation from working
  - **Root Cause**: Broad exception handler (`except Exception: return []`) was silently swallowing all errors, causing the method to return empty list on any failure
  - **Impact**: When artifact updates occurred, no background recalculation was triggered because affected user discovery failed silently
  - **Symptom**: Missing logs for "Marked X summaries as stale" and "Submitted background recalculation task", but artifact updates still succeeded
  - **Fix**: Added comprehensive error logging to diagnose silent failures:
    - DEBUG logs showing resource groups and direct rules found
    - WARNING logs for individual group/rule processing failures
    - ERROR logs with full traceback when entire method fails
    - INFO log showing total affected users found
  - **Files Changed**:
    - `medha_one_access/core/controller.py`:
      - Lines 944-1011 (async version): Added 5 new logging statements
      - Lines 3057-3113 (sync version): Added 5 new logging statements
      - Lines 509, 2778: Added "No affected users found" log when skipping recalculation

### Changed
- **Error Visibility**: Exception handling now logs errors before returning empty list instead of silently failing
- **Debugging Support**: Added detailed logging at each stage of affected user discovery to diagnose issues
- **Performance Monitoring**: INFO log shows total affected users found for each artifact change

### Technical Details
- **Logging Added**:
  - `DEBUG: Found X resource groups to check for artifact 'id'` - Shows how many groups need checking
  - `DEBUG: Found X direct rules for artifact 'id'` - Shows how many direct rules found
  - `WARNING: Error processing resource group 'id': {error}` - Individual group failures
  - `WARNING: Error processing access rule 'id': {error}` - Individual rule failures
  - `INFO: Found X affected users for artifact 'id' change` - Final count before recalculation
  - `INFO: No affected users found for artifact 'id' update - skipping recalculation` - Distinguishes legitimate empty result from error
  - `ERROR: Failed to get affected users for artifact 'id': {error}` - Top-level failures with traceback

### Migration Notes
- **No Breaking Changes**: Only adds logging, does not change behavior
- **Log Volume Impact**: Adds ~5 log lines per artifact update operation
- **Debugging**: These logs help diagnose why background recalculation may not be triggered
- **Recommended Action**: Update to this version to get visibility into background recalculation issues

## [0.3.4] - 2026-01-27

### Added
- **Configurable Time-Based Cache Expiration**: Added ability to disable time-based cache expiration for systems that rely solely on event-based invalidation
  - **New Configuration Parameters**:
    - `enable_time_based_cache_expiration: bool = True` - Enable/disable time-based cache age checking (default: True for backward compatibility)
    - `default_cache_age_minutes: int = 60` - Default maximum cache age in minutes when time-based expiration is enabled
  - **Environment Variables**:
    - `MEDHA_ENABLE_TIME_BASED_CACHE_EXPIRATION` - Set to "false" to disable time-based expiration
    - `MEDHA_DEFAULT_CACHE_AGE_MINUTES` - Configure default cache age (default: 60)
  - **Use Case**: For systems with robust event-based invalidation and no time-constrained access rules, disabling time-based expiration improves performance
  - **Performance Impact**: ~5-10% faster cache reads when disabled (eliminates timestamp calculations)
  - **Files Changed**:
    - `medha_one_access/core/config.py`: Added new configuration parameters
    - `medha_one_access/core/controller.py`: Modified `_get_cached_user_access()` methods (async line ~823-858, sync line ~2371-2406)
    - `README.md`: Added comprehensive "Cache Expiration Strategy" documentation section

### Changed
- **Cache Expiration Logic**: Time-based expiration now controlled by configuration flag instead of being always active
  - When enabled (default): Behavior unchanged - cache expires based on age AND data changes
  - When disabled: Cache only expires on data changes (event-based `is_stale` flag)
  - Cache age metadata still calculated for monitoring even when time-based expiration is disabled

### Documentation
- Added "Cache Expiration Strategy" section to README explaining:
  - Event-based vs time-based invalidation
  - When to enable/disable time-based expiration
  - Configuration examples (programmatic and environment variables)
  - Performance impact comparison
- Created detailed implementation plan in `CACHE_EXPIRATION_OPTIMIZATION.md`

### Migration Notes
- **No Breaking Changes**: Default behavior is unchanged (`enable_time_based_cache_expiration=True`)
- **Opt-in Feature**: Explicitly set `enable_time_based_cache_expiration=False` to disable time-based expiration
- **Recommended For**:
  - Systems with no time-constrained access rules
  - Robust background recalculation enabled (`auto_recalc_mode="batched"`)
  - All database changes go through the API (no direct SQL modifications)
  - Consistent freshness requirements across all consumers

## [0.3.3] - 2025-01-13

### Fixed
- **CRITICAL: Transaction Rollback Error**: Fixed SQLAlchemy error "Can't reconnect until invalid transaction is rolled back" that occurred on EVERY access resolution request
  - **Root Cause**: When `scalar_one_or_none()` raised an exception (e.g., "Multiple rows found"), the error handler attempted to execute a debug query within the same invalid transaction
  - **Impact**: All async access resolution requests were failing with transaction errors, making the system unusable
  - **Symptom**: Error message "Failed to resolve user access: Can't reconnect until invalid transaction is rolled back. Please rollback() fully before proceeding (Background on this error at: https://sqlalche.me/e/20/8s2b)"
  - **Fix**: Removed debug queries from exception handlers that were executing within invalid transaction states
  - **Files Changed**:
    - `medha_one_access/core/resolver.py`:
      - Line 1205-1219: `AsyncBODMASResolver.resolve_user_access()` - User lookup error handler
      - Line 1299-1314: `AsyncBODMASResolver.resolve_user_access()` - Artifact lookup error handler
      - Line 1383-1398: `AsyncBODMASResolver.resolve_resource_access()` - Resource lookup error handler
    - `medha_one_access/core/controller.py`:
      - Line 17: Added SQLAlchemy exception imports (`InvalidRequestError`, `PendingRollbackError`, `DBAPIError`)
      - Line 604-620: Added specific error handling for transaction and database errors with helpful diagnostics

### Changed
- **Error Handling**: Exception handlers no longer attempt to query the database when transaction is in invalid state
- **Error Messages**: Improved error messages to provide clearer guidance without requiring additional database queries
- **Transaction Safety**: All async database operations now properly respect transaction boundaries

### Technical Details
- **Before**: `scalar_one_or_none()` exception → catch → execute debug query → "Can't reconnect" error
- **After**: `scalar_one_or_none()` exception → catch → raise helpful error message → transaction rolls back cleanly
- **Why It Failed Always**: The v0.3.2 fix added database queries to group detection methods, increasing query frequency and making this bug trigger on every request instead of intermittently
- **Session Management**: The `AsyncDatabaseManager.session_scope()` context manager properly handles rollback, but only if no queries are attempted after initial failure

### Migration Notes
- **No Breaking Changes**: This fix only improves error handling without changing API behavior
- **Performance Impact**: None - actually improved by removing unnecessary debug queries
- **Recommended Action**: Update to this version immediately if experiencing transaction errors

## [0.3.2] - 2025-01-12

### Fixed
- **CRITICAL: Artifact Group Access Resolution Bug**: Fixed major bug in `_involves_resource_groups()` and `_involves_user_groups()` methods that prevented proper access resolution for groups
  - **Root Cause**: Heuristic check only detected groups if their IDs contained keywords like "group", "cluster", "team", etc.
  - **Impact**: Resource/user groups without these keywords were incorrectly treated as individual entities, causing incomplete BODMAS resolution
  - **Symptom**: New user access wasn't fully resolved for artifact groups until those groups were modified in the UI
  - **Fix**: Replaced keyword-based heuristic with proper database queries to check entity types (RESOURCEGROUP, USERGROUP)
  - **Files Changed**:
    - `medha_one_access/core/resolver.py` (lines 967-989 for sync, 1978-2032 for async)

### Changed
- **Synchronous Resolver**: `_involves_user_groups()` and `_involves_resource_groups()` now query database to check actual entity types
- **Async Resolver**: Methods now process all expressions to avoid async/sync access issues, with actual filtering during expression resolution

### Technical Details
- **Before**: `return any(indicator in expression_lower for indicator in ["group", "cluster", ...])`
- **After (Sync)**: Database query to check `Artifact.type == "RESOURCEGROUP"` or `User.type == "USERGROUP"`
- **After (Async)**: Return True for all valid expressions to ensure comprehensive processing
- **Fallback**: If parsing fails, assumes group involvement to prevent skipping rules
- **BODMAS Steps Affected**: Steps 1 (UserGroup×ResourceGroup) and 3 (User×ResourceGroup) are now correctly executed

### Migration Notes
- **No Breaking Changes**: This fix improves access resolution accuracy without changing API
- **Performance Impact**: Minimal - adds lightweight database query for sync resolver
- **Recommended Action**: Update to this version immediately to fix access resolution issues

## [0.2.2] - 2025-08-26

### Fixed
- **Expression Validation**: Added support for additional common characters in entity names:
  - Colons `:` (e.g., `"Entity: Test"`)
  - Commas `,` (e.g., `"Entity, Demo"`) 
  - Apostrophes `'` (e.g., `"FD's Snapshot"`)
- **Character Validation**: Updated allowed character set for comprehensive entity name support

### Changed
- **Validation Regex**: Enhanced pattern to: `r"[^a-zA-Z0-9_+\-|.\s@&#\"():,']"`
- **Error Messages**: Updated to include colons, commas, and apostrophes in allowed characters list

## [0.2.1] - 2025-08-26

### Fixed
- **Expression Validation**: Added support for parentheses `()` in entity names (e.g., `"Manpower Budget (Input to Finance) FY26"`)
- **Character Validation**: Updated allowed character set to include parentheses for entity names with brackets

### Changed
- **Validation Regex**: Updated validation pattern to allow parentheses: `r'[^a-zA-Z0-9_+\-|.\s@&#"()]'`
- **Error Messages**: Updated validation error messages to include parentheses in allowed characters list

## [0.2.0] - 2025-08-26

### Added
- **Quoted Entity Support**: Added support for quoted entities in expressions to handle entity names with hyphens and special characters
- **Enhanced Expression Validation**: Added validation for properly matched quotes in expressions

### Fixed
- **Critical Expression Parsing Bug**: Fixed major bug where entity IDs containing hyphens (e.g., `user-service-api`) were incorrectly parsed as mathematical operations
- **Expression Validation**: Updated validation to allow quotes in expressions while maintaining security

### Changed
- **Expression Parser**: Updated core expression parsing regex to support quoted entities: `"entity-with-hyphens"`
- **Backward Compatibility**: Maintained 100% compatibility with existing unquoted expressions

### Technical Details
- Updated `ExpressionParser.parse_expression()` regex pattern to: `r'([+-]?)(".*?"|[^+-]+)'`
- Added automatic quote stripping in token processing
- Enhanced `validate_expression()` to check for unmatched quotes
- Updated allowed character validation to include quote characters

### Migration
- **No Breaking Changes**: All existing expressions continue to work unchanged
- **New Feature**: Entities with special characters can now be quoted for proper parsing
- **Examples**: 
  - Old (broken): `user-service-api+admin-panel` 
  - New (working): `"user-service-api"+"admin-panel"`
  - Still works: `simpleuser+basicgroup`

## [0.1.1] - 2025-08-25

### Fixed
- **Pagination Defaults**: Fixed hardcoded 100-record limits in all list methods (list_users, list_artifacts, list_access_rules)
- **User Group Resolution**: Fixed `get_usergroup_members` method to use correct `resolve_user_expression` method instead of non-existent `resolve_expression`
- **Query Optimization**: Updated all list methods to support optional limit parameter for unlimited record loading

### Changed
- **list_users()**: Changed limit parameter from `int = 100` to `Optional[int] = None`
- **list_artifacts()**: Changed limit parameter from `int = 100` to `Optional[int] = None` 
- **list_access_rules()**: Changed limit parameter from `int = 100` to `Optional[int] = None`
- **Query Logic**: Added conditional query execution to apply limit only when specified

## [0.1.0] - 2025-08-19

### Added
- Initial release of Access Control Library
- BODMAS-based access resolution engine with 4-step priority system
- Expression-based user and resource grouping with + (include) and - (exclude) operators
- Time-based access constraints (date ranges, time windows, day-of-week restrictions)
- Comprehensive audit trails for access decisions
- SQLAlchemy models and Pydantic schemas for all entities
- Database management with Alembic migrations
- AccessController class providing clean Python API
- CLI tools for database management, data import/export, and access checking
- FastAPI integration module for optional web APIs
- Complete test suite with fixtures and examples
- Type hints and py.typed marker for full typing support
- Support for PostgreSQL and SQLite databases
- Hierarchical organization structures
- Context managers for database sessions
- Expression validation and error handling

### Supported Features
- **User Management**: Create individual users and user groups with expressions
- **Resource Management**: Create individual resources and resource groups with expressions
- **Access Rules**: Define flexible access rules with user/resource expressions and permissions
- **Time Constraints**: Apply temporal restrictions to access rules
- **BODMAS Resolution**: Mathematical precedence-based access resolution
- **Audit Trails**: Detailed logging of access resolution steps
- **CLI Interface**: Command-line tools for all operations
- **REST API**: Optional FastAPI integration for web services
- **Database Support**: PostgreSQL (recommended) and SQLite
- **Migration Support**: Alembic-based database schema management

### Technical Specifications
- Python 3.8+ support
- SQLAlchemy 2.0+ with async support
- Pydantic v2 for data validation
- FastAPI for optional web API
- Click for CLI interface
- Comprehensive test coverage
- Type hints throughout
- Modern Python packaging (pyproject.toml)

## [Unreleased]

### Planned Features
- Redis caching for improved performance
- Webhook notifications for access events
- LDAP/Active Directory integration
- Role-based access control (RBAC) helpers
- Attribute-based access control (ABAC) extensions
- GraphQL API support
- Performance optimizations and query optimization
- Additional database backend support (MySQL, MongoDB)
- Docker containerization
- Kubernetes deployment examples