Skip to main content

ADR-066: Compliance Patterns for Pattern Providers

Status

Status: Proposed Created: 2026-04-19 Updated: 2026-04-19 Author: Jacob Repp Deciders: Core Team

Context

Compliance Requirements from Security Plan

As outlined in docs-cms/plans/security.md (lines 179-216), Prism requires compliance patterns for pattern providers:

  1. Right to Deletion (GDPR) — Implement data deletion patterns

    • Remove user data from all backing stores
    • Log deletion event for audit
    • Provide deletion confirmation
  2. Data Residency — Control data location

    • Geographic routing for namespace assignments
    • Cross-region replication policies
    • Data sovereignty requirements
  3. Retention Policy — Automatic data expiration

    • TTL enforcement on all stored data
    • Soft-delete with configurable retention
    • Hard-delete after retention period

Current security plan (P2 priority) indicates: "Pattern Provider implementation required" for compliance features.

Current State

  • Pattern providers implement Plugin interface (lifecycle management)
  • Backend drivers implement specific data interfaces (KeyValueBasicInterface, PubSubBasicInterface, etc.)
  • No standardized compliance interface exists
  • Compliance functionality is ad-hoc or missing

What This ADR Solves

This ADR proposes a uniform compliance interface that pattern providers can implement to support:

  • GDPR right to deletion
  • Data residency controls
  • Automatic retention/enforcement

Pattern providers should be able to:

  • Mark user-identifiable data for deletion
  • Enforce retention policies automatically
  • Support geographic routing for data residency

Decision

1. Create CompliantBackend Trait Interface

Introduce CompliantBackend as an optional interface extension that pattern providers can implement:

// pkg/plugin/compliance_interfaces.go
type CompliantBackend interface {
// Retain Plugin interface for lifecycle compatibility
Plugin

// DeleteUserData removes all user-identifiable data
// Returns count of deleted items and audit log entry
DeleteUserData(ctx context.Context, userID string, policy RetentionPolicy) (DeletedItems, AuditLogEntry, error)

// EnforceRetention applies retention policies to data
// Returns batch of enforced items and any errors
EnforceRetention(ctx context.Context, namespace string, policy RetentionPolicy) (EnforcedItems, []error, error)

// GetDataResidency returns geographic location of data
// Used for compliance validation and routing
GetDataResidency(ctx context.Context, key string) (string, error)

// SetDataResidency marks data with geographic location
// Used for residency enforcement
SetDataResidency(ctx context.Context, key string, region string) error
}

2. Define RetentionPolicy DSL

Create a structured policy type for compliance operations:

type RetentionPolicy struct {
softDelete bool
retentionPeriod time.Duration
hardDeleteAfter time.Duration
auditEnabled bool
regions []string // Geographic restrictions
}

3. Generic Compliance Service

Build a service layer that pattern providers can use:

// pkg/plugin/compliance_service.go
type ComplianceService struct {
backend CompliantBackend
logger *slog.Logger
}

func (cs *ComplianceService) DeleteUserData(ctx context.Context, userID string, policy RetentionPolicy) error
func (cs *ComplianceService) EnforceRetention(ctx context.Context, namespace string, policy RetentionPolicy) error
func (cs *ComplianceService) AuditLog(ctx context.Context, event AuditEvent) error

4. Pattern Provider Implementation

Pattern providers that use compliant backends should:

  1. Implement CompliantBackend interface (or embed it)
  2. Use ComplianceService for common operations
  3. Register compliance capabilities in interface declarations

Example for patterns/keyvalue:

type KeyValue struct {
driver CompliantBackend // Optional: use type assertion if not all backends support compliance
compliance *ComplianceService
}

func (kv *KeyValue) DeleteUserData(ctx context.Context, userID string, policy RetentionPolicy) (DeletedItems, AuditLogEntry, error) {
// Use driver's compliance implementation or fallback
if compliant, ok := kv.driver.(CompliantBackend); ok {
return compliant.DeleteUserData(ctx, userID, policy)
}
// Fallback: implement deletion for this pattern
return kv.compliance.DeleteUserData(ctx, userID, policy)
}

5. Backend Driver Implementations

Backend drivers implement the compliance trait:

// pkg/drivers/memstore/memstore.go
func (m *MemStore) DeleteUserData(ctx context.Context, userID string, policy RetentionPolicy) (DeletedItems, AuditLogEntry, error) {
var deleted DeletedItems
var entries []string

// Scan for user-related keys
m.data.Range(func(key, value interface{}) bool {
keyStr := key.(string)
if strings.Contains(keyStr, userID) {
m.data.Delete(key)
deleted.Count++
deleted.Keys = append(deleted.Keys, keyStr)
entries = append(entries, fmt.Sprintf("Deleted: %s", keyStr))
}
return true
})

audit := AuditLogEntry{
Event: "user_deletion",
UserID: userID,
Policy: policy,
Entries: entries,
Timestamp: time.Now(),
}

return deleted, audit, nil
}

