diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
new file mode 100644
index 0000000000000000000000000000000000000000..0e61a8f9c152c209311f0ae33e8b5f438e5327a2
--- /dev/null
+++ b/.gitlab-ci.yml
@@ -0,0 +1,14 @@
+image: registre.unicaen.fr:5000/unicaen-dev-php7.3-apache
+
+stages:
+- publish
+
+cache:
+  key: ${CI_COMMIT_REF_SLUG}
+  paths:
+  - vendor/
+
+update-satis:
+  stage: publish
+  script:
+    - curl https://gest.unicaen.fr/packagist/update
diff --git a/Module.php b/Module.php
index 8d902d7672106a33aff26dda14c83888e78ed54a..213858199b1be65c68d2ba77a62344ec19e9cb77 100644
--- a/Module.php
+++ b/Module.php
@@ -39,16 +39,16 @@ class Module implements ConsoleUsageProviderInterface
     public function getConsoleUsage(AdapterInterface $console)
     {
         return [
-            'run import --name=' => 'Lance un import par son nom (name)',
-            ['--name', "Nom unique de l'import (clé 'name')"],
+            'run import [--name=<name>]' => 'Lance un import par son nom',
+            ['<name>', "Nom unique de l'import (clé de config 'name')"],
 
-            'run import --all' => 'Lance tous les imports',
+            'run import' => 'Lance tous les imports',
             [],
 
-            'run synchro --name=' => 'Lance une synchronisation par son nom (name)',
-            ['--name', "Nom unique de la synchronisation (clé 'name')"],
+            'run synchro [--name=<name>]' => 'Lance une synchronisation par son nom',
+            ['<name>', "Nom unique de la synchronisation (clé de config 'name')"],
 
-            'run synchro --all' => 'Lance toutes les synchronisations',
+            'run synchro' => 'Lance toutes les synchronisations',
             [],
         ];
     }
diff --git a/config/module.config.php b/config/module.config.php
index 171f74264f04fbf17216405de2eac0766402a686..2a6d1d7212106eebe735013378d2855825c9ba00 100644
--- a/config/module.config.php
+++ b/config/module.config.php
@@ -16,6 +16,11 @@ use UnicaenDbImport\Entity\Db\Service\ImportObserv\ImportObservService;
 use UnicaenDbImport\Entity\Db\Service\ImportObserv\ImportObservServiceFactory;
 use UnicaenDbImport\Entity\Db\Service\ImportObservResult\ImportObservResultService;
 use UnicaenDbImport\Entity\Db\Service\ImportObservResult\ImportObservResultServiceFactory;
+use UnicaenDbImport\Entity\Db\Service\Source\SourceService;
+use UnicaenDbImport\Entity\Db\Service\Source\SourceServiceFactory;
+use UnicaenDbImport\Entity\Db\Source;
+use UnicaenDbImport\ORM\Event\Listeners\SourceListener;
+use UnicaenDbImport\ORM\Event\Listeners\SourceListenerFactory;
 use UnicaenDbImport\Service\ApiService;
 use UnicaenDbImport\Service\ApiServiceFactory;
 use UnicaenDbImport\Service\CodeGeneratorPluginManager;
