Implemented Rollback Functionality
This commit is contained in:
390
.kiro/specs/price-rollback/design.md
Normal file
390
.kiro/specs/price-rollback/design.md
Normal file
@@ -0,0 +1,390 @@
|
||||
# Design Document
|
||||
|
||||
## Overview
|
||||
|
||||
The Price Rollback feature extends the existing Shopify Price Updater application to support reversing pricing changes by setting the main product price to the current compare-at price and removing the compare-at price. This functionality will be integrated into the existing application architecture, providing dual operation modes (price update and rollback) within the same codebase and infrastructure.
|
||||
|
||||
## Architecture
|
||||
|
||||
The rollback functionality will be integrated into the existing modular architecture with minimal changes:
|
||||
|
||||
```
|
||||
shopify-price-updater/
|
||||
├── src/
|
||||
│ ├── config/
|
||||
│ │ └── environment.js # Extended to support operation mode configuration
|
||||
│ ├── services/
|
||||
│ │ ├── shopify.js # Existing Shopify API client (no changes)
|
||||
│ │ ├── product.js # Extended with rollback methods
|
||||
│ │ └── progress.js # Extended to log rollback operations
|
||||
│ ├── utils/
|
||||
│ │ ├── price.js # Extended with rollback price utilities
|
||||
│ │ └── logger.js # Extended to distinguish operation types
|
||||
│ └── index.js # Extended to support dual operation modes
|
||||
├── .env.example # Updated with operation mode variable
|
||||
├── package.json # Updated scripts for rollback mode
|
||||
└── Progress.md # Contains both update and rollback logs
|
||||
```
|
||||
|
||||
## Operation Mode Selection
|
||||
|
||||
The application will determine its operation mode through environment configuration:
|
||||
|
||||
### Environment Variable
|
||||
|
||||
- `OPERATION_MODE`: Controls which operation to perform
|
||||
- `"update"` (default): Performs price updates with percentage adjustments
|
||||
- `"rollback"`: Performs price rollbacks using compare-at prices
|
||||
|
||||
### Backward Compatibility
|
||||
|
||||
- If `OPERATION_MODE` is not specified, defaults to `"update"` mode
|
||||
- All existing environment variables remain unchanged
|
||||
- Existing scripts and workflows continue to work without modification
|
||||
|
||||
## Components and Interfaces
|
||||
|
||||
### Environment Configuration (`config/environment.js`)
|
||||
|
||||
**Extensions:**
|
||||
|
||||
- Add `OPERATION_MODE` environment variable loading and validation
|
||||
- Validate operation mode is either "update" or "rollback"
|
||||
- Export operation mode in configuration object
|
||||
- Maintain backward compatibility when operation mode is not specified
|
||||
|
||||
**New Configuration Object:**
|
||||
|
||||
```javascript
|
||||
{
|
||||
shopDomain: string,
|
||||
accessToken: string,
|
||||
targetTag: string,
|
||||
priceAdjustmentPercentage: number, // Only used in update mode
|
||||
operationMode: 'update' | 'rollback' // New field
|
||||
}
|
||||
```
|
||||
|
||||
### Product Service (`services/product.js`)
|
||||
|
||||
**New Methods:**
|
||||
|
||||
1. **`validateProductsForRollback(products)`**
|
||||
|
||||
- Validates products have variants with compare-at prices
|
||||
- Skips products/variants without compare-at prices
|
||||
- Logs validation warnings for products that cannot be rolled back
|
||||
- Returns array of products with rollback-eligible variants
|
||||
|
||||
2. **`rollbackProductPrices(products)`**
|
||||
|
||||
- Main rollback orchestration method
|
||||
- Processes products in batches to manage rate limits
|
||||
- Returns results object with rollback statistics
|
||||
- Logs progress and errors during rollback operations
|
||||
|
||||
3. **`processProductForRollback(product, results)`**
|
||||
|
||||
- Processes individual product for rollback
|
||||
- Iterates through variants and performs rollback operations
|
||||
- Updates results object with success/failure counts
|
||||
- Handles variant-level error logging
|
||||
|
||||
4. **`rollbackVariantPrice(variant, productId)`**
|
||||
- Updates individual variant price to compare-at price value
|
||||
- Sets compare-at price to null (removes it)
|
||||
- Uses existing GraphQL mutation infrastructure
|
||||
- Returns success/failure result with error details
|
||||
|
||||
**GraphQL Mutation for Rollback:**
|
||||
|
||||
```graphql
|
||||
mutation productVariantsBulkUpdate(
|
||||
$productId: ID!
|
||||
$variants: [ProductVariantsBulkInput!]!
|
||||
) {
|
||||
productVariantsBulkUpdate(productId: $productId, variants: $variants) {
|
||||
productVariants {
|
||||
id
|
||||
price
|
||||
compareAtPrice
|
||||
}
|
||||
userErrors {
|
||||
field
|
||||
message
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Rollback Mutation Variables:**
|
||||
|
||||
```javascript
|
||||
{
|
||||
productId: "gid://shopify/Product/123",
|
||||
variants: [{
|
||||
id: "gid://shopify/ProductVariant/456",
|
||||
price: "750.00", // Set to current compare-at price
|
||||
compareAtPrice: null // Remove compare-at price
|
||||
}]
|
||||
}
|
||||
```
|
||||
|
||||
### Price Utilities (`utils/price.js`)
|
||||
|
||||
**New Functions:**
|
||||
|
||||
1. **`validateRollbackEligibility(variant)`**
|
||||
|
||||
- Checks if variant has a valid compare-at price
|
||||
- Validates compare-at price is different from current price
|
||||
- Returns boolean indicating rollback eligibility
|
||||
- Provides reason for ineligibility if applicable
|
||||
|
||||
2. **`prepareRollbackUpdate(variant)`**
|
||||
- Prepares price update object for rollback operation
|
||||
- Sets new price to current compare-at price value
|
||||
- Sets compare-at price to null
|
||||
- Validates the rollback operation is safe to perform
|
||||
|
||||
**Example Usage:**
|
||||
|
||||
```javascript
|
||||
// Check if variant can be rolled back
|
||||
const isEligible = validateRollbackEligibility(variant);
|
||||
|
||||
// Prepare rollback update
|
||||
const rollbackUpdate = prepareRollbackUpdate(variant);
|
||||
// Returns: { newPrice: 750.00, compareAtPrice: null }
|
||||
```
|
||||
|
||||
### Logger Utilities (`utils/logger.js`)
|
||||
|
||||
**Extensions:**
|
||||
|
||||
1. **`logRollbackStart(config)`**
|
||||
|
||||
- Logs rollback operation start with configuration
|
||||
- Distinguishes from price update operations in logs
|
||||
- Includes operation mode in log entries
|
||||
|
||||
2. **`logRollbackUpdate(updateDetails)`**
|
||||
|
||||
- Logs successful rollback operations
|
||||
- Includes original price, compare-at price, and new price
|
||||
- Formats specifically for rollback operations
|
||||
|
||||
3. **`logRollbackSummary(results)`**
|
||||
- Logs rollback completion summary
|
||||
- Includes rollback-specific statistics
|
||||
- Distinguishes from price update summaries
|
||||
|
||||
### Main Application (`index.js`)
|
||||
|
||||
**Extensions:**
|
||||
|
||||
1. **Operation Mode Detection:**
|
||||
|
||||
- Read operation mode from configuration
|
||||
- Route to appropriate workflow based on mode
|
||||
- Maintain single entry point for both operations
|
||||
|
||||
2. **Rollback Workflow Methods:**
|
||||
|
||||
- `fetchAndValidateProductsForRollback()`: Fetch and validate products for rollback
|
||||
- `rollbackPrices(products)`: Execute rollback operations
|
||||
- `displayRollbackSummary(results)`: Display rollback-specific summary
|
||||
|
||||
3. **Unified Error Handling:**
|
||||
- Extend existing error handling to support rollback operations
|
||||
- Maintain consistent error reporting across both modes
|
||||
- Preserve existing signal handling and graceful shutdown
|
||||
|
||||
## Data Models
|
||||
|
||||
### Rollback Validation Result
|
||||
|
||||
```javascript
|
||||
{
|
||||
isEligible: boolean,
|
||||
reason?: string, // Present if not eligible
|
||||
variant: {
|
||||
id: string,
|
||||
currentPrice: number,
|
||||
compareAtPrice: number | null
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Rollback Update Object
|
||||
|
||||
```javascript
|
||||
{
|
||||
newPrice: number, // Set to current compare-at price
|
||||
compareAtPrice: null // Always null to remove compare-at price
|
||||
}
|
||||
```
|
||||
|
||||
### Rollback Results
|
||||
|
||||
```javascript
|
||||
{
|
||||
totalProducts: number,
|
||||
totalVariants: number,
|
||||
eligibleVariants: number, // New field for rollback
|
||||
successfulRollbacks: number,
|
||||
failedRollbacks: number,
|
||||
skippedVariants: number, // Variants without compare-at prices
|
||||
errors: Array<{
|
||||
productId: string,
|
||||
productTitle: string,
|
||||
variantId: string,
|
||||
errorMessage: string
|
||||
}>
|
||||
}
|
||||
```
|
||||
|
||||
### Progress Entry for Rollback
|
||||
|
||||
```javascript
|
||||
{
|
||||
timestamp: Date,
|
||||
operationType: 'rollback', // Distinguishes from 'update'
|
||||
productId: string,
|
||||
productTitle: string,
|
||||
variantId: string,
|
||||
oldPrice: number, // Original price before rollback
|
||||
compareAtPrice: number, // Compare-at price being used as new price
|
||||
newPrice: number, // New price (same as compare-at price)
|
||||
status: 'success' | 'error' | 'skipped',
|
||||
errorMessage?: string,
|
||||
skipReason?: string // For variants without compare-at prices
|
||||
}
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
### Rollback-Specific Error Scenarios
|
||||
|
||||
1. **No Compare-At Price:**
|
||||
|
||||
- Skip variant and log warning
|
||||
- Continue processing other variants
|
||||
- Include in skipped count for summary
|
||||
|
||||
2. **Invalid Compare-At Price:**
|
||||
|
||||
- Skip variant if compare-at price is null, zero, or negative
|
||||
- Log validation warning with specific reason
|
||||
- Continue processing other variants
|
||||
|
||||
3. **Same Price Values:**
|
||||
|
||||
- Skip variant if current price equals compare-at price
|
||||
- Log informational message (no rollback needed)
|
||||
- Continue processing other variants
|
||||
|
||||
4. **API Update Failures:**
|
||||
- Use existing retry logic for rate limiting
|
||||
- Log specific error messages from Shopify API
|
||||
- Continue processing remaining variants
|
||||
|
||||
### Enhanced Error Reporting
|
||||
|
||||
- Distinguish rollback errors from update errors in logs
|
||||
- Provide rollback-specific error analysis in completion summary
|
||||
- Include skipped variant statistics in error reporting
|
||||
- Maintain existing error handling patterns for consistency
|
||||
|
||||
## Testing Strategy
|
||||
|
||||
### Unit Tests
|
||||
|
||||
**New Test Cases:**
|
||||
|
||||
- Test rollback price calculation utilities
|
||||
- Test rollback eligibility validation
|
||||
- Test rollback update object preparation
|
||||
- Test operation mode configuration loading
|
||||
|
||||
**Extended Test Cases:**
|
||||
|
||||
- Test product service rollback methods
|
||||
- Test logger rollback-specific methods
|
||||
- Test main application rollback workflow
|
||||
|
||||
### Integration Tests
|
||||
|
||||
**New Test Scenarios:**
|
||||
|
||||
- Test rollback operations with development store
|
||||
- Test rollback with products having various compare-at price scenarios
|
||||
- Test rollback mode selection and configuration
|
||||
- Test mixed scenarios (some variants eligible, some not)
|
||||
|
||||
**Extended Test Scenarios:**
|
||||
|
||||
- Test dual operation mode functionality
|
||||
- Test backward compatibility with existing configurations
|
||||
- Test progress logging for rollback operations
|
||||
|
||||
### End-to-End Tests
|
||||
|
||||
**Rollback Workflow Tests:**
|
||||
|
||||
- Test complete rollback workflow with test products
|
||||
- Verify prices are correctly set to compare-at values
|
||||
- Verify compare-at prices are removed after rollback
|
||||
- Test error recovery and continuation scenarios
|
||||
|
||||
**Dual Mode Tests:**
|
||||
|
||||
- Test switching between update and rollback modes
|
||||
- Test that both modes use same infrastructure correctly
|
||||
- Verify progress logging distinguishes between operations
|
||||
|
||||
### Manual Testing Checklist
|
||||
|
||||
**Rollback Functionality:**
|
||||
|
||||
- Test rollback with products having compare-at prices
|
||||
- Test rollback with products missing compare-at prices
|
||||
- Test rollback with mixed variant scenarios
|
||||
- Verify Progress.md logging for rollback operations
|
||||
|
||||
**Integration Testing:**
|
||||
|
||||
- Test backward compatibility with existing configurations
|
||||
- Test operation mode switching
|
||||
- Test that existing update functionality remains unchanged
|
||||
- Verify error handling consistency across both modes
|
||||
|
||||
## Implementation Considerations
|
||||
|
||||
### Code Reuse Strategy
|
||||
|
||||
- Maximize reuse of existing Shopify API infrastructure
|
||||
- Extend existing classes rather than creating new ones
|
||||
- Maintain consistent error handling patterns
|
||||
- Preserve existing logging and progress tracking mechanisms
|
||||
|
||||
### Performance Considerations
|
||||
|
||||
- Use same batching strategy as existing price updates
|
||||
- Apply same rate limiting and retry logic
|
||||
- Maintain existing pagination patterns for product fetching
|
||||
- Preserve existing delay mechanisms between operations
|
||||
|
||||
### Backward Compatibility
|
||||
|
||||
- Default to existing behavior when operation mode not specified
|
||||
- Maintain all existing environment variables and their behavior
|
||||
- Preserve existing script entry points and command line usage
|
||||
- Ensure existing Progress.md format remains compatible
|
||||
|
||||
### Configuration Management
|
||||
|
||||
- Add new environment variable with sensible default
|
||||
- Validate operation mode values during configuration loading
|
||||
- Provide clear error messages for invalid operation modes
|
||||
- Update .env.example with new configuration option
|
||||
Reference in New Issue
Block a user