11 KiB
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_MODEis 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_MODEenvironment 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:
{
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:
-
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
-
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
-
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
-
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:
mutation productVariantsBulkUpdate(
$productId: ID!
$variants: [ProductVariantsBulkInput!]!
) {
productVariantsBulkUpdate(productId: $productId, variants: $variants) {
productVariants {
id
price
compareAtPrice
}
userErrors {
field
message
}
}
}
Rollback Mutation Variables:
{
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:
-
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
-
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:
// 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:
-
logRollbackStart(config)- Logs rollback operation start with configuration
- Distinguishes from price update operations in logs
- Includes operation mode in log entries
-
logRollbackUpdate(updateDetails)- Logs successful rollback operations
- Includes original price, compare-at price, and new price
- Formats specifically for rollback operations
-
logRollbackSummary(results)- Logs rollback completion summary
- Includes rollback-specific statistics
- Distinguishes from price update summaries
Main Application (index.js)
Extensions:
-
Operation Mode Detection:
- Read operation mode from configuration
- Route to appropriate workflow based on mode
- Maintain single entry point for both operations
-
Rollback Workflow Methods:
fetchAndValidateProductsForRollback(): Fetch and validate products for rollbackrollbackPrices(products): Execute rollback operationsdisplayRollbackSummary(results): Display rollback-specific summary
-
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
{
isEligible: boolean,
reason?: string, // Present if not eligible
variant: {
id: string,
currentPrice: number,
compareAtPrice: number | null
}
}
Rollback Update Object
{
newPrice: number, // Set to current compare-at price
compareAtPrice: null // Always null to remove compare-at price
}
Rollback Results
{
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
{
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
-
No Compare-At Price:
- Skip variant and log warning
- Continue processing other variants
- Include in skipped count for summary
-
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
-
Same Price Values:
- Skip variant if current price equals compare-at price
- Log informational message (no rollback needed)
- Continue processing other variants
-
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