This class diagram illustrates the complete architecture of the EasySave application according to the MVVM (Model-View-ViewModel) pattern, featuring a clear separation of concerns.
Class Diagram v3.0 - MVVM Architecture
The diagram is organized into several thematic packages according to the MVVM architecture:
- Enums: Enumerations for types and states
- Models: Business data models
- Context: Execution context shared between services
- Interfaces: Contracts defining behaviors
- Services: Business implementations and application logic
- Strategies: Backup strategies (Strategy Pattern)
- EasyLog.dll: External logging library
- Commands: Command implementations (ICommand for WPF)
- ViewModels: Presentation logic and data binding with views
- Views: User interfaces (Console and WPF Graphical)
Defines the available backup types:
- Full: Complete backup
- Differential: Differential backup
Represents the possible states of a backup job:
- INACTIVE: Waiting for execution
- ACTIVE: Currently running
- END: Successfully completed
- ERROR: Failed with error
Represents the languages supported by the application:
- FR: French
- EN: English
Available logging formats:
- JSON: JSON format
- XML: XML format
Represents a backup job with its attributes:
- Id:
int— Unique identifier - Name:
string— Job name - SourcePath:
string— Source path - TargetPath:
string— Destination path - Type:
BackupType— Backup type
Captures the real-time state of a backup:
- Name:
string— Job name - SourceFilePath:
string— Current source file - TargetFilePath:
string— Current target file - State:
JobState— Current state - TotalFilesToCopy:
int— Total number of files - TotalFilesSize:
long— Total size in bytes - NbFilesLeftToDo:
int— Remaining files - SizeLeftToDo:
long— Remaining size - Progression:
int— Progression percentage - Timestamp:
DateTime— Timestamp
Global application configuration:
- BackupJobs:
List<BackupJob>— List of jobs (max 5) - CurrentLanguage:
Language— Active language - LogFormat:
LogFormat— Log format - LogPath:
string— Path to the log file - StatePath:
string— Path to the state file
Result of a file transfer:
- Success:
bool— Success or failure - FileSize:
long— File size - TransferTimeMs:
long— Transfer time in milliseconds - ErrorMessage:
string— Eventual error message
Result of a job validation:
- IsValid:
bool— Job validity - Errors:
List<string>— List of detected errors
Tracks backup progress without creating strong coupling:
- JobName:
string— Name of the current job - ProgressPercent:
int— Progression percentage - CurrentFile:
string— File currently being copied - FilesRemaining:
int— Remaining files - TotalFiles:
int— Total number of files
Shared context during a backup execution, gathering dependencies required by strategies:
- TransferService:
IFileTransferService— File transfer service - StateManager:
IStateManager— State manager - Logger:
ILogger— Logging service
Method:
BackupContext(transferService, stateManager, logger): Constructor via injection
Contract for the backup engine:
ExecuteBackup(job: BackupJob) : void— Executes an individual backupExecuteAllBackups(jobs: List<BackupJob>) : void— Executes all backups
Manages the CRUD of backup jobs:
CreateJob(job: BackupJob) : void— Create a jobGetJob(id: int) : BackupJob— Retrieve a job by its identifierGetAllJobs() : List<BackupJob>— List all jobsUpdateJob(job: BackupJob) : void— Update an existing jobDeleteJob(id: int) : void— Delete a jobCanAddJob() : bool— Checks if the 5-job limit is reachedGetJobCount() : int— Returns the number of registered jobs
Contract for the file transfer service:
CopyFile(source: string, target: string) : FileTransferResult— Copies a fileGetAllFiles(directory: string) : List<string>— Recursive list of files in a directoryGetTotalSize(files: List<string>) : long— Calculates the total size of a list of filesShouldCopyFile(source: string, target: string) : bool— Determines if a file should be copied (differential backup)
Contract for the Strategy Design Pattern:
Execute(job: BackupJob, context: BackupContext) : void— Executes the backup strategy
Manages the lifecycle of backup states:
InitializeStates(jobs: List<BackupJob>) : void— Initializes statesSetJobActive(jobName: string) : void— Marks a job as activeUpdateProgress(jobName, sourceFile, targetFile, progress, remaining, sizeLeft) : void— Updates progressSetJobComplete(jobName: string) : void— Marks a job as completedSetJobError(jobName: string) : void— Marks a job as failedSetJobInactive(jobName: string) : void— Marks a job as inactiveGetJobState(jobName: string) : StateEntry— Retrieves the current state of a jobSaveState() : void— Persists the state to disk
Manages configuration persistence:
LoadConfig() : AppConfig— Loads configuration from the JSON fileSaveConfig(config: AppConfig) : void— Saves the configuration
Multilingual translation service:
GetString(key: string) : string— Retrieves the translated string for a given keySetLanguage(language: Language) : void— Changes the active languageGetCurrentLanguage() : Language— Returns the currently active language
Validates job data before creation or modification:
Validate(job: BackupJob) : ValidationResult— Full validation of a BackupJob objectValidateJobData(name: string, source: string, target: string) : ValidationResult— Partial validation of raw data
Implements: IBackupEngine
Main backup engine:
Attributes:
_strategies : Dictionary<BackupType, IBackupStrategy>— Dictionary of strategies indexed by type_transferService : IFileTransferService— Transfer service_stateManager : IStateManager— State manager_logger : ILogger— Logging service
Methods:
BackupEngine(transferService, stateManager, logger): Constructor with dependency injectionExecuteBackup(job: BackupJob) : void— Selects the appropriate strategy and executes the backupExecuteAllBackups(jobs: List<BackupJob>) : void— Iterates through all jobs and executes them
Responsibilities:
- Applies the Strategy Pattern via its strategy dictionary
- Builds the
BackupContextand passes it to the strategies - Coordinates
transferService,stateManager, andlogger
Implements: IFileTransferService
Manages low-level file copy operations:
Methods:
CopyFile(source: string, target: string) : FileTransferResult— Copies a file with error handlingGetAllFiles(directory: string) : List<string>— Recursive directory traversalGetTotalSize(files: List<string>) : long— Sum of file sizesShouldCopyFile(source: string, target: string) : bool— Comparison of modification dates for differential mode
Implements: IBackupJobManager
Job manager with a 5-job limitation:
Attributes:
_config : AppConfig— Active configuration in memory_configService : IConfigService— Configuration persistence service_validator : IBackupJobValidator— Job validator
Responsibilities:
- Delegates validation to
IBackupJobValidator - Delegates persistence to
IConfigService - Ensures the 5-job limit is respected via
CanAddJob()
Implements: IBackupJobValidator
Validates data before any job creation or modification:
Methods:
Validate(job: BackupJob) : ValidationResult— Full object validationValidateJobData(name: string, source: string, target: string) : ValidationResult— Individual field validation
Performed Validations:
- Existence of source and target paths
- Non-emptiness and uniqueness of the job name
- Returns a detailed
ValidationResultwith the list of errors
Implements: IStateManager
Manages real-time state with safe concurrent access:
Attributes:
_states : List<StateEntry>— List of current states_statePath : string— Path to the JSON state file_lockObject : object— Lock for thread-safety
Responsibilities:
- Initializes and updates real-time states during backups
- Persists the state in a JSON file after each update
- Guarantees thread-safety through the use of a
lock
Implements: IConfigService
Responsible for persisting the configuration in JSON:
Attributes:
_configPath : string— Path to the configuration file
Methods:
LoadConfig() : AppConfig— Deserializes configuration from the JSON fileSaveConfig(config: AppConfig) : void— Serializes and writes configuration to disk
Responsibilities:
- Provides a default configuration if the file is missing
- Isolates all JSON read/write logic within this service
Implements: ITranslationService
Translation service based on an in-memory dictionary:
Attributes:
_translations : Dictionary<Language, Dictionary<string, string>>— Translations indexed by language and key_currentLanguage : Language— Active language
Methods:
GetString(key: string) : string— Returns the translation or the key if missingSetLanguage(language: Language) : void— Changes the language on the flyGetCurrentLanguage() : Language— Returns the active language
Utility for analyzing command-line arguments:
Methods:
ParseRange(input: string) : List<int>— Interprets a range (e.g.:"1-3"→[1, 2, 3])ParseSelection(input: string) : List<int>— Interprets a selection (e.g.:"1,3,5"→[1, 3, 5])
Standard WPF interface for command binding:
Execute(parameter: object) : void— Executes the commandCanExecute(parameter: object) : bool— Indicates if the command can executeCanExecuteChanged : EventHandler— Event triggered upon state change
Generic and reusable implementation of ICommand:
Attributes:
_execute : Action<object>— Delegate representing the action to execute_canExecute : Func<object, bool>— Predicate determining the enabled/disabled state
Methods:
RelayCommand(execute, canExecute)— ConstructorExecute(parameter: object) : void— Invokes the_executedelegateCanExecute(parameter: object) : bool— Evaluates the_canExecutepredicateRaiseCanExecuteChanged() : void— Manually triggersCanExecuteChanged
Responsibilities:
- Encapsulates any user action within an ICommand object
- Allows declarative binding of buttons and controls in XAML
- Dynamically manages the enabled/disabled state of UI controls
Instantiated in MainViewModel as RelayCommand:
- CreateJobCommand: Create a new backup job
- UpdateJobCommand: Modify an existing job
- DeleteJobCommand: Delete the selected job
- ExecuteBackupCommand: Execute the backup of the selected job
- ExecuteAllBackupsCommand: Execute all backups
- PauseBackupCommand: Pause a running backup
- ResumeBackupCommand: Resume a paused backup
- ChangeLanguageCommand: Change application language
- ChangeLogFormatCommand: Toggle between JSON and XML formats
Implements: IBackupStrategy
Implements full backup:
Method:
Execute(job: BackupJob, context: BackupContext) : void
Behavior:
- Copies all files from the source directory to the destination
- Faithfully recreates the complete directory structure
Implements: IBackupStrategy
Implements differential backup:
Method:
Execute(job: BackupJob, context: BackupContext) : void
Behavior:
- Copies only new or modified files since the last full backup
- Relies on
ShouldCopyFile()fromIFileTransferServiceto detect changes
Logging interface exposed by the DLL:
Log(entry: LogEntry) : void— Records a log entryGetLogPath() : string— Returns the current log file path
Interface defining the formatting of log entries:
Format(entry: LogEntry) : string— Formates a single entryFormatBatch(entries: List<LogEntry>) : string— Formates a set of entriesFileExtension : string { get; }— Extension of the produced file (.jsonor.xml)
Model for a log entry:
- Name:
string— Name of the backed-up file - SourceFilePath:
string— Source path - TargetFilePath:
string— Target path - FileSize:
long— Size in bytes - TransferTimeMs:
long— Transfer duration in milliseconds - Timestamp:
DateTime— Operation timestamp
Implements: ILogger
Concrete implementation of the logger:
Attributes:
_formatter : ILogFormatter— Currently used formatter_logDirectory : string— Storage directory for log files_lockObject : object— Lock for thread-safety
Methods:
EasyLogger(formatter, logDirectory): ConstructorLog(entry: LogEntry) : void— Writes the entry into the daily log fileGetLogPath() : string— Returns the current file path
Responsibilities:
- Daily logging with file rotation (one file per day)
- Thread-safe through the use of a lock
- Interchangeable based on the injected formatter (JSON or XML)
Implements: ILogFormatter
Formatter producing logs in JSON format:
FileExtension : string { get; } = ".json"- Serializes entries into structured JSON
Implements: ILogFormatter
Formatter producing logs in XML format:
FileExtension : string { get; } = ".xml"- Serializes entries into structured XML
User interface in console mode:
Attributes:
_viewModel : ConsoleViewModel— Associated ViewModel
Methods:
ConsoleView(viewModel): ConstructorDisplayMainMenu() : void— Displays the main menuDisplayJobs(jobs: List<BackupJob>) : void— Displays the list of jobsGetUserChoice() : string— Reads the choice entered by the userDisplayMessage(message: string) : void— Displays an informative messageDisplayError(error: string) : void— Displays an error message
Responsibilities:
- Pure display, without any business logic
- Delegates all actions to the
ConsoleViewModel - Lightweight and readable interface in the terminal
WPF graphical interface with XAML binding:
Attributes:
DataContext : MainViewModel— ViewModel linked via WPF's DataContext property
Declared XAML Bindings:
ItemsSource="{Binding Jobs}"— Data source for the backup jobs listSelectedItem="{Binding SelectedJob}"— Real-time selected jobCommand="{Binding CreateJobCommand}"— Commands linked to action buttonsValue="{Binding ProgressPercent}"— Value for the progress barText="{Binding StatusMessage}"— Displayed status message
UI Components:
DataGrid— Display table for backup jobsProgressBar— Real-time progression indicatorButton— Action buttons linked to ViewModel commandsTextBox— Input fields for job creation and modificationComboBox— Selectors for language and log formatStatusBar— Status bar at the bottom of the window
Responsibilities:
- Purely declarative interface definition in XAML
- Automatic two-way binding with the ViewModel via
INotifyPropertyChanged - Minimal code-behind, without business logic
Main ViewModel for the WPF graphical interface:
Attributes:
_jobManager : IBackupJobManager— Backup job manager_engine : IBackupEngine— Backup execution engine_stateManager : IStateManager— Real-time state manager_configService : IConfigService— Configuration service_translator : ITranslationService— Translation service_logger : ILogger— Logging service_config : AppConfig— Active configuration in memoryJobs : ObservableCollection<BackupJob>— Observable collection of jobs (automatic binding)SelectedJob : BackupJob— Currently selected job in the UIProgressPercent : int— Current progression value (0-100)StatusMessage : string— Status message displayed to the userIsRunning : bool— Indicates if a backup is currently running
Commands (ICommand):
CreateJobCommand,UpdateJobCommand,DeleteJobCommandExecuteBackupCommand,ExecuteAllBackupsCommandChangeLanguageCommand,ChangeLogFormatCommand
Events:
PropertyChanged : PropertyChangedEventHandler— Property change notification viaINotifyPropertyChanged
Responsibilities:
- Implements
INotifyPropertyChangedfor automatic two-way binding - Exposes data and commands to the view without direct display logic
- Orchestrates presentation logic and handles user interactions
- Updates the UI in real-time via observable properties
ViewModel dedicated to the console interface:
Attributes:
_jobManager,_engine,_stateManager,_configService,_translator,_logger— Same dependencies asMainViewModel_argumentParser : ArgumentParser— Command-line argument parser_config : AppConfig— Active configuration
Methods:
ConsoleViewModel(...)— Constructor with injection of all dependenciesRun(args: string[]) : void— Main entry point, manages the application loopShowMainMenu() : void— Displays and processes the interactive menuCreateJob() : void,ListJobs() : void,ExecuteBackups() : voidChangeLanguage() : void,ChangeLogFormat() : void
Responsibilities:
- Adapts business logic for the console interface without reactive binding
- Manages the main interaction loop and the menu
- Processes command-line arguments via
ArgumentParser - Does not require
INotifyPropertyChanged(no XAML binding)
Entry point for the console application:
Methods:
Main(args: string[]) : void— Main methodConfigureServices() : ServiceProvider— Configures the dependency injection container
Responsibilities:
- Initializes the console application and the IoC container
- Instantiates
ConsoleViewModelandConsoleView, then starts the main loop
Entry point for the graphical application:
Methods:
OnStartup(e: StartupEventArgs) : void— WPF startup eventConfigureServices() : ServiceProvider— Configures the dependency injection container
Responsibilities:
- Initializes the WPF application and the IoC container
- Instantiates
MainViewModel, createsMainWindow, and configures itsDataContext