diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..8d82edc
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,44 @@
+sudo: required
+
+language: java
+
+services:
+ - docker
+
+addons:
+ sonarqube:
+ organization: "differentway-github"
+ token:
+ secure: "fnzS5t/buOCMWV5xx8sGOcPG+6P3LZwFuyOjOI9efm8s6uaYc2dHaKz9A45W2FB6O74pCohO8hVOh+C610fdnlES4JZ3kEy0V4/NWB9jun6w0dT+kPFRCUPmcyrS1zVZvEtlzuy2dUSPUgKfWQKnufZMex1VxghJge022+bGKbxsSYCcn0/EkOnHKN3hcP/WtjgfMQ7NrGrR+nGzZIblQRDL2bLyhx7skI7aVyo4qv93GyFGk5dIqmJtXlh+p8ylzImrJnM+V74NbRQe+YkgYZbH1VNaAzhCiSCRc8YltrAyJXJ1kLS778rIaQptLu2kn3wsZbC1dgGikg0rhy++on/cMvYWPo8LhQO7hGq31pTIblXI3+l0aU+FrKCXbpofIxbXwzBmZUOLa+StfnB9ANvsC9sn2RZ0A73U7lo/4jGY5EmjjyCze7TcyDonySyA/BrmwvDgnxKXrkAcI5jsY4bK+3Zy8pZkCYhoqilTwMsvs54m5skmLA3qv6l4tdmtNRgZD3EUnNutkjpp86gbrMa6d4k0/b2pxSjnK+MhQWKcpgXbH+Z935gTVTUcWxslu+kPXOhuH2uuiScOCCc0O/R7kPjVbFWakdjylOLFubaGKi9PmCyoYfiAcjfhFGoD7t6pXWjQdo3aRSp1d20qnioKi/c0w66hVQImiSU77Dw="
+ branches:
+ - master
+ - develop
+
+script:
+ # JaCoCo is used to have code coverage, the agent has to be activated
+ - mvn clean org.jacoco:jacoco-maven-plugin:prepare-agent package sonar:sonar
+
+deploy:
+ provider: script
+ skip_cleanup: true
+ script: release/deploy.sh
+ on:
+ tags: true
+ branch: master
+
+env:
+ global:
+ # OSSRH_JIRA_USERNAME
+ - secure: "caws3wHcWWqniMDyBq0TejNpJdgZYogiLWsWNMRAbnKvvwtwP21OQDAs/fIW8/7R85U1gT/WY9J/W375EzMHLn7kCqd8H15DMvWbr06WPhs/oxcWIaRaijv9YmVxX/aqPc/31B0YsEY/f5bDtZcu8guVKvhGpBsZMVTK1pHshUbskYvx/0NLDkJgC/KhW0taYfYoQ+6aKS6s15kqUyC+kXMrf7qNiiajWPbgARWAAPHci/XWzlqn9QD+kUq4YK2xgtq6ris5fudfrA1/z5EG+7E5qdsZ7UZaJfs3PGnBv1tpLTKWt2KxcgMVI+P5nEsjxpZ//RJDW7g9wKvJFbwgfB+2b44dAMzer4xOjzK+PeueiOsgXP42MzyUXDlTSAks7+W2u48qntQVYCOv9pMb0rKjUk5LL6SaGQuiZPgNs13jZXiPH8EVxwsf67qjz/wf0KNpejoDxhwa5mnlqOLyTc/+NufIf0Zea1t3Et5YwXZR7i9DvS+N8j01eeHYhIPjMtSAidO7lj+3oRMTw4O+hrnplj3khUJd3J585I6QEPYxcPYH/2gUOmrl7rXuPC0CHa7oiXsHcpBZsGdDxzkkv1s4qTEH6Y3uujb+rXV3CF1cUMGqXwXztyed0WO9KSdXvTjYK/8jQussSVJanbVd3XGUFSYqhJxOWMpxBIqDgQk="
+ # OSSRH_JIRA_PASSWORD
+ - secure: "cYNSycG67mhSUHrOZRcsXeuxMJJ2laScbXT9BNXTThu8GGHat2H/uHIBWvmUl8XVzNGTcQb6L0iI2EGYDAXwqmSWD2qhBStcRBmwSEPvEHmExEiBy8vL33YVH/YWOg50f39A3AZNZAWarrqEZV1UAMiC3Eqgsmn0xkl+C+KJ5WWPMOQItYfV+jq3Gl+MCO6zKF0CLJWfkm4KFbvGkUeQDAgg7+F9kqTAN8Tj/fTxV5PY2MqsqNKVbi91ObhYM3ChW1ZrA/4CTbUAoooAXyc8yJGDgHNVqeOfC4Pe6+BZyl231438x0jf1M2SHA3izx9OHLirSWAOFyseOImxYrTUw+4yB0u43p/2EtY7Njls0dTTVXDjTadskIKYnM/yFVjlw7IGULSahOyICLA/t5bWnl8CMHsPv83ezdRnloMha6My0oB9k4Qk8JHDv4ZP7o/FSKQpngbA/0KEunclLIqlkjqAJ+5vyQrdCyp2KbAGFQEDv6/3U7P8KxM6HSgy21I8r1M3QBrvTHfbw9UbTNBZeDRy0LPwBGo6A7UH6SALW3gYkX8RGan2otEZxUFKX/ZGDnTK9sWiNyUYPlBfMTKCdQlcTKtRorK/4ypQdvcm29jV+44mxKvmvikddAi92sLUgvhfo7nSVgQ5JJYGVLyZEhK2SDzqimJTDq5gsJe+KwA="
+ # GPG_KEY_NAME
+ - secure: "amjeDAgcasXubwZ9hIYf1SfuwmYg9/CQxYwR5vDEzxXbKGzXJWUWy5aDWv/8b6NZ6lOm+wiaGutEvmF/M43SYhc+7NUQZfNBJQQJMZrILsUhFN6hCVeQKSZQ8932fvHnlXzGMrleiUpW/5m5YajS9GyCkV3+Z7hSxW8MuLsYeFGkmCU8S0idUGjt17EklBn4ZNYN1UQr6VJsRgf1ZLzdmdULeQaJBToZNdrP3HH7nfwACa/l7Hq1b1wN87du9QwWcPONc/7JMeZwXpX2kYdQgAaGTk91Z0Kycp7yjMw5SQKm349y3cvensWz0EAmq9ElEUJStafHSat57NjcHXR+fuynfwde0wRkVa9pfJb126lQCnv0E5rT3pJn7GeRXTcUKFKV8pzITEZbU4Xv6j0WFgLF5Ms9Tw01bpCVASq3e1ebO2yjGxLYPhCTOfSw3N5Pubo5DsTDVvFZcZ9aH1/E6wbJ+b1J4lvzyH+xWVw3aFa/hoksfu+vMfOe24YNymaOeOc9V++bi71Ddf8+cWuOHcESPa7M4YEBO6PpfGKqXPK/7W8DrKjfupAfH4qIMUI5KTDPBtjvujyQcQU3949B0QcJcvHGyjk4P0F6L47xUhE4CnyVRV3FkIZita25atZJFc9o3ZiBCJIQ8Jau2u/H/lgGc9EkS7pirmJlwWWcOEY="
+ # GPG_PASSPHRASE
+ - secure: "DR4U1DbQBQyVfsKay6QHlQ//sZmQpvx/N0vkECtQqUtZuROBsoIwQj/s5Sc79VIIWjFQGLOaOaOKd8nC0s1Om0RTB2a1DdaUIrBlsLP7vfVeGwCE4FsJdrIY3mDfg7V+gQenbzvhqtupx7/+l2lQcXQb84Jqd9cECjfRUpNy9l441oTlnmV9p8NiM6hkFI2t2SLZAmTjkzIaaOZO16jBKgoALTd+OpGvmYLUYDlNXwpSI0sdyzWMIEudREDAWUsJRGiOFUdy4AyfhZpfGHV2PhKo4wBNIZLH6l5Ifb3KKVtOeavgN4rQ5u+tNPI/PoRnyoTbHHBFe5ICjvZewwhxJPxlw7UOF4iPURlla+3QTvQCV1ptQHmJ7E/fZZ1jZbDIEb8se4XtLOk5Nxcfp6FTcKvVBAoo3mezONDxBSC2w3LnNtwPLRVtfH3BaqnEQwZ4yb5JGjFwgQ4mbMzc1fF6w+L26LgsoayUoykulKwaKvqk1BSyIVvC0/To6bIPUsqWACAIXFmlqhGt3aCQhoAAxF2uItGPBbMW/+KepOS0PRsM13TrZDdqc8TWiSsW8KdfsvswR1dT7BDfsNtwNCCSx2m2qFxdxwAd81IcVtVgcpQiWj6R9378SUnTr4KtM2UCMumV5xcpn5/rZ2pqQSOFVl5M6xiiOK4Q9It7whapZUc="
+
+cache:
+ directories:
+ - '$HOME/.m2/repository'
+ - '$HOME/.sonar/cache'
+
diff --git a/README.md b/README.md
index a01e02b..270dad3 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,18 @@
-# couchmove
\ No newline at end of file
+
+
+### What is Couchmove?
+
+Couchmove is an open-source Java migration tool for [Couchbase](https://www.couchbase.com/), which is an NoSQL document-oriented database, well know for it's performance and scalability.
+
+Couchmove can help you *track*, *manage* and *apply changes* in your Couchbase buckets. The concept is very similar to other database migration tools such as [Liquibase](http://www.liquibase.org), [Flyway](http://flywaydb.org), [mongeez](https://github.com/secondmarket/mongeez), [mongobee](http://mongodb-tools.com/tool/mongobee/) ...
+
+### What's special?
+
+Couchmove is widely inspired from [Flyway](http://flywaydb.org) : it strongly favors simplicity and convention over configuration : There is *no XML configuration files*. Just **json documents**, **design documents** to import and **n1ql** files to execute.
+
+### How to use?
+
+Check out our [wiki](https://github.com/differentway/couchmove/wiki)
+
+---
+[![Build Status](https://travis-ci.org/differentway/couchmove.svg?branch=develop)](https://travis-ci.org/differentway/couchmove) [![Quality Gate](https://sonarcloud.io/api/badges/gate?key=com.github.differentway:couchmove:develop)](https://sonarqube.com/dashboard/index/com.github.differentway:couchmove:develop) [![Licence](https://img.shields.io/hexpm/l/plug.svg)](https://github.com/differentway/couchmove/blob/master/LICENSE)
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..ebbe56b
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,219 @@
+
+
+
+ * CAS is for Check And Swap, which is an identifier that permit optimistic concurrency
+ */
+ @Nullable
+ @JsonIgnore
+ private Long cas;
+}
diff --git a/src/main/java/com/github/couchmove/pojo/Status.java b/src/main/java/com/github/couchmove/pojo/Status.java
new file mode 100644
index 0000000..9c71f43
--- /dev/null
+++ b/src/main/java/com/github/couchmove/pojo/Status.java
@@ -0,0 +1,25 @@
+package com.github.couchmove.pojo;
+
+/**
+ * Describes the current status of a {@link ChangeLog} execution
+ *
+ * @author ctayeb
+ * Created on 03/06/2017
+ */
+public enum Status {
+
+ /**
+ * The {@link ChangeLog} was successfully executed
+ */
+ EXECUTED,
+
+ /**
+ * The {@link ChangeLog} execution has failed
+ */
+ FAILED,
+
+ /**
+ * The {@link ChangeLog} execution was ignored
+ */
+ SKIPPED
+}
diff --git a/src/main/java/com/github/couchmove/pojo/Type.java b/src/main/java/com/github/couchmove/pojo/Type.java
new file mode 100644
index 0000000..0adeb6b
--- /dev/null
+++ b/src/main/java/com/github/couchmove/pojo/Type.java
@@ -0,0 +1,41 @@
+package com.github.couchmove.pojo;
+
+import com.couchbase.client.java.query.N1qlQuery;
+import com.couchbase.client.java.view.DesignDocument;
+import lombok.Getter;
+
+/**
+ * Describes the type of the {@link ChangeLog}
+ *
+ * @author ctayeb
+ * Created on 27/05/2017
+ */
+public enum Type {
+
+ /**
+ * json documents
+ */
+ DOCUMENTS(""),
+
+ /**
+ * json document representing a {@link DesignDocument}
+ */
+ DESIGN_DOC(Constants.JSON),
+
+ /**
+ * n1ql file containing a list of {@link N1qlQuery}
+ */
+ N1QL(Constants.N1QL);
+
+ @Getter
+ private final String extension;
+
+ Type(String extension) {
+ this.extension = extension;
+ }
+
+ public static class Constants {
+ public static final String JSON = "json";
+ public static final String N1QL = "n1ql";
+ }
+}
diff --git a/src/main/java/com/github/couchmove/repository/CouchbaseRepository.java b/src/main/java/com/github/couchmove/repository/CouchbaseRepository.java
new file mode 100644
index 0000000..a3f47ae
--- /dev/null
+++ b/src/main/java/com/github/couchmove/repository/CouchbaseRepository.java
@@ -0,0 +1,85 @@
+package com.github.couchmove.repository;
+
+import com.couchbase.client.java.Bucket;
+import com.couchbase.client.java.query.N1qlQuery;
+import com.couchbase.client.java.view.DesignDocument;
+import com.github.couchmove.pojo.CouchbaseEntity;
+
+/**
+ * A repository for encapsulating storage, retrieval, and removal of json documents to Couchbase {@link Bucket}
+ *
+ * @param
+ * Otherwise it {@link CouchbaseRepository#save(String, CouchbaseEntity)}
+ *
+ * @param id the per-bucket unique document id
+ * @param entity entity to convert and save
+ * @return saved entity with CAS
+ * @throws com.couchbase.client.java.error.CASMismatchException if the cas of entity is different from existing one
+ * @throws com.couchbase.client.java.error.DocumentAlreadyExistsException if the cas is not set and the document exists on couchbase
+ */
+ E checkAndSave(String id, E entity);
+
+ /**
+ * Removes a {@link CouchbaseEntity} from Couchbase Bucket identified by its id
+ *
+ * @param id the id of the document to remove
+ */
+ void delete(String id);
+
+ /**
+ * Retrieves a document from Couchbase {@link Bucket} by its ID.
+ *
+ * - If the document exists, convert it to {@link CouchbaseEntity} with CAS set (Check And Swap for optimistic concurrency)
+ *
+ * {@value PREFIX_ID} + {@link ChangeLog#version}
+ *
+ * @param changeLog The ChangeLog to save
+ * @return {@link ChangeLog} entity with CAS (Check And Swap, for optimistic concurrency) set
+ */
+ public ChangeLog save(ChangeLog changeLog) {
+ return repository.save(PREFIX_ID + changeLog.getVersion(), changeLog);
+ }
+
+ /**
+ * Inserts a {@link DesignDocument} into production
+ *
+ * @param name name of the {@link DesignDocument} to insert
+ * @param content the content of the {@link DesignDocument} to insert
+ */
+ public void importDesignDoc(String name, String content) {
+ logger.info("Inserting Design Document '{}'...", name);
+ repository.importDesignDoc(name, content);
+ }
+
+ /**
+ * Queries Couchbase {@link Bucket} with multiple {@link N1qlQuery}
+ *
+ * @param content containing multiple {@link N1qlQuery}
+ */
+ public void executeN1ql(String content) {
+ List
+ * Exemple : 188,100,312 {@link TimeUnit#MILLISECONDS} → 2d 4h 15m 15s 312ms
+ *
+ * @param duration duration to format
+ * @param timeUnit source timeUnit
+ * @return human readable duration format
+ */
+ public static String prettyFormatDuration(long duration, TimeUnit timeUnit) {
+ StringBuffer sb = new StringBuffer();
+ duration = appendUnit(sb, duration, timeUnit, DAYS/* */, "d", timeUnit::toDays);
+ duration = appendUnit(sb, duration, timeUnit, HOURS/* */, "h", timeUnit::toHours);
+ duration = appendUnit(sb, duration, timeUnit, MINUTES/* */, "min", timeUnit::toMinutes);
+ duration = appendUnit(sb, duration, timeUnit, SECONDS/* */, "s", timeUnit::toSeconds);
+ duration = appendUnit(sb, duration, timeUnit, MILLISECONDS, "ms", timeUnit::toMillis);
+ duration = appendUnit(sb, duration, timeUnit, MICROSECONDS, "μs", timeUnit::toMicros);
+ /* */
+ appendUnit(sb, duration, timeUnit, NANOSECONDS, "ns", timeUnit::toNanos);
+ return sb.toString();
+ }
+
+ private static long appendUnit(StringBuffer sb, long duration, TimeUnit source, TimeUnit destination, String unit, Function
+ * - Otherwise it return null
+ *
+ *
+ *
+ * @param changeLogs to load from database
+ * @return database version of changeLogs
+ * @throws CouchmoveException if checksum doesn't match
+ */
+ public List
+ *
+ *
+ *
+ *
+ * @param content content from where the requests are extracted
+ * @return multiple requests
+ */
+ static List