# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Integration Package Overview

The integration package (`com.ycwl.basic.integration`) is responsible for external microservice integrations using Spring Cloud OpenFeign and Nacos service discovery. It provides a standardized approach for calling external services with proper error handling, configuration management, and response processing.

## Architecture

### Core Components

#### Common Infrastructure (`com.ycwl.basic.integration.common`)
- **IntegrationProperties**: Centralized configuration properties for all integrations
- **FeignConfig**: Global Feign configuration with error decoder and request interceptors
- **FeignErrorDecoder**: Custom error decoder that converts Feign errors to IntegrationException
- **IntegrationException**: Standardized exception for integration failures
- **CommonResponse/PageResponse**: Standard response wrappers for external service calls
- **ConfigValueUtil**: Utility for handling configuration values
- **IntegrationFallbackService**: Universal fallback service for handling integration failures

#### Service-Specific Integrations
Currently implemented:
- **Scenic Integration** (`com.ycwl.basic.integration.scenic`): ZT-Scenic microservice integration
- **Device Integration** (`com.ycwl.basic.integration.device`): ZT-Device microservice integration
- **Render Worker Integration** (`com.ycwl.basic.integration.render`): ZT-Render-Worker microservice integration
- **Questionnaire Integration** (`com.ycwl.basic.integration.questionnaire`): ZT-Questionnaire microservice integration
- **Profit Share Integration** (`com.ycwl.basic.integration.profitshare`): ZT-ProfitShare microservice integration for revenue sharing
- **Message Integration** (`com.ycwl.basic.integration.message`): ZT-Message Kafka producer integration

### Integration Pattern

Each external service integration follows this structure:
```
service/
├── client/          # Feign clients for HTTP calls
├── config/          # Service-specific configuration
├── dto/             # Data transfer objects
└── service/         # Service layer with business logic
```

## Integration Fallback Mechanism

### Overview
The integration package includes a comprehensive fallback mechanism that provides automatic degradation when external microservices are unavailable or return errors. This mechanism ensures system resilience and maintains service availability even when dependencies fail.

### Core Components

#### IntegrationFallbackService
Universal fallback service that handles failure degradation for all microservice integrations:

**Key Features:**
- **Automatic Fallback**: Transparently handles service failures and returns cached results
- **Configurable TTL**: Service-specific cache TTL configuration (default: 7 days)
- **Cache Management**: Comprehensive cache statistics, cleanup, and monitoring
- **Service Isolation**: Per-service cache namespacing and configuration
- **Operation Types**: Supports both query operations (return cached data) and mutation operations (ignore failures with history)

**Core Methods:**
```java
// Query operations with fallback
<T> T executeWithFallback(String serviceName, String cacheKey, Supplier<T> operation, Class<T> resultClass)

// Mutation operations with fallback
void executeWithFallback(String serviceName, String cacheKey, Runnable operation)

// Cache management
boolean hasFallbackCache(String serviceName, String cacheKey)
void clearFallbackCache(String serviceName, String cacheKey)
void clearAllFallbackCache(String serviceName)
FallbackCacheStats getFallbackCacheStats(String serviceName)
```

### Fallback Strategy

#### Query Operations (GET methods) - WITH FALLBACK
1. **Normal Execution**: Execute the primary operation
2. **Success Handling**: Store successful result in fallback cache for future degradation
3. **Failure Handling**: On failure, attempt to retrieve cached result from previous success
4. **Final Fallback**: If no cached result exists, propagate the original exception

#### Mutation Operations (PUT/POST/DELETE methods) - NO FALLBACK
1. **Direct Execution**: Execute the primary operation directly without fallback
2. **Success Handling**: Operation completes successfully
3. **Failure Handling**: Immediately propagate the original exception to caller
4. **Rationale**: Users need to know if their create/update/delete operations truly succeeded or failed

### Configuration

#### Properties Structure
```yaml
integration:
  fallback:
    enabled: true                    # Global fallback switch
    cachePrefix: "integration:fallback:"  # Global cache prefix
    defaultTtlDays: 7               # Default cache TTL in days
    
    # Service-specific configurations
    scenic:
      enabled: true                 # Service-specific fallback switch
      ttlDays: 10                  # Custom TTL for scenic service
      cachePrefix: "scenic:fallback:"  # Custom cache prefix (optional)
    
    device:
      enabled: true
      ttlDays: 5                   # Custom TTL for device service
```

#### Configuration Priority
1. **Service-specific settings**: Override global defaults when specified
2. **Global defaults**: Used when service-specific settings are not provided
3. **Hardcoded defaults**: Final fallback when no configuration is available

### Cache Key Strategy

Cache keys follow a standardized naming convention:
```
{cachePrefix}{serviceName}:{operationType}:{resourceId}
```

**Examples:**
- `integration:fallback:zt-device:device:1001` - Device info cache
- `integration:fallback:zt-device:device:config:1001` - Device config cache  
- `integration:fallback:zt-scenic:scenic:2001` - Scenic info cache
- `integration:fallback:zt-scenic:scenic:flat:config:2001` - Scenic flat config cache

## Scenic Integration (ZT-Scenic Microservice)

### Key Components

#### Feign Clients
- **ScenicV2Client**: Main scenic operations (CRUD, filtering, listing)
- **ScenicConfigV2Client**: Scenic configuration management
- **DefaultConfigClient**: Default configuration operations

#### Services
- **ScenicIntegrationService**: High-level scenic operations (with automatic fallback)
- **ScenicConfigIntegrationService**: Configuration management (with automatic fallback)
- **DefaultConfigIntegrationService**: Default configuration handling

#### Configuration
```yaml
integration:
  scenic:
    enabled: true
    serviceName: zt-scenic
    connectTimeout: 5000
    readTimeout: 10000
    retryEnabled: false
    maxRetries: 3
```

### Usage Examples

#### Basic Scenic Operations (with Automatic Fallback)
```java
@Autowired
private ScenicIntegrationService scenicService;

// Get scenic with configuration (automatically falls back to cache on failure)
ScenicV2WithConfigDTO scenic = scenicService.getScenicWithConfig(scenicId);

// Get scenic basic info (automatically falls back to cache on failure)
ScenicV2DTO scenicInfo = scenicService.getScenic(scenicId);

// Get flat configuration (automatically falls back to cache on failure)
Map<String, Object> config = scenicService.getScenicFlatConfig(scenicId);

// Create new scenic (direct operation, fails immediately on error)
CreateScenicRequest request = new CreateScenicRequest();
request.setName("Test Scenic");
ScenicV2DTO result = scenicService.createScenic(request);

// Update scenic (direct operation, fails immediately on error)
UpdateScenicRequest updateRequest = new UpdateScenicRequest();
updateRequest.setName("Updated Scenic");
ScenicV2DTO updated = scenicService.updateScenic(scenicId, updateRequest);

// Filter scenics (no fallback for complex queries)
ScenicFilterRequest filterRequest = new ScenicFilterRequest();
// configure filters...
ScenicFilterPageResponse response = scenicService.filterScenics(filterRequest);
```

#### Configuration Management (with Automatic Fallback)
```java
@Autowired
private ScenicConfigIntegrationService configService;

// Get flat configuration (automatically falls back to cache on failure)
Map<String, Object> config = configService.getFlatConfigs(scenicId);

// Batch update configurations (direct operation, fails immediately on error)
BatchConfigRequest batchRequest = new BatchConfigRequest();
// configure batch updates...
BatchUpdateResponse result = configService.batchUpdateConfigs(scenicId, batchRequest);

// Batch flat update configurations (direct operation, fails immediately on error)
Map<String, Object> flatUpdates = new HashMap<>();
flatUpdates.put("max_visitors", "5000");
flatUpdates.put("opening_hours", "08:00-18:00");
BatchUpdateResponse flatResult = configService.batchFlatUpdateConfigs(scenicId, flatUpdates);
```

#### Fallback Cache Management for Scenics
```java
@Autowired  
private IntegrationFallbackService fallbackService;

// Check fallback cache status
boolean hasScenicCache = fallbackService.hasFallbackCache("zt-scenic", "scenic:2001");
boolean hasConfigCache = fallbackService.hasFallbackCache("zt-scenic", "scenic:flat:configs:2001");

// Get cache statistics
IntegrationFallbackService.FallbackCacheStats stats = fallbackService.getFallbackCacheStats("zt-scenic");
log.info("Scenic fallback cache: {} items, TTL: {} days", stats.getTotalCacheCount(), stats.getFallbackTtlDays());

// Clear specific cache
fallbackService.clearFallbackCache("zt-scenic", "scenic:2001");

// Clear all scenic caches
fallbackService.clearAllFallbackCache("zt-scenic");
```

## Device Integration (ZT-Device Microservice)

### Key Components

#### Feign Clients
- **DeviceV2Client**: Main device operations (CRUD, filtering, listing)
- **DeviceConfigV2Client**: Device configuration management
- **DefaultConfigClient**: Default configuration management

#### Services
- **DeviceIntegrationService**: High-level device operations (with automatic fallback)
- **DeviceConfigIntegrationService**: Device configuration management (with automatic fallback)
- **DefaultConfigIntegrationService**: Default configuration management (with automatic fallback)

#### Configuration
```yaml
integration:
  device:
    enabled: true
    serviceName: zt-device
    connectTimeout: 5000
    readTimeout: 10000
    retryEnabled: false
    maxRetries: 3
  render:
    enabled: true
    serviceName: zt-render-worker
    connectTimeout: 5000
    readTimeout: 10000
    retryEnabled: false
    maxRetries: 3
```

### Usage Examples

#### Basic Device Operations (with Automatic Fallback)
```java
@Autowired
private DeviceIntegrationService deviceService;

// Create IPC camera device (operation tracked for future fallback)
DeviceV2DTO ipcDevice = deviceService.createIpcDevice("前门摄像头", "CAM001", scenicId);

// Get device with configuration (automatically falls back to cache on failure)
DeviceV2WithConfigDTO device = deviceService.getDeviceWithConfig(deviceId);

// Get device by number (automatically falls back to cache on failure)
DeviceV2DTO deviceByNo = deviceService.getDeviceByNo("CAM001");

// Get basic device info (automatically falls back to cache on failure)
DeviceV2DTO basicDevice = deviceService.getDevice(deviceId);

// List scenic devices (no fallback for list operations)
DeviceV2ListResponse deviceList = deviceService.getScenicIpcDevices(scenicId, 1, 10);

// Enable/disable device (direct operation, fails immediately on error)
deviceService.enableDevice(deviceId);
deviceService.disableDevice(deviceId);

// Update device (direct operation, fails immediately on error)
UpdateDeviceRequest updateRequest = new UpdateDeviceRequest();
updateRequest.setName("更新后的摄像头");
deviceService.updateDevice(deviceId, updateRequest);
```

