diff --git a/backend/src/uxbox/util/exceptions.clj b/backend/src/uxbox/util/exceptions.clj
index b39a9e8ce..f5bdde57b 100644
--- a/backend/src/uxbox/util/exceptions.clj
+++ b/backend/src/uxbox/util/exceptions.clj
@@ -4,6 +4,8 @@
 ;;
 ;; Copyright (c) 2016 Andrey Antukh <niwi@niwi.nz>
 
+;; WARNING: DEPRECATED: please use uxbox.common.exceptions
+
 (ns uxbox.util.exceptions
   "A helpers for work with exceptions."
   (:require [clojure.spec.alpha :as s]))
diff --git a/backend/src/uxbox/util/spec.clj b/backend/src/uxbox/util/spec.clj
index efd8561d9..1fac49aaf 100644
--- a/backend/src/uxbox/util/spec.clj
+++ b/backend/src/uxbox/util/spec.clj
@@ -4,6 +4,8 @@
 ;;
 ;; Copyright (c) 2016-2019 Andrey Antukh <niwi@niwi.nz>
 
+;; WARNING: DEPRECATED: please use uxbox.common.spec
+
 (ns uxbox.util.spec
   (:refer-clojure :exclude [keyword uuid vector boolean map set])
   (:require
diff --git a/common/uxbox/common/exceptions.cljc b/common/uxbox/common/exceptions.cljc
new file mode 100644
index 000000000..1b271c36e
--- /dev/null
+++ b/common/uxbox/common/exceptions.cljc
@@ -0,0 +1,33 @@
+;; This Source Code Form is subject to the terms of the Mozilla Public
+;; License, v. 2.0. If a copy of the MPL was not distributed with this
+;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
+;;
+;; Copyright (c) 2016 Andrey Antukh <niwi@niwi.nz>
+
+(ns uxbox.common.exceptions
+  "A helpers for work with exceptions."
+  (:require [clojure.spec.alpha :as s]))
+
+(s/def ::type keyword?)
+(s/def ::code keyword?)
+(s/def ::mesage string?)
+(s/def ::hint string?)
+(s/def ::cause #?(:clj #(instance? Throwable %)
+                  :cljs #(instance? js/Error %)))
+(s/def ::error-params
+  (s/keys :req-un [::type]
+          :opt-un [::code
+                   ::hint
+                   ::mesage
+                   ::cause]))
+
+(defn error
+  [& {:keys [type code message hint cause] :as params}]
+  (s/assert ::error-params params)
+  (let [message (or message hint "")
+        payload (dissoc params :cause :message)]
+    (ex-info message payload cause)))
+
+(defmacro raise
+  [& args]
+  `(throw (error ~@args)))
diff --git a/common/uxbox/common/pages.cljc b/common/uxbox/common/pages.cljc
index a93ce7942..6be202fe9 100644
--- a/common/uxbox/common/pages.cljc
+++ b/common/uxbox/common/pages.cljc
@@ -1,6 +1,7 @@
 (ns uxbox.common.pages
   "A common (clj/cljs) functions and specs for pages."
   (:require
+   [uxbox.common.spec :as us]
    [clojure.spec.alpha :as s]
    [uxbox.common.data :as d]))
 
@@ -136,10 +137,6 @@
 
 ;; --- Changes Processing Impl
 
-(defn change
-  [data]
-  (s/assert ::change data))
-
 (declare process-change)
 (declare process-mod-shape)
 (declare process-mod-opts)
@@ -151,7 +148,7 @@
 
 (defn process-changes
   [data items]
-  (->> (s/assert ::changes items)
+  (->> (us/assert ::changes items)
        (reduce process-change data)))
 
 (defn- process-change
diff --git a/common/uxbox/common/spec.cljc b/common/uxbox/common/spec.cljc
new file mode 100644
index 000000000..f3319f733
--- /dev/null
+++ b/common/uxbox/common/spec.cljc
@@ -0,0 +1,133 @@
+;; This Source Code Form is subject to the terms of the Mozilla Public
+;; License, v. 2.0. If a copy of the MPL was not distributed with this
+;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
+;;
+;; Copyright (c) 2016-2019 Andrey Antukh <niwi@niwi.nz>
+
+(ns uxbox.common.spec
+  "Data manipulation and query helper functions."
+  (:refer-clojure :exclude [assert])
+  #?(:cljs (:require-macros [uxbox.common.spec :refer [assert]]))
+  (:require
+   #?(:clj [datoteka.core :as fs])
+   #?(:clj [clojure.spec.alpha :as s]
+      :cljs [cljs.spec.alpha :as s])
+   [expound.alpha :as expound]
+   [uxbox.common.exceptions :as ex]
+   [cuerdas.core :as str]))
+
+(s/check-asserts true)
+
+;; --- Constants
+
+(def email-rx
+  #"^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$")
+
+(def uuid-rx
+  #"^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$")
+
+;; --- Conformers
+
+(defn- uuid-conformer
+  [v]
+  (if (uuid? v)
+    v
+    (if (string? v)
+      (if (re-matches uuid-rx v)
+        #?(:cljs (uuid v)
+           :clj (java.util.UUID/fromString v))
+
+        (if (str/empty? v) nil ::s/invalid))
+      ::s/invalid)))
+
+(defn boolean-conformer
+  [v]
+  (if (boolean? v)
+    v
+    (if (string? v)
+      (if (re-matches #"^(?:t|true|false|f|0|1)$" v)
+        (contains? #{"t" "true" "1"} v)
+        ::s/invalid)
+      ::s/invalid)))
+
+(defn boolean-unformer
+  [v]
+  (if v "true" "false"))
+
+(defn- number-conformer
+  [v]
+  (cond
+    (number? v) v
+    (str/numeric? v)
+    #?(:clj (Double/parseDouble v)
+       :cljs (js/parseFloat v))
+    :else ::s/invalid))
+
+(defn- integer-conformer
+  [v]
+  (cond
+    (integer? v) v
+    (string? v)
+    (if (re-matches #"^[-+]?\d+$" v)
+      #?(:clj (Long/parseLong v)
+         :cljs (js/parseInt v 10))
+      ::s/invalid)
+    :else ::s/invalid))
+
+(defn- color-conformer
+  [v]
+  (if (and (string? v) (re-matches #"^#[0-9A-Fa-f]{6}$" v))
+    v
+    ::s/invalid))
+
+(defn- email-conformer
+  [v]
+  (if (and (string? v) (re-matches email-rx v))
+    v
+    ::s/invalid))
+
+#?(:clj
+   (defn path-conformer
+     [v]
+     (cond
+       (string? v) (fs/path v)
+       (fs/path? v) v
+       :else ::s/invalid)))
+
+
+;; --- Default Specs
+
+(s/def ::inst inst?)
+(s/def ::email (s/conformer email-conformer str))
+(s/def ::color (s/conformer color-conformer str))
+(s/def ::uuid (s/conformer uuid-conformer str))
+(s/def ::boolean (s/conformer boolean-conformer boolean-unformer))
+(s/def ::number (s/conformer number-conformer str))
+(s/def ::integer (s/conformer integer-conformer str))
+(s/def ::not-empty-string (s/and string? #(not (str/empty? %))))
+#?(:clj (s/def ::path (s/conformer path-conformer str)))
+
+;; --- Macros
+
+(defn assert*
+  [spec x]
+  (s/assert* spec x))
+
+#?(:clj
+   (defmacro assert
+     "Always active assertion macro (does not obey to :elide-asserts)"
+     [spec x]
+     `(assert* ~spec ~x)))
+
+;; --- Public Api
+
+(defn conform
+  [spec data]
+  (let [result (s/conform spec data)]
+    (when (= result ::s/invalid)
+      (throw (ex/error :type :validation
+                       :code :spec-validation
+                       :explain (with-out-str
+                                  (expound/printer data))
+                       :data (::s/problems data))))
+    result))
diff --git a/frontend/src/uxbox/main.cljs b/frontend/src/uxbox/main.cljs
index 2902cfe37..f792c0194 100644
--- a/frontend/src/uxbox/main.cljs
+++ b/frontend/src/uxbox/main.cljs
@@ -27,8 +27,6 @@
 ;; --- i18n
 
 (declare reinit)
-(s/check-asserts true)
-
 (rx/sub! i18n/locale-sub #(reinit))
 
 ;; --- Error Handling
diff --git a/frontend/src/uxbox/main/data/auth.cljs b/frontend/src/uxbox/main/data/auth.cljs
index 8506e9b14..bdac80ea1 100644
--- a/frontend/src/uxbox/main/data/auth.cljs
+++ b/frontend/src/uxbox/main/data/auth.cljs
@@ -9,12 +9,12 @@
    [cljs.spec.alpha :as s]
    [beicon.core :as rx]
    [potok.core :as ptk]
+   [uxbox.common.spec :as us]
    [uxbox.main.repo :as rp]
    [uxbox.main.store :refer [initial-state]]
    [uxbox.main.data.users :as du]
    [uxbox.util.messages :as um]
    [uxbox.util.router :as rt]
-   [uxbox.util.spec :as us]
    [uxbox.util.i18n :as i18n :refer [tr]]
    [uxbox.util.storage :refer [storage]]))
 
@@ -45,7 +45,7 @@
 
 (defn login
   [{:keys [username password] :as data}]
-  (s/assert ::login-params data)
+  (us/assert ::login-params data)
   (ptk/reify ::login
     ptk/UpdateEvent
     (update [_ state]
@@ -98,8 +98,8 @@
 (defn register
   "Create a register event instance."
   [data on-error]
-  (s/assert ::register-params data)
-  (s/assert ::us/fn on-error)
+  (us/assert ::register-params data)
+  (us/assert fn? on-error)
   (ptk/reify ::register
     ptk/WatchEvent
     (watch [_ state stream]
@@ -123,7 +123,7 @@
 
 (defn recovery-request
   [data]
-  (s/assert ::recovery-request-params data)
+  (us/assert ::recovery-request-params data)
   (ptk/reify ::recover-request
     ptk/WatchEvent
     (watch [_ state stream]
@@ -166,7 +166,7 @@
 
 (defn recovery
   [{:keys [token password] :as data}]
-  (s/assert ::recovery-params data)
+  (us/assert ::recovery-params data)
   (ptk/reify ::recovery
     ptk/WatchEvent
     (watch [_ state stream]
diff --git a/frontend/src/uxbox/main/data/history.cljs b/frontend/src/uxbox/main/data/history.cljs
index 011b3570a..891e046b8 100644
--- a/frontend/src/uxbox/main/data/history.cljs
+++ b/frontend/src/uxbox/main/data/history.cljs
@@ -9,21 +9,21 @@
    [beicon.core :as rx]
    [cljs.spec.alpha :as s]
    [potok.core :as ptk]
+   [uxbox.common.spec :as us]
    [uxbox.main.data.projects :as dp]
    [uxbox.main.repo :as rp]
-   [uxbox.util.data :refer [replace-by-id index-by]]
-   [uxbox.util.spec :as us]))
+   [uxbox.util.data :refer [replace-by-id index-by]]))
 
 ;; --- Schema
 
-(s/def ::pinned ::us/bool)
-(s/def ::id ::us/uuid)
-(s/def ::label ::us/string)
-(s/def ::project ::us/uuid)
-(s/def ::created-at ::us/inst)
-(s/def ::modified-at ::us/inst)
-(s/def ::version ::us/number)
-(s/def ::user ::us/uuid)
+(s/def ::pinned boolean?)
+(s/def ::id uuid?)
+(s/def ::label string?)
+(s/def ::project uuid?)
+(s/def ::created-at inst?)
+(s/def ::modified-at inst?)
+(s/def ::version number?)
+(s/def ::user uuid?)
 
 (s/def ::shapes
   (s/every ::dp/minimal-shape :kind vector?))
@@ -52,7 +52,7 @@
 
 (defn initialize
   [id]
-  (s/assert ::us/uuid id)
+  (us/assert ::us/uuid id)
   (ptk/reify ::initialize
     ptk/UpdateEvent
     (update [_ state]
@@ -71,7 +71,7 @@
 
 (defn watch-page-changes
   [id]
-  (s/assert ::us/uuid id)
+  (us/assert ::us/uuid id)
   (reify
     ptk/WatchEvent
     (watch [_ state stream]
@@ -87,7 +87,7 @@
 
 (defn pinned-history-fetched
   [items]
-  (s/assert ::history-entries items)
+  (us/assert ::history-entries items)
   (ptk/reify ::pinned-history-fetched
     ptk/UpdateEvent
     (update [_ state]
@@ -104,7 +104,7 @@
 
 (defn fetch-pinned-history
   [id]
-  (s/assert ::us/uuid id)
+  (us/assert ::us/uuid id)
   (ptk/reify ::fetch-pinned-history
     ptk/WatchEvent
     (watch [_ state s]
@@ -117,7 +117,7 @@
 
 (defn history-fetched
   [items]
-  (s/assert ::history-entries items)
+  (us/assert ::history-entries items)
   (ptk/reify ::history-fetched
     ptk/UpdateEvent
     (update [_ state]
@@ -140,7 +140,7 @@
   ([id]
    (fetch-history id nil))
   ([id {:keys [since max]}]
-   (s/assert ::us/uuid id)
+   (us/assert ::us/uuid id)
    (ptk/reify ::fetch-history
      ptk/WatchEvent
      (watch [_ state s]
@@ -182,7 +182,7 @@
 
 (defn select
   [version]
-  (s/assert int? version)
+  (us/assert int? version)
   (ptk/reify ::select
     ptk/UpdateEvent
     (update [_ state]
@@ -238,7 +238,7 @@
 
 (defn history-updated
   [item]
-  (s/assert ::history-entry item)
+  (us/assert ::history-entry item)
   (ptk/reify ::history-item-updated
     ptk/UpdateEvent
     (update [_ state]
diff --git a/frontend/src/uxbox/main/data/images.cljs b/frontend/src/uxbox/main/data/images.cljs
index 51802dc1d..b635987d4 100644
--- a/frontend/src/uxbox/main/data/images.cljs
+++ b/frontend/src/uxbox/main/data/images.cljs
@@ -10,6 +10,7 @@
    [cuerdas.core :as str]
    [beicon.core :as rx]
    [potok.core :as ptk]
+   [uxbox.common.spec :as us]
    [uxbox.main.store :as st]
    [uxbox.main.repo.core :as rp]
    [uxbox.util.i18n :refer [tr]]
@@ -17,7 +18,6 @@
    [uxbox.util.data :refer (jscoll->vec)]
    [uxbox.util.uuid :as uuid]
    [uxbox.util.time :as ts]
-   [uxbox.util.spec :as us]
    [uxbox.util.router :as r]
    [uxbox.util.files :as files]))
 
@@ -29,11 +29,11 @@
 (s/def ::modified-at inst?)
 (s/def ::created-at inst?)
 (s/def ::mimetype string?)
-(s/def ::thumbnail us/url-str?)
+(s/def ::thumbnail string?)
 (s/def ::id uuid?)
-(s/def ::url us/url-str?)
-(s/def ::collection-id (s/nilable ::us/uuid))
-(s/def ::user-id ::us/uuid)
+(s/def ::url string?)
+(s/def ::collection-id (s/nilable uuid?))
+(s/def ::user-id uuid?)
 
 (s/def ::collection-entity
   (s/keys :req-un [::id
@@ -59,7 +59,7 @@
 
 (defn collections-fetched
   [items]
-  (s/assert (s/every ::collection-entity) items)
+  (us/assert (s/every ::collection-entity) items)
   (ptk/reify ::collections-fetched
     ptk/UpdateEvent
     (update [_ state]
@@ -83,7 +83,7 @@
 
 (defn collection-created
   [item]
-  (s/assert ::collection-entity item)
+  (us/assert ::collection-entity item)
   (ptk/reify ::collection-created
     ptk/UpdateEvent
     (update [_ state]
@@ -109,7 +109,7 @@
 
 (defn collection-updated
   [item]
-  {:pre [(us/valid? ::collection-entity item)]}
+  (us/assert ::collection-entity item)
   (CollectionUpdated. item))
 
 ;; --- Update Collection
@@ -161,7 +161,7 @@
 
 (defn image-created
   [item]
-  (s/assert ::image-entity item)
+  (us/assert ::image-entity item)
   (ptk/reify ::image-created
     ptk/UpdateEvent
     (update [_ state]
@@ -174,8 +174,8 @@
 (defn create-images
   ([id files] (create-images id files identity))
   ([id files on-uploaded]
-   (s/assert (s/nilable ::us/uuid) id)
-   (s/assert fn? on-uploaded)
+   (us/assert (s/nilable ::us/uuid) id)
+   (us/assert fn? on-uploaded)
    (ptk/reify ::create-images
      ptk/UpdateEvent
      (update [_ state]
@@ -225,7 +225,7 @@
 
 (defn images-fetched
   [items]
-  (s/assert (s/every ::image-entity) items)
+  (us/assert (s/every ::image-entity) items)
   (ptk/reify ::images-fetched
     ptk/UpdateEvent
     (update [_ state]
@@ -239,7 +239,7 @@
 (defn fetch-images
   "Fetch a list of images of the selected collection"
   [id]
-  (s/assert (s/nilable ::us/uuid) id)
+  (us/assert (s/nilable ::us/uuid) id)
   (ptk/reify ::fetch-images
     ptk/WatchEvent
     (watch [_ state s]
diff --git a/frontend/src/uxbox/main/data/projects.cljs b/frontend/src/uxbox/main/data/projects.cljs
index 9f95c455a..b519d4c7d 100644
--- a/frontend/src/uxbox/main/data/projects.cljs
+++ b/frontend/src/uxbox/main/data/projects.cljs
@@ -11,9 +11,9 @@
    [cuerdas.core :as str]
    [potok.core :as ptk]
    [uxbox.common.pages :as cp]
+   [uxbox.common.spec :as us]
    [uxbox.main.repo.core :as rp]
    [uxbox.util.router :as rt]
-   [uxbox.util.spec :as us]
    [uxbox.util.time :as dt]
    [uxbox.util.timers :as ts]
    [uxbox.util.uuid :as uuid]))
@@ -21,9 +21,9 @@
 ;; --- Specs
 
 (s/def ::id ::us/uuid)
-(s/def ::name ::us/string)
+(s/def ::name string?)
 (s/def ::user ::us/uuid)
-(s/def ::type ::us/keyword)
+(s/def ::type keyword?)
 (s/def ::file-id ::us/uuid)
 (s/def ::project-id ::us/uuid)
 (s/def ::created-at ::us/inst)
@@ -134,7 +134,7 @@
 
 (defn projects-fetched
   [projects]
-  (s/assert (s/every ::project) projects)
+  (us/assert (s/every ::project) projects)
   (ptk/reify ::projects-fetched
     ptk/UpdateEvent
     (update [_ state]
@@ -158,7 +158,7 @@
 
 (defn fetch-file
   [id]
-  (s/assert ::us/uuid id)
+  (us/assert ::us/uuid id)
   (ptk/reify ::fetch-file
     ptk/WatchEvent
     (watch [_ state stream]
@@ -169,7 +169,7 @@
 
 (defn files-fetched
   [files]
-  (s/assert (s/every ::file) files)
+  (us/assert (s/every ::file) files)
   (ptk/reify ::files-fetched
     cljs.core/IDeref
     (-deref [_] files)
@@ -227,7 +227,7 @@
 
 (defn delete-project
   [id]
-  (s/assert ::us/uuid id)
+  (us/assert ::us/uuid id)
   (ptk/reify ::delete-project
     ptk/UpdateEvent
     (update [_ state]
@@ -242,7 +242,7 @@
 
 (defn delete-file
   [id]
-  (s/assert ::us/uuid id)
+  (us/assert ::us/uuid id)
   (ptk/reify ::delete-file
     ptk/UpdateEvent
     (update [_ state]
@@ -273,7 +273,7 @@
 
 (defn go-to
   [file-id]
-  (s/assert ::us/uuid file-id)
+  (us/assert ::us/uuid file-id)
   (ptk/reify ::go-to
     ptk/WatchEvent
     (watch [_ state stream]
@@ -284,7 +284,7 @@
 
 (defn go-to-project
   [id]
-  (s/assert (s/nilable ::us/uuid) id)
+  (us/assert (s/nilable ::us/uuid) id)
   (ptk/reify ::go-to-project
     ptk/WatchEvent
     (watch [_ state stream]
@@ -299,7 +299,7 @@
 
 (defn fetch-pages
   [file-id]
-  (s/assert ::us/uuid file-id)
+  (us/assert ::us/uuid file-id)
   (reify
     ptk/WatchEvent
     (watch [_ state s]
@@ -310,7 +310,7 @@
 
 (defn pages-fetched
   [pages]
-  (s/assert (s/every ::page) pages)
+  (us/assert (s/every ::page) pages)
   (ptk/reify ::pages-fetched
     IDeref
     (-deref [_] pages)
@@ -326,7 +326,7 @@
 (defn fetch-page
   "Fetch page by id."
   [id]
-  (s/assert ::us/uuid id)
+  (us/assert ::us/uuid id)
   (reify
     ptk/WatchEvent
     (watch [_ state s]
@@ -337,7 +337,7 @@
 
 (defn page-fetched
   [data]
-  (s/assert ::page data)
+  (us/assert ::page data)
   (ptk/reify ::page-fetched
     IDeref
     (-deref [_] data)
@@ -377,7 +377,7 @@
 
 (defn page-created
   [{:keys [id file-id] :as page}]
-  (s/assert ::page page)
+  (us/assert ::page page)
   (ptk/reify ::page-created
     cljs.core/IDeref
     (-deref [_] page)
@@ -393,7 +393,7 @@
 
     ptk/WatchEvent
     (watch [_ state stream]
-      (rx/of (uxbox.main.data.projects/fetch-file file-id)))))
+      (rx/of (fetch-file file-id)))))
 
 ;; --- Rename Page
 
@@ -402,8 +402,8 @@
 
 (defn rename-page
   [id name]
-  (s/assert ::us/uuid id)
-  (s/assert string? name)
+  (us/assert ::us/uuid id)
+  (us/assert string? name)
   (ptk/reify ::rename-page
     ptk/UpdateEvent
     (update [_ state]
@@ -461,7 +461,7 @@
 
 (defn page-persisted
   [{:keys [id] :as page}]
-  (s/assert ::page page)
+  (us/assert ::page page)
   (ptk/reify ::page-persisted
     cljs.core/IDeref
     (-deref [_] page)
diff --git a/frontend/src/uxbox/main/data/undo.cljs b/frontend/src/uxbox/main/data/undo.cljs
index 34b56e4fe..b0cfebc99 100644
--- a/frontend/src/uxbox/main/data/undo.cljs
+++ b/frontend/src/uxbox/main/data/undo.cljs
@@ -9,9 +9,9 @@
    [beicon.core :as rx]
    [cljs.spec.alpha :as s]
    [potok.core :as ptk]
+   [uxbox.common.spec :as us]
    [uxbox.main.data.projects :as dp]
-   [uxbox.main.store :as st]
-   [uxbox.util.spec :as us]))
+   [uxbox.main.store :as st]))
 
 (def MAX-STACK-SIZE 50)
 
@@ -24,7 +24,7 @@
 
 (defn watch-page-changes
   [id]
-  (s/assert ::us/uuid id)
+  (us/assert ::us/uuid id)
   (ptk/reify ::watch-page-changes
     ptk/WatchEvent
     (watch [_ state stream]
@@ -40,7 +40,7 @@
 
 (defn save-undo-entry
   [id]
-  (s/assert ::us/uuid id)
+  (us/assert ::us/uuid id)
   (letfn [(cons-entry [stack entry]
             (let [stack (cons entry stack)]
               (if (> (count stack) MAX-STACK-SIZE)
diff --git a/frontend/src/uxbox/main/data/users.cljs b/frontend/src/uxbox/main/data/users.cljs
index 3785731d0..4aa2fcc0d 100644
--- a/frontend/src/uxbox/main/data/users.cljs
+++ b/frontend/src/uxbox/main/data/users.cljs
@@ -6,14 +6,14 @@
 
 (ns uxbox.main.data.users
   (:require
-   [cljs.spec.alpha :as s]
    [beicon.core :as rx]
+   [cljs.spec.alpha :as s]
    [cuerdas.core :as str]
    [potok.core :as ptk]
+   [uxbox.common.spec :as us]
    [uxbox.main.repo.core :as rp]
    [uxbox.util.i18n :as i18n :refer [tr]]
    [uxbox.util.messages :as uum]
-   [uxbox.util.spec :as us]
    [uxbox.util.storage :refer [storage]]))
 
 ;; --- Common Specs
@@ -42,7 +42,7 @@
 
 (defn profile-fetched
   [data]
-  (s/assert ::profile-fetched data)
+  (us/assert ::profile-fetched data)
   (ptk/reify ::profile-fetched
     ptk/UpdateEvent
     (update [_ state]
@@ -73,9 +73,9 @@
 
 (defn form->update-profile
   [data on-success on-error]
-  (s/assert ::update-profile-params data)
-  (s/assert ::us/fn on-error)
-  (s/assert ::us/fn on-success)
+  (us/assert ::update-profile-params data)
+  (us/assert fn? on-error)
+  (us/assert fn? on-success)
   (reify
     ptk/WatchEvent
     (watch [_ state s]
@@ -102,9 +102,9 @@
 
 (defn update-password
   [data {:keys [on-success on-error]}]
-  (s/assert ::update-password-params data)
-  (s/assert ::us/fn on-success)
-  (s/assert ::us/fn on-error)
+  (us/assert ::update-password-params data)
+  (us/assert fn? on-success)
+  (us/assert fn? on-error)
   (reify
     ptk/WatchEvent
     (watch [_ state s]
@@ -127,9 +127,11 @@
          (rx/do done)
          (rx/map (constantly fetch-profile)))))
 
+(s/def ::file #(instance? js/File %))
+
 (defn update-photo
   ([file] (update-photo file (constantly nil)))
   ([file done]
-   {:pre [(us/file? file)
-          (fn? done)]}
+   (us/assert ::file file)
+   (us/assert fn? done)
    (UpdatePhoto. file done)))
diff --git a/frontend/src/uxbox/main/data/workspace.cljs b/frontend/src/uxbox/main/data/workspace.cljs
index 820c3fc79..acf736c14 100644
--- a/frontend/src/uxbox/main/data/workspace.cljs
+++ b/frontend/src/uxbox/main/data/workspace.cljs
@@ -11,6 +11,7 @@
    [potok.core :as ptk]
    [uxbox.common.data :as d]
    [uxbox.common.pages :as cp]
+   [uxbox.common.spec :as us]
    [uxbox.config :as cfg]
    [uxbox.main.constants :as c]
    [uxbox.main.data.icons :as udi]
@@ -28,7 +29,6 @@
    [uxbox.util.math :as mth]
    [uxbox.util.perf :as perf]
    [uxbox.util.router :as rt]
-   [uxbox.util.spec :as us]
    [uxbox.util.time :as dt]
    [uxbox.util.transit :as t]
    [uxbox.util.uuid :as uuid]
@@ -130,7 +130,7 @@
 
 (defn handle-who
   [{:keys [users] :as msg}]
-  (s/assert set? users)
+  (us/assert set? users)
   (ptk/reify ::handle-who
     ptk/UpdateEvent
     (update [_ state]
@@ -195,8 +195,8 @@
 (defn initialize
   "Initialize the workspace state."
   [file-id page-id]
-  (s/assert ::us/uuid file-id)
-  (s/assert ::us/uuid page-id)
+  (us/assert ::us/uuid file-id)
+  (us/assert ::us/uuid page-id)
   (ptk/reify ::initialize
     ptk/WatchEvent
     (watch [_ state stream]
@@ -218,7 +218,7 @@
 
 (defn- initialized
   [file-id]
-  (s/assert ::us/uuid file-id)
+  (us/assert ::us/uuid file-id)
   (ptk/reify ::initialized
     ptk/UpdateEvent
     (update [_ state]
@@ -231,8 +231,8 @@
 
 (defn finalize
   [file-id page-id]
-  (s/assert ::us/uuid file-id)
-  (s/assert ::us/uuid page-id)
+  (us/assert ::us/uuid file-id)
+  (us/assert ::us/uuid page-id)
   (ptk/reify ::finalize
     ptk/UpdateEvent
     (update [_ state]
@@ -289,7 +289,7 @@
 
 (defn toggle-layout-flag
   [flag]
-  (s/assert keyword? flag)
+  (us/assert keyword? flag)
   (ptk/reify ::toggle-layout-flag
     ptk/UpdateEvent
     (update [_ state]
@@ -303,7 +303,7 @@
 
 (defn activate-flag
    [flag]
-  (s/assert keyword? flag)
+  (us/assert keyword? flag)
   (ptk/reify ::activate-flag
     ptk/UpdateEvent
     (update [_ state]
@@ -315,7 +315,7 @@
 
 (defn deactivate-flag
   [flag]
-  (s/assert keyword? flag)
+  (us/assert keyword? flag)
   (ptk/reify ::deactivate-flag
     ptk/UpdateEvent
     (update [_ state]
@@ -323,7 +323,7 @@
 
 (defn toggle-flag
   [flag]
-  (s/assert keyword? flag)
+  (us/assert keyword? flag)
   (ptk/reify ::toggle-flag
     ptk/WatchEvent
     (watch [_ state stream]
@@ -483,7 +483,7 @@
 
 ;; (defn initialize-alignment
 ;;   [id]
-;;   (s/assert ::us/uuid id)
+;;   (us/assert ::us/uuid id)
 ;;   (ptk/reify ::initialize-alignment
 ;;     ptk/WatchEvent
 ;;     (watch [_ state stream]
@@ -541,7 +541,7 @@
 
 (defn add-shape
   [data]
-  (s/assert ::shape-attrs data)
+  (us/assert ::shape-attrs data)
   (let [id (uuid/random)]
     (ptk/reify ::add-shape
       ptk/UpdateEvent
@@ -570,7 +570,7 @@
 
 (defn add-canvas
   [data]
-  (s/assert ::shape-attrs data)
+  (us/assert ::shape-attrs data)
   (let [id (uuid/random)]
     (ptk/reify ::add-canvas
       ptk/UpdateEvent
@@ -621,7 +621,7 @@
 
 (defn select-shape
   [id]
-  (s/assert ::us/uuid id)
+  (us/assert ::us/uuid id)
   (ptk/reify ::select-shape
     ptk/UpdateEvent
     (update [_ state]
@@ -683,8 +683,8 @@
 
 (defn update-shape
   [id attrs]
-  (s/assert ::us/uuid id)
-  (s/assert ::shape-attrs attrs)
+  (us/assert ::us/uuid id)
+  (us/assert ::shape-attrs attrs)
   (ptk/reify ::update-shape
     IBatchedChange
     ptk/UpdateEvent
@@ -704,7 +704,7 @@
 
 (defn update-options
   [opts]
-  (s/assert ::cp/options opts)
+  (us/assert ::cp/options opts)
   (ptk/reify ::update-options
     IBatchedChange
     ptk/UpdateEvent
@@ -763,8 +763,8 @@
 
 (defn move-selected
   [direction align?]
-  (s/assert ::direction direction)
-  (s/assert boolean? align?)
+  (us/assert ::direction direction)
+  (us/assert boolean? align?)
 
   (ptk/reify ::move-selected
     ptk/WatchEvent
@@ -816,8 +816,8 @@
 
 (defn rename-shape
   [id name]
-  (s/assert ::us/uuid id)
-  (s/assert string? name)
+  (us/assert ::us/uuid id)
+  (us/assert string? name)
   (ptk/reify ::rename-shape
     ptk/UpdateEvent
     (update [_ state]
@@ -838,7 +838,7 @@
 
 (defn order-selected-shapes
   [loc]
-  (s/assert ::direction loc)
+  (us/assert ::direction loc)
   (ptk/reify ::move-selected-layer
     ptk/UpdateEvent
     (update [_ state]
@@ -867,8 +867,8 @@
 
 (defn temporal-shape-order-change
   [id index]
-  (s/assert ::us/uuid id)
-  (s/assert number? index)
+  (us/assert ::us/uuid id)
+  (us/assert number? index)
   (ptk/reify ::change-shape-order
     ptk/UpdateEvent
     (update [_ state]
@@ -896,8 +896,8 @@
 
 (defn change-canvas-order
   [{:keys [id index] :as params}]
-  (s/assert ::us/uuid id)
-  (s/assert ::us/number index)
+  (us/assert ::us/uuid id)
+  (us/assert ::us/number index)
   (ptk/reify ::change-canvas-order
     ptk/UpdateEvent
     (update [_ state]
@@ -912,7 +912,7 @@
 (defn initial-selection-align
   "Align the selection of shapes."
   [ids]
-  (s/assert ::set-of-uuid ids)
+  (us/assert ::set-of-uuid ids)
   (ptk/reify ::initialize-shapes-align-in-bulk
     ptk/WatchEvent
     (watch [_ state stream]
@@ -929,8 +929,8 @@
 
 (defn assoc-temporal-modifier-in-bulk
   [ids xfmt]
-  (s/assert ::set-of-uuid ids)
-  (s/assert gmt/matrix? xfmt)
+  (us/assert ::set-of-uuid ids)
+  (us/assert gmt/matrix? xfmt)
   (ptk/reify ::assoc-temporal-modifier-in-bulk
     ptk/UpdateEvent
     (update [_ state]
@@ -940,8 +940,8 @@
   "Apply the same displacement delta to all shapes identified by the
   set if ids."
   [ids delta]
-  (s/assert ::set-of-uuid ids)
-  (s/assert gpt/point? delta)
+  (us/assert ::set-of-uuid ids)
+  (us/assert gpt/point? delta)
   (letfn [(process-shape [state id]
             (let [prev (get-in state [:workspace-data :shapes-by-id id :modifier-mtx] (gmt/matrix))
                   xfmt (gmt/translate prev delta)]
@@ -989,7 +989,7 @@
 
 (defn commit-changes
   [changes]
-  (s/assert ::cp/changes changes)
+  (us/assert ::cp/changes changes)
   (ptk/reify ::commit-changes
     ptk/UpdateEvent
     (update [_ state]
@@ -1019,7 +1019,7 @@
 
 (defn shapes-changes-commited
   [{:keys [page-id version changes] :as params}]
-  (s/assert ::shapes-changes-commited params)
+  (us/assert ::shapes-changes-commited params)
   (ptk/reify ::shapes-changes-commited
     ptk/UpdateEvent
     (update [_ state]
@@ -1089,8 +1089,8 @@
   of the shape using the width and height attrs
   instread final point of coordinates."
   [id dimensions]
-  (s/assert ::us/uuid id)
-  (s/assert ::update-dimensions dimensions)
+  (us/assert ::us/uuid id)
+  (us/assert ::update-dimensions dimensions)
   (ptk/reify ::update-dimensions
     ptk/UpdateEvent
     (update [_ state]
@@ -1113,8 +1113,8 @@
 
 (defn update-position
   [id point]
-  (s/assert ::us/uuid id)
-  (s/assert gpt/point? point)
+  (us/assert ::us/uuid id)
+  (us/assert gpt/point? point)
   (ptk/reify ::update-position
     ptk/UpdateEvent
     (update [_ state]
@@ -1159,8 +1159,8 @@
 ;; TODO: revisit
 (defn set-hidden-attr
   [id value]
-  (s/assert ::us/uuid id)
-  (s/assert ::us/boolean value)
+  (us/assert ::us/uuid id)
+  (us/assert ::us/boolean value)
   (letfn [(impl-set-hidden [state id]
             (let [{:keys [type] :as shape} (get-in state [:shapes id])]
               (as-> state $
@@ -1182,8 +1182,8 @@
 ;; TODO: revisit
 (defn set-blocked-attr
   [id value]
-  (s/assert ::us/uuid id)
-  (s/assert ::us/boolean value)
+  (us/assert ::us/uuid id)
+  (us/assert ::us/boolean value)
   (letfn [(impl-set-blocked [state id]
             (let [{:keys [type] :as shape} (get-in state [:shapes id])]
               (as-> state $
@@ -1245,7 +1245,7 @@
 
 (defn select-canvas
   [id]
-  (s/assert ::us/uuid id)
+  (us/assert ::us/uuid id)
   (ptk/reify ::select-canvas
     ptk/UpdateEvent
     (update [_ state]
@@ -1266,7 +1266,7 @@
 
 (defn go-to-page
   [page-id]
-  (s/assert ::us/uuid page-id)
+  (us/assert ::us/uuid page-id)
   (ptk/reify ::go-to
     ptk/WatchEvent
     (watch [_ state stream]
diff --git a/frontend/src/uxbox/main/ui/auth/login.cljs b/frontend/src/uxbox/main/ui/auth/login.cljs
index 5510e02f2..31c654871 100644
--- a/frontend/src/uxbox/main/ui/auth/login.cljs
+++ b/frontend/src/uxbox/main/ui/auth/login.cljs
@@ -9,6 +9,7 @@
   (:require
    [cljs.spec.alpha :as s]
    [rumext.alpha :as mf]
+   [uxbox.common.spec :as us]
    [uxbox.builtins.icons :as i]
    [uxbox.config :as cfg]
    [uxbox.main.data.auth :as da]
@@ -17,8 +18,7 @@
    [uxbox.util.dom :as dom]
    [uxbox.util.forms :as fm]
    [uxbox.util.i18n :refer [tr]]
-   [uxbox.util.router :as rt]
-   [uxbox.util.spec :as us]))
+   [uxbox.util.router :as rt]))
 
 (s/def ::username ::us/not-empty-string)
 (s/def ::password ::us/not-empty-string)
diff --git a/frontend/src/uxbox/main/ui/workspace/sidebar/options/interactions.cljs b/frontend/src/uxbox/main/ui/workspace/sidebar/options/interactions.cljs
index 8df360ec0..20d79ef22 100644
--- a/frontend/src/uxbox/main/ui/workspace/sidebar/options/interactions.cljs
+++ b/frontend/src/uxbox/main/ui/workspace/sidebar/options/interactions.cljs
@@ -17,8 +17,7 @@
    [uxbox.main.ui.lightbox :as lbx]
    [uxbox.util.data :refer [read-string]]
    [uxbox.util.dom :as dom]
-   [uxbox.util.i18n :refer [tr]]
-   [uxbox.util.spec :refer [color?]]))
+   [uxbox.util.i18n :refer [tr]]))
 
 ;; --- Helpers
 
diff --git a/frontend/src/uxbox/main/ui/workspace/sidebar/options/page.cljs b/frontend/src/uxbox/main/ui/workspace/sidebar/options/page.cljs
index c504d3ed5..43e1b8b18 100644
--- a/frontend/src/uxbox/main/ui/workspace/sidebar/options/page.cljs
+++ b/frontend/src/uxbox/main/ui/workspace/sidebar/options/page.cljs
@@ -21,8 +21,7 @@
    [uxbox.main.ui.workspace.colorpicker :refer [colorpicker-modal]]
    [uxbox.util.data :refer [parse-int]]
    [uxbox.util.dom :as dom]
-   [uxbox.util.i18n :refer [tr]]
-   [uxbox.util.spec :refer [color?]]))
+   [uxbox.util.i18n :refer [tr]]))
 
 ;; (mf/defc metadata-options
 ;;   [{:keys [page] :as props}]
diff --git a/frontend/src/uxbox/main/websockets.cljs b/frontend/src/uxbox/main/websockets.cljs
index 27a691b7a..5086a66e4 100644
--- a/frontend/src/uxbox/main/websockets.cljs
+++ b/frontend/src/uxbox/main/websockets.cljs
@@ -7,11 +7,9 @@
 (ns uxbox.main.websockets
   "A interface to webworkers exposed functionality."
   (:require
-   [cljs.spec.alpha :as s]
    [goog.events :as ev]
    [beicon.core :as rx]
-   [potok.core :as ptk]
-   [uxbox.util.spec :as us])
+   [potok.core :as ptk])
   (:import
    goog.net.WebSocket
    goog.net.WebSocket.EventType))
diff --git a/frontend/src/uxbox/main/workers.cljs b/frontend/src/uxbox/main/workers.cljs
index ba9cf85c3..a2dd727e8 100644
--- a/frontend/src/uxbox/main/workers.cljs
+++ b/frontend/src/uxbox/main/workers.cljs
@@ -9,7 +9,7 @@
   (:require [cljs.spec.alpha :as s]
             [beicon.core :as rx]
             [potok.core :as ptk]
-            [uxbox.util.spec :as us]
+            [uxbox.common.spec :as us]
             [uxbox.util.workers :as uw]))
 
 (s/def ::width number?)
@@ -36,6 +36,6 @@
 
 (defn initialize-alignment
   [params]
-  {:pre [(us/valid? ::initialize-alignment-params params)]}
+  (us/assert ::initialize-alignment-params params)
   (let [message (assoc params :cmd :grid-init)]
     (uw/send! worker message)))
diff --git a/frontend/src/uxbox/util/forms.cljs b/frontend/src/uxbox/util/forms.cljs
index 02f91253f..a27054547 100644
--- a/frontend/src/uxbox/util/forms.cljs
+++ b/frontend/src/uxbox/util/forms.cljs
@@ -13,8 +13,8 @@
    [lentes.core :as l]
    [potok.core :as ptk]
    [rumext.alpha :as mf]
+   [uxbox.common.spec :as us]
    [uxbox.util.dom :as dom]
-   [uxbox.util.spec :as us]
    [uxbox.util.i18n :refer [tr]]))
 
 ;; --- Handlers Helpers
@@ -119,4 +119,3 @@
 (s/def ::email ::us/email)
 (s/def ::not-empty-string ::us/not-empty-string)
 (s/def ::color ::us/color)
-(s/def ::number-str ::us/number-str)
diff --git a/frontend/src/uxbox/util/spec.cljs b/frontend/src/uxbox/util/spec.cljs
deleted file mode 100644
index 4bbe132f7..000000000
--- a/frontend/src/uxbox/util/spec.cljs
+++ /dev/null
@@ -1,103 +0,0 @@
-;; This Source Code Form is subject to the terms of the Mozilla Public
-;; License, v. 2.0. If a copy of the MPL was not distributed with this
-;; file, You can obtain one at http://mozilla.org/MPL/2.0/.
-;;
-;; Copyright (c) 2015-2016 Andrey Antukh <niwi@niwi.nz>
-
-(ns uxbox.util.spec
-  (:require [cljs.spec.alpha :as s]
-            [cuerdas.core :as str]))
-
-
-;; --- Constants
-
-(def email-rx
-  #"^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$")
-
-(def uuid-rx
-  #"^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$")
-
-(def number-rx
-  #"^[+-]?([0-9]*\.?[0-9]+|[0-9]+\.?[0-9]*)([eE][+-]?[0-9]+)?$")
-
-(def ^:private color-re
-  #"^#[0-9A-Fa-f]{6}$")
-
-;; --- Predicates
-
-(defn email?
-  [v]
-  (and (string? v)
-       (re-matches email-rx v)))
-
-(defn color?
-  [v]
-  (and (string? v)
-       (re-matches #"^#[0-9A-Fa-f]{6}$" v)))
-
-(defn file?
-  [v]
-  (instance? js/File v))
-
-(defn url-str?
-  [v]
-  (string? v))
-
-;; --- Default Specs
-
-(s/def ::bool boolean?)
-(s/def ::uuid uuid?)
-(s/def ::email email?)
-(s/def ::color color?)
-(s/def ::string string?)
-(s/def ::positive pos?)
-(s/def ::inst inst?)
-(s/def ::keyword keyword?)
-(s/def ::fn fn?)
-(s/def ::set set?)
-(s/def ::coll coll?)
-
-(s/def ::not-empty-string
-  (s/and string? #(not (str/empty? %))))
-
-
-(defn- conform-number
-  [v]
-  (cond
-    (number? v) v
-    (and (string? v) (re-matches number-rx v))  (js/parseFloat v)
-    :else ::s/invalid))
-
-(s/def ::number
-  (s/conformer conform-number str))
-
-;; NOTE: backward compatibility (revisit the code and remove)
-(s/def ::number-str ::number)
-
-(s/def ::color color?)
-
-;; --- Public Api
-
-(defn valid?
-  [spec data]
-  (let [valid (s/valid? spec data)]
-    (when-not valid
-      (js/console.error (str "Spec validation error:\n" (s/explain-str spec data))))
-    valid))
-
-(defn extract
-  "Given a map spec, performs a `select-keys`
-  like exctraction from the object.
-
-  NOTE: this function does not executes
-  the conform or validation of the data,
-  is responsability of the user to do it."
-  [data spec]
-  (let [desc (s/describe spec)
-        {:keys [req-un opt-un]} (apply hash-map (rest desc))
-        keys (concat
-              (map (comp keyword name) req-un)
-              (map (comp keyword name) opt-un))]
-    (select-keys data keys)))
-
-