Context and Problem Statement
HDIM requires caching for:
Critical Constraint: HIPAA requires minimizing PHI exposure. Cached PHI must be invalidated quickly to respect patient consent revocations and data freshness requirements.
Decision Drivers
Considered Options
Decision Outcome
Chosen option: "Redis 7 with 5-minute PHI TTL"
Rationale: Redis provides:
Critical Policy: All PHI cached in Redis MUST have a maximum TTL of 5 minutes (300 seconds). This is enforced at the infrastructure level and cannot be overridden by application code.
Consequences
Positive
@Cacheable annotationsNegative
Mitigations:
Neutral
Pros and Cons of Options
Option 1: Redis 7 with 5-minute PHI TTL
In-memory data store with strict TTL enforcement.
| Criterion | Assessment |
|-----------|------------|
| Performance | Good - Sub-millisecond access |
| HIPAA Compliance | Good - Configurable TTL, encryption in transit |
| Spring Integration | Good - Spring Data Redis, Spring Cache |
| Multi-tenancy | Good - Key namespacing by tenant |
| Data Structures | Good - Rich set of data types |
| Cluster Support | Good - Redis Cluster for HA |
Summary: Best balance of performance, compliance, and flexibility.
Option 2: Memcached
Distributed memory caching system.
| Criterion | Assessment |
|-----------|------------|
| Performance | Good - Very fast for simple key-value |
| HIPAA Compliance | Neutral - TTL support but less feature-rich |
| Spring Integration | Neutral - Requires separate integration |
| Multi-tenancy | Neutral - Key-based isolation only |
| Data Structures | Bad - Simple key-value only |
| Cluster Support | Good - Distributed by design |
Summary: Fast but lacks rich data structures and features.
Option 3: Hazelcast
Java-based distributed caching and computing platform.
| Criterion | Assessment |
|-----------|------------|
| Performance | Good - In-memory performance |
| HIPAA Compliance | Neutral - TTL support, encryption available |
| Spring Integration | Good - Spring Cache support |
| Multi-tenancy | Good - Namespace support |
| Java Native | Good - Native Java integration |
| Operational Complexity | Neutral - More complex than Redis |
Summary: Good Java integration but less ecosystem support than Redis.
Option 4: Caffeine (Local Cache Only)
High-performance Java caching library.
| Criterion | Assessment |
|-----------|------------|
| Performance | Good - Fastest (no network) |
| HIPAA Compliance | Neutral - TTL support |
| Distributed | Bad - Local cache only, no sharing between instances |
| Spring Integration | Good - Spring Cache support |
| Operational Simplicity | Good - No infrastructure required |
Summary: Excellent for local caching but cannot share across instances.
Option 5: No Caching for PHI
Database-only access for all PHI data.
| Criterion | Assessment |
|-----------|------------|
| Performance | Bad - All requests hit database |
| HIPAA Compliance | Good - No cached PHI exposure |
| Simplicity | Good - No cache invalidation concerns |
| Database Load | Bad - Significantly higher load |
| Scalability | Bad - Database becomes bottleneck |
Summary: Safest for compliance but unacceptable performance impact.
Implementation Notes
Version Selected
Redis 7.2 - Latest stable release with enhanced performance
Deployment Model
TTL Policy (CRITICAL)
| Data Category | TTL | Rationale |
|---------------|-----|-----------|
| PHI (patient data) | 5 minutes (300s) | HIPAA minimum necessary |
| User sessions | 15 minutes | Security best practice |
| Reference data (code systems) | 1 hour | Infrequently changes |
| Measure definitions | 1 hour | Version-controlled |
| API rate limits | 1 minute | Short-term throttling |
Key Naming Convention
{tenantId}:{resourceType}:{resourceId}
Examples:
- TENANT001:patient:12345
- TENANT001:measure:BCS
- TENANT001:session:user-abc-123
- global:codesystem:icd10Cache Configuration
application.yml
spring:
data:
redis:
host: ${REDIS_HOST:localhost}
port: ${REDIS_PORT:6380}
password: ${REDIS_PASSWORD:}
timeout: 2000ms
lettuce:
pool:
max-active: 50
max-idle: 10
min-idle: 5
HIPAA Compliance - PHI cache TTL (DO NOT INCREASE)
cache:
phi:
ttl-seconds: 300 # 5 minutes maximum
reference:
ttl-seconds: 3600 # 1 hour
session:
ttl-seconds: 900 # 15 minutes
Spring Cache Integration
// PHI caching with 5-minute TTL (enforced by configuration)
@Cacheable(value = "patientData", key = "#tenantId + ':patient:' + #patientId")
public Patient getPatient(String patientId, String tenantId) {
return patientRepository.findByIdAndTenant(patientId, tenantId)
.orElseThrow(() -> new ResourceNotFoundException("Patient", patientId));
}
// Cache eviction on update
@CacheEvict(value = "patientData", key = "#tenantId + ':patient:' + #patient.id")
public Patient updatePatient(Patient patient, String tenantId) {
return patientRepository.save(patient);
}Cache Configuration Class
@Configuration
@EnableCaching
public class CacheConfig {
@Value("${cache.phi.ttl-seconds:300}")
private long phiTtlSeconds;
@Bean
public RedisCacheConfiguration phiCacheConfiguration() {
return RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofSeconds(phiTtlSeconds))
.disableCachingNullValues()
.serializeKeysWith(
RedisSerializationContext.SerializationPair.fromSerializer(
new StringRedisSerializer()))
.serializeValuesWith(
RedisSerializationContext.SerializationPair.fromSerializer(
new GenericJackson2JsonRedisSerializer()));
}
}Performance Targets
| Metric | Target | Actual (Dec 2024) |
|--------|--------|-------------------|
| Cache Hit Rate | >80% | 87% |
| Get Latency (p95) | <5ms | 2ms |
| Set Latency (p95) | <10ms | 4ms |
| Memory Usage | <2GB per tenant | 1.2GB avg |
Monitoring
Prometheus metrics (via Redis Exporter)
HIPAA Compliance Documentation
Why 5 Minutes?
The 5-minute PHI cache TTL balances:
Audit Trail
All cache operations are logged:
Encryption
Links
Version History
| Version | Date | Author | Changes |
|---------|------|--------|---------|
| 1.0 | 2024-Q3 | Architecture Team | Initial decision |
| 1.1 | 2024-12-30 | Architecture Team | Added TTL policy details, compliance section |
*This ADR follows the template in /docs/templates/ADR_TEMPLATE.md*