#### Device Configuration Management (with Automatic Fallback)  
```java
@Autowired
private DeviceConfigIntegrationService configService;

// Get device configurations (with fallback)
List<DeviceConfigV2DTO> configs = configService.getDeviceConfigs(deviceId);

// Get flat configuration (automatically falls back to cache on failure)
Map<String, Object> config = configService.getDeviceFlatConfig(deviceId);

// Get flat configuration by device number (with fallback)
Map<String, Object> configByNo = configService.getDeviceFlatConfigByNo("CAM001");

// Batch update configurations (direct operation, fails immediately on error)
BatchDeviceConfigRequest batchRequest = configService.createBatchConfigBuilder()
    .addConfig("brightness", "50")
    .addConfig("contrast", "80")
    .build();
configService.batchUpdateDeviceConfig(deviceId, batchRequest);

// New batch configuration API with detailed results
BatchDeviceConfigRequest request = configService.createBatchConfigBuilder()
    .addVideoConfig("4K", 30, "H265")  // Add video configuration
    .addNetworkConfig("192.168.1.100", 554, "RTSP")  // Add network configuration
    .addAuthConfig("admin", "password")  // Add authentication configuration
    .addConfig("recording_enabled", "true")  // Use default configuration
    .addConfig("custom_setting", "value", "string", "Custom setting")  // Custom configuration
    .build();

BatchUpdateResponse result = configService.batchUpdateDeviceConfigWithResult(deviceId, request);
if (result.getFailed() > 0) {
    // Handle partial failure
    result.getProcessedItems().stream()
        .filter(item -> "failed".equals(item.getStatus()))
        .forEach(item -> log.warn("Config {} failed: {}", item.getConfigKey(), item.getMessage()));
}
```

#### Device Management Patterns
```java
// Create and configure camera in one operation (both operations direct, no fallback)
DeviceV2DTO camera = deviceService.createIpcDevice("摄像头1", "CAM001", scenicId);
// Use batch configuration to set camera parameters (direct operation)
BatchDeviceConfigRequest cameraConfig = configService.createBatchConfigBuilder()
    .addConfig("ip_address", "192.168.1.100")
    .addConfig("resolution", "1920x1080")
    .addConfig("framerate", "30")
    .addConfig("protocol", "RTSP")
    .addConfig("username", "admin")
    .addConfig("password", "password")
    .build();
configService.batchUpdateDeviceConfig(camera.getId(), cameraConfig);

// Get scenic camera status
DeviceV2WithConfigListResponse camerasWithConfig = 
    deviceService.listDevicesWithConfig(1, 100, null, null, "IPC", 1, scenicId);

// Batch update camera resolution (direct operations, no fallback)
for (DeviceV2WithConfigDTO device : camerasWithConfig.getList()) {
    BatchDeviceConfigRequest resolutionUpdate = configService.createBatchConfigBuilder()
        .addConfig("resolution", "2560x1440")
        .build();
    configService.batchUpdateDeviceConfig(device.getId(), resolutionUpdate);
}

// Monitor device configuration completeness (with automatic fallback)
for (DeviceV2DTO device : activeDevices.getList()) {
    Map<String, Object> config = configService.getDeviceFlatConfig(device.getId());
    boolean hasIpConfig = config.containsKey("ip_address");
    // log configuration status...
}
```

#### Fallback Cache Management for Devices
```java
@Autowired
private IntegrationFallbackService fallbackService;

// Check fallback cache status  
boolean hasDeviceCache = fallbackService.hasFallbackCache("zt-device", "device:1001");
boolean hasConfigCache = fallbackService.hasFallbackCache("zt-device", "device:flat:config:1001");

// Get cache statistics
IntegrationFallbackService.FallbackCacheStats stats = fallbackService.getFallbackCacheStats("zt-device");
log.info("Device fallback cache: {} items, TTL: {} days", stats.getTotalCacheCount(), stats.getFallbackTtlDays());

// Clear specific cache
fallbackService.clearFallbackCache("zt-device", "device:1001");

// Clear all device caches  
fallbackService.clearAllFallbackCache("zt-device");
```

## Default Configuration Management (ZT-Device Microservice)

### Key Components

#### Default Configuration API
The zt-device microservice provides a comprehensive default configuration management API at `/api/device/config/v2/defaults` that allows:
- Creating and managing default configuration templates
- Batch operations with conflict detection
- Configuration type validation and enforcement
- Usage tracking and analytics

#### Feign Client
- **DefaultConfigClient**: Default configuration management operations

#### Service
- **DefaultConfigIntegrationService**: High-level default configuration operations (with automatic fallback for queries)

### Usage Examples

#### Basic Default Configuration Operations (with Automatic Fallback)
```java
@Autowired
private DefaultConfigIntegrationService defaultConfigService;

// Get default configuration list (automatically falls back to cache on failure)
PageResponse<DefaultConfigResponse> configList = defaultConfigService.listDefaultConfigs(1, 10);
log.info("Default configs: total={}, current page={}", 
        configList.getData().getTotal(), configList.getData().getList().size());

// Get specific default configuration (automatically falls back to cache on failure)
DefaultConfigResponse config = defaultConfigService.getDefaultConfig("resolution");
if (config != null) {
    log.info("Default resolution: {}", config.getConfigValue());
}

// Create new default configuration (direct operation, fails immediately on error)
DefaultConfigRequest newConfig = new DefaultConfigRequest();
newConfig.setConfigKey("bitrate");
newConfig.setConfigValue("2000000");
newConfig.setConfigType("int");
newConfig.setDescription("Default video bitrate in bps");
boolean created = defaultConfigService.createDefaultConfig(newConfig);

// Update default configuration with conflict detection (direct operation)
Map<String, Object> updates = new HashMap<>();
updates.put("configValue", "4000000");
updates.put("description", "Updated default bitrate - high quality");
DefaultConfigConflict conflict = defaultConfigService.updateDefaultConfig("bitrate", updates);

if (conflict != null) {
    log.warn("Configuration update conflict detected:");
    log.warn("  Key: {}, Type: {}, Affected devices: {}", 
            conflict.getConfigKey(), conflict.getConflictType(), conflict.getDeviceCount());
    log.warn("  Current type: {}, Proposed type: {}", 
            conflict.getCurrentType(), conflict.getProposedType());
    
    // Handle conflict - show affected device IDs
    if (conflict.getConflictDevices() != null) {
        log.warn("  Conflicted device IDs: {}", conflict.getConflictDevices());
    }
} else {
    log.info("Configuration updated successfully without conflicts");
}

// Delete default configuration (direct operation, fails immediately on error)
boolean deleted = defaultConfigService.deleteDefaultConfig("bitrate");
```

#### Batch Default Configuration Operations
```java
// Using Builder Pattern for batch operations
BatchDefaultConfigRequest batchRequest = defaultConfigService.createBatchConfigBuilder()
    .addVideoConfig("1920x1080", 30, "H265")  // Add video configuration group
    .addNetworkConfig("192.168.1.100", 554, "RTSP")  // Add network configuration group
    .addConfig("recording_enabled", "true", "bool", "Enable recording by default")
    .addConfig("storage_retention", "30", "int", "Storage retention in days")
    .addConfig("quality_profile", "high", "string", "Default video quality profile")
    .build();

// Execute batch update (direct operation, no fallback)
BatchDefaultConfigResponse result = defaultConfigService.batchUpdateDefaultConfigs(batchRequest);

// Process batch results
log.info("Batch operation completed: {} success, {} failed", result.getSuccess(), result.getFailed());

// Handle conflicts
if (result.getConflicts() != null && !result.getConflicts().isEmpty()) {
    log.warn("Configuration conflicts detected:");
    for (DefaultConfigConflict conflict : result.getConflicts()) {
        log.warn("  Key: {}, Type: {}, Devices affected: {}", 
                conflict.getConfigKey(), conflict.getConflictType(), conflict.getDeviceCount());
    }
}

// Review processed items
if (result.getProcessedItems() != null) {
    result.getProcessedItems().forEach(item -> {
        if ("success".equals(item.getStatus())) {
            log.info("✅ {} {} successfully (type: {})", 
                    item.getConfigKey(), item.getAction(), item.getFinalType());
        } else {
            log.warn("❌ {} failed: {}", item.getConfigKey(), item.getMessage());
        }
    });
}

// Handle errors
if (result.getErrors() != null && !result.getErrors().isEmpty()) {
    result.getErrors().forEach(error -> log.error("Batch operation error: {}", error));
}
```

#### Device Type Specific Default Configuration Patterns
```java
// Create IPC camera default configurations
BatchDefaultConfigRequest ipcDefaults = defaultConfigService.createBatchConfigBuilder()
    .addVideoConfig("1920x1080", 25, "H264")  // Standard HD resolution
    .addConfig("night_vision", "true", "bool", "Enable night vision")
    .addConfig("motion_detection", "true", "bool", "Enable motion detection")
    .addConfig("stream_profile", "main", "string", "Default stream profile")
    .addConfig("ptz_enabled", "false", "bool", "PTZ control enabled")
    .addConfig("audio_enabled", "true", "bool", "Audio recording enabled")
    .build();

// Create NVR default configurations
BatchDefaultConfigRequest nvrDefaults = defaultConfigService.createBatchConfigBuilder()
    .addConfig("max_channels", "16", "int", "Maximum supported channels")
    .addConfig("storage_mode", "continuous", "string", "Recording storage mode")
    .addConfig("backup_enabled", "true", "bool", "Enable automatic backup")
    .addConfig("raid_level", "5", "int", "Default RAID level")
    .addConfig("disk_quota", "80", "int", "Disk usage quota percentage")
    .build();

// Apply device-type-specific defaults
BatchDefaultConfigResponse ipcResult = defaultConfigService.batchUpdateDefaultConfigs(ipcDefaults);
BatchDefaultConfigResponse nvrResult = defaultConfigService.batchUpdateDefaultConfigs(nvrDefaults);

log.info("IPC defaults: {} success, {} failed", ipcResult.getSuccess(), ipcResult.getFailed());
log.info("NVR defaults: {} success, {} failed", nvrResult.getSuccess(), nvrResult.getFailed());
```

#### Configuration Validation and Management Patterns
```java
// Validate system configuration completeness
PageResponse<DefaultConfigResponse> allDefaults = defaultConfigService.listDefaultConfigs(1, 100);

// Check for required default configurations
String[] requiredDefaults = {
    "resolution", "frameRate", "codec", "bitrate", 
    "protocol", "port", "username", "password"
};

Map<String, Boolean> configStatus = new HashMap<>();
for (String required : requiredDefaults) {
    boolean exists = allDefaults.getData().getList().stream()
        .anyMatch(config -> required.equals(config.getConfigKey()));
    configStatus.put(required, exists);
    
    if (!exists) {
        log.warn("Missing required default configuration: {}", required);
    }
}

// Generate configuration completeness report
long totalConfigs = allDefaults.getData().getTotal();
long completeConfigs = configStatus.values().stream().mapToLong(exists -> exists ? 1 : 0).sum();
double completeness = (double) completeConfigs / requiredDefaults.length * 100;

log.info("Configuration completeness: {:.1f}% ({}/{} required configs present)", 
        completeness, completeConfigs, requiredDefaults.length);
log.info("Total default configurations in system: {}", totalConfigs);

// Analyze configuration type distribution
Map<String, Long> typeDistribution = allDefaults.getData().getList().stream()
    .collect(Collectors.groupingBy(
        DefaultConfigResponse::getConfigType,
        Collectors.counting()
    ));

log.info("Configuration type distribution: {}", typeDistribution);

// Find most and least used configurations
DefaultConfigResponse mostUsed = allDefaults.getData().getList().stream()
    .max(Comparator.comparing(DefaultConfigResponse::getUsageCount))
    .orElse(null);

DefaultConfigResponse leastUsed = allDefaults.getData().getList().stream()
    .min(Comparator.comparing(DefaultConfigResponse::getUsageCount))
    .orElse(null);

if (mostUsed != null) {
    log.info("Most used default config: {} (used {} times)", 
            mostUsed.getConfigKey(), mostUsed.getUsageCount());
}
if (leastUsed != null) {
    log.info("Least used default config: {} (used {} times)", 
            leastUsed.getConfigKey(), leastUsed.getUsageCount());
}
```

#### Advanced Batch Configuration with Error Handling
```java
// Complex batch operation with comprehensive error handling
try {
    BatchDefaultConfigRequest complexBatch = defaultConfigService.createBatchConfigBuilder()
        .addVideoConfig("3840x2160", 60, "H265")  // 4K configuration
        .addConfig("hdr_enabled", "true", "bool", "HDR video support")
        .addConfig("ai_analysis", "enabled", "string", "AI analysis features")
        .addConfig("edge_processing", "true", "bool", "Edge computing enabled")
        .addConfig("cloud_sync", "auto", "string", "Cloud synchronization mode")
        .build();
    
    BatchDefaultConfigResponse result = defaultConfigService.batchUpdateDefaultConfigs(complexBatch);
    
    // Detailed result analysis
    if (result.getSuccess() == complexBatch.getConfigs().size()) {
        log.info("✅ All {} configurations processed successfully", result.getSuccess());
    } else if (result.getSuccess() > 0) {
        log.warn("⚠️ Partial success: {} succeeded, {} failed", result.getSuccess(), result.getFailed());
        
        // Analyze what succeeded vs failed
        if (result.getProcessedItems() != null) {
            Map<String, Long> statusCounts = result.getProcessedItems().stream()
                .collect(Collectors.groupingBy(
                    ProcessedConfigItem::getStatus,
                    Collectors.counting()
                ));
            log.info("Processing breakdown: {}", statusCounts);
        }
    } else {
        log.error("❌ All configurations failed to process");
    }
    
    // Handle different types of conflicts
    if (result.getConflicts() != null) {
        Map<String, List<DefaultConfigConflict>> conflictsByType = result.getConflicts().stream()
            .collect(Collectors.groupingBy(DefaultConfigConflict::getConflictType));
        
        conflictsByType.forEach((conflictType, conflicts) -> {
            log.warn("Conflict type '{}' affects {} configurations:", conflictType, conflicts.size());
            conflicts.forEach(conflict -> 
                log.warn("  {} affects {} devices", conflict.getConfigKey(), conflict.getDeviceCount())
            );
        });
    }
    
} catch (Exception e) {
    log.error("Batch default configuration operation failed", e);
    // Implement retry logic or fallback behavior as needed
}
```

#### Fallback Cache Management for Default Configurations
```java
@Autowired
private IntegrationFallbackService fallbackService;

// Check fallback cache status for default configurations
boolean hasDefaultListCache = fallbackService.hasFallbackCache("zt-device", "defaults:list:1:10");
boolean hasSpecificConfigCache = fallbackService.hasFallbackCache("zt-device", "defaults:config:resolution");

// Get cache statistics
IntegrationFallbackService.FallbackCacheStats stats = fallbackService.getFallbackCacheStats("zt-device");
log.info("Default config fallback cache: {} items, TTL: {} days", 
         stats.getTotalCacheCount(), stats.getFallbackTtlDays());

// Clear specific default configuration cache
fallbackService.clearFallbackCache("zt-device", "defaults:config:resolution");

// Clear all default configuration caches
fallbackService.clearAllFallbackCache("zt-device");
```

### Default Configuration Types and Common Keys

#### Video Configuration Defaults
- `resolution`: Video resolution ("1920x1080", "3840x2160", "1280x720")
- `frameRate`: Video frame rate (integer: 15, 25, 30, 60)
- `codec`: Video codec ("H264", "H265", "MJPEG")
- `bitrate`: Video bitrate in bps (integer)
- `quality`: Video quality level ("low", "medium", "high", "ultra")

#### Network Configuration Defaults
- `protocol`: Network protocol ("RTSP", "HTTP", "ONVIF")
- `port`: Network port (integer: 554, 80, 8080)
- `timeout`: Connection timeout in seconds (integer)
- `retry_count`: Maximum retry attempts (integer)

#### Authentication Defaults
- `username`: Default username (string)
- `password`: Default password (string)
- `auth_method`: Authentication method ("basic", "digest", "none")

#### Storage and Recording Defaults
- `storage_path`: Default storage path (string)
- `recording_enabled`: Enable recording (boolean)
- `retention_days`: Storage retention period (integer)
- `max_file_size`: Maximum file size in MB (integer)

#### Feature Control Defaults
- `motion_detection`: Enable motion detection (boolean)
- `night_vision`: Enable night vision (boolean)
- `audio_enabled`: Enable audio recording (boolean)
- `ptz_enabled`: Enable PTZ control (boolean)
- `ai_analysis`: AI analysis features ("enabled", "disabled", "auto")

### Error Handling and Responses

#### HTTP Status Codes
- **200 OK**: Configuration retrieved/updated successfully
- **201 Created**: New configuration created successfully
- **202 Accepted**: Operation completed with conflicts (check response for details)
- **400 Bad Request**: Invalid request parameters or validation errors
- **404 Not Found**: Configuration key not found
- **409 Conflict**: Configuration conflicts prevent operation (includes conflict details)

#### Conflict Resolution
When updating default configurations that are actively used by devices, the API performs conflict detection:

1. **Type Conflicts**: Changing configuration type when devices use different types
2. **Value Validation**: Ensuring new values are compatible with existing device configurations
3. **Dependency Conflicts**: Checking for configuration dependencies and relationships

The response includes detailed conflict information to help resolve issues:
```java
// Example conflict handling
DefaultConfigConflict conflict = updateResult;
if (conflict != null) {
    switch (conflict.getConflictType()) {
        case "TYPE_MISMATCH":
            log.warn("Type conflict: {} devices using '{}' type, proposed '{}'type", 
                    conflict.getDeviceCount(), conflict.getCurrentType(), conflict.getProposedType());
            // Handle type conversion or device updates
            break;
            
        case "VALUE_RANGE":
            log.warn("Value range conflict for key '{}' affects {} devices", 
                    conflict.getConfigKey(), conflict.getDeviceCount());
            // Handle value range adjustments
            break;
            
        case "DEPENDENCY":
            log.warn("Dependency conflict detected for '{}'", conflict.getConfigKey());
            // Handle dependency resolution
            break;
    }
}
```

### Enhanced Batch Configuration API

Device Integration now supports an enhanced batch configuration API that provides detailed processing results and supports default configuration rules.

#### Default Configuration Rules
The system uses `device_id = 0` configurations as default templates:
- **Configurations with defaults**: System enforces default `config_type` and `description`, only `configValue` is updated
- **Configurations without defaults**: Allows custom `config_type` and `description`

#### Usage Examples
```java
// 1. Using Builder Pattern
BatchDeviceConfigRequest request = configService.createBatchConfigBuilder()
    .addVideoConfig("1920x1080", 30, "H264")  // Video settings
    .addNetworkConfig("192.168.1.100", 554, "RTSP")  // Network settings  
    .addAuthConfig("admin", "password123")  // Authentication
    .addConfig("recording_enabled", "true")  // Use default config rule
    .addConfig("custom_path", "/data", "string", "Storage path")  // Custom config
    .build();

BatchUpdateResponse result = configService.batchUpdateDeviceConfigWithResult(deviceId, request);

// 2. Processing Results
log.info("Batch update: {} success, {} failed", result.getSuccess(), result.getFailed());

for (ProcessedConfigItem item : result.getProcessedItems()) {
    if ("success".equals(item.getStatus())) {
        log.info("✅ {} updated (action: {}, hasDefault: {})", 
                item.getConfigKey(), item.getAction(), item.getHasDefault());
    } else {
        log.warn("❌ {} failed: {}", item.getConfigKey(), item.getMessage());
    }
}

// 3. Error Handling
if (result.getFailed() > 0) {
    result.getErrors().forEach(error -> log.warn("Error: {}", error));
}
```

#### Response Format
- **200 OK**: All configurations updated successfully
- **202 Accepted**: Partial success (some configurations failed)
- **400 Bad Request**: All configurations failed

Each processed item includes:
- `status`: "success" or "failed"
- `action`: "create" or "update"
- `hasDefault`: Whether default configuration rules were applied
- `finalType`/`finalDescription`: Actually used type and description

### Device Types
- **IPC**: IP Camera devices for video monitoring
- **CUSTOM**: Custom device types for sensors, controllers, etc.

### Testing Default Configuration Integration

```bash
# Run default configuration integration tests
mvn test -Dtest=DefaultConfigIntegrationServiceTest

# Run all device integration tests (including default configs)
mvn test -Dtest="com.ycwl.basic.integration.device.*Test"
```

### Common Configuration Keys
- `ip_address`: Device IP address
- `resolution`: Video resolution (e.g., "1920x1080", "3840x2160")
- `framerate`: Video frame rate (integer)
- `protocol`: Communication protocol (e.g., "RTSP", "HTTP")
- `username`: Authentication username
- `password`: Authentication password
- `brightness`: Display brightness (0-100)
- `contrast`: Display contrast (0-100)
- `quality`: Video quality ("low", "medium", "high")

## Adding New Service Integrations

### 1. Create Package Structure
```
com.ycwl.basic.integration.{service-name}/
├── client/
├── config/
├── dto/
└── service/
```

### 2. Add Configuration Properties
Update `IntegrationProperties` to include new service configuration:
```java
@Data
public static class NewServiceConfig {
    private boolean enabled = true;
    private String serviceName = "service-name";
    private int connectTimeout = 5000;
    private int readTimeout = 10000;
    // other configs...
}
```

### 3. Create Feign Client
```java
@FeignClient(name = "service-name", contextId = "service-context", path = "/api/path")
public interface NewServiceClient {
    @GetMapping("/endpoint")
    CommonResponse<ResponseDTO> getData(@PathVariable Long id);
    // other endpoints...
}
```

### 4. Implement Service Layer
```java
@Service
@RequiredArgsConstructor
public class NewServiceIntegrationService {
    private final NewServiceClient client;
    
    public ResponseDTO getData(Long id) {
        CommonResponse<ResponseDTO> response = client.getData(id);
        return handleResponse(response, "Failed to get data");
    }
    
    private <T> T handleResponse(CommonResponse<T> response, String errorMessage) {
        if (response == null || !response.isSuccess()) {
            String msg = response != null && response.getMessage() != null 
                        ? response.getMessage() 
                        : errorMessage;
            Integer code = response != null ? response.getCode() : 5000;
            throw new IntegrationException(code, msg, "service-name");
        }
        return response.getData();
    }
}
```

## Error Handling

### IntegrationException
All integration failures are wrapped in `IntegrationException`:
```java
public class IntegrationException extends RuntimeException {
    private final Integer code;
    private final String serviceName;
    // constructors and getters...
}
```

### FeignErrorDecoder
Automatically converts Feign errors to IntegrationException:
- Parses CommonResponse error format
- Extracts service name from method key
- Provides meaningful error messages

## Configuration Management

### Properties Structure
```yaml
integration:
  # Fallback configuration
  fallback:
    enabled: true                           # Global fallback switch
    cachePrefix: "integration:fallback:"    # Global cache prefix
    defaultTtlDays: 7                      # Default cache TTL in days
    
    # Service-specific fallback configurations
    scenic:
      enabled: true                        # Enable fallback for scenic service
      ttlDays: 10                         # Custom TTL for scenic (longer due to stable data)
      # cachePrefix: "scenic:fallback:"   # Optional custom prefix
    
    device:
      enabled: true                        # Enable fallback for device service  
      ttlDays: 5                          # Custom TTL for device (shorter due to dynamic data)
      # cachePrefix: "device:fallback:"   # Optional custom prefix
      
    render:
      enabled: true                        # Enable fallback for render worker service
      ttlDays: 7                          # Custom TTL for render worker (medium due to stable worker data)
      # cachePrefix: "render:fallback:"   # Optional custom prefix

  # Service configurations
  scenic:
    enabled: true
    serviceName: zt-scenic
    connectTimeout: 5000
    readTimeout: 10000
    retryEnabled: false
    maxRetries: 3
  device:
    enabled: true
    serviceName: zt-device
    connectTimeout: 5000
    readTimeout: 10000
    retryEnabled: false
    maxRetries: 3
```

### Configuration Refresh
Uses `@RefreshScope` to support dynamic configuration updates without restart.

## Testing Integration Services

### Unit Testing
Test service layers by mocking Feign clients:
```java
@ExtendWith(MockitoExtension.class)
class ScenicIntegrationServiceTest {
    @Mock
    private ScenicV2Client scenicV2Client;
    
    @InjectMocks
    private ScenicIntegrationService scenicService;
    
    @Test
    void testGetScenic() {
        // Mock response
        CommonResponse<ScenicV2DTO> response = new CommonResponse<>();
        response.setSuccess(true);
        response.setData(new ScenicV2DTO());
        
        when(scenicV2Client.getScenic(1L)).thenReturn(response);
        
        // Test
        ScenicV2DTO result = scenicService.getScenic(1L);
        assertNotNull(result);
    }
}
```

### Integration Testing
Use `@SpringBootTest` with test profiles and mock external services.

## Render Worker Integration (ZT-Render-Worker Microservice)

### Key Components

#### Feign Clients
- **RenderWorkerV2Client**: Main render worker operations (CRUD, listing)
- **RenderWorkerConfigV2Client**: Render worker configuration management

#### Services
- **RenderWorkerIntegrationService**: High-level render worker operations (with automatic fallback)
- **RenderWorkerConfigIntegrationService**: Configuration management (with automatic fallback)

#### Configuration
```yaml
integration:
  render:
    enabled: true
    serviceName: zt-render-worker
    connectTimeout: 5000
    readTimeout: 10000
    retryEnabled: false
    maxRetries: 3
```

### Usage Examples

#### Basic Render Worker Operations (with Automatic Fallback)
```java
@Autowired
private RenderWorkerIntegrationService renderWorkerService;

// Get render worker basic info (automatically falls back to cache on failure)
RenderWorkerV2DTO worker = renderWorkerService.getWorker(workerId);

// Get render worker with configuration (automatically falls back to cache on failure)
RenderWorkerV2WithConfigDTO workerWithConfig = renderWorkerService.getWorkerWithConfig(workerId);

// Get render worker by key (automatically falls back to cache on failure)
RenderWorkerV2DTO workerByKey = renderWorkerService.getWorkerByKey("video-renderer-001");

// Get render worker with config by key (automatically falls back to cache on failure)
RenderWorkerV2WithConfigDTO workerWithConfigByKey = renderWorkerService.getWorkerWithConfigByKey("video-renderer-001");

// Create new render worker (direct operation, fails immediately on error)
CreateRenderWorkerRequest request = new CreateRenderWorkerRequest();
request.setName("Video Renderer");
request.setKey("video-renderer-001");
request.setIsActive(1);
RenderWorkerV2DTO newWorker = renderWorkerService.createWorker(request);

// Update render worker (direct operation, fails immediately on error)
UpdateRenderWorkerRequest updateRequest = new UpdateRenderWorkerRequest();
updateRequest.setName("Updated Video Renderer");
renderWorkerService.updateWorker(workerId, updateRequest);

// Delete render worker (direct operation, fails immediately on error)
renderWorkerService.deleteWorker(workerId);

// List render workers (no fallback for list operations)
List<RenderWorkerV2DTO> workers = renderWorkerService.listWorkers(1, 10, 1, null);

// List render workers with config (no fallback for list operations)
List<RenderWorkerV2WithConfigDTO> workersWithConfig = 
    renderWorkerService.listWorkersWithConfig(1, 10, 1, null);
```

#### Configuration Management (with Automatic Fallback)
```java
@Autowired
private RenderWorkerConfigIntegrationService configService;

// Get worker configurations (with fallback)
List<RenderWorkerConfigV2DTO> configs = configService.getWorkerConfigs(workerId);

// Get flat configuration (automatically falls back to cache on failure)
Map<String, Object> flatConfig = configService.getWorkerFlatConfig(workerId);

// Get specific configuration by key (with fallback)
RenderWorkerConfigV2DTO config = configService.getWorkerConfigByKey(workerId, "render_quality");

// Create configuration (direct operation, fails immediately on error)
RenderWorkerConfigV2DTO newConfig = new RenderWorkerConfigV2DTO();
newConfig.setConfigKey("max_concurrent_tasks");
newConfig.setConfigValue("4");
newConfig.setConfigType("int");
newConfig.setDescription("Maximum concurrent render tasks");
newConfig.setIsActive(1);
RenderWorkerConfigV2DTO created = configService.createWorkerConfig(workerId, newConfig);

// Update configuration (direct operation, fails immediately on error)
Map<String, Object> updates = new HashMap<>();
updates.put("configValue", "8");
configService.updateWorkerConfig(workerId, configId, updates);

// Delete configuration (direct operation, fails immediately on error)
configService.deleteWorkerConfig(workerId, configId);
```

#### Enhanced Batch Configuration API
```java
// Using Builder Pattern for batch configuration
BatchRenderWorkerConfigRequest request = configService.createBatchConfigBuilder()
    .addRenderConfig("high", "mp4", "1920x1080")  // Render settings
    .addPerformanceConfig(8, 3600)  // Performance settings
    .addConfig("output_path", "/data/renders", "string", "Output directory")
    .addConfig("enable_gpu", "true", "bool", "Enable GPU acceleration")
    .build();

// Batch update configurations (direct operation, fails immediately on error)
configService.batchUpdateWorkerConfigs(workerId, request);

// Batch flat update configurations (direct operation, fails immediately on error)
Map<String, Object> flatUpdates = new HashMap<>();
flatUpdates.put("render_quality", "ultra");
flatUpdates.put("max_concurrent_tasks", 12);
flatUpdates.put("enable_preview", true);
configService.batchFlatUpdateWorkerConfigs(workerId, flatUpdates);
```

#### Render Worker Management Patterns
```java
// Create and configure render worker in one operation
CreateRenderWorkerRequest workerRequest = new CreateRenderWorkerRequest();
workerRequest.setName("4K Video Renderer");
workerRequest.setKey("4k-video-renderer");
RenderWorkerV2DTO worker = renderWorkerService.createWorker(workerRequest);

// Configure the worker for 4K video rendering
BatchRenderWorkerConfigRequest config = configService.createBatchConfigBuilder()
    .addRenderConfig("ultra", "mp4", "3840x2160")
    .addPerformanceConfig(4, 7200) // 4 concurrent tasks, 2 hour timeout
    .addConfig("gpu_memory_limit", "8192", "int", "GPU memory limit in MB")
    .addConfig("codec", "h265", "string", "Video codec")
    .addConfig("bitrate", "50000", "int", "Video bitrate in kbps")
    .build();
configService.batchUpdateWorkerConfigs(worker.getId(), config);

// Monitor worker configuration completeness (with automatic fallback)
Map<String, Object> workerConfig = configService.getWorkerFlatConfig(worker.getId());
boolean hasRenderConfig = workerConfig.containsKey("render_quality");
boolean hasPerformanceConfig = workerConfig.containsKey("max_concurrent_tasks");
// log configuration status...

// Get all active workers for monitoring
List<RenderWorkerV2WithConfigDTO> activeWorkers = 
    renderWorkerService.listWorkersWithConfig(1, 100, 1, null);

// Check worker health and configuration
for (RenderWorkerV2WithConfigDTO activeWorker : activeWorkers) {
    Map<String, Object> config = activeWorker.getConfig();
    boolean isConfigured = config.containsKey("render_quality") && 
                          config.containsKey("max_concurrent_tasks");
    // log worker status...
}
```

#### Fallback Cache Management for Render Workers
```java
@Autowired
private IntegrationFallbackService fallbackService;

// Check fallback cache status
boolean hasWorkerCache = fallbackService.hasFallbackCache("zt-render-worker", "worker:1001");
boolean hasWorkerByKeyCache = fallbackService.hasFallbackCache("zt-render-worker", "worker:key:video-renderer-001");
boolean hasConfigCache = fallbackService.hasFallbackCache("zt-render-worker", "worker:flat:config:1001");
boolean hasConfigByKeyCache = fallbackService.hasFallbackCache("zt-render-worker", "worker:key:config:video-renderer-001");

// Get cache statistics
IntegrationFallbackService.FallbackCacheStats stats = 
    fallbackService.getFallbackCacheStats("zt-render-worker");
log.info("Render worker fallback cache: {} items, TTL: {} days", 
         stats.getTotalCacheCount(), stats.getFallbackTtlDays());

// Clear specific cache
fallbackService.clearFallbackCache("zt-render-worker", "worker:1001");

// Clear all render worker caches
fallbackService.clearAllFallbackCache("zt-render-worker");
```

### Render Worker Types and Configuration

