diff --git a/env/dev/cljs/geocsv/app.cljs b/env/dev/cljs/geocsv/app.cljs
index 4283167..9e65331 100644
--- a/env/dev/cljs/geocsv/app.cljs
+++ b/env/dev/cljs/geocsv/app.cljs
@@ -1,6 +1,6 @@
 (ns^:figwheel-no-load geocsv.app
   (:require
-    [geocsv.core :as core]
+    [geocsv.client.core :as core]
     [cljs.spec.alpha :as s]
     [expound.alpha :as expound]
     [devtools.core :as devtools]))
diff --git a/project.clj b/project.clj
index b4d1cc9..824d41a 100644
--- a/project.clj
+++ b/project.clj
@@ -107,7 +107,7 @@
                   :cljsbuild{:builds
                    {:app
                     {:source-paths ["src/cljs" "src/cljc" "env/dev/cljs"]
-                     :figwheel {:on-jsload "geocsv.core/mount-components"}
+                     :figwheel {:on-jsload "geocsv.client.core/mount-components"}
                      :compiler
                      {:output-dir "target/cljsbuild/public/js/out"
                       :closure-defines {"re_frame.trace.trace_enabled_QMARK_" true}
diff --git a/src/cljs/geocsv/ajax.cljs b/src/cljs/geocsv/client/ajax.cljs
similarity index 97%
rename from src/cljs/geocsv/ajax.cljs
rename to src/cljs/geocsv/client/ajax.cljs
index 4605fd6..2d55989 100644
--- a/src/cljs/geocsv/ajax.cljs
+++ b/src/cljs/geocsv/client/ajax.cljs
@@ -1,4 +1,4 @@
-(ns geocsv.ajax
+(ns geocsv.client.ajax
   (:require
     [ajax.core :as ajax]
     [luminus-transit.time :as time]
diff --git a/src/cljs/geocsv/core.cljs b/src/cljs/geocsv/client/core.cljs
similarity index 95%
rename from src/cljs/geocsv/core.cljs
rename to src/cljs/geocsv/client/core.cljs
index 92bf1c7..b67025d 100644
--- a/src/cljs/geocsv/core.cljs
+++ b/src/cljs/geocsv/client/core.cljs
@@ -1,15 +1,15 @@
-(ns geocsv.core
+(ns geocsv.client.core
   (:require
     [day8.re-frame.http-fx]
     [reagent.core :as r]
     [re-frame.core :as rf]
-    [geocsv.gis :as gis]
-    [geocsv.views.map :as mv]
+    [geocsv.client.gis :as gis]
+    [geocsv.client.views.map :as mv]
     [goog.events :as events]
     [goog.history.EventType :as HistoryEventType]
     [markdown.core :refer [md->html]]
-    [geocsv.ajax :as ajax]
-    [geocsv.events]
+    [geocsv.client.ajax :as ajax]
+    [geocsv.client.events]
     [reitit.core :as reitit]
     [reitit.frontend.easy :as rfe]
     [clojure.string :as s])
diff --git a/src/cljs/geocsv/db.cljs b/src/cljs/geocsv/client/db.cljs
similarity index 96%
rename from src/cljs/geocsv/db.cljs
rename to src/cljs/geocsv/client/db.cljs
index 0f2cb73..cba96d4 100644
--- a/src/cljs/geocsv/db.cljs
+++ b/src/cljs/geocsv/client/db.cljs
@@ -1,6 +1,6 @@
 (ns ^{:doc "geocsv app initial database."
       :author "Simon Brooke"}
-  geocsv.db)
+  geocsv.client.db)
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;;;;
@@ -37,5 +37,7 @@
                            "Operator"
                            "Other-key-customers"
                            "Power-supplier"}  ;; need to be fetched from server side
+   :latitude 56
+   :longitude -4
    :map {:map-centre [56 -4]
          :map-zoom  6}})
diff --git a/src/cljs/geocsv/events.cljs b/src/cljs/geocsv/client/events.cljs
similarity index 92%
rename from src/cljs/geocsv/events.cljs
rename to src/cljs/geocsv/client/events.cljs
index 9b0e1aa..342db20 100644
--- a/src/cljs/geocsv/events.cljs
+++ b/src/cljs/geocsv/client/events.cljs
@@ -1,9 +1,9 @@
-(ns geocsv.events
+(ns geocsv.client.events
   (:require [ajax.core :as ajax]
             [ajax.json :refer [json-request-format json-response-format]]
             [cemerick.url :refer [url url-encode]]
-            [geocsv.db :refer [default-db]]
-            [geocsv.gis :refer [refresh-map-pins]]
+            [geocsv.client.db :refer [default-db]]
+            [geocsv.client.gis :refer [compute-centre refresh-map-pins]]
             [re-frame.core :as rf]
             [reitit.frontend.easy :as rfe]
             [reitit.frontend.controllers :as rfc]))
@@ -40,7 +40,6 @@
     :query nil
     :anchor nil))
 
-
 ;;dispatchers: keep in alphabetical order, please.
 (rf/reg-event-fx
   :bad-data
@@ -138,12 +137,15 @@
   ;; TODO: why is this an `-fx`? Does it need to be?
   (fn
     [{db :db} [_ response]]
-    (let [data (js->clj response)]
-    (js/console.log (str "processing fetched JSON data"))
-    {:db (if
-           (:view db)
-           (refresh-map-pins (assoc db :data data))
-           db)})))
+    (let [db' (assoc db :data (js->clj response))]
+      (js/console.log (str "processing fetched JSON data"))
+      {:db (if-let [data (:data db')]
+             (let [centre (compute-centre data)]
+               (if
+                 (:view db')
+                 (refresh-map-pins (merge db' centre))
+                 db)
+               db))})))
 
 (rf/reg-event-fx
   :process-pin-image-names
diff --git a/src/cljs/geocsv/gis.cljs b/src/cljs/geocsv/client/gis.cljs
similarity index 80%
rename from src/cljs/geocsv/gis.cljs
rename to src/cljs/geocsv/client/gis.cljs
index 59d8323..298fbfa 100644
--- a/src/cljs/geocsv/gis.cljs
+++ b/src/cljs/geocsv/client/gis.cljs
@@ -1,6 +1,6 @@
 (ns ^{:doc "geocsv app map stuff."
       :author "Simon Brooke"}
-  geocsv.gis
+  geocsv.client.gis
   (:require [ajax.core :refer [GET]]
             [ajax.json :refer [json-request-format json-response-format]]
             [cljs.reader :refer [read-string]]
@@ -158,17 +158,52 @@
                    (.removeLayer view %)))
     view))
 
+(defn compute-zoom
+  "See [explanation here](https://leafletjs.com/examples/zoom-levels/). Brief
+  summary: it's hard, but it doesn't need to be precise."
+  [min-lat max-lat min-lng max-lng]
+  (let [n (min (/ 360 (- max-lng min-lng)) (/ 180 (- max-lat min-lat)))]
+    (first
+      (remove
+        nil?
+        (map
+          #(if (> (reduce * (repeat 2 %)) n) %)
+          (range))))))
+
+(defn compute-centre
+  "Compute, and return as a map with keys `:latitude` and `:longitude`, the
+  centre of the locations of these records as indicated by the values of their
+  `:latitude` and `:longitude` keys."
+  [records]
+  (let [lats (filter number? (map :latitude records))
+        min-lat (apply min lats)
+        max-lat (apply max lats)
+        lngs (filter number? (map :longitude records))
+        min-lng (apply min lngs)
+        max-lng (apply max lngs)]
+    (if-not
+      (or (empty? lats) (empty? lngs))
+      {:latitude (+ min-lat (/ (- max-lat min-lat) 2))
+       :longitude (+ min-lng (/ (- max-lng min-lng) 2))
+       :zoom (compute-zoom min-lat max-lat min-lng max-lng)}
+      {})))
 
 (defn refresh-map-pins
   "Refresh the map pins on the current map. Side-effecty; liable to be
     problematic."
   [db]
   (let [view (map-remove-pins @(subscribe [:view]))
-        data (:data db)]
+        data (:data db)
+        centre (compute-centre data)]
     (if
       view
       (let [added (remove nil? (map #(add-map-pin db %1 %2 view) data (range)))]
         (js/console.log (str "Adding " (count added) " pins"))
-        db)
+        (if
+          (:latitude centre)
+          (do
+            (js/console.log (str "computed centre: " centre))
+            (.setView view (clj->js [(:latitude centre) (:longitude centre)]) (:zoom centre))
+            (merge db centre))
+          db))
       (do (js/console.log "View is not yet ready") db))))
-
diff --git a/src/cljs/geocsv/views/map.cljs b/src/cljs/geocsv/client/views/map.cljs
similarity index 93%
rename from src/cljs/geocsv/views/map.cljs
rename to src/cljs/geocsv/client/views/map.cljs
index e4f4329..bb01c2d 100644
--- a/src/cljs/geocsv/views/map.cljs
+++ b/src/cljs/geocsv/client/views/map.cljs
@@ -1,11 +1,11 @@
 (ns ^{:doc "a map onto which to project CSV data."
       :author "Simon Brooke"}
-  geocsv.views.map
+  geocsv.client.views.map
   (:require [cljsjs.leaflet]
             [re-frame.core :refer [reg-sub subscribe dispatch dispatch-sync]]
             [reagent.core :as reagent]
             [recalcitrant.core :refer [error-boundary]]
-            [geocsv.gis :refer [refresh-map-pins get-current-location]]))
+            [geocsv.client.gis :refer [refresh-map-pins get-current-location]]))
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;;;;
@@ -61,9 +61,8 @@
   (let [view (.setView
                (.map js/L
                      "map"
-                     ;; (clj->js {:zoomControl false})
-                     )
-               #js [56 -4] ;;[@(subscribe [:latitude]) @(subscribe [:longitude])]
+                     (clj->js {:zoomControl false}))
+               #js [@(subscribe [:latitude]) @(subscribe [:longitude])]
                @(subscribe [:zoom]))]
     (.addTo (.tileLayer js/L osm-url
                         (clj->js {:attribution osm-attrib