Index: Dev/trunk/src/server/bin/upgrade-db-2-to-3.js
===================================================================
--- Dev/trunk/src/server/bin/upgrade-db-2-to-3.js	(revision 506)
+++ Dev/trunk/src/server/bin/upgrade-db-2-to-3.js	(revision 506)
@@ -0,0 +1,59 @@
+var env = require('../env')
+  , upgradeCouch = require('../config/upgrade-couchdb')
+  , cryptoken = require('../util/crypto-token')
+  , Q = require('q')
+  , _ = require('underscore')
+  ;
+
+function strip(obj) {
+    var subcoded = false;
+    var res = [];
+    if ( _.isArray(obj) ) {
+        res = _.map(obj,strip);
+    } else if ( _.isObject(obj) ) {
+        if ( obj.type === "Question" ) {
+            _.each(obj.content, function(value,vindex) {
+                switch(value.type) {
+                case "StringInput":
+                case "TextInput":
+                case "NumberInput":
+                    if ( !value.subcode ) {
+                        value.subcode = '' + vindex;
+                        subcoded = true;
+                    }
+                    break;
+                case "ScaleInput":
+                case "MultipleChoiceInput":
+                    _.each(value.items, function(item,iindex) {
+                        if ( !item.subcode ) {
+                            item.subcode = '' + vindex + iindex;
+                            subcoded = true;
+                        }
+                    });
+                    break;
+                }
+            });
+        }
+        res = _.map(obj,function(val,key) {
+            if ( val === null || val === "" ) {
+                delete obj[key];
+                return true;
+            } else {
+                return strip(val);
+            }
+        });
+    }
+    return subcoded || _.contains(res,true);
+}
+
+upgradeCouch(env.couchServerURL,env.dbName,function(doc){
+    if ( strip(doc) ) {
+        return doc;
+    } else {
+        return Q.reject();
+    }
+}).then(function(res){
+    console.log("done",res);
+}, function(err){
+    console.error("fail",err);
+});
Index: Dev/trunk/src/server/config/couchdb-design-docs.js
===================================================================
--- Dev/trunk/src/server/config/couchdb-design-docs.js	(revision 501)
+++ Dev/trunk/src/server/config/couchdb-design-docs.js	(revision 506)
@@ -11,5 +11,5 @@
 
     "qed/schemaInfo": {
-        version: "2"
+        version: "3"
     },
 
Index: Dev/trunk/src/server/config/couchdb-schema.json
===================================================================
--- Dev/trunk/src/server/config/couchdb-schema.json	(revision 501)
+++ Dev/trunk/src/server/config/couchdb-schema.json	(revision 506)
@@ -2,5 +2,5 @@
   "$schema": "http://json-schema.org/draft-04/schema#",
   "title": "QED Object Schema",
-  "version": "2",
+  "version": "3",
   "type": "object",
   "oneOf": [
@@ -9,10 +9,11 @@
   ],
   "definitions": {
+    "nonEmptyString": { "type": "string", "minLength": 1 },
     "schemaInfo": {
       "type": "object",
       "properties": {
           "_id": { "type": "string", "pattern": "^schemaInfo$" },
-          "_rev": { "type": "string" },
-          "version": { "type": "string" }
+          "_rev": { "$ref": "#/definitions/nonEmptyString" },
+          "version": { "$ref": "#/definitions/nonEmptyString" }
       },
       "required": ["_id","version"],
@@ -33,13 +34,13 @@
         "properties": {
           "type": { "type": "string", "pattern": "^Question$" },
-          "_id": { "type": "string" },
-          "_rev": { "type": "string" },
-          "categories": { "type": "array", "items": { "type": "string" } },
-          "code": { "type": "string", "minLength": 1 },
+          "_id": { "$ref": "#/definitions/nonEmptyString" },
+          "_rev": { "$ref": "#/definitions/nonEmptyString" },
+          "categories": { "type": "array", "items": { "$ref": "#/definitions/nonEmptyString" } },
+          "code": { "$ref": "#/definitions/nonEmptyString" },
           "content": { "type": "array", "items": { "$ref": "#/definitions/content/any" } },
-          "description": { "type": "string" },
+          "description": { "$ref": "#/definitions/nonEmptyString" },
           "publicationDate": { "type": "string", "format": "datetime" },
-          "title": { "type": "string" },
-          "topic": { "type": "string" }
+          "title": { "$ref": "#/definitions/nonEmptyString" },
+          "topic": { "$ref": "#/definitions/nonEmptyString" }
         },
         "required": ["type","categories","code","content","title"],
@@ -50,10 +51,10 @@
         "properties": {
           "type": { "type": "string", "pattern": "^Survey$" },
-          "_id": { "type": "string" },
-          "_rev": { "type": "string" },
-          "description": { "type": "string" },
+          "_id": { "$ref": "#/definitions/nonEmptyString" },
+          "_rev": { "$ref": "#/definitions/nonEmptyString" },
+          "description": { "$ref": "#/definitions/nonEmptyString" },
           "publicationDate": { "type": "string", "format": "datetime" },
           "questions": { "type": "array", "items": { "$ref": "#/definitions/docs/Question" } },
-          "title": { "type": "string" }
+          "title": { "$ref": "#/definitions/nonEmptyString" }
         },
         "required": ["type","questions","title"],
@@ -64,17 +65,17 @@
         "properties": {
           "type": { "type": "string", "pattern": "^SurveyRun$" },
-          "_id": { "type": "string" },
-          "_rev": { "type": "string" },
-          "description": { "type": "string" },
+          "_id": { "$ref": "#/definitions/nonEmptyString" },
+          "_rev": { "$ref": "#/definitions/nonEmptyString" },
+          "description": { "$ref": "#/definitions/nonEmptyString" },
           "endDate": { "type": "string", "format": "datetime" },
-          "liveName": { "type": "string" },
+          "liveName": { "$ref": "#/definitions/nonEmptyString" },
           "mode": { "type": "string", "enum": [ "open", "closed" ] },
           "respondentCanDeleteOwnResponse": { "type": "boolean" },
-          "secret": { "type": "string", "minLength": 1 },
+          "secret": { "$ref": "#/definitions/nonEmptyString" },
           "startDate": { "type": "string", "format": "datetime" },
           "survey": { "$ref": "#/definitions/docs/Survey" },
-          "title": { "type": "string" }
-        },
-        "required": ["type","description","mode","secret","survey","title"],
+          "title": { "$ref": "#/definitions/nonEmptyString" }
+        },
+        "required": ["type","mode","secret","survey","title"],
         "additionalProperties": false
       },
