Skip to content

Conversation

@psd-coder
Copy link
Member

Overview

This PR introduces a comprehensive configuration versioning and migration system for Harmonizer. It adds support for schema versioning, type-safe sequential migrations, and replaces the legacy compact config format with modern deflate compression for URL hashes. The system is designed to ensure backward compatibility while enabling safe evolution of the config schema.

Problem Statement

The Harmonizer application needed a robust way to handle configuration schema changes over time. Without a versioning system, any breaking changes to the config format would break existing shared URLs and saved configurations. The legacy compact format for URL hashes was also limited and not easily extensible.

Key issues addressed:

  • No mechanism to handle config schema evolution
  • Legacy URL hash format was not future-proof
  • Risk of breaking existing user configurations during schema updates
  • Lack of test coverage for config parsing and migration logic

Solution Approach

  1. Config Versioning System: Added a version field to the export config schema starting at v1, with CURRENT_CONFIG_VERSION constant tracking the latest version (currently v2). All configs now carry explicit version information.

  2. Type-Safe Migration Builder: Implemented MigrationBuilder pattern that enables chaining migrations with full TypeScript type inference. Each migration transforms the config from one version to the next, with the builder automatically injecting version numbers into outputs.

  3. Deflate Compression for URL Hashes: Replaced the legacy compact config format with native CompressionStream API using deflate-raw compression combined with URL-safe base64 encoding. This provides better compression and a cleaner, more extensible format.

  4. Backward Compatibility: Hash decoding attempts the new deflate format first, then falls back to legacy base64 compact format, ensuring existing shared URLs continue to work.

  5. Async Config Parsing: Made config parsing asynchronous to support async compression/decompression operations via native browser APIs.

  6. Comprehensive Test Infrastructure: Added Vitest configuration with 100% coverage targets for critical files, extensive test fixtures for v1/v2 configs and legacy formats, and 400+ lines of tests covering schema validation, parsing, migration, and roundtrip operations.

  7. CI Integration: Added GitHub Actions workflow for automated testing on all branches.

  8. Schema v2 Introduction: Added showContrastLabels boolean setting to demonstrate the migration system, with v1→v2 migration defaulting this field to false.

Breaking Changes

None. The changes are fully backward compatible:

  • Existing URL hashes using the legacy compact format continue to work
  • Configs without a version field are treated as v1 and migrated automatically
  • All parsing functions now return promises (internal change, affects only internal consumers)

Establishes the foundation for implementing a comprehensive config
versioning system by setting up Vitest as the test framework. This
infrastructure will enable us to write regression tests before making
schema changes, ensuring backward compatibility and safe migrations.

Key additions:
- Vitest 4 configuration with 100% coverage targets for critical files
- Test scripts for local development (test, test:watch) and CI
- GitHub Actions workflow for automated testing on all branches
- Test fixture structure with v1 configs and legacy formats
- Test utilities for loading JSON and hash fixtures

This infrastructure allows us to:
1. Document current behavior through tests before refactoring
2. Verify migrations don't break existing functionality
3. Maintain confidence during schema evolution
4. Enforce high code quality standards via CI
Adds 47 test cases covering current schema validation, parsing, compact
format conversion, and roundtrip operations. These tests serve as
regression tests before implementing the versioned schema system.

Key test coverage:
- exportConfigSchema validation with all field types
- parseExportConfig with string/object inputs and error handling
- compactExportConfigSchema validation of flat array format
- toCompactExportConfig conversion to flat arrays
- toExportConfig reconstruction from compact format
- Roundtrip data preservation (config → compact → config)
- All test fixtures (minimal, full, chromaCap, invalid cases)

Notable current behaviors documented:
- chromaCap null values stay as null (Valibot optional() behavior)
- parseExportConfig wraps all errors in generic message
- Compact format uses flat arrays for levels/hues
- All chroma values set to 0 during compact conversion
…ing native APIs and safe base64 encoder/decoder. Add unit tests for them.
Introduce CURRENT_CONFIG_VERSION constant and add version field to export config schema with validation (minimum value 1, defaults to 1). Update default config, store, and conversion functions to include the version field. Add comprehensive tests covering valid versions, future versions, and invalid version handling.
Introduce a comprehensive migration system to handle future config schema changes. Implement versioned schemas with explicit v1 variants, migration builder pattern for type-safe sequential migrations, and hash decoding that supports both new deflate-based and legacy base64 compact formats with automatic fallback to defaults.
Ensure bgLightStart setting is within the valid range of defined color levels to prevent out-of-bounds errors
Implement migration framework to handle config version transitions. Make config parsing asynchronous to support async compression/decompression, update all call sites to await parsing, switch from compact hash to deflate compression, and make decodeHashConfig return null instead of default config on failure for explicit error handling.
Migrate legacy compact format to dedicated migration module and implement
new compression strategy using deflate + url-safe base64 for URL hashes.
Maintains backward compatibility with existing legacy hashes.
Update MigrationBuilder to automatically inject the version property into migration outputs, removing the need for migrations to manually set version fields. This reduces boilerplate and enforces consistency by having the builder track and apply versions automatically. Update tests to reflect simplified migration syntax.
Introduce version 2 of the export config schema to support the showContrastLabels boolean setting. Add migration from v1 that defaults showContrastLabels to false for backward compatibility. Include test fixtures and comprehensive tests for v2 config parsing and hash encoding/decoding.
@github-actions
Copy link

github-actions bot commented Jan 19, 2026

Visit the preview URL for this PR (updated for commit fc0dcd6):

https://harmonizer-web--pr56-config-migrations-2cgfsxsx.web.app

(expires Tue, 27 Jan 2026 00:45:51 GMT)

🔥 via Firebase Hosting GitHub Action 🌎

Sign: 0b46b8946d697564b3f98633c5cd230a6ede1236

Document test commands in README, exclude coverage directories from git tracking, and remove redundant test:core alias in favor of pnpm core test syntax
@psd-coder psd-coder merged commit 7b170aa into main Jan 20, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants