391 lines
11 KiB
Markdown
391 lines
11 KiB
Markdown
# 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
|