@@ -83,11 +84,11 @@
         "properties": {
           "type": { "type": "string", "pattern": "^Response$" },
-          "_id": { "type": "string" },
-          "_rev": { "type": "string" },
+          "_id": { "$ref": "#/definitions/nonEmptyString" },
+          "_rev": { "$ref": "#/definitions/nonEmptyString" },
           "answers": { "type": "object" },
           "email": { "type": "string", "format": "email" },
           "publicationDate": { "type": "string", "format": "datetime" },
-          "secret": { "type": "string", "minLength": 1 },
-          "surveyRunId": { "type": "string" }
+          "secret": { "$ref": "#/definitions/nonEmptyString" },
+          "surveyRunId": { "$ref": "#/definitions/nonEmptyString" }
         },
         "required": ["type","answers","secret","surveyRunId"],
@@ -95,5 +96,5 @@
       }
     },
-    "content":{
+    "content": {
       "any": {
         "type": "object",
@@ -113,5 +114,5 @@
         "properties": {
           "type": { "type": "string", "pattern": "^Header$" },
-          "text": { "type": "string" }
+          "text": { "$ref": "#/definitions/nonEmptyString" }
         },
         "required": ["type","text"],
@@ -122,5 +123,5 @@
         "properties": {
           "type": { "type": "string", "pattern": "^Text$" },
-          "text": { "type": "string" }
+          "text": { "$ref": "#/definitions/nonEmptyString" }
         },
         "required": ["type","text"],
@@ -138,7 +139,8 @@
         "properties": {
           "type": { "type": "string", "pattern": "^StringInput$" },
-          "text": { "type": "string" }
-        },
-        "required":["type","text"],
+          "subcode": { "$ref": "#/definitions/nonEmptyString" },
+          "text": { "$ref": "#/definitions/nonEmptyString" }
+        },
+        "required":["type","subcode"],
         "additionalProperties": false
       },
@@ -148,7 +150,8 @@
           "type": { "type": "string", "pattern": "^TextInput$" },
           "maxLength": { "type": "integer" },
-          "text": { "type": "string" }
-        },
-        "required":["type","text"],
+          "subcode": { "$ref": "#/definitions/nonEmptyString" },
+          "text": { "$ref": "#/definitions/nonEmptyString" }
+        },
+        "required":["type","subcode"],
         "additionalProperties": false
       },
@@ -160,7 +163,8 @@
           "max": { "type": "integer" },
           "places": { "type": "integer" },
-          "text": { "type": "string" }
-        },
-        "required":["type","text"],
+          "subcode": { "$ref": "#/definitions/nonEmptyString" },
+          "text": { "$ref": "#/definitions/nonEmptyString" }
+        },
+        "required":["type","subcode"],
         "additionalProperties": false
       },
@@ -169,17 +173,18 @@
         "properties": {
           "type": { "type": "string", "pattern": "^ScaleInput$" },
-          "minLabel": { "type": "string" },
+          "minLabel": { "$ref": "#/definitions/nonEmptyString" },
           "min": { "type": "integer" },
           "max": { "type": "integer" },
-          "maxLabel": { "type": "string" },
-          "naLabel": { "type": "string" },
+          "maxLabel": { "$ref": "#/definitions/nonEmptyString" },
+          "naLabel": { "$ref": "#/definitions/nonEmptyString" },
           "items": { "type": "array", "items": {
             "type": "object",
             "properties": {
-              "text": { "type": "string" },
-              "minLabel": { "type": "string" },
-              "maxLabel": { "type": "string" }
+              "minLabel": { "$ref": "#/definitions/nonEmptyString" },
+              "maxLabel": { "$ref": "#/definitions/nonEmptyString" },
+              "subcode": { "$ref": "#/definitions/nonEmptyString" },
+              "text": { "$ref": "#/definitions/nonEmptyString" }
             },
-            "required":["text"],
+            "required":["subcode","text"],
             "additionalProperties": false
           } }
@@ -196,9 +201,19 @@
               "type": "object",
               "properties": {
-                  "text": { "type": "string" }
+                  "subcode": { "$ref": "#/definitions/nonEmptyString" },
+                  "text": { "$ref": "#/definitions/nonEmptyString" }
               },
-              "required": ["text"],
+              "required": ["subcode","text"],
               "additionalProperties": false
-          } }
+          } },
+          "otherItem": {
+              "type": "object",
+              "properties": {
+                  "subcode": { "$ref": "#/definitions/nonEmptyString" },
+                  "text": { "$ref": "#/definitions/nonEmptyString" }
+              },
+              "required": ["subcode","text"],
+              "additionalProperties": false
+          }
         },
         "required":["type","items"],
