diff --git a/Model/Executor/TransformationExecutor.php b/Model/Executor/TransformationExecutor.php
index f275e86f1a82418c2c29e9c20049794bc3105b7b..da9634b5f7ab9f38572df49d0fc2efc2050d2e1f 100644
--- a/Model/Executor/TransformationExecutor.php
+++ b/Model/Executor/TransformationExecutor.php
@@ -93,35 +93,49 @@ class TransformationExecutor extends AbstractExecutor
         foreach ($files as $filepath) {
             $fileInfo = new \SplFileInfo($filepath);
 
+            // Ignore the OK file
             if (strtolower($fileInfo->getExtension()) === 'ok') {
                 continue;
             }
 
-            $fileCount++;
-
+            // Open a file stream for source CSV file
             $sourceFileName = $fileInfo->getBasename();
             $source = $this->readFactory->create($workingDirectory . '/' . $sourceFileName, DriverPool::FILE);
 
+            // Create target file name
+            $fileCount++;
             $targetFileName = 'product-import_'
                 . $timestamp
                 . '_' . str_pad((string)$fileCount, 2, '0', STR_PAD_LEFT)
                 . '.csv';
+
+            // Add file name to import file list (this will be written to the OK file as content)
             $importFiles[] = $targetFileName;
 
             $targetPath = $workingDirectory . '/' . $targetFileName;
+
+            // Create an empty CSV file, since writeFactory requires an existing file
             $this->io->write($targetPath, '');
+
+            // Open a file stream for target CSV file
             $target = $this->writeFactory->create($targetPath, DriverPool::FILE, "w");
 
+            // Fetch the first row from source file
             $header = $source->readCsv();
+            // and write it to the target file, while pass it thru the mapping chain
             $target->writeCsv($this->mapping->header($header));
+
+            // Process all the other rows while pass them thru the mapping chain
             while (($row = $source->readCsv()) !== false) {
                 $target->writeCsv($this->mapping->row(array_combine($header, $row)));
             }
 
+            // close file streams
             $source->close();
             $target->close();
         }
 
+        // Create OK file for the import steps, while add a list of import files as content
         $okFileName = 'product-import_' . $timestamp . '.ok';
         $this->io->write($workingDirectory . '/' . $okFileName, implode(PHP_EOL, $importFiles));
     }
diff --git a/README.md b/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..915b5c3e72a10c6c985674f2cdfc3d944c56bbac
--- /dev/null
+++ b/README.md
@@ -0,0 +1,60 @@
+# Pacemaker customization example
+
+This example demonstrates
+- how to change a step executor for an existing pipeline
+- how to implement a CSV based data mapping layer for the transformation step
+- how to manipulate default configuration
+
+Please refer also the 
+[Pacemaker documentation](https://docs.met.tdintern.de/pacemaker/1.2/how-to-extend/import-processes/transform-foreign-import-source.html)
+
+## The Executor
+
+The executor is the central entry point for this module. The executor will be called by the 
+[pipeline runners](https://docs.met.tdintern.de/pacemaker/1.2/get-started/how-to-configure-the-runners.html).
+To learn how this module works, you should start analysing the code of the executor
+`\TechDivision\CsvSourceTransformationExample\Model\Executor\TransformationExecutor`.
+
+## Mapping Chain
+
+For data mapping this module introduces a chain. Therefore an interface 
+`\TechDivision\CsvSourceTransformationExample\Api\MappingInterface` is defined. There is a default
+preference given in the `di.xml` of this module:
+
+```xml
+<preference for="TechDivision\CsvSourceTransformationExample\Api\MappingInterface" type="TechDivision\CsvSourceTransformationExample\Model\MappingChain" />
+``` 
+
+If you look into the `\TechDivision\CsvSourceTransformationExample\Model\MappingChain` you will see, that this
+class delegates the whole logic to set of mapper instances, which are injected via DI. This approach make the chain
+very flexible and extendable, since you just need to add additional mapper via DI.
+
+```xml
+ <type name="TechDivision\CsvSourceTransformationExample\Model\MappingChain">
+    <arguments>
+        <argument name="mapper" xsi:type="array">
+            <item name="categories" xsi:type="object">TechDivision\CsvSourceTransformationExample\Model\Mapping\Categories</item>
+            <item name="website_code" xsi:type="object">TechDivision\CsvSourceTransformationExample\Model\Mapping\WebsiteCode</item>
+        </argument>
+    </arguments>
+</type>
+```
+
+This example module defines two mapper. Each mapper is responsible for one dedicated value type e.g. categories or 
+website code. This is also an advantage of the used chain pattern.
+
+## The Transformation
+
+You'll find some example CSV files in the `test-files` directory of this module. We need to change the column key
+for `categories`, which is `cat_path` in the given file. And there is a value `_DEFAULT_` in the column 
+`product_websites`, which needs to be replaces by the default website code. The provided category path is also 
+incomplete since there is not `Default Category` as the category root.
+
+## The Configuration
+
+This module also changes the default configuration for the catalog import by manipulating the file pattern in 
+`etc/config.xml`.
+
+```xml
+<file_name_pattern><![CDATA[/pim-source_(?P<identifier>[0-9a-z\-]*)([_0-9]*?).(csv|ok)/i]]></file_name_pattern>
+```