#### Common Configuration Keys
- `render_quality`: Render quality level ("low", "medium", "high", "ultra")
- `render_format`: Output format ("mp4", "avi", "mov", "webm")
- `render_resolution`: Video resolution ("1920x1080", "3840x2160", "1280x720")
- `max_concurrent_tasks`: Maximum concurrent render tasks (integer)
- `task_timeout`: Task timeout in seconds (integer)
- `output_path`: Render output directory path (string)
- `enable_gpu`: Enable GPU acceleration (boolean)
- `gpu_memory_limit`: GPU memory limit in MB (integer)
- `codec`: Video codec ("h264", "h265", "vp9")
- `bitrate`: Video bitrate in kbps (integer)
- `enable_preview`: Enable preview generation (boolean)

#### Worker Status
- **Active (isActive=1)**: Worker is available for tasks
- **Inactive (isActive=0)**: Worker is disabled

## Render Template Integration (ZT-Render-Worker Microservice)

### Key Components

#### Feign Clients
- **RenderTemplateV2Client**: Template CRUD operations, segment management

#### Services
- **RenderTemplateIntegrationService**: High-level template operations (with automatic fallback for queries)

### Usage Examples

#### Basic Template Operations
```java
@Autowired
private RenderTemplateIntegrationService templateService;

// Create template (direct operation, fails immediately on error)
CreateTemplateRequest createRequest = new CreateTemplateRequest();
createRequest.setScenicId(1001L);
createRequest.setName("新年贺卡模板");
createRequest.setDescription("用于新年祝福的模板");
createRequest.setDefaultDurationMs(10000L);

OutputSpecDTO outputSpec = new OutputSpecDTO();
outputSpec.setWidth(1080);
outputSpec.setHeight(1920);
outputSpec.setFps(30);
createRequest.setOutputSpec(outputSpec);

TemplateV2DTO template = templateService.createTemplate(createRequest);

// Get template details (automatically falls back to cache on failure)
TemplateV2DTO templateInfo = templateService.getTemplate(templateId);

// Get template with segments (automatically falls back to cache on failure)
TemplateV2WithSegmentsDTO templateWithSegments = templateService.getTemplateWithSegments(templateId);

// List templates (no fallback for list operations)
PageResponse<TemplateV2DTO> templates = templateService.listTemplates(1, 10, scenicId, 1, null);

// Update template (direct operation, fails immediately on error)
UpdateTemplateRequest updateRequest = new UpdateTemplateRequest();
updateRequest.setName("更新后的模板名称");
templateService.updateTemplate(templateId, updateRequest);

// Publish template (direct operation, fails immediately on error)
templateService.publishTemplate(templateId);

// Create new version (direct operation, fails immediately on error)
TemplateV2DTO newVersion = templateService.createTemplateVersion(templateId);

// Delete template (direct operation, fails immediately on error)
templateService.deleteTemplate(templateId);
```

#### Segment Management
```java
// Get template segments (automatically falls back to cache on failure)
List<TemplateV2SegmentDTO> segments = templateService.getTemplateSegments(templateId);

// Create segment (direct operation, fails immediately on error)
CreateSegmentRequest segmentRequest = new CreateSegmentRequest();
segmentRequest.setSegmentIndex(0);
segmentRequest.setSegmentType("RENDER");
segmentRequest.setSourceType("SLOT");
segmentRequest.setSourceRef("slot1");
segmentRequest.setDurationMs(2000L);
segmentRequest.setTransitionType("fade");
segmentRequest.setTransitionMs(500);

RenderSpecDTO renderSpec = new RenderSpecDTO();
renderSpec.setCropEnable(true);
renderSpec.setSpeed("1.0");
segmentRequest.setRenderSpec(renderSpec);

TemplateV2SegmentDTO segment = templateService.createSegment(templateId, segmentRequest);

// Update segment (direct operation, fails immediately on error)
UpdateSegmentRequest updateSegmentRequest = new UpdateSegmentRequest();
updateSegmentRequest.setDurationMs(3000L);
templateService.updateSegment(templateId, segmentId, updateSegmentRequest);

// Delete segment (direct operation, fails immediately on error)
templateService.deleteSegment(templateId, segmentId);

// Replace all segments (direct operation, fails immediately on error)
ReplaceSegmentsRequest replaceRequest = new ReplaceSegmentsRequest();
replaceRequest.setSegments(Arrays.asList(segmentRequest1, segmentRequest2));
templateService.replaceSegments(templateId, replaceRequest);
```

### Template Status
- **0**: Draft - Template is being edited
- **1**: Published - Template is live and available for rendering

### Segment Types
- **FIXED**: Fixed asset segment
- **RENDER**: Segment that needs to be rendered with user materials

### Source Types
- **ASSET**: Fixed asset resource
- **PLACEHOLDER_VIDEO**: Video placeholder slot
- **PLACEHOLDER_IMAGE**: Image placeholder slot
- **SLOT**: Material slot

## Render Job Integration (ZT-Render-Worker Microservice)

### Key Components

#### Feign Clients
- **RenderJobV2Client**: Job creation, status queries, admin operations

#### Services
- **RenderJobIntegrationService**: High-level job operations (with automatic fallback for queries)

### Usage Examples

#### Creating and Managing Render Jobs
```java
@Autowired
private RenderJobIntegrationService jobService;

// Create preview job (direct operation, fails immediately on error)
CreatePreviewRequest previewRequest = new CreatePreviewRequest();
previewRequest.setTemplateId(123L);
previewRequest.setScenicId(456L);
previewRequest.setFaceId(789L);
previewRequest.setMemberId(101L);

// Set materials by slot
Map<String, List<MaterialDTO>> materialsBySlot = new HashMap<>();
MaterialDTO material = new MaterialDTO();
material.setUrl("https://example.com/video.mp4");
material.setType("video");
material.setDuration(5000L);
materialsBySlot.put("slot1", Arrays.asList(material));
previewRequest.setMaterialsBySlot(materialsBySlot);

CreatePreviewResponse previewResponse = jobService.createPreview(previewRequest);
log.info("作业创建成功, jobId: {}, playUrl: {}", previewResponse.getJobId(), previewResponse.getPlayUrl());

// Get job status (automatically falls back to cache on failure)
JobStatusResponse status = jobService.getJobStatus(jobId);
log.info("作业状态: {}, 进度: {}%", status.getStatus(), status.getProgress());

// Get playlist info (automatically falls back to cache on failure)
PlaylistInfoDTO playlistInfo = jobService.getPlaylistInfo(jobId);
log.info("总片段: {}, 已发布: {}", playlistInfo.getSegmentCount(), playlistInfo.getPublishedCount());

// Get HLS playlist (direct call, returns M3U8 content)
String hlsPlaylist = jobService.getHlsPlaylist(jobId);

// Cancel job (direct operation, fails immediately on error)
jobService.cancelJob(jobId);
```

#### Admin Operations
```java
// List jobs (no fallback for list operations)
PageResponse<RenderJobV2DTO> jobs = jobService.listJobs(scenicId, templateId, "RUNNING", "PREVIEW", 1, 20);
log.info("查询到 {} 条作业", jobs.getTotal());

// Get job detail (automatically falls back to cache on failure)
RenderJobV2DTO jobDetail = jobService.getJobDetail(jobId);
log.info("作业详情: templateId={}, status={}", jobDetail.getTemplateId(), jobDetail.getStatus());

// Get job segments (automatically falls back to cache on failure)
List<RenderJobSegmentV2DTO> jobSegments = jobService.getJobSegments(jobId);
for (RenderJobSegmentV2DTO segment : jobSegments) {
    log.info("片段 {}: status={}, tsUrl={}", segment.getPlanSegmentIndex(), segment.getStatus(), segment.getTsUrl());
}
```

### Job Status
- **PENDING**: Job is waiting to be processed
- **RUNNING**: Job is currently being processed
- **SUCCESS**: Job completed successfully
- **FAILED**: Job failed
- **CANCELED**: Job was canceled

### Job Types
- **PREVIEW**: Preview job (HLS streaming)
- **PREVIEW_HLS**: HLS preview job
- **FINAL_MP4**: Final MP4 export job

### Segment Status
- **PENDING**: Segment is waiting to be processed
- **RENDERING**: Segment is being rendered
- **VIDEO_READY**: Video is ready
- **PACKAGING**: Segment is being packaged
- **TS_READY**: TS file is ready
- **PUBLISHED**: Segment is published and available
- **FAILED**: Segment processing failed

### Fallback Cache Management for Templates and Jobs
```java
@Autowired
private IntegrationFallbackService fallbackService;

// Check fallback cache status for templates
boolean hasTemplateCache = fallbackService.hasFallbackCache("zt-render-worker", "template:1001");
boolean hasTemplateSegmentsCache = fallbackService.hasFallbackCache("zt-render-worker", "template:segments:1001");

// Check fallback cache status for jobs
boolean hasJobStatusCache = fallbackService.hasFallbackCache("zt-render-worker", "job:status:2001");
boolean hasJobDetailCache = fallbackService.hasFallbackCache("zt-render-worker", "job:detail:2001");

// Get cache statistics
IntegrationFallbackService.FallbackCacheStats stats =
    fallbackService.getFallbackCacheStats("zt-render-worker");
log.info("Render fallback cache: {} items, TTL: {} days",
         stats.getTotalCacheCount(), stats.getFallbackTtlDays());

// Clear specific cache
fallbackService.clearFallbackCache("zt-render-worker", "template:1001");
fallbackService.clearFallbackCache("zt-render-worker", "job:status:2001");

// Clear all render worker caches
fallbackService.clearAllFallbackCache("zt-render-worker");
```

## ZT-Message Integration (Kafka Producer)

### Overview
The zt-message microservice accepts messages via Kafka on topic `zt-message`. This integration provides a simple producer service to publish notification messages.

- Topic: `zt-message`
- Key: Use `channelId` for partitioning stability
- Value: UTF-8 JSON with fields: `channelId` (required), `title` (required), `content` (required), `target` (required), `extra` (object, optional), `sendReason` (optional), `sendBiz` (optional)

### Components
- `com.ycwl.basic.integration.message.dto.ZtMessage`: DTO for message body
- `com.ycwl.basic.integration.message.service.ZtMessageProducerService`: Producer service using Spring Kafka

### Configuration
```yaml
kafka:
  enabled: true                      # enable Kafka integration
  bootstrap-servers: 127.0.0.1:9092  # adjust per environment
  zt-message-topic: zt-message       # topic name (default already zt-message)
  producer:
    acks: all
    enable-idempotence: true
    retries: 5
    linger-ms: 10
    batch-size: 32768
    compression-type: snappy
```

### Usage
```java
@Autowired
private ZtMessageProducerService producer;

public void sendWelcome() {
    ZtMessage msg = ZtMessage.of("dummy", "欢迎", "注册成功", "user-001");
    Map<String, Object> extra = new HashMap<>();
    extra.put("k", "v");
    msg.setExtra(extra);
    msg.setSendReason("REGISTER");
    msg.setSendBiz("USER");

    producer.send(msg); // key uses channelId, value is JSON
}
```

### Notes
- Required fields must be non-empty: `channelId`, `title`, `content`, `target`
- Keep message body small (< 100 KB)
- Use string for 64-bit integers in `extra` to avoid JS precision loss
- Service logs the partition/offset upon success, errors on failure

## Common Development Tasks

### Running Integration Tests
```bash
# Run specific integration test class
mvn test -Dtest=ScenicIntegrationServiceTest

# Run all integration tests
mvn test -Dtest="com.ycwl.basic.integration.*Test"

# Run device integration tests
mvn test -Dtest=DeviceIntegrationServiceTest
mvn test -Dtest="com.ycwl.basic.integration.device.*Test"

# Run render worker integration tests
mvn test -Dtest=RenderWorkerIntegrationServiceTest
mvn test -Dtest="com.ycwl.basic.integration.render.*Test"
```

### Adding New DTOs
1. Create DTO classes in the appropriate `dto` package
2. Follow existing patterns with proper Jackson annotations
3. Use `@JsonProperty` for field mapping when needed

### Debugging Integration Issues
1. Enable Feign client logging in `application-dev.yml`:
```yaml
logging:
  level:
    com.ycwl.basic.integration: DEBUG
```

2. Check Nacos service discovery in development
3. Verify service configurations and timeouts
4. Review FeignErrorDecoder logs for detailed error information

## Best Practices

### Response Handling
- Always use the `handleResponse` pattern for consistent error handling
- Provide meaningful error messages for business context
- Include service name in IntegrationException for debugging

### Fallback Strategy Best Practices
- **Query operations only**: Only apply fallback to GET operations (data retrieval)
- **No fallback for mutations**: CREATE/UPDATE/DELETE operations should fail immediately to provide clear feedback
- **Cache key design**: Use clear, hierarchical cache keys for easy identification and cleanup
- **TTL management**: Set appropriate TTL based on data freshness requirements
- **Monitoring**: Regularly check fallback cache statistics and cleanup stale entries
- **Service isolation**: Configure service-specific fallback settings based on reliability needs
- **Error transparency**: Let users know exactly when their modification operations fail

### Configuration
- Use environment-specific configuration profiles
- Set appropriate timeouts based on service characteristics
- Enable retries only when safe (idempotent operations)
- Configure fallback TTL based on business requirements:
  - **Critical data**: Longer TTL (7-14 days) for essential operations
  - **Volatile data**: Shorter TTL (1-3 days) for frequently changing data
  - **Configuration data**: Medium TTL (5-7 days) for semi-static settings

### DTOs and Mapping
- Keep DTOs simple and focused on data transfer
- Use proper Jackson annotations for field mapping
- Separate request/response DTOs for clarity

### Service Layer Design
- Keep integration services focused on external service calls
- Handle response transformation and error conversion
- Avoid business logic in integration services
- Use fallback service for resilience without changing business logic

### Cache Management Strategies
- **Proactive cleanup**: Monitor cache size and clean up periodically
- **Service-specific management**: Separate cache management per service
- **Debugging support**: Use cache statistics for troubleshooting
- **Configuration validation**: Ensure fallback configuration matches service requirements

## Questionnaire Integration (ZT-Questionnaire Microservice)

### Key Components

#### Feign Client
- **QuestionnaireClient**: Comprehensive questionnaire operations (CRUD, answer submission, statistics)

#### Service
- **QuestionnaireIntegrationService**: High-level questionnaire operations (with automatic fallback for queries)

#### Configuration
```yaml
integration:
  questionnaire:
    enabled: true
    serviceName: zt-questionnaire
    connectTimeout: 5000
    readTimeout: 10000
    retryEnabled: false
    maxRetries: 3
  fallback:
    questionnaire:
      enabled: true
      ttlDays: 7
```

### Usage Examples

#### Basic Questionnaire Operations (with Automatic Fallback)
```java
@Autowired
private QuestionnaireIntegrationService questionnaireService;

// Get questionnaire details (automatically falls back to cache on failure)
QuestionnaireResponse questionnaire = questionnaireService.getQuestionnaire(questionnaireId);

// Get questionnaire list with filters (automatically falls back to cache on failure)
QuestionnaireListResponse list = questionnaireService.getQuestionnaireList(1, 10, "客户调查", 2, null);

// Get questionnaire statistics (automatically falls back to cache on failure)
QuestionnaireStatistics stats = questionnaireService.getStatistics(questionnaireId);

// Get response records (automatically falls back to cache on failure)
ResponseListResponse responses = questionnaireService.getResponseList(1, 10, questionnaireId, null, null, null);

// Get response details (automatically falls back to cache on failure)
ResponseDetailResponse responseDetail = questionnaireService.getResponseDetail(responseId);
```

#### Questionnaire Management Operations (Direct Operations)
```java
// Create questionnaire (direct operation, fails immediately on error)
CreateQuestionnaireRequest request = new CreateQuestionnaireRequest();
request.setName("客户满意度调查");
request.setDescription("收集客户对服务的满意度反馈");
request.setIsAnonymous(true);
request.setMaxAnswers(1000);

// Add single-choice question
CreateQuestionRequest question1 = new CreateQuestionRequest();
question1.setTitle("您对我们的服务满意吗？");
question1.setType(1); // 单选题
question1.setIsRequired(true);
question1.setSort(1);

List<CreateQuestionOptionRequest> options1 = new ArrayList<>();
options1.add(new CreateQuestionOptionRequest("非常满意", "5", 1));
options1.add(new CreateQuestionOptionRequest("满意", "4", 2));
options1.add(new CreateQuestionOptionRequest("一般", "3", 3));
options1.add(new CreateQuestionOptionRequest("不满意", "2", 4));
options1.add(new CreateQuestionOptionRequest("非常不满意", "1", 5));
question1.setOptions(options1);

// Add multiple-choice question
CreateQuestionRequest question2 = new CreateQuestionRequest();
question2.setTitle("您感兴趣的服务有哪些？");
question2.setType(2); // 多选题
question2.setIsRequired(false);
question2.setSort(2);

List<CreateQuestionOptionRequest> options2 = new ArrayList<>();
options2.add(new CreateQuestionOptionRequest("技术支持", "tech_support", 1));
options2.add(new CreateQuestionOptionRequest("产品培训", "training", 2));
options2.add(new CreateQuestionOptionRequest("定制开发", "custom_dev", 3));
options2.add(new CreateQuestionOptionRequest("其他", "others", 4));
question2.setOptions(options2);

// Add text area question
CreateQuestionRequest question3 = new CreateQuestionRequest();
question3.setTitle("您还有什么建议吗？");
question3.setType(4); // 文本域题
question3.setIsRequired(false);
question3.setSort(3);
question3.setOptions(null); // 文本域题不需要选项

request.setQuestions(Arrays.asList(question1, question2, question3));

QuestionnaireResponse created = questionnaireService.createQuestionnaire(request, "admin");

// Update questionnaire (direct operation, fails immediately on error)
CreateQuestionnaireRequest updateRequest = new CreateQuestionnaireRequest();
updateRequest.setName("更新后的客户满意度调查");
QuestionnaireResponse updated = questionnaireService.updateQuestionnaire(questionnaireId, updateRequest, "admin");

// Publish questionnaire (direct operation, fails immediately on error)
QuestionnaireResponse published = questionnaireService.publishQuestionnaire(questionnaireId, "admin");

// Stop questionnaire (direct operation, fails immediately on error)
QuestionnaireResponse stopped = questionnaireService.stopQuestionnaire(questionnaireId, "admin");

// Delete questionnaire (direct operation, fails immediately on error)
questionnaireService.deleteQuestionnaire(questionnaireId, "admin");
```

#### Answer Submission
```java
// Submit questionnaire answers (direct operation, no fallback)
SubmitAnswerRequest answerRequest = new SubmitAnswerRequest();
answerRequest.setQuestionnaireId(questionnaireId);
answerRequest.setUserId("user123");

List<AnswerRequest> answers = new ArrayList<>();
// Single-choice answer
answers.add(new AnswerRequest(123L, "4")); // 满意
// Multiple-choice answer  
answers.add(new AnswerRequest(124L, "tech_support,training")); // 技术支持和产品培训
// Text area answer
answers.add(new AnswerRequest(125L, "服务很好，希望能增加更多实用功能"));

answerRequest.setAnswers(answers);

ResponseDetailResponse response = questionnaireService.submitAnswer(answerRequest);
log.info("答案提交成功，回答ID: {}", response.getId());
```

#### Question Types and Answer Formats

##### 1. Single Choice (Type 1)
```java
// Creating single-choice question
CreateQuestionRequest singleChoice = new CreateQuestionRequest();
singleChoice.setTitle("您的性别是？");
singleChoice.setType(1);
singleChoice.setIsRequired(true);
singleChoice.setSort(1);

List<CreateQuestionOptionRequest> options = new ArrayList<>();
options.add(new CreateQuestionOptionRequest("男", "male", 1));
options.add(new CreateQuestionOptionRequest("女", "female", 2));
options.add(new CreateQuestionOptionRequest("不愿透露", "prefer_not_to_say", 3));
singleChoice.setOptions(options);

// Submitting single-choice answer
AnswerRequest singleChoiceAnswer = new AnswerRequest(123L, "male");
```

##### 2. Multiple Choice (Type 2)
```java
// Creating multiple-choice question
CreateQuestionRequest multipleChoice = new CreateQuestionRequest();
multipleChoice.setTitle("您感兴趣的编程语言有哪些？");
multipleChoice.setType(2);
multipleChoice.setIsRequired(false);
multipleChoice.setSort(2);

List<CreateQuestionOptionRequest> options = new ArrayList<>();
options.add(new CreateQuestionOptionRequest("Java", "java", 1));
options.add(new CreateQuestionOptionRequest("Python", "python", 2));
options.add(new CreateQuestionOptionRequest("Go", "go", 3));
options.add(new CreateQuestionOptionRequest("JavaScript", "javascript", 4));
multipleChoice.setOptions(options);

// Submitting multiple-choice answer (comma-separated values)
AnswerRequest multipleChoiceAnswer = new AnswerRequest(124L, "java,python,go");
```

##### 3. Fill in Blank (Type 3)
```java
// Creating fill-in-blank question
CreateQuestionRequest fillInBlank = new CreateQuestionRequest();
fillInBlank.setTitle("请输入您的姓名");
fillInBlank.setType(3);
fillInBlank.setIsRequired(true);
fillInBlank.setSort(3);
fillInBlank.setOptions(null); // No options needed

// Submitting fill-in-blank answer
AnswerRequest fillAnswer = new AnswerRequest(125L, "张三");
```

##### 4. Text Area (Type 4)
```java
// Creating text area question
CreateQuestionRequest textArea = new CreateQuestionRequest();
textArea.setTitle("请详细描述您对我们产品的建议");
textArea.setType(4);
textArea.setIsRequired(false);
textArea.setSort(4);
textArea.setOptions(null); // No options needed

// Submitting text area answer
AnswerRequest textAnswer = new AnswerRequest(126L, "建议增加更多功能，提升用户体验...");
```

##### 5. Rating (Type 5)
```java
// Creating rating question
CreateQuestionRequest rating = new CreateQuestionRequest();
rating.setTitle("请对我们的服务进行评分（1-10分）");
rating.setType(5);
rating.setIsRequired(true);
rating.setSort(5);
rating.setOptions(null); // No options needed, range controlled by frontend

// Submitting rating answer
AnswerRequest ratingAnswer = new AnswerRequest(127L, "8");
```

#### Complete Questionnaire Workflow
```java
// 1. Create questionnaire
CreateQuestionnaireRequest createRequest = buildSampleQuestionnaire();
QuestionnaireResponse questionnaire = questionnaireService.createQuestionnaire(createRequest, "admin");

// 2. Publish questionnaire
QuestionnaireResponse published = questionnaireService.publishQuestionnaire(questionnaire.getId(), "admin");

// 3. Users submit answers
SubmitAnswerRequest answerRequest = buildSampleAnswers(questionnaire.getId());
ResponseDetailResponse answerResponse = questionnaireService.submitAnswer(answerRequest);

// 4. View statistics
QuestionnaireStatistics statistics = questionnaireService.getStatistics(questionnaire.getId());
log.info("Statistics - Total responses: {}, Completion rate: {}%", 
         statistics.getTotalResponses(), statistics.getCompletionRate() * 100);

// 5. Stop questionnaire when done
QuestionnaireResponse stopped = questionnaireService.stopQuestionnaire(questionnaire.getId(), "admin");
```

#### Fallback Cache Management for Questionnaires
```java
@Autowired
private IntegrationFallbackService fallbackService;

// Check fallback cache status
boolean hasQuestionnaireCache = fallbackService.hasFallbackCache("zt-questionnaire", "questionnaire:1001");
boolean hasListCache = fallbackService.hasFallbackCache("zt-questionnaire", "questionnaire:list:1:10:null:null:null");
boolean hasStatsCache = fallbackService.hasFallbackCache("zt-questionnaire", "questionnaire:statistics:1001");

// Get cache statistics
IntegrationFallbackService.FallbackCacheStats stats = fallbackService.getFallbackCacheStats("zt-questionnaire");
log.info("Questionnaire fallback cache: {} items, TTL: {} days", 
         stats.getTotalCacheCount(), stats.getFallbackTtlDays());

// Clear specific cache
fallbackService.clearFallbackCache("zt-questionnaire", "questionnaire:1001");

// Clear all questionnaire caches
fallbackService.clearAllFallbackCache("zt-questionnaire");
```

### Question Types and Validation Rules

| Question Type | Type Value | Description | Options Required | Answer Format |
|---------------|------------|-------------|------------------|---------------|
| Single Choice | 1 | User can select one answer | Yes (2+ options) | Single option value |
| Multiple Choice | 2 | User can select multiple answers | Yes (2+ options) | Comma-separated option values |
| Fill in Blank | 3 | User inputs short text | No | Text content (1-200 chars) |
| Text Area | 4 | User inputs long text | No | Text content (1-2000 chars) |
| Rating | 5 | User provides numerical rating | No | Number as string (e.g., "1", "10") |

### Answer Validation Rules

| Question Type | Validation Rules | Example |
|---------------|------------------|---------|
| Single Choice | Must be existing option value | "male", "female" |
| Multiple Choice | Comma-separated existing option values | "java,python", "option1,option2,option3" |
| Fill in Blank | Non-empty string, 1-200 characters | "张三", "北京市" |
| Text Area | String, 1-2000 characters | "这是一段较长的文本内容..." |
| Rating | Numeric string, typically 1-10 range | "1", "5", "10" |

### Questionnaire Status

- **1**: Draft - Questionnaire is being edited
- **2**: Published - Questionnaire is live and accepting responses
- **3**: Stopped - Questionnaire is no longer accepting responses
- **4**: Deleted - Questionnaire has been deleted

### Common Use Cases

#### Customer Satisfaction Survey
```java
// Create customer satisfaction questionnaire with rating and feedback
CreateQuestionnaireRequest customerSurvey = new CreateQuestionnaireRequest();
customerSurvey.setName("客户满意度调查");
customerSurvey.setDescription("收集客户对服务的满意度反馈");
customerSurvey.setIsAnonymous(true);

// Add rating question
CreateQuestionRequest ratingQ = new CreateQuestionRequest();
ratingQ.setTitle("整体满意度评分（1-10分）");
ratingQ.setType(5);
ratingQ.setIsRequired(true);

// Add feedback question
CreateQuestionRequest feedbackQ = new CreateQuestionRequest();
feedbackQ.setTitle("请提供具体的改进建议");
feedbackQ.setType(4);
feedbackQ.setIsRequired(false);

customerSurvey.setQuestions(Arrays.asList(ratingQ, feedbackQ));
```

#### Product Feature Feedback
```java
// Create product feature questionnaire with multiple choice and priorities
CreateQuestionnaireRequest featureSurvey = new CreateQuestionnaireRequest();
featureSurvey.setName("产品功能需求调研");
featureSurvey.setIsAnonymous(false);

// Priority features question
CreateQuestionRequest featuresQ = new CreateQuestionRequest();
featuresQ.setTitle("您最希望我们优先开发哪些功能？");
featuresQ.setType(2); // Multiple choice
featuresQ.setIsRequired(true);

List<CreateQuestionOptionRequest> featureOptions = new ArrayList<>();
featureOptions.add(new CreateQuestionOptionRequest("移动端适配", "mobile_support", 1));
featureOptions.add(new CreateQuestionOptionRequest("数据导出", "data_export", 2));
featureOptions.add(new CreateQuestionOptionRequest("API集成", "api_integration", 3));
featureOptions.add(new CreateQuestionOptionRequest("高级分析", "advanced_analytics", 4));
featuresQ.setOptions(featureOptions);

featureSurvey.setQuestions(Arrays.asList(featuresQ));
```

### Error Handling and HTTP Status Codes

#### HTTP Status Codes
- **200 OK**: Operation successful
- **201 Created**: Questionnaire/response created successfully
- **400 Bad Request**: Invalid request parameters or validation errors
- **404 Not Found**: Questionnaire or response not found
- **500 Internal Server Error**: Server error occurred

#### Common Error Scenarios
```java
try {
    QuestionnaireResponse questionnaire = questionnaireService.getQuestionnaire(invalidId);
} catch (IntegrationException e) {
    switch (e.getCode()) {
        case 404:
            log.warn("问卷不存在: {}", invalidId);
            break;
        case 400:
            log.warn("请求参数错误: {}", e.getMessage());
            break;
        case 500:
            log.error("服务器内部错误: {}", e.getMessage());
            break;
        default:
            log.error("未知错误: {}", e.getMessage());
    }
}
```

### Testing Questionnaire Integration

```bash
# Run questionnaire integration tests
mvn test -Dtest=QuestionnaireIntegrationServiceTest

# Run all integration tests
mvn test -Dtest="com.ycwl.basic.integration.*Test"

# Enable example runner in application-dev.yml
integration:
  questionnaire:
    example:
      enabled: true
```

### Configuration Properties

```yaml
integration:
  questionnaire:
    enabled: true                    # Enable questionnaire integration
    serviceName: zt-questionnaire    # Service name for Nacos discovery
    connectTimeout: 5000             # Connection timeout in ms
    readTimeout: 10000               # Read timeout in ms
    retryEnabled: false              # Enable retry mechanism
    maxRetries: 3                    # Maximum retry attempts
    
  fallback:
    questionnaire:
      enabled: true                  # Enable fallback for questionnaire service
      ttlDays: 7                     # Cache TTL in days
      cachePrefix: "questionnaire:fallback:"  # Optional custom prefix
```

### Best Practices for Questionnaire Integration

#### Query vs Mutation Operations
- **Query operations (GET)**: Use fallback - questionnaire details, lists, statistics, responses
- **Mutation operations (POST/PUT/DELETE)**: No fallback - create, update, delete, publish, stop, submit

#### Cache Key Design
- `questionnaire:{id}` - Individual questionnaire cache
- `questionnaire:list:{page}:{size}:{name}:{status}:{createdBy}` - List cache
- `questionnaire:statistics:{id}` - Statistics cache
- `response:{id}` - Individual response cache
- `responses:list:{page}:{size}:{questionnaireId}:{userId}` - Response list cache

#### Answer Submission Best Practices
- Validate question types before submission
- Handle validation errors gracefully
- Provide clear error messages for users
- Log submission attempts for audit purposes

#### Performance Considerations
- Use appropriate page sizes for questionnaire lists
- Cache frequently accessed questionnaires
- Monitor response submission patterns
- Implement rate limiting for public questionnaires

## Profit Share Integration (ZT-ProfitShare Microservice)

### Overview
The zt-profitshare microservice provides comprehensive revenue sharing management for scenic areas, supporting multiple payment systems (Alipay, WeChat, UnionPay) and various distribution rules. It offers both HTTP REST API for management operations and Kafka messaging for automatic profit sharing triggered by payment events.

### Key Components

#### Feign Client
- **ProfitShareClient**: Complete profit share operations (rules, records, manual sharing, calculations)

#### Services
- **ProfitShareIntegrationService**: High-level profit share operations (with automatic fallback for queries)
- **ProfitShareKafkaProducer**: Kafka message producer for profit share and refund events

#### Configuration
```yaml
integration:
  profitshare:
    enabled: true
    serviceName: zt-profitshare
    connectTimeout: 5000
    readTimeout: 10000
    retryEnabled: false
    maxRetries: 3
  fallback:
    profitshare:
      enabled: true
      ttlDays: 7

kafka:
  enabled: true
  profit-share-topic: zt-profitshare
  refund-topic: zt-refund
```

### Usage Examples

#### Rule Management Operations

```java
@Autowired
private ProfitShareIntegrationService profitShareService;

// Create profit share rule (direct operation, fails immediately on error)
CreateRuleRequest ruleRequest = new CreateRuleRequest();
ruleRequest.setScenicId(1001L);
ruleRequest.setRuleName("标准分账规则");
ruleRequest.setRuleType("percentage");
ruleRequest.setDescription("平台收取5%手续费");

// Add platform recipient
CreateRecipientRequest platform = new CreateRecipientRequest();
platform.setRecipientName("平台手续费");
platform.setRecipientType("platform");
platform.setAccountInfo("platform_001");
platform.setShareType("percentage");
platform.setShareValue(5.0);
platform.setPriority(1);

Map<String, Object> platformExt = new HashMap<>();
platformExt.put("payment_system", "alipay");
platformExt.put("sub_merchant_id", "platform_001");
platform.setExtConfig(platformExt);

// Add scenic recipient
CreateRecipientRequest scenic = new CreateRecipientRequest();
scenic.setRecipientName("景区收款账户");
scenic.setRecipientType("merchant");
scenic.setAccountInfo("merchant_001");
scenic.setShareType("percentage");
scenic.setShareValue(95.0);
scenic.setPriority(2);

Map<String, Object> scenicExt = new HashMap<>();
scenicExt.put("payment_system", "alipay");
scenicExt.put("sub_merchant_id", "scenic_001");
scenicExt.put("settle_period", "T+1");
scenic.setExtConfig(scenicExt);

ruleRequest.setRecipients(Arrays.asList(platform, scenic));

RuleVO createdRule = profitShareService.createRule(ruleRequest);
log.info("分账规则创建成功: {}", createdRule.getId());

// Get rule details (automatically falls back to cache on failure)
RuleVO rule = profitShareService.getRule(ruleId);
log.info("规则名称: {}, 状态: {}", rule.getRuleName(), rule.getStatus());

// List rules (automatically falls back to cache on failure)
PageResponse<RuleVO> rules = profitShareService.listRules(1001L, "active", "percentage", 1, 10);
log.info("查询到 {} 条规则", rules.getData().getTotal());

// Update rule (direct operation, fails immediately on error)
CreateRuleRequest updateRequest = new CreateRuleRequest();
updateRequest.setRuleName("更新后的分账规则");
RuleVO updated = profitShareService.updateRule(ruleId, updateRequest);

// Enable/disable rule (direct operations, fail immediately on error)
profitShareService.enableRule(ruleId);
profitShareService.disableRule(ruleId);

// Delete rule (direct operation, fails immediately on error)
profitShareService.deleteRule(ruleId);
```

#### Record Query Operations (with Automatic Fallback)

```java
// Get scenic profit share records (automatically falls back to cache on failure)
PageResponse<RecordVO> records = profitShareService.getRecordsByScenic(1001L, 1, 10);
log.info("景区分账记录: {} 条", records.getData().getTotal());

records.getData().getList().forEach(record -> {
    log.info("订单: {}, 金额: {}, 状态: {}", 
            record.getOrderId(), record.getTotalAmount(), record.getStatus());
});

// Get record detail by ID (automatically falls back to cache on failure)
RecordDetailVO detail = profitShareService.getRecordById(recordId);
log.info("分账记录详情:");
detail.getDetails().forEach(shareDetail -> {
    log.info("  接收人: {}, 金额: {}, 状态: {}", 
            shareDetail.getRecipientName(), shareDetail.getShareAmount(), shareDetail.getStatus());
});

// Get record by order ID (automatically falls back to cache on failure)
RecordDetailVO recordByOrder = profitShareService.getRecordByOrderId("ORDER_123456");
```

#### Kafka Message Production

```java
@Autowired
private ProfitShareKafkaProducer profitShareProducer;

// Send profit share message after payment success
@Transactional
public void handleOrderPaymentSuccess(Order order) {
    // 1. Update order status
    order.setStatus("PAID");
    order.setPaymentTime(new Date());
    orderRepository.save(order);

    // 2. Build profit share message
    OrderMessage message = OrderMessage.of(
            order.getOrderId(),
            order.getScenicId(),
            order.getTotalAmount().doubleValue(),
            order.getPaymentChannel(), // "alipay", "wechat", "union"
            order.getPaymentOrderId()
    );

    // 3. Send to Kafka (async profit sharing)
    profitShareProducer.sendProfitShareMessage(message);
    
    log.info("订单支付成功，已发送分账消息: orderId={}, amount={}", 
            order.getOrderId(), order.getTotalAmount());
}

// Send refund message after refund success
@Transactional
public void handleOrderRefundSuccess(Order order, BigDecimal refundAmount) {
    // 1. Update order status
    order.setStatus("REFUNDED");
    orderRepository.save(order);

    // 2. Build refund message
    RefundMessage message = RefundMessage.of(
            order.getOrderId(),
            order.getScenicId(),
            refundAmount.doubleValue(),
            order.getPaymentChannel(),
            order.getRefundOrderId()
    );

    // 3. Send refund message
    profitShareProducer.sendRefundMessage(message);
    
    log.info("订单退款成功，已发送退款消息: orderId={}, amount={}", 
            order.getOrderId(), refundAmount);
}
```

#### Manual Profit Sharing

```java
// Manual trigger profit sharing (direct operation, fails immediately on error)
// Used for compensation scenarios or delayed profit sharing
profitShareService.manualShare("ORDER_123456");
log.info("手动分账触发成功");
```

#### Calculate Profit Share

```java
// Calculate profit share without execution (automatically falls back to cache on failure)
CalculateShareRequest calcRequest = new CalculateShareRequest();
calcRequest.setScenicId(1001L);
calcRequest.setTotalAmount(1000.0);
calcRequest.setRuleType("percentage");
calcRequest.setRecipients(Arrays.asList(platform, scenic));

CalculateResultVO result = profitShareService.calculateShare(calcRequest);
log.info("总金额: {}, 分账明细:", result.getTotalAmount());
result.getDetails().forEach(detail -> {
    log.info("  {}: {} 元", detail.getRecipientName(), detail.getShareAmount());
});

// Get supported types (automatically falls back to cache on failure)
TypesVO types = profitShareService.getSupportedTypes();
log.info("支持的规则类型: {}", types.getRuleTypes());
log.info("支持的接收人类型: {}", types.getRecipientTypes());
```

#### Fallback Cache Management

```java
@Autowired
private IntegrationFallbackService fallbackService;

// Check fallback cache status
boolean hasRuleCache = fallbackService.hasFallbackCache("zt-profitshare", "rule:1001");
boolean hasRecordsCache = fallbackService.hasFallbackCache("zt-profitshare", "records:scenic:1001:1:10");

// Get cache statistics
IntegrationFallbackService.FallbackCacheStats stats = fallbackService.getFallbackCacheStats("zt-profitshare");
log.info("Profit share fallback cache: {} items, TTL: {} days", 
         stats.getTotalCacheCount(), stats.getFallbackTtlDays());

// Clear specific cache
fallbackService.clearFallbackCache("zt-profitshare", "rule:1001");

// Clear all profit share caches
fallbackService.clearAllFallbackCache("zt-profitshare");
```

### Rule Types and Configuration

#### Rule Types
- **percentage**: Percentage-based distribution (e.g., platform 5%, merchant 95%)
- **fixed_amount**: Fixed amount distribution
- **scaled_amount**: Tiered amount distribution based on order amount

#### Recipient Types
- **platform**: Platform service fee recipient
- **merchant**: Merchant/scenic area recipient
- **agent**: Agent/distributor recipient

#### Share Types
- **percentage**: Share as percentage of total amount
- **fixed_amount**: Share as fixed amount

#### Payment Systems
- **alipay**: Alipay payment system
- **wechat**: WeChat Pay payment system
- **union**: UnionPay payment system

### Extended Configuration Examples

#### Alipay Configuration
```json
{
  "payment_system": "alipay",
  "sub_merchant_id": "2088xxx",
  "settle_period": "T+1",
  "account_type": "ALIPAY_LOGON_ID"
}
```

#### WeChat Configuration
```json
{
  "payment_system": "wechat",
  "sub_mch_id": "1234567890",
  "settle_period": "T+0",
  "account_type": "MERCHANT_ID"
}
```

#### Tiered Sharing Configuration
```json
{
  "scales": [
    {
      "min_amount": 0,
      "max_amount": 1000,
      "share_value": 3.0,
      "share_type": "percentage"
    },
    {
      "min_amount": 1000,
      "max_amount": 5000,
      "share_value": 5.0,
      "share_type": "percentage"
    },
    {
      "min_amount": 5000,
      "max_amount": 0,
      "share_value": 8.0,
      "share_type": "percentage"
    }
  ]
}
```

### Record Status

- **pending**: Profit share request pending
- **processing**: Profit share in progress
- **success**: Profit share completed successfully
- **failed**: Profit share failed (requires manual intervention)

### Cache Key Design

- `rule:{id}` - Individual rule cache
- `rules:list:{scenicId}:{status}:{ruleType}:{page}:{size}` - Rule list cache
- `record:{id}` - Individual record cache
- `record:order:{orderId}` - Record by order ID cache
- `records:scenic:{scenicId}:{page}:{size}` - Scenic records cache
- `calculate:{scenicId}:{amount}` - Calculation cache
- `types` - Supported types cache

### Best Practices

#### When to Use HTTP API vs Kafka
- **HTTP API**: 
  - Rule management (create, update, enable/disable, delete)
  - Query operations (records, statistics)
  - Manual compensation scenarios
  - Profit share calculation (dry run)

- **Kafka Messages** (Recommended):
  - Automatic profit sharing after order payment
  - Automatic reversal after order refund
  - Asynchronous processing with retry capability
  - Decoupled from main order flow

#### Idempotency Handling
```java
// Check before sending Kafka message
if (profitShareRecordRepository.existsByOrderId(orderId)) {
    log.warn("订单已发起分账，跳过: orderId={}", orderId);
    return;
}

// Record profit share request
ProfitShareRequest request = new ProfitShareRequest();
request.setOrderId(orderId);
request.setStatus("PENDING");
request.setCreatedAt(new Date());
profitShareRecordRepository.save(request);

// Send Kafka message
profitShareProducer.sendProfitShareMessage(message);
```

#### Monitoring and Alerts
```java
// Monitor Kafka message send success rate
metricRegistry.counter("profit_share.kafka.send.success").inc();
metricRegistry.counter("profit_share.kafka.send.failure").inc();

// Monitor profit share record status
metricRegistry.gauge("profit_share.records.pending", () -> 
    profitShareRecordRepository.countByStatus("pending"));
metricRegistry.gauge("profit_share.records.failed", () -> 
    profitShareRecordRepository.countByStatus("failed"));

// Alert on failures
if (!response.getSuccess()) {
    alertService.send("分账服务异常", response.getMessage());
}
```

### Common Issues and Solutions

#### Q1: Kafka message sent but no profit share record created?
**A**: Troubleshooting steps:
1. Check Kafka broker connectivity
2. Verify topic `zt-profitshare` exists
3. Check profit share service logs for consumption errors
4. Query record by order ID to verify processing status

#### Q2: Profit share calculation incorrect?
**A**: Verify:
- Amount unit is in Yuan (元), not Fen (分)
- Percentage shares sum up to 100% or less
- Check `min_amount` and `max_amount` limits
- Review recipient priority ordering

#### Q3: How to handle profit share failures?
**A**: Profit share service automatically retries (max 3 times). If still fails:
1. Query record detail for error message
2. Fix data or rule issues
3. Call manual share API to retry
4. Set up alerts for failed records

#### Q4: Can I modify rule after orders are processed?
**A**: Yes, but:
- New orders use the updated rule
- Existing profit share records are not affected
- Consider creating new rule instead of modifying active one
- Disable old rule and enable new one for clean transition

### Testing Profit Share Integration

```bash
# Run profit share integration tests
mvn test -Dtest=ProfitShareIntegrationServiceTest

# Run all integration tests
mvn test -Dtest="com.ycwl.basic.integration.*Test"
```