@@ -31,6 +36,9 @@ use UnicaenDbImport\Service\SynchroServiceFactory;
 
 return [
     'import' => [
+        'source_entity_class' => Source::class,
+        'default_source_code' => 'app',
+
         'import_observ_entity_class' => ImportObserv::class,
         'import_observ_result_entity_class' => ImportObservResult::class,
 
@@ -41,6 +49,9 @@ return [
         'synchros' => [],
     ],
 
+    'UnicaenDbImport.Entity.Db.Source.dcm.xml',
+    'UnicaenDbImport.Entity.Db.Source.dcm.xml',
+
     'doctrine'     => [
         'driver'     => [
             'orm_default'        => [
@@ -57,6 +68,13 @@ return [
                 ],
             ],
         ],
+        'eventmanager' => [
+            'orm_default' => [
+                'subscribers' => [
+                    SourceListener::class,
+                ],
+            ],
+        ],
     ],
 
     'console' => [
@@ -65,7 +83,7 @@ return [
                 'execute_imports' => [
                     'type'    => 'simple',
                     'options' => [
-                        'route'    => 'run import [--all|-a] [--name=]',
+                        'route'    => 'run import [--name=]',
                         'defaults' => [
                             'controller' => 'UnicaenDbImport\Controller\Console',
                             'action'     => 'runImport',
@@ -75,7 +93,7 @@ return [
                 'execute_synchro' => [
                     'type'    => 'simple',
                     'options' => [
-                        'route'    => 'run synchro [--all|-a] [--name=]',
+                        'route'    => 'run synchro [--name=]',
                         'defaults' => [
                             'controller' => 'UnicaenDbImport\Controller\Console',
                             'action'     => 'runSynchro',
@@ -95,16 +113,21 @@ return [
     'service_manager' => [
         'factories' => [
             Config::class => ConfigFactory::class,
+
             ImportService::class => ImportServiceFactory::class,
             SynchroService::class => SynchroServiceFactory::class,
             FacadeService::class => FacadeServiceFactory::class,
             DatabaseService::class => DatabaseServiceFactory::class,
             ApiService::class => ApiServiceFactory::class,
+
             CodeGeneratorPluginManager::class => CodeGeneratorPluginManagerFactory::class,
 
+            SourceService::class => SourceServiceFactory::class,
             ImportLogService::class => ImportLogServiceFactory::class,
             ImportObservService::class => ImportObservServiceFactory::class,
             ImportObservResultService::class => ImportObservResultServiceFactory::class,
+
+            SourceListener::class => SourceListenerFactory::class,
         ],
         'abstract_factories' => [
             HelperAbstractFactory::class,
diff --git a/config/unicaen-db-import.global.php.dist b/config/unicaen-db-import.global.php.dist
index c95a071b3c14081a279dfa65574d678279c9f7dc..eaf88a7a6fcde1d907e02cae08933d07fce70e4b 100644
--- a/config/unicaen-db-import.global.php.dist
+++ b/config/unicaen-db-import.global.php.dist
@@ -5,12 +5,24 @@
 
 namespace Application;
 
+use \UnicaenDbImport\Entity\Db\Source;
+
 return [
     'import' => [
         'connections' => [
             // Cf. `./unicaen-db-import.local.php.dist`
         ],
 
+        //
+        // Classe de l'entité Doctrine représentant une "Source".
+        //
+        'source_entity_class' => Source::class,
+
+        //
+        // Code de la Source par défaut (injectée dans les entités implémentant SoucreAwareInterface).
+        //
+        'default_source_code' => 'app',
+
         //
         // Alias éventuels des noms de colonnes d'historique.
         //
@@ -105,6 +117,7 @@ return [
                 // - 'table'              : nom de la table source contenant les données à importer
                 // - 'select'             : select SQL de mise en forme des données source à importer (NB: antinomique avec 'table')
                 // - 'source_code_column' : nom de la colonne dans la table/vue source contenant l'identifiant unique
+                // - 'where'              : filtre SQL éventuel à appliquer aux données sources.
                 //
                 'source' => [
                     'name'               => 'TABLE PAYS DE APOGÉE',
@@ -112,6 +125,7 @@ return [
                     //'table'              => 'PAYS', // Équivalent de SELECT * FROM PAYS;
                     'connection'         => 'apogee',
                     'source_code_column' => 'COD_PAY',
+                    //'where'            => "TEM_OUV_DRT_SSO_PAY = 'N'",
                 ],
                 //
                 // Configuration de la destination des données importées :
@@ -157,12 +171,14 @@ return [
                 // - 'select'             : select SQL de mise en forme des données source à importer (NB: antinomique avec 'table')
                 // - 'connection'         : identifiant de la connexion à la bdd source (cf. clé 'connections' plus haut)
                 // - 'source_code_column' : nom de la colonne dans la table/vue source contenant l'identifiant unique
+                // - 'where'              : filtre éventuel à apliquer aux données sources 
                 //
                 'source' => [
                     'name'               => 'TABLE MES_PAYS_TEMPORAIRES',
                     'table'              => 'MES_PAYS_TEMPORAIRES',
                     'connection'         => 'default',
                     'source_code_column' => 'COD_PAY',
+                    //'where'            => "TEM_OUV_DRT_SSO_PAY = 'N'",
                 ],
 
                 //
@@ -171,12 +187,15 @@ return [
                 // - 'connection'         : identifiant de la connexion à la bdd destination (cf. clé 'connections' plus haut)
                 // - 'table'              : nom de la table destination vers laquelle les données sont synchronisées
                 // - 'source_code_column' : nom de la colonne dans la table destination contenant l'identifiant unique
+                // - 'where'              : filtre SQL éventuel permettant de restreindre les données destinations concernées
+                //                          (les noms de colonnes doivent être préfixés par l'alias de la table destination 'd')
                 //
                 'destination' => [
                     'name'               => 'TABLE PAYS',
                     'table'              => 'PAYS',
                     'connection'         => 'default',
                     'source_code_column' => 'COD_PAY',
+                    //'where'            => "d.TEM_OUV_DRT_SSO_PAY = 'N'",
                     //
                     // Forçage éventuel du nom de la table où seront inscrits les logs (créée automatiquement si nécessaire).
                     // En l'absence de ce forçage, le nom de la table sera 'import_log'.
diff --git a/src/UnicaenDbImport/CodeGenerator/CodeGenerator.php b/src/UnicaenDbImport/CodeGenerator/CodeGenerator.php
index 56b52d8208291f6b5c829532bac718c07d743e32..719fad04e2f776468e83455aadbae7be06738344 100644
--- a/src/UnicaenDbImport/CodeGenerator/CodeGenerator.php
+++ b/src/UnicaenDbImport/CodeGenerator/CodeGenerator.php
@@ -198,12 +198,17 @@ abstract class CodeGenerator implements CodeGeneratorInterface
     public function generateSQLForSelectFromSource(SourceInterface $source)
     {
         if ($source->getSelect()) {
-            return $source->getSelect();
+            $query = $source->getSelect();
+        } else {
+            $sourceTable = $source->getTable();
+            $query = $this->tableHelper->generateSQLForSelectFromTable($sourceTable);
         }
 
-        $sourceTable = $source->getTable();
+        if ($where = $source->getWhere()) {
+            $query = sprintf('SELECT * FROM (%s) tmp WHERE (%s)', $query, $where);
+        }
 
-        return $this->tableHelper->generateSQLForSelectFromTable($sourceTable);
+        return $query;
     }
 
     /**
@@ -313,6 +318,7 @@ abstract class CodeGenerator implements CodeGeneratorInterface
     {
         $destinationTable = $destination->getTable();
         $idColumnSequence = $destination->getIdColumnSequence();
+        $where = $destination->getWhere();
         $sourceCodeColumn = $source->getSourceCodeColumn();
         $columns = $source->getColumns();
 
@@ -331,19 +337,22 @@ abstract class CodeGenerator implements CodeGeneratorInterface
                 $sql = $this->tableHelper->generateSQLForUpdateOperationInDestinationTable(
                         $destinationTable,
                         $sourceCodeColumn,
-                        $columns);
+                        $columns,
+                        $where);
                 break;
             case Operation::OPERATION_DELETE;
                 $sql = $this->tableHelper->generateSQLForDeleteOperationInDestinationTable(
                         $destinationTable,
                         $sourceCodeColumn,
-                        $columns);
+                        $columns,
+                        $where);
                 break;
             case Operation::OPERATION_UNDELETE;
                 $sql = $this->tableHelper->generateSQLForUndeleteOperationInDestinationTable(
                         $destinationTable,
                         $sourceCodeColumn,
-                        $columns);
+                        $columns,
+                        $where);
                 break;
             default:
                 throw new RuntimeException("Opération inattendue");
@@ -386,9 +395,10 @@ EOS;
 
     /**
      * @param array $importObservRow
+     * @param string $where
      * @return string
      */
-    protected function generateSQLForSelectingDiffViewFromImportObservRow(array $importObservRow)
+    protected function generateSQLForSelectingDiffViewFromImportObservRow(array $importObservRow, $where = null)
     {
         $id = $importObservRow['id'];
         $tableName = $importObservRow['tableName'];
@@ -408,8 +418,17 @@ EOS;
         // Ex: "v.COLONNE = 'VALEUR'" ou "v.COLONNE IS NULL".
         $toValueCond = 'v.' . $sColName . ($toValue === null ? ' is null' : (" = '" . $toValue . "'"));
 
-        // Eventuel filtre.
-        $andWhere = $filter ? 'and ' . $filter : '';
+        // Eventuels filtres : celui de la table IMPORT_OBSERV + celui spécifié dans la config de la destination.
+        $wheres = [];
+        if ($filter) $wheres[] = sprintf('(%s)', $filter);
+        if ($where) $wheres[] = sprintf('(%s)', str_ireplace('d.', 't.', $where));
+        $andWhere = $wheres ? 'and ' . implode(' and ', $wheres) : '';
+
+        // Colonne 'detail'. Ex: "coalesce(t.RESULTAT::varchar, '') || '>' || coalesce(v.RESULTAT::varchar, '')"
+        $detail =
+            'coalesce(' . $this->tableHelper->generateSQLForCastToString("t.$columnName") . ", '')" .
+            " || '>' || " .
+            'coalesce(' . $this->tableHelper->generateSQLForCastToString("v.$sColName") . ", '')";
 
         // Construction de la requête recherchant dans la vue V_DIFF_X les lignes correspondant à :
         // une prise de valeur particulière spécifiée par IMPORT_OBSERV.TO_VALUE,
@@ -417,7 +436,7 @@ EOS;
         // dans la table spécifiée par IMPORT_OBSERV.TABLE_NAME.
         return <<<EOS
 select $id import_observ_id, v.source_code, 
-t.$columnName || '>' || v.$sColName detail 
+$detail detail 
 from V_DIFF_$tableName v 
 join $tableName t on t.source_code = v.source_code 
 where $uColName = 1 and $toValueCond
@@ -426,25 +445,29 @@ EOS;
     }
 
     /**
+     * @param DestinationInterface $destination
      * @param array $importObservRows
      * @return string
      */
-    public function generateSQLForInsertionIntoImportObservResult(array $importObservRows)
+    public function generateSQLForInsertionIntoImportObservResult(DestinationInterface $destination, array $importObservRows)
     {
+        $where = $destination->getWhere();
         $now = $this->platform->getNowExpression();
 
         $selects = [];
         foreach ($importObservRows as $importObservRow) {
-            $selects[] = $this->generateSQLForSelectingDiffViewFromImportObservRow($importObservRow);
+            $selects[] = $this->generateSQLForSelectingDiffViewFromImportObservRow($importObservRow, $where);
         }
         $selects = implode(PHP_EOL . 'UNION ALL' . PHP_EOL, $selects);
 
+        $nextval = $this->tableHelper->generateSQLForSequenceNextVal('import_observ_result_id_seq');
+
         return <<<EOS
 insert into import_observ_result (id, date_creation, import_observ_id, source_code, resultat) 
 with tmp as (
     $selects
 )
-select import_observ_result_id_seq.nextval, $now, import_observ_id, source_code, detail 
+select $nextval, $now, import_observ_id, source_code, detail 
 from tmp
 EOS;
     }
diff --git a/src/UnicaenDbImport/CodeGenerator/Helper/TableHelper.php b/src/UnicaenDbImport/CodeGenerator/Helper/TableHelper.php
index e2a89e64fb9b60e2b9928495950d696604627dfc..7948f7e0c000065b1d67c202b3634de02f21fab0 100644
--- a/src/UnicaenDbImport/CodeGenerator/Helper/TableHelper.php
+++ b/src/UnicaenDbImport/CodeGenerator/Helper/TableHelper.php
@@ -512,6 +512,12 @@ EOT;
         return $tableName . '_ID_SEQ';
     }
 
+    /**
+     * @param string $columnName
+     * @return string
+     */
+    abstract public function generateSQLForCastToString(string $columnName);
+
     /**
      * @param string $sequenceName
      * @return string
@@ -522,23 +528,26 @@ EOT;
      * @param string $destinationTable
      * @param string $sourceCodeColumn
      * @param array $columns
+     * @param string $where
      * @return string
      */
-    abstract public function generateSQLForUpdateOperationInDestinationTable($destinationTable, $sourceCodeColumn, array $columns);
+    abstract public function generateSQLForUpdateOperationInDestinationTable($destinationTable, $sourceCodeColumn, array $columns, $where = null);
 
     /**
      * @param string $destinationTable
      * @param string $sourceCodeColumn
      * @param array $columns
+     * @param string $where
      * @return string
      */
-    abstract public function generateSQLForUndeleteOperationInDestinationTable($destinationTable, $sourceCodeColumn, array $columns);
+    abstract public function generateSQLForUndeleteOperationInDestinationTable($destinationTable, $sourceCodeColumn, array $columns, $where = null);
 
     /**
      * @param string $destinationTable
      * @param string $sourceCodeColumn
      * @param array $columns
+     * @param string $where
      * @return string
      */
-    abstract public function generateSQLForDeleteOperationInDestinationTable($destinationTable, $sourceCodeColumn, array $columns);
+    abstract public function generateSQLForDeleteOperationInDestinationTable($destinationTable, $sourceCodeColumn, array $columns, $where = null);
 }
\ No newline at end of file
diff --git a/src/UnicaenDbImport/CodeGenerator/Oracle/Helper/TableHelper.php b/src/UnicaenDbImport/CodeGenerator/Oracle/Helper/TableHelper.php
index dbb8e6a7b13873a60ab4ae326fd49bbdb08befa7..3b88a50ba61060033512ee1f6438f89bbb389797 100644
--- a/src/UnicaenDbImport/CodeGenerator/Oracle/Helper/TableHelper.php
+++ b/src/UnicaenDbImport/CodeGenerator/Oracle/Helper/TableHelper.php
@@ -80,25 +80,25 @@ class TableHelper extends \UnicaenDbImport\CodeGenerator\Helper\TableHelper
     /**
      * {@inheritDoc}
      */
-    public function generateSQLForUpdateOperationInDestinationTable($destinationTable, $sourceCodeColumn, array $columns)
+    public function generateSQLForUpdateOperationInDestinationTable($destinationTable, $sourceCodeColumn, array $columns, $where = null)
     {
-        return $this->generateSQLUpdate(Operation::OPERATION_UPDATE, $destinationTable, $sourceCodeColumn, $columns);
+        return $this->generateSQLUpdate(Operation::OPERATION_UPDATE, $destinationTable, $sourceCodeColumn, $columns, $where);
     }
 
     /**
      * {@inheritDoc}
      */
-    public function generateSQLForUndeleteOperationInDestinationTable($destinationTable, $sourceCodeColumn, array $columns)
+    public function generateSQLForUndeleteOperationInDestinationTable($destinationTable, $sourceCodeColumn, array $columns, $where = null)
     {
-        return $this->generateSQLUpdate(Operation::OPERATION_UNDELETE, $destinationTable, $sourceCodeColumn, $columns);
+        return $this->generateSQLUpdate(Operation::OPERATION_UNDELETE, $destinationTable, $sourceCodeColumn, $columns, $where);
     }
 
     /**
      * {@inheritDoc}
      */
-    public function generateSQLForDeleteOperationInDestinationTable($destinationTable, $sourceCodeColumn, array $columns)
+    public function generateSQLForDeleteOperationInDestinationTable($destinationTable, $sourceCodeColumn, array $columns, $where = null)
     {
-        return $this->generateSQLUpdate(Operation::OPERATION_DELETE, $destinationTable, $sourceCodeColumn, $columns);
+        return $this->generateSQLUpdate(Operation::OPERATION_DELETE, $destinationTable, $sourceCodeColumn, $columns, $where);
     }
 
     /**
@@ -106,9 +106,10 @@ class TableHelper extends \UnicaenDbImport\CodeGenerator\Helper\TableHelper
      * @param string $destinationTable
      * @param string $sourceCodeColumn
      * @param array $columns
+     * @param string $where
      * @return string
      */
-    protected function generateSQLUpdate($operation, $destinationTable, $sourceCodeColumn, array $columns)
+    protected function generateSQLUpdate($operation, $destinationTable, $sourceCodeColumn, array $columns, $where = null)
     {
         $diffViewName = $this->generateDiffViewName($destinationTable);
         $setters = $this->generateSQLUpdateSetters($operation, $columns);
@@ -132,4 +133,12 @@ class TableHelper extends \UnicaenDbImport\CodeGenerator\Helper\TableHelper
     {
         return $sequenceName . '.nextval';
     }
+
+    /**
+     * @inheritDoc
+     */
+    public function generateSQLForCastToString(string $columnName)
+    {
+        return $columnName . "||''";
+    }
 }
\ No newline at end of file
diff --git a/src/UnicaenDbImport/CodeGenerator/PostgreSQL/Helper/TableHelper.php b/src/UnicaenDbImport/CodeGenerator/PostgreSQL/Helper/TableHelper.php
index dbe18c0290e36b5e3f1ee7652d3ae565d5e83389..28cb3b9b1ddc1b5c8ad3d9b2d3c575a2de063c22 100644
--- a/src/UnicaenDbImport/CodeGenerator/PostgreSQL/Helper/TableHelper.php
+++ b/src/UnicaenDbImport/CodeGenerator/PostgreSQL/Helper/TableHelper.php
@@ -35,25 +35,25 @@ class TableHelper extends \UnicaenDbImport\CodeGenerator\Helper\TableHelper
     /**
      * {@inheritDoc}
      */
-    public function generateSQLForUpdateOperationInDestinationTable($destinationTable, $sourceCodeColumn, array $columns)
+    public function generateSQLForUpdateOperationInDestinationTable($destinationTable, $sourceCodeColumn, array $columns, $where = null)
     {
-        return $this->generateSQLUpdate(Operation::OPERATION_UPDATE, $destinationTable, $sourceCodeColumn, $columns);
+        return $this->generateSQLUpdate(Operation::OPERATION_UPDATE, $destinationTable, $sourceCodeColumn, $columns, $where);
     }
 
     /**
      * {@inheritDoc}
      */
-    public function generateSQLForUndeleteOperationInDestinationTable($destinationTable, $sourceCodeColumn, array $columns)
+    public function generateSQLForUndeleteOperationInDestinationTable($destinationTable, $sourceCodeColumn, array $columns, $where = null)
     {
-        return $this->generateSQLUpdate(Operation::OPERATION_UNDELETE, $destinationTable, $sourceCodeColumn, $columns);
+        return $this->generateSQLUpdate(Operation::OPERATION_UNDELETE, $destinationTable, $sourceCodeColumn, $columns, $where);
     }
 
     /**
      * {@inheritDoc}
      */
-    public function generateSQLForDeleteOperationInDestinationTable($destinationTable, $sourceCodeColumn, array $columns)
+    public function generateSQLForDeleteOperationInDestinationTable($destinationTable, $sourceCodeColumn, array $columns, $where = null)
     {
-        return $this->generateSQLUpdate(Operation::OPERATION_DELETE, $destinationTable, $sourceCodeColumn, $columns);
+        return $this->generateSQLUpdate(Operation::OPERATION_DELETE, $destinationTable, $sourceCodeColumn, $columns, $where);
     }
 
     /**
@@ -61,20 +61,24 @@ class TableHelper extends \UnicaenDbImport\CodeGenerator\Helper\TableHelper
      * @param string $destinationTable
      * @param string $sourceCodeColumn
      * @param array $columns
+     * @param string $where
      * @return string
      */
-    protected function generateSQLUpdate($operation, $destinationTable, $sourceCodeColumn, array $columns)
+    protected function generateSQLUpdate($operation, $destinationTable, $sourceCodeColumn, array $columns, $where = null)
     {
         $diffViewName = $this->generateDiffViewName($destinationTable);
         $setters = $this->generateSQLUpdateSetters($operation, $columns);
-        $where = "diff.operation = '$operation' AND d.$sourceCodeColumn = diff.$sourceCodeColumn";
+        $wheres = "diff.operation = '$operation' AND d.$sourceCodeColumn = diff.$sourceCodeColumn";
+        if ($where) {
+            $wheres .= sprintf(" AND (%s)", $where);
+        }
 
         // instruction de mise à jour de la table destination
         $markup = '';
         $markup .= "UPDATE $destinationTable d SET " . PHP_EOL;
         $markup .= $setters . PHP_EOL;
         $markup .= "FROM (SELECT * FROM $diffViewName) AS diff " . PHP_EOL;
-        $markup .= "WHERE $where";
+        $markup .= "WHERE $wheres";
 
         return $markup;
     }
@@ -87,4 +91,12 @@ class TableHelper extends \UnicaenDbImport\CodeGenerator\Helper\TableHelper
     {
         return "nextval('" . $sequenceName . "')";
     }
+
+    /**
+     * @inheritDoc
+     */
+    public function generateSQLForCastToString(string $columnName)
+    {
+        return $columnName . '::varchar';
+    }
 }
\ No newline at end of file
diff --git a/src/UnicaenDbImport/Config/Config.php b/src/UnicaenDbImport/Config/Config.php
index a6c4a0536cadcc6d9b272b213922029e1c1d9792..4628c2c42f9f74238225d9c86a6898fce24c1e65 100644
--- a/src/UnicaenDbImport/Config/Config.php
+++ b/src/UnicaenDbImport/Config/Config.php
@@ -10,6 +10,9 @@ use UnicaenDbImport\Domain\SynchroInterface;
  */
 class Config
 {
+    const KEY_default_source_code = 'default_source_code';
+    const KEY_source_entity_class = 'source_entity_class';
+
     const COLUMN_CREATED_ON = 'created_on';
     const COLUMN_UPDATED_ON = 'updated_on';
     const COLUMN_DELETED_ON = 'deleted_on';
@@ -17,6 +20,16 @@ class Config
     const COLUMN_UPDATED_BY = 'updated_by';
     const COLUMN_DELETED_BY = 'deleted_by';
 
+    /**
+     * @var string
+     */
+    protected $sourceEntityClass;
+
+    /**
+     * @var string
+     */
+    protected $defaultSourceCode;
+
     /**
      * @var string
      */
@@ -80,6 +93,42 @@ class Config
      */
     protected $synchros = [];
 
+    /**
+     * @param string $sourceEntityClass
+     * @return self
+     */
+    public function setSourceEntityClass(string $sourceEntityClass): self
+    {
+        $this->sourceEntityClass = $sourceEntityClass;
+        return $this;
+    }
+
+    /**
+     * @return string
+     */
+    public function getSourceEntityClass(): string
+    {
+        return $this->sourceEntityClass;
+    }
+
+    /**
+     * @return string
+     */
+    public function getDefaultSourceCode(): string
+    {
+        return $this->defaultSourceCode;
+    }
+
+    /**
+     * @param string $defaultSourceCode
+     * @return Config
+     */
+    public function setDefaultSourceCode(string $defaultSourceCode): Config
+    {
+        $this->defaultSourceCode = $defaultSourceCode;
+        return $this;
+    }
+
     /**
      * @return string
      */
diff --git a/src/UnicaenDbImport/Config/ConfigException.php b/src/UnicaenDbImport/Config/ConfigException.php
index 74244c4e01214b1435be9825b6ba57022dcc5576..cc2d817eb334b3a398a7bb9c52e1692b071690ca 100644
--- a/src/UnicaenDbImport/Config/ConfigException.php
+++ b/src/UnicaenDbImport/Config/ConfigException.php
@@ -6,9 +6,28 @@ use UnicaenApp\Exception\RuntimeException;
 
 class ConfigException extends RuntimeException
 {
+    public static function missingKeyInImport($key, $name = null)
+    {
+        return $name ?
+            new static("Le tableau de config de l'import '$name' doit contenir une clé '$key'") :
+            new static("Le tableau de config d'un import ne contient pas la clé '$key' attendue");
+    }
+
+    public static function missingKeyInSynchro($key, $name = null)
+    {
+        return $name ?
+            new static("Le tableau de config de la synchro '$name' doit contenir une clé '$key'") :
+            new static("Le tableau de config d'une synchro ne contient pas la clé '$key' attendue");
+    }
+
+    public static function missingRootKey($key)
+    {
+        return new static("La config de l'appli doit contenir la clé '$key' contenant la config du module");
+    }
+
     public static function missingKey($key)
     {
-        return new static("Clé de config '$key' introuvable");
+        return new static("Le tableau de config du module doit contenir la clé '$key'");
     }
 
     public static function missingKeyInConnections($key)
diff --git a/src/UnicaenDbImport/Config/ConfigFactory.php b/src/UnicaenDbImport/Config/ConfigFactory.php
index beb8d0bc58fd04b33a68e1ad4b71ad37b53c8545..21e8dd351badfeefdd43ad6b288df9a0bec76b8f 100644
--- a/src/UnicaenDbImport/Config/ConfigFactory.php
+++ b/src/UnicaenDbImport/Config/ConfigFactory.php
@@ -17,7 +17,7 @@ use Zend\ServiceManager\ServiceLocatorInterface;
 
 class ConfigFactory
 {
-    const CONFIG_KEY = 'import';
+    const CONFIG_ROOT_KEY = 'import';
 
     /**
      * @var ServiceLocatorInterface
@@ -43,6 +43,7 @@ class ConfigFactory
         $this->container = $container;
         $this->moduleConfig = $this->getModuleConfig();
 
+        $defaultSourceCode = $this->getDefaultSourceCode();
         $importObservEntityClass = $this->getImportObservEntityClass();
         $importObservResultEntityClass = $this->getImportObservResultEntityClass();
         $codeGeneratorsConfig = $this->getCodeGeneratorsConfig();
@@ -54,6 +55,7 @@ class ConfigFactory
         $synchros = $this->createSynchros();
 
         $config = new Config();
+        $config->setDefaultSourceCode($defaultSourceCode);
         $config->setImportObservEntityClass($importObservEntityClass);
         $config->setImportObservResultEntityClass($importObservResultEntityClass);
         $config->setCodeGeneratorsMappingConfig($codeGeneratorsConfig);
@@ -74,13 +76,27 @@ class ConfigFactory
     {
         $appConfig = $this->container->get('Config');
 
-        if (!array_key_exists($key = self::CONFIG_KEY, $appConfig)) {
-            throw ConfigException::missingKey($key);
+        if (!array_key_exists($key = self::CONFIG_ROOT_KEY, $appConfig)) {
+            throw ConfigException::missingRootKey($key);
         }
 
         return $appConfig[$key];
     }
 
+    /**
+     * @return string
+     */
+    private function getDefaultSourceCode()
+    {
+        try {
+            Assertion::keyExists($this->moduleConfig, $key = 'default_source_code');
+        } catch (AssertionFailedException $e) {
+            throw ConfigException::missingKey($key);
+        }
+
+        return $this->moduleConfig[$key];
+    }
+
     /**
      * @return string
      */
@@ -185,11 +201,16 @@ class ConfigFactory
      */
     private function createImport(array $importConfig)
     {
+        if (!array_key_exists($key = 'name', $importConfig)) {
+            throw ConfigException::missingKeyInImport($key);
+        }
+        $name = $importConfig['name'];
+
         if (!array_key_exists($key = 'source', $importConfig)) {
-            throw ConfigException::missingKey($key);
+            throw ConfigException::missingKeyInImport($key, $name);
         }
         if (!array_key_exists($key = 'destination', $importConfig)) {
-            throw ConfigException::missingKey($key);
+            throw ConfigException::missingKeyInImport($key, $name);
         }
 
         $source = $this->createSource($importConfig['source']);
@@ -222,11 +243,16 @@ class ConfigFactory
      */
     private function createSynchro(array $synchroConfig)
     {
+        if (!array_key_exists($key = 'name', $synchroConfig)) {
+            throw ConfigException::missingKeyInImport($key);
+        }
+        $name = $synchroConfig['name'];
+
         if (!array_key_exists($key = 'source', $synchroConfig)) {
-            throw ConfigException::missingKey($key);
+            throw ConfigException::missingKeyInSynchro($key, $name);
         }
         if (!array_key_exists($key = 'destination', $synchroConfig)) {
-            throw ConfigException::missingKey($key);
+            throw ConfigException::missingKeyInSynchro($key, $name);
         }
 
         $source = $this->createSource($synchroConfig['source']);
diff --git a/src/UnicaenDbImport/Controller/ConsoleController.php b/src/UnicaenDbImport/Controller/ConsoleController.php
index 85c1b887166336bb9233b61312c018a0a0841f6b..d9b4599f3f9eaf5bb5393ffffe672181261ade96 100644
--- a/src/UnicaenDbImport/Controller/ConsoleController.php
+++ b/src/UnicaenDbImport/Controller/ConsoleController.php
@@ -135,25 +135,14 @@ class ConsoleController extends AbstractConsoleController
     {
         /** @var Request $request */
         $request = $this->getRequest();
-
-        //Passage de code à probablement concaténer en un (redonant au moins 3 fois)
-        $all = $request->getParam('all') || $request->getParam('a');
         $name = $request->getParam('name');
 
-        if ($all && $name !== null) {
-            $this->getConsole()->writeLine("Les paramètres 'all' et 'name' sont antinomiques", ColorInterface::RED);
-        }
-
-        if (!$all && $name === null) {
-            $all = TRUE;
-        }
-
         $this->getConsole()->writeLine();
         $this->getConsole()->writeLine("######################## IMPORTS ########################", ColorInterface::BLUE);
         $this->getConsole()->writeLine();
 
         try {
-            if ($all) {
+            if ($name === null) {
                 $imports = $this->importService->getImports();
             } else {
                 try {
@@ -183,25 +172,14 @@ class ConsoleController extends AbstractConsoleController
     {
         /** @var Request $request */
         $request = $this->getRequest();
-
-        //Passage de code à probablement concaténer en un (redonant au moins 3 fois)
-        $all = $request->getParam('all') || $request->getParam('a');
         $name = $request->getParam('name');
 
-        if ($all && $name !== null) {
-            $this->getConsole()->writeLine("Les paramètres 'all' et 'name' sont antinomiques", ColorInterface::RED);
-        }
-
-        if (!$all && $name === null) {
-            $all = TRUE;
-        }
-
         $this->getConsole()->writeLine();
         $this->getConsole()->writeLine("######################## SYNCHROS ########################", ColorInterface::BLUE);
         $this->getConsole()->writeLine();
 
         try {
-            if ($all) {
+            if ($name === null) {
                 $synchros = $this->synchroService->getSynchros();
             } else {
                 try {
diff --git a/src/UnicaenDbImport/Domain/Destination.php b/src/UnicaenDbImport/Domain/Destination.php
index efa9c8edb7122a67f851e9643a2a18a08fb58b4e..beb54c836171863bc9409fd8f2e42d0f4c1c8e58 100644
--- a/src/UnicaenDbImport/Domain/Destination.php
+++ b/src/UnicaenDbImport/Domain/Destination.php
@@ -62,6 +62,11 @@ class Destination implements DestinationInterface
             throw ConfigException::illegalKey('select');
         }
 
+        if ($where = $this->config->get($key = 'where'))
+            (new AssertionChain($where, "Une string non vide est requise pour la clé suivante: $key"))
+                ->notEmpty()
+                ->string();
+
         (new AssertionChain($this->config->get($key = 'connection'), "Une instance de " . Connection::class . " est requise pour la clé suivante: $key"))
             ->notEmpty()
             ->isInstanceOf(Connection::class);
@@ -82,6 +87,11 @@ class Destination implements DestinationInterface
         return $this->config->get('table');
     }
 
+    public function getWhere()
+    {
+        return $this->config->get('where');
+    }
+
     public function getConnection()
     {
         return $this->config->get('connection');
diff --git a/src/UnicaenDbImport/Domain/DestinationInterface.php b/src/UnicaenDbImport/Domain/DestinationInterface.php
index c4213c6ce50dd4b11f5ad48e0bce25a034312a70..1bfdd897966aa5e81dc0d9f5fafffaa507513f58 100644
--- a/src/UnicaenDbImport/Domain/DestinationInterface.php
+++ b/src/UnicaenDbImport/Domain/DestinationInterface.php
@@ -24,6 +24,13 @@ interface DestinationInterface
      */
     public function getTable();
 
+    /**
+     * Retourne le filtre SQL éventuel permettant de restreindre les données destinations concernées.
+     *
+     * @return string
+     */
+    public function getWhere();
+
     /**
      * Retourne l'instance de la connexion Doctrine vers cette destination.
      *
diff --git a/src/UnicaenDbImport/Domain/Source.php b/src/UnicaenDbImport/Domain/Source.php
index 7e3b9e0ea225b1312872c165da8a768009722e27..b79d54bce34018c667bbdf07f17f95d0349fed47 100644
--- a/src/UnicaenDbImport/Domain/Source.php
+++ b/src/UnicaenDbImport/Domain/Source.php
@@ -80,6 +80,14 @@ class Source implements SourceInterface
         return $this->config->get('select');
     }
 
+    /**
+     * {@inheritDoc}
+     */
+    public function getWhere()
+    {
+        return $this->config->get('where');
+    }
+
     /**
      * {@inheritDoc}
      */
@@ -167,6 +175,11 @@ class Source implements SourceInterface
             throw ConfigException::atLeastOneKey(['table', 'select']);
         }
 
+        if ($where = $this->config->get($key = 'where'))
+            (new AssertionChain($where, "Une string non vide est requise pour la clé suivante: $key"))
+                ->notEmpty()
+                ->string();
+
         $conn = $this->config->get($key = 'connection');
         if (! $conn instanceof DbConnection && ! $conn instanceof ApiConnection) {
             throw new InvalidArgumentException(
diff --git a/src/UnicaenDbImport/Domain/SourceInterface.php b/src/UnicaenDbImport/Domain/SourceInterface.php
index 9dc69759195cc11212f2551def33d996aeeccb94..b1de74313775d8b5fd2da19a5c8fe39683a719c0 100644
--- a/src/UnicaenDbImport/Domain/SourceInterface.php
+++ b/src/UnicaenDbImport/Domain/SourceInterface.php
@@ -28,6 +28,13 @@ interface SourceInterface
      */
     public function getSelect();
 
+    /**
+     * Retourne le filtre SQL éventuel à appliquer aux données sources.
+     *
+     * @return string
+     */
+    public function getWhere();
+
     /**
      * Retourne l'instance de la connexion Doctrine vers cette source.
      *
diff --git a/src/UnicaenDbImport/Entity/Db/Interfaces/SourceAwareInterface.php b/src/UnicaenDbImport/Entity/Db/Interfaces/SourceAwareInterface.php
index bcedb15745ef2ef2db3d6824f4152cdda98beaa4..e40cf54ba486c643eaeeee02a0148fdce321c437 100644
--- a/src/UnicaenDbImport/Entity/Db/Interfaces/SourceAwareInterface.php
+++ b/src/UnicaenDbImport/Entity/Db/Interfaces/SourceAwareInterface.php
@@ -12,13 +12,12 @@ use UnicaenDbImport\Entity\Db\Source;
 interface SourceAwareInterface
 {
     /**
-     * @param Source $source
-     * @return self
+     * @param SourceInterface|null $source
      */
-    public function setSource(Source $source = null);
+    public function setSource(SourceInterface $source = null);
 
     /**
-     * @return Source
+     * @return SourceInterface|null
      */
-    public function getSource();
+    public function getSource(): ?SourceInterface;
 }
\ No newline at end of file
diff --git a/src/UnicaenDbImport/Entity/Db/Interfaces/SourceInterface.php b/src/UnicaenDbImport/Entity/Db/Interfaces/SourceInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..247d40f1a5138977d4a85a59e5de338d94707741
--- /dev/null
+++ b/src/UnicaenDbImport/Entity/Db/Interfaces/SourceInterface.php
@@ -0,0 +1,48 @@
+<?php
+
+namespace UnicaenDbImport\Entity\Db\Interfaces;
+
+use UnicaenDbImport\Entity\Db\Source;
+
+/**
+ * Interface décrivant une "source".
+ *
+ * @see Source
+ */
+interface SourceInterface
+{
+    /**
+     * Get id
+     *
+     * @return int
+     */
+    public function getId(): int;
+
+    /**
+     * Get code
+     *
+     * @return string
+     */
+    public function getCode(): string;
+
+    /**
+     * Get importable
+     *
+     * @return boolean
+     */
+    public function getImportable(): bool;
+
+    /**
+     * Get libelle
+     *
+     * @return string
+     */
+    public function getLibelle(): string;
+
+    /**
+     * Retourne la représentation littérale de cette source.
+     *
+     * @return string
+     */
+    public function __toString(): string;
+}
\ No newline at end of file
diff --git a/src/UnicaenDbImport/Entity/Db/Mapping/UnicaenDbImport.Entity.Db.Source.dcm.xml b/src/UnicaenDbImport/Entity/Db/Mapping/UnicaenDbImport.Entity.Db.Source.dcm.xml
index a732cc546a77c2230b92953945515bcaf96b86d4..84dd784ec08993e5f98fdad9748fb234595d3b2d 100644
--- a/src/UnicaenDbImport/Entity/Db/Mapping/UnicaenDbImport.Entity.Db.Source.dcm.xml
+++ b/src/UnicaenDbImport/Entity/Db/Mapping/UnicaenDbImport.Entity.Db.Source.dcm.xml
@@ -2,7 +2,6 @@
 <doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
                   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                   xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping http://doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
-
     <entity name="UnicaenDbImport\Entity\Db\Source" table="SOURCE">
 
         <id name="id" type="integer" column="ID">
@@ -12,5 +11,6 @@
         <field name="code" column="CODE"/>
         <field name="importable" type="boolean" column="IMPORTABLE"/>
         <field name="libelle" column="LIBELLE"/>
+
     </entity>
 </doctrine-mapping>
diff --git a/src/UnicaenDbImport/Entity/Db/Service/ServiceException.php b/src/UnicaenDbImport/Entity/Db/Service/ServiceException.php
new file mode 100644
index 0000000000000000000000000000000000000000..9da4a43275ac96c706ec7f0f227e86642c874e31
--- /dev/null
+++ b/src/UnicaenDbImport/Entity/Db/Service/ServiceException.php
@@ -0,0 +1,8 @@
+<?php
+
+namespace UnicaenDbImport\Entity\Db\Service;
+
+class ServiceException extends \Exception
+{
+
+}
\ No newline at end of file
diff --git a/src/UnicaenDbImport/Entity/Db/Service/Source/SourceService.php b/src/UnicaenDbImport/Entity/Db/Service/Source/SourceService.php
new file mode 100644
index 0000000000000000000000000000000000000000..c7657fedb3f300e88dd403f2583fbc7232626360
--- /dev/null
+++ b/src/UnicaenDbImport/Entity/Db/Service/Source/SourceService.php
@@ -0,0 +1,51 @@
+<?php
+
+namespace UnicaenDbImport\Entity\Db\Service\Source;
+
+use UnicaenDbImport\Entity\Db\Service\ServiceException;
+use UnicaenDbImport\Entity\Db\Source;
+use UnicaenDbImport\Entity\Db\Service\AbstractService;
+
+class SourceService extends AbstractService
+{
+    /**
+     * @var string
+     */
+    protected $defaultSourceCode;
+
+    /**
+     * @param string $defaultSourceCode
+     * @return SourceService
+     */
+    public function setDefaultSourceCode(string $defaultSourceCode): SourceService
+    {
+        $this->defaultSourceCode = $defaultSourceCode;
+        return $this;
+    }
+
+    /**
+     * @inheritDoc
+     */
+    public function getRepository()
+    {
+        return $this->getEntityManager()->getRepository(Source::class);
+    }
+
+    /**
+     * Retourne la Source par défaut (celle dont le code est spécifié dans la config du module).
+     *
+     * @return Source
+     * @throws ServiceException Source introuvable
+     */
+    public function fetchDefaultSource(): Source
+    {
+        /** @var Source|null $source */
+        $source = $this->getRepository()->findOneBy(['code' => $this->defaultSourceCode]);
+
+        if ($source === null) {
+            throw new ServiceException("Source introuvable avec ce code : " . $this->defaultSourceCode);
+        }
+
+        return $source;
+    }
+}
\ No newline at end of file
diff --git a/src/UnicaenDbImport/Entity/Db/Service/Source/SourceServiceAwareTrait.php b/src/UnicaenDbImport/Entity/Db/Service/Source/SourceServiceAwareTrait.php
new file mode 100644
index 0000000000000000000000000000000000000000..293edffaf211d1902e7302ee784573ec15033ccf
--- /dev/null
+++ b/src/UnicaenDbImport/Entity/Db/Service/Source/SourceServiceAwareTrait.php
@@ -0,0 +1,19 @@
+<?php
+
+namespace UnicaenDbImport\Entity\Db\Service\Source;
+
+trait SourceServiceAwareTrait
+{
+    /**
+     * @var SourceService
+     */
+    protected $sourceService;
+
+    /**
+     * @param SourceService $serviceSource
+     */
+    public function setSourceService(SourceService $serviceSource)
+    {
+        $this->sourceService = $serviceSource;
+    }
+}
\ No newline at end of file
diff --git a/src/UnicaenDbImport/Entity/Db/Service/Source/SourceServiceFactory.php b/src/UnicaenDbImport/Entity/Db/Service/Source/SourceServiceFactory.php
new file mode 100644
index 0000000000000000000000000000000000000000..2c76fbc860c3a5273186fa9a8b7d577c9aad04b6
--- /dev/null
+++ b/src/UnicaenDbImport/Entity/Db/Service/Source/SourceServiceFactory.php
@@ -0,0 +1,20 @@
+<?php
+
+namespace UnicaenDbImport\Entity\Db\Service\Source;
+
+use Interop\Container\ContainerInterface;
+use UnicaenDbImport\Config\Config;
+
+class SourceServiceFactory
+{
+    public function __invoke(ContainerInterface $container): SourceService
+    {
+        /** @var Config $config */
+        $config = $container->get(Config::class);
+
+        $service = new SourceService();
+        $service->setDefaultSourceCode($config->getDefaultSourceCode());
+
+        return $service;
+    }
+}
\ No newline at end of file
diff --git a/src/UnicaenDbImport/Entity/Db/Source.php b/src/UnicaenDbImport/Entity/Db/Source.php
index 4266fb13bc3cbfc22d331236026008803346e624..0d3af25798ad3d0f37ce467bc70cdab71cb48e7e 100644
--- a/src/UnicaenDbImport/Entity/Db/Source.php
+++ b/src/UnicaenDbImport/Entity/Db/Source.php
@@ -2,10 +2,12 @@
 
 namespace UnicaenDbImport\Entity\Db;
 
+use UnicaenDbImport\Entity\Db\Interfaces\SourceInterface;
+
 /**
  * Source
  */
-class Source
+class Source implements SourceInterface
 {
     /**
      * @var int
@@ -30,9 +32,9 @@ class Source
     /**
      * Get id
      *
-     * @return integer
+     * @return int
      */
-    public function getId()
+    public function getId(): int
     {
         return $this->id;
     }
@@ -41,14 +43,10 @@ class Source
      * Set code
      *
      * @param string $code
-     *
-     * @return Source
      */
-    public function setCode($code)
+    public function setCode(string $code)
     {
         $this->code = $code;
-
-        return $this;
     }
 
     /**
@@ -56,7 +54,7 @@ class Source
      *
      * @return string
      */
-    public function getCode()
+    public function getCode(): string
     {
         return $this->code;
     }
@@ -65,14 +63,10 @@ class Source
      * Set importable
      *
      * @param boolean $importable
-     *
-     * @return Source
      */
-    public function setImportable($importable)
+    public function setImportable(bool $importable)
     {
         $this->importable = $importable;
-
-        return $this;
     }
 
     /**
@@ -80,7 +74,7 @@ class Source
      *
      * @return boolean
      */
-    public function getImportable()
+    public function getImportable(): bool
     {
         return $this->importable;
     }
@@ -89,14 +83,10 @@ class Source
      * Set libelle
      *
      * @param string $libelle
-     *
-     * @return Source
      */
-    public function setLibelle($libelle)
+    public function setLibelle(string $libelle)
     {
         $this->libelle = $libelle;
-
-        return $this;
     }
 
     /**
@@ -104,7 +94,7 @@ class Source
      *
      * @return string
      */
-    public function getLibelle()
+    public function getLibelle(): string
     {
         return $this->libelle;
     }
@@ -114,23 +104,8 @@ class Source
      *
      * @return string
      */
-    public function __toString()
+    public function __toString(): string
     {
         return $this->getLibelle();
     }
-
-    /**
-     * @return array
-     * @since PHP 5.6.0
-     * This method is called by var_dump() when dumping an object to get the properties that should be shown.
-     * If the method isn't defined on an object, then all public, protected and private properties will be shown.
-     *
-     * @link  http://php.net/manual/en/language.oop5.magic.php#language.oop5.magic.debuginfo
-     */
-    function __debugInfo()
-    {
-        return [
-            'libelle' => $this->libelle,
-        ];
-    }
 }
\ No newline at end of file
diff --git a/src/UnicaenDbImport/Entity/Db/Traits/SourceAwareTrait.php b/src/UnicaenDbImport/Entity/Db/Traits/SourceAwareTrait.php
index bf54f7797ae5d67e7a0a4a7b1e670b78972cde70..6f5dc3451c0cb42bd989eed4585780ea40684ab4 100644
--- a/src/UnicaenDbImport/Entity/Db/Traits/SourceAwareTrait.php
+++ b/src/UnicaenDbImport/Entity/Db/Traits/SourceAwareTrait.php
@@ -2,30 +2,27 @@
 
 namespace UnicaenDbImport\Entity\Db\Traits;
 
-use UnicaenDbImport\Entity\Db\Source;
+use UnicaenDbImport\Entity\Db\Interfaces\SourceInterface;
 
 trait SourceAwareTrait
 {
     /**
-     * @var Source
+     * @var SourceInterface
      */
     protected $source;
 
     /**
-     * @param Source $source
-     * @return self
+     * @param SourceInterface|null $source
      */
-    public function setSource(Source $source = null): self
+    public function setSource(SourceInterface $source = null)
     {
         $this->source = $source;
-
-        return $this;
     }
 
     /**
-     * @return Source
+     * @return SourceInterface|null
      */
-    public function getSource(): Source
+    public function getSource(): ?SourceInterface
     {
         return $this->source;
     }
diff --git a/src/UnicaenDbImport/ORM/Event/Listeners/SourceListener.php b/src/UnicaenDbImport/ORM/Event/Listeners/SourceListener.php
new file mode 100644
index 0000000000000000000000000000000000000000..d33727e106c0227eb6b8b68a4093086c35507414
--- /dev/null
+++ b/src/UnicaenDbImport/ORM/Event/Listeners/SourceListener.php
@@ -0,0 +1,120 @@
+<?php
+
+namespace UnicaenDbImport\ORM\Event\Listeners;
+
+use Doctrine\Common\EventSubscriber;
+use Doctrine\ORM\EntityManager;
+use Doctrine\ORM\Event\LifecycleEventArgs;
+use Doctrine\ORM\Event\PreUpdateEventArgs;
+use Doctrine\ORM\Events;
+use RuntimeException;
+use UnicaenDbImport\Entity\Db\Interfaces\SourceAwareInterface;
+use UnicaenDbImport\Entity\Db\Source;
+
+/**
+ * Listener Doctrine chargé d'injecter si besoin une Source par défaut dans les entités
+ * implémentant {@see SourceAwareInterface}.
+ *
+ * Déclenchement : avant que l'entité ne soit persistée (création) ou mis à jour (update).
+ *
+ * @author Bertrand GAUTHIER <bertrand.gauthier at unicaen.fr>
+ * @see SourceAwareInterface
+ */
+class SourceListener implements EventSubscriber
+{
+    /**
+     * @var string
+     */
+    protected $sourceEntityClass;
+
+    /**
+     * @param string $sourceEntityClass
+     * @return self
+     */
+    public function setSourceEntityClass(string $sourceEntityClass): self
+    {
+        $this->sourceEntityClass = $sourceEntityClass;
+        return $this;
+    }
+
+    /**
+     * @var string
+     */
+    protected $defaultSourceCode;
+
+    /**
+     * @param string $defaultSourceCode
+     * @return self
+     */
+    public function setDefaultSourceCode(string $defaultSourceCode): self
+    {
+        $this->defaultSourceCode = $defaultSourceCode;
+        return $this;
+    }
+
+    /**
+     * @param LifecycleEventArgs $args
+     * @throws RuntimeException Aucun utilisateur disponible pour en faire l'auteur de la création/modification
+     */
+    protected function updateSource(LifecycleEventArgs $args)
+    {
+        $entity = $args->getEntity();
+
+        if (! $entity instanceof SourceAwareInterface) {
+            return;
+        }
+        if ($entity->getSource() !== null) {
+            return;
+        }
+
+        $defaultSource = $this->fetchDefaultSource($args->getEntityManager());
+
+        $entity->setSource($defaultSource);
+    }
+
+    /**
+     * @param EntityManager $entityManager
+     * @return Source
+     */
+    private function fetchDefaultSource(EntityManager $entityManager): Source
+    {
+        if ($this->sourceEntityClass === null) {
+            throw new RuntimeException("La classe d'entité Source n'a pas été spécifiée");
+        }
+        if ($this->defaultSourceCode === null) {
+            throw new RuntimeException("Aucun code n'a été spécifié pour la Source par défaut");
+        }
+
+        /** @var Source $defaultSource */
+        $defaultSource = $entityManager->getRepository($this->sourceEntityClass)->findOneBy(['code' => $this->defaultSourceCode]);
+        if ($defaultSource === null) {
+            throw new RuntimeException("Source par défaut introuvable avec ce code : " . $this->defaultSourceCode);
+        }
+
+        return $defaultSource;
+    }
+
+    /**
+     * @param LifecycleEventArgs $args
+     */
+    public function prePersist(LifecycleEventArgs $args)
+    {
+        $this->updateSource($args);
+    }
+
+    /**
+     * @param PreUpdateEventArgs $args
+     */
+    public function preUpdate(PreUpdateEventArgs $args)
+    {
+        $this->updateSource($args);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getSubscribedEvents()
+    {
+        return [Events::prePersist, Events::preUpdate];
+    }
+}
\ No newline at end of file
diff --git a/src/UnicaenDbImport/ORM/Event/Listeners/SourceListenerFactory.php b/src/UnicaenDbImport/ORM/Event/Listeners/SourceListenerFactory.php
new file mode 100644
index 0000000000000000000000000000000000000000..e144ec312d3e354050297444ac5e148873aeb187
--- /dev/null
+++ b/src/UnicaenDbImport/ORM/Event/Listeners/SourceListenerFactory.php
@@ -0,0 +1,37 @@
+<?php
+
+namespace UnicaenDbImport\ORM\Event\Listeners;
+
+use Interop\Container\ContainerInterface;
+use UnicaenDbImport\Config\Config;
+use UnicaenDbImport\Config\ConfigException;
+
+class SourceListenerFactory
+{
+    /**
+     * @param ContainerInterface $container
+     * @return SourceListener
+     */
+    public function __invoke(ContainerInterface $container): SourceListener
+    {
+        //
+        // ATTENTION aux boucles de dépendance (ex: SourceListener => SourceService => EntityManager => SourceListener),
+        // donc maheureusement mieux vaut n'injecter aucun service dans un listener Doctrine.
+        //
+
+        /** @var array $config */
+        $config = $container->get('Config')['import'];
+        if (!isset($config[$key = Config::KEY_source_entity_class])) {
+            throw ConfigException::missingKey($key);
+        }
+        if (!isset($config[$key = Config::KEY_default_source_code])) {
+            throw ConfigException::missingKey($key);
+        }
+
+        $listener = new SourceListener();
+        $listener->setSourceEntityClass($config[Config::KEY_source_entity_class]);
+        $listener->setDefaultSourceCode($config[Config::KEY_default_source_code]);
+
+        return $listener;
+    }
+}
diff --git a/src/UnicaenDbImport/QueryExecutor.php b/src/UnicaenDbImport/QueryExecutor.php
index 1e190d2ff232596b9956f2f07738fd27163c222c..20c76d458a43a430ddc7b92cf7048f283170958a 100644
--- a/src/UnicaenDbImport/QueryExecutor.php
+++ b/src/UnicaenDbImport/QueryExecutor.php
@@ -60,7 +60,7 @@ class QueryExecutor
         $statement = $this->executeQuery($sql, $connection);
 
         $rows = [];
-        while ($row = $statement->fetch(\PDO::FETCH_ASSOC)) {
+        while ($row = $statement->fetchAssociative()) {
             $rows[] = $row;
             yield $row;
         }
@@ -83,12 +83,16 @@ class QueryExecutor
     /**
      * @param string     $sql
      * @param Connection $connection
-     * @return array
+     * @return array|null
      */
     public function fetch($sql, Connection $connection)
     {
         $statement = $this->executeQuery($sql, $connection);
 
+        if ($statement->rowCount() === 0) {
+            return null;
+        }
+
         return $statement->fetch(\PDO::FETCH_ASSOC);
     }
 
diff --git a/src/UnicaenDbImport/Service/DatabaseService.php b/src/UnicaenDbImport/Service/DatabaseService.php
index 65de97b3596349f24c0b935ee7ab3acbf742d5be..2e0b75d9f5b58ec90ba9d65f9c1cffe2c3940dac 100644
--- a/src/UnicaenDbImport/Service/DatabaseService.php
+++ b/src/UnicaenDbImport/Service/DatabaseService.php
@@ -400,7 +400,7 @@ class DatabaseService
         $importObservRows = $qb->getQuery()->getResult(Query::HYDRATE_ARRAY);
 
         if (!empty($importObservRows)) {
-            $sql = $this->codeGenerator->generateSQLForInsertionIntoImportObservResult($importObservRows);
+            $sql = $this->codeGenerator->generateSQLForInsertionIntoImportObservResult($this->destination, $importObservRows);
             try {
                 $this->queryExecutor->exec($sql, $this->destination->getConnection());
             } catch (DBALException $e) {
@@ -482,7 +482,7 @@ class DatabaseService
     /**
      * Requête la Source pour obtenir le 1er enregistrements des données sources.
      *
-     * @return array
+     * @return array|null
      */
     public function fetchSourceFirstRow()
     {
diff --git a/src/UnicaenDbImport/Service/FacadeService.php b/src/UnicaenDbImport/Service/FacadeService.php
index 960c52aeebe91d9688fa04c1ad1609b6d7dcd49f..645c2b3209b36add5b79d876e68c126ca3b26ff5 100644
--- a/src/UnicaenDbImport/Service/FacadeService.php
+++ b/src/UnicaenDbImport/Service/FacadeService.php
@@ -275,12 +275,16 @@ class FacadeService
                     break;
 
                 case $connection instanceof DbConnection:
-                    $data = [ $this->databaseService->fetchSourceFirstRow() ];
+                    $firstRow = $this->databaseService->fetchSourceFirstRow();
+                    if ($firstRow === null) {
+                        throw new RuntimeException(
+                            "Impossible de découvrir la liste des colonnes à partir des données sources car celles-ci sont vides");
+                    }
+                    $data = [ $firstRow ];
                     break;
 
                 default:
                     throw new RuntimeException("Type de connexion source inattendue");
-                    break;
             }
         }
 
@@ -295,11 +299,6 @@ class FacadeService
      */
     private function extractColumnsFromSourceFetchResults(array $rows)
     {
-        if (empty($rows)) {
-            throw new RuntimeException(
-                "Impossible de déterminer la liste des colonnes à partir des données sources car celles-ci sont vides");
-        }
-
         $first = current($rows);
 
         if ($first instanceof stdClass) {
@@ -311,9 +310,7 @@ class FacadeService
                 "Impossible de déterminer la liste des colonnes à partir des données sources car leur type est inconnu (ni array ni stdClass)");
         }
 
-        $columns = array_diff($columns, ['source_id', 'SOURCE_ID']);
-        
-        return $columns;
+        return array_diff($columns, ['source_id', 'SOURCE_ID']);
     }
 
     /**