# 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
- **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

## 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