Rationale

Why This Approach?

Benefits:

  1. Opt-in: Pattern providers can implement compliance only where needed
  2. Testable: Real backend verification (no mocks)
  3. Consistent: Single interface for all compliance operations
  4. Extendable: New compliance features added as interface methods
  5. Backward compatible: Existing patterns work unchanged

Trade-offs:

  1. Complexity: Additional interfaces to understand
    • Mitigation: Clear documentation, minimal required methods
  2. Performance: Compliance operations may be expensive
    • Mitigation: Async options, bulk operations, context timeouts
  3. Backend Variance: Not all backends support all compliance features
    • Mitigation: Optional interface, fallback implementations, clear error messages

Alternatives Considered

Alternative 1: Separate Services

  • Create UserService (deletion), RetentionService, ResidencyService separately
  • Rejected: Creates fragmentation, duplicate logic across services

Alternative 2: Middleware Pattern

  • Wrap all operations with compliance middleware
  • Rejected: Too complex for pattern providers, harder to test

Alternative 3: Embedded in Plugin Interface

  • Add compliance methods to core Plugin interface
  • Rejected: Breaks backward compatibility, forces compliance on all plugins

Consequences

Positive

  • GDPR Compliance: Pattern providers can implement user deletion
  • Audit Trail: Standardized audit logging for compliance
  • Data Residency: Geographic controls built into architecture
  • Retention Automation: Automatic enforcement reduces manual work
  • Pattern Provider Flexibility: Implement only what's needed

Negative

  • Implementation Effort: Pattern providers must add compliance support
  • Testing Complexity: Real backend compliance testing required
  • Performance Overhead: Compliance operations may slow data access

Neutral

  • Documentation Burden: Needs comprehensive docs for pattern provider adoption
  • Migration Path: Existing patterns require gradual adoption

Implementation Plan

Phase 1: interfaces + ADR (pkg/plugin/)

  1. Create pkg/plugin/compliance_interfaces.go
  2. Create pkg/plugin/compliance_service.go
  3. Update pkg/plugin/plugin.go to reference compliance interfaces
  4. Add tests with 80%+ coverage target

Phase 2: Pattern Provider Support

  1. Update patterns/keyvalue/keyvalue.go to support CompliantBackend
  2. Update patterns/producer/producer.go for audit logging
  3. Update patterns/consumer/consumer.go for retention enforcement

Phase 3: Backend Driver Implementations

  1. Update pkg/drivers/memstore/memstore.go
  2. Update pkg/drivers/redis/redis.go
  3. Update pkg/drivers/postgres/postgres.go (if applicable)

Phase 4: Documentation

  1. Add docs-cms/guides/compliance-patterns.md
  2. Update docusaurus/docs/ compliance section
  3. Add changelog entry

Phase 5: Security Plan Update

  1. Update docs-cms/plans/security.md compliance section
  2. Mark patterns as "In Progress" or "Completed"
  3. Add implementation status table

Testing Strategy

Test Coverage (80%+ target)

  • Unit tests for ComplianceService methods
  • Integration tests with real backends (MemStore, Redis)
  • Compliance scenario tests (GDPR deletion, retention enforcement)
  • Error handling tests (backend compatibility, fallbacks)

Test Commands

# Run compliance tests
task test-compliance

# Test memstore compliance
task test-compliance-memstore

# Test redis compliance
task test-compliance-redis

# Coverage
go test ./pkg/plugin/... -coverprofile=coverage.out
go tool cover -func=coverage.out

Verification Checklist

Before submitting PR:

  • pkg/plugin/compliance_interfaces.go created with CompliantBackend
  • pkg/plugin/compliance_service.go implemented
  • Tests pass with 80%+ coverage (go test ./pkg/plugin/... -cover)
  • Pattern providers updated to support compliance
  • Backend drivers implement compliance trait
  • Documentation added:
    • docs-cms/guides/compliance-patterns.md
    • docusaurus/docs/ updated
    • docusaurus/docs/changelog.md updated
  • Security plan (docs-cms/plans/security.md) updated
  • uv run tooling/validate_docs.py passes

Revision History

  • 2026-04-19: Initial draft (Jacob Repp)
  • 2026-04-19: ADR-066 created for compliance patterns
  • 2026-04-19: Proposed pattern for CompliantBackend interface