Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

Status
colourGreen
titleAccurate

Code Block
languagejs
linenumberstrue
{
  "config": { // All clients listen here permanently
    "articleBaseUrl": "http://cloud-storage.com/articles/",
  },   "userslegalsUrl": {"http://impossible.am/legalstuff/",
    "user_id_01for7MW": {
  //  Clients listen here permanently"facebookPage": "",
      "usernamefacebookGroup": "user",
      "emailinstagramUser": "user@somewhere.com",
      "fitnessLevelfaqsUrl": ""
  10,  },
    "fitnessBiasforAfterburner": 1,{
      "createdfacebookPage": 987654345"",
// Unix timestamp (seconds)      "facebookGroup": "maxImpactCredit": 3,
      "impactCreditinstagramUser": 0.9"",
      "updatedICfaqsUrl": 987654345,""
// Unix timestamp (seconds) }
  },
  "triggersFiredusers": ["triggerId_01","triggerId_02"],{
      "sessions"user_id_01": { // Clients listen here permanently
      "for7MWusername": 2"user", // [default:null]
      "forAfterburneremail": 0
 "user@somewhere.com", // [default:null]
    }  "fitnessLevel": 10,  }// [default:10]
   },   "visibleWorkoutDefsfitnessBias": {1, // [default:1]
Workout defs that are visible to the user
    "user_id_01": { "created": 987654345, // Unix timestamp (seconds) [default:0]
      "for7MWmaxImpactCredit": {3, // 7MW[default:0]
clients listen here permanently for ChildAdded, ChildChanged and ChildRemoved
 "impactCredit": 0.9, // [default:0]
       "wktdef1updatedIC": {987654345, // Unix timestamp (seconds) [default:0]
      "recommendedtriggersFired": { "triggerId_01": true, // Not recommended, just visible
	"triggerId_02": true }, // [default:null]
      "lockedsessions": true,{
// Not available to user (unlocked via IAP and/or journey trigger)
		  "lockString": "Finish 6 more workouts before Thurs 9th June", // Displayed to user "for7MW": 2, // [default:0]
        "forAfterburner": 0 // [default:0]
      },
      "MWItotalActivities": 0.542, // [default:0]
        "breakdowntotalActivities7MW": {1,      // [default:0]
      "epoctotalActivitiesAF": 0.1, // [default:0]
          "cardiofirstActivity7MW": 0.1987654345, // Unix timestamp (seconds) [default:0]
       "metabolicfirstActivityAF": 0.1987654345, // Unix timestamp (seconds) [default:0]
       "strengthtimedNotifSeqVersion": 0.1, // Version of timed notif sequence user is on (server }
use) [default:0]
      "testMode": }false, // Puts the app in 'test mode' for "wktdef2": {
   this user [default:false]
      "recommendednotifTokens": "You{ need// toAPN worktokens onfor your abs", // Recommended and reason for this to be shown to user
		  "locked": falsethe user's devices [default:null]
        "for7MW": { "apn_token": true }, // Available to user
		  "lockString": "",Where 'api_token' is the actual token string
        "forAfterburner": { "MWIapn_token": 0.54,true }
      }
  "breakdown": { }
  },
  "visibles": {
    "epocworkoutDefs": 0.1,
        { // Workout defs that are visible to the user
      "cardiouser_id_01": 0.1,{ 
           "metabolicfor7MW": 0.1,
         { // 7MW clients listen here permanently for ChildAdded, ChildChanged and ChildRemoved
   "strength": 0.1      "wktdef1": {
   }         }
      },
"recommended": "", // Not recommended, just visible // [default:null]
     "forAfterburner": { // Afterburner clients listen here permanently for ChildAdded"locked": true, ChildChanged// andNot ChildRemovedavailable to user (unlocked via IAP and/or journey  "wktdef1": {
  trigger) [default:false]
  	        "recommendedlockString": "",Finish //6 Notmore recommended,workouts justbefore visibleThurs 	      "locked": false9th June", // AvailableDisplayed to user 		  "lockString": "",[default:null]
            "MWI": 0.54, // [default:0.5]
            "breakdown": {
              "epoc": 0.1, // [default:0.25]
              "cardio": 0.1, // [default:0.25]
              "metabolic": 0.1,     // [default:0.25]
              "strength": 0.1 // [default:0.25]
            }
          },
          "wktdef2": {
            "recommended": "You need to work on your abs", // Recommended and reason for this to be shown to user
		
            "locked": false, // Available to user
		            "lockString": "",
            "MWI": 0.54,
            "breakdown": {
              "epoc": 0.1,
              "cardio": 0.1,
              "metabolic": 0.1,
              "strength": 0.1

         }   }
     }     }
 }     }   },
  "workouts": {     "activitiesforAfterburner": { // Afterburner clients listen here  "user_id_01": { // Clients listen here permanently for permanently for ChildAdded, ChildChanged and ChildRemoved
        "workout_id_01  "wktdef1": {
// Clients post new activity to here with auto id, server listens           "workoutDefId"recommended": "wktdef1", // Not recommended, just visible
  	        "finishlocked": 987654345false, // UnixAvailable timestampto (seconds)user
  	        "exertionlockString": 0.5,"",
            "finalHeartRateBPMMWI": 1600.54,
            "finalHeartRateDelaybreakdown": {
0, // Length of delay (in secs) after the workout before the HR was measured"epoc": (0 if they didn't press the 'start again' button)
		  "app": "7MW" // Short code of the app the activity was performed in: 7MW, AF, etc
 .1,
              "cardio": 0.1,
              "metabolic": 0.1,
      }       } "strength": 0.1
  },     "results": {    }
  "user_id_01": { // Clients listen here permanently for ChildAdded},
ChildChanged and ChildRemoved         "workout_id_01wktdef2": { // Server
posts workout results here           "workoutDefIdrecommended": "wktdef1",You need to work on       "finish": 987654345your abs", // UnixRecommended timestampand (seconds)reason for this to be shown to user
   "AWI": 0.1,           "responseDurationlocked": 3456false, // Available to user
        "intensity": 0.9, 		  "applockString": "7MW",
  // Short code of the app the activity was performed in"MWI": 7MW0.54,
AF, etc           "responsesbreakdown": {
              "cardioepoc": {0.1,
              "stresscardio": 430.1,
              "magnitudeProductmetabolic": 0.61,
              "halflifeProductstrength": 0.3,1
            }
 "duration": 5678,        }
      "volume": 3456 }
      }
    },
    "routines": {
      "strengthuser_id_01": { 
        "for7MW": { // 7MW  "stress": 43,
   clients listen here permanently for ChildAdded, ChildChanged and ChildRemoved
          "magnitudeProductroutine_id_01": 0.6,{
              "halflifeProductlocked": 0.3true, // Not available to user (unlocked via IAP and/or journey trigger) [default:false]
  "duration": 5678,         "lockString": "Finish 6 more workouts before Thurs "volume9th June": 3456// Displayed to user [default:null]
          },

           "epocroutine_id_02": {

             "stresslocked": 43true,
             "lockString": "magnitudeProduct": 0.6,
         // No lock string, so only unlocked via IAP [default:null]
     "halflifeProduct": 0.3,    },
          "durationroutine_id_03": 5678,{
              "volumelocked": 3456false, // Available
             },"lockString": ""
          }
 "metabolic": {      },
        "stressforAfterburner": 43 { // 7MW clients listen here permanently for ChildAdded, ChildChanged and ChildRemoved
           "magnitudeProductroutine_id_03": 0.6,{
              "halflifeProductlocked": 0.3false, // Available
            "durationlockString": 5678,""
          }
   "volume": 3456    }
        }
    }
     },
  "workouts": {
      "muscleGroupsactivities": {
      "user_id_01": { // Clients listen here permanently "upper": 0.3for ChildAdded, ChildChanged and ChildRemoved
         "lowerworkout_id_01": 0.3,
            "core": 0.4 { // Clients post new activity to here with auto id, server listens
          "workoutDefId": "wktdef1",  }// [no default]
         } "finish": 987654345, // Unix timestamp  }(seconds) [default:0]
    }   },   "afterburniterations": {
    "user_id_01": { // Clients listen here permanently1.5, // Number of times it was performed [default:1]
          "startexertion": 3456789870.5, // Unix timestamp (seconds)[default:0.5]
          "responsefinalHeartRateBPM": {160, // [default:140]
          "resolutionfinalHeartRateDelay": 6000, // SecsLength of delay (in secs) after the workout before "epoc": [0.6,0.5,0.3,0.2,0.1,0.0],
        "cardio": [0.6,0.5,0.3,0.2,0.1,0.0],
        "strength": [0.6,0.5,0.3,0.2,0.1,0.0],
        "metabolic": [0.6,0.5,0.3,0.2,0.1,0.0]the HR was measured (0 if they didn't press the 'start again' button) [default:0]
		  "app": "7MW" // Short code of the app the activity was performed in: 7MW, AF, etc [default:null]
        },
      }
    },
    "impactCreditresults": {
 
      "resolutionuser_id_01": 600,{ // SecsClients listen here permanently for ChildAdded, ChildChanged and  "futureCredit": 0.9,ChildRemoved
         "pendingworkout_id_01": [0.0,0.1,0.2,0.3,0.4,0.5]
   { // Server posts workout results here
   },       "messagesworkoutDefId": ["wktdef1", // Messages displayed below the radar chart[no default]
          {"t":0,"body"finish":"Restoring body temperature", "detail": ""},
  987654345, // Unix timestamp (seconds) // [no default]
      {"t":120,"body":"Replenishing glycogen stores", "detail": "detail/glycogen"}
    "AWI": 0.1, // [default:0.5]
     ],       "notificationsresponseDuration": 3456, // [default: 0]
          {"tintensity":6000,"body":"Great workout! You're still burning calories and building strength."},
        {"t":14400,"body":"Fitness test unlocked! You're ready to take another fitness test."}
       0.9, // [default:0.5]
		  "app": "7MW", // Short code of the app the activity was performed in: 7MW, AF, etc [no default]
    }   },   "timelineArticlesresponses": { // [no default]
 "user_id_01           "cardio": {
// Clients listen here permanently for ChildAdded, ChildChanged and ChildRemoved       "article_id_01stress": { 43,
              "datemagnitudeProduct": 45678909870.6,
//   Unix timestamp (seconds)         "titlehalflifeProduct": "Post title", 0.3,
              "readduration": false5678,
              "locationvolume": "post/location.html",
		"icon": "default",3456
           "appMask": "7MW,AF" },
      }     } "strength": {
},   "journeyTriggers: {     "forAfterburner": {   	  "trigger01stress": 43,
   { 	    "category": "achievement", 	    "triggerTypemagnitudeProduct": "activeDaysInWeeks"0.6,
	    "condition1": 4, // 4 active days 	    "condition2halflifeProduct": 80.3,
// every week for 8 weeks 	    "actions": [ 		  {"actionTypeduration":"postArticle","articleId":"article_id_01","data":"e.g. url parameters"},
		  {"actionType":"unlockWorkout","workoutDefId":"workoutDef_id_01","articleId":"article_id_02","data":""}
	    ]
	  },
	  "trigger02": {
	    "category": "education",
	    "triggerType": "totalActivities",
	    "condition1": 10, // 10 activities
	    "condition2": 0, // Not used
	    "actions": [
		  {"actionType":"postArticle","articleId":"article_id_01","data":"e.g. url parameters"}
	    ]
	  } 5678,
              "volume": 3456
            },
            "epoc": {
              "stress": 43,
              "magnitudeProduct": 0.6,
              "halflifeProduct": 0.3,
              "duration": 5678,
              "volume": 3456
            },
      "for7MW": {   	  "trigger01metabolic": {
	              "categorystress": "achievement"43,
	              "triggerTypemagnitudeProduct": "activeDaysInWeeks",
	0.6,
              "condition1halflifeProduct": 4, // 4 active days
	0.3,
              "condition2duration": 85678,
  //   every week for 8 weeks 	    "actionsvolume": [3456
		  {"actionType":"postArticle","articleId":"article_id_01","data":"e.g. url parameters"}, 		  {"actionType":"unlockWorkout","workoutDefId":"workoutDef_id_01","articleId":"article_id_02","data":""} 	    ]}
	  }, 	  "trigger02": { 	   },
          "categorymuscleGroups": "education",
	 {
      "triggerType": "totalActivities", 	    "condition1upper": 100.3, // 10 activities
	 [default: 0.3]
            "condition2lower": 0.3, // Not used
	 [default: 0.3]
        "actions": [ 		  {"actionType":"postArticle","articleId":"article_id_01","data":"e.g. url parameters"}
	core": 0.4 // [default: 0.3]
          }
        }
   ] 	  }
    }
  },
  "definitionsafterburn": {
	"version": 1,     "exerciseDefs"user_id_01": { // Clients listen here permanently for ChildAdded, ChildChanged and ChildRemoved
      "exdef1start": {345678987, // Unix timestamp (seconds) // [no default]
 "behaviour": 1,    "response": {    "title": "Cruches",// [default:null]
        "videoresolution": "01-Crunches.mp4"600, // Secs
        "imageepoc": "abs"[0.6,0.5,0.3,0.2,0.1,0.0],
        "desccardio": "A crunch begins with lying face up on the floor with knees bent. The movement begins by curling the shoulders towards the pelvis. The hands can be behind or beside the neck or crossed over the chest. Injury can be caused by pushing against the head or neck with hands.",[0.6,0.5,0.3,0.2,0.1,0.0],
        "strength": [0.6,0.5,0.3,0.2,0.1,0.0],
        "metabolic": [0.6,0.5,0.3,0.2,0.1,0.0]
      },
      "impactCredit": { // [default:null]
        "resolution": 600, // Secs
        "subtitlefutureCredit": "Target your abs for a balanced set of stomach muscles.",
 0.9,
        "pending": [0.0,0.1,0.2,0.3,0.4,0.5]
      },
      "calPerSecmessages": 5,[ // Messages displayed below the radar chart  "skill": 0.2,[default:null]
        {"t":0,"body":"Restoring body temperature", "strengthdetail": 0.7""},
        "cardio{"t":120,"body": 0.1"Replenishing glycogen stores", "detail": "detail/glycogen"}
      "epoc": 0.4,
 ],
      "metabolicnotifications": 0.4,[ // [default:null]
        {"uppert": 0.5,
        "core": 0.56000,"body":"Great workout! You're still burning calories and building strength."},
        "lower{"t":14400,"body": 0.5"Fitness test unlocked! You're ready to take another fitness test."}
      ]
    },
  },
   "exdef2timelineArticles": {
    "user_id_01": { // Clients listen here permanently "behaviour": 1for ChildAdded, ChildChanged and ChildRemoved
      "titlearticle_id_01": "Squats",{
        "videodate": "02-Squats.mp4"4567890987, // Unix timestamp (seconds) // [no default]
 "image": "abs",         "desctitle": "SquatsPost are an excellent exercise for training the lower body and core muscles, if done regularly they help to define thighs and buttocks.",
        "subtitle": "Train your lower body and core.",title", // [no default]
        "read": false, // [default:true]
        "location": "post/location.html", // [no default]
		"icon": "default", // [default:"default"]
        "calPerSecappMask": 4,"7MW,AF", // [default: all apps]
        "skillpromptRating": 0.2,
true // [default:false]
      }
"strength": 0.6,   }
  },
  "cardiodefinitions": 0.3,{
    "routines": { //  "epoc": 0.4,
  Clients listen here permanently for ChildAdded, ChildChanged and ChildRemoved
      "metabolicroutine_id_01": 0.6,{
        "uppertitle": 0.5,
 "The Wonder Routine", // [no default]
        "coreimage": 0.5,"wonder-routine", // [default:"default-routine"]
        "lowerdesc": 0.5"Big long description", // [default:null]
  }     },     "workoutDefsappStoreId7MW": {"routine01", // ClientsStoreKit listenproduct here permanently for ChildAdded, ChildChanged and ChildRemovedid [default:null]
         "wktdef1in7MW": {true, // For server      "type": 1,use [default:false]
         "titleinAfterburner": "Aerobic"false, // For server      "image": "abs",use [default:false]
         "desclockedIn7MW": "Aerobic Basic Movement",
 false, // For server use [default:false]
      "breakDuration": 5, 		"lockedInAfterburner"appStoreId: "workout01"false, // StoreKitFor server product iduse [default:false]
        "in7MWvideo": true"", // For[default:null]
server use         "inAfterburnerminFitnessLevel": false4, // For[default:1]
server use       "workoutDefs":  "exercises":{ // [no default]
          "wktdef1": {
            "idtype": "exdef1",1, // [default:1]
            "durationtitle": 20
  "Aerobic", // [no default]
       },     "image": "abs",     {// [default:"default"]
            "iddesc": "exdef2Aerobic Basic Movement", // [default:null]
            "durationbreakDuration": 155, // // [default:10]
       },     "appStoreId7MW": "workout01", // StoreKit product id {[default:null]
            "idlocked": false, "exdef3",// For server use [default:false]
			"MWI": 0.54, // [default:0.5]
            "durationexercises": 10[ // [no default]
       },       {
   {             "id": "exdef4exdef1", // [no default]
                "duration": 5 20 // [no default]
              },
              {
                "id": "exdef5exdef2",
                "duration": 1015
          }    },
    ],         "adaptiveStress": {
          "strength": 0.2,     "id": "exdef3",
    "cardio": 0.9,           "metabolicduration": 0.6,10
          "epoc": 0.6    },
         },     {
   "muscleStress":  {           "upperid": 10"exdef4",
          "lower": 10,     "duration": 5
    "core": 10         },
      },       "wktdef2": {
        "type": 1,         "titleid": "Thai Boxingexdef5",
        "image": "abs",         "descduration": "Boxing10
  With Kicking",         "breakDuration": 4,
		"appStoreId: "", // StoreKit product id }
             "in7MW": false],
// For server use         "inAfterburneradaptiveStress": true, // For server use{
              "exercisesstrength": [
 0.2, // [default:1]
        {      "cardio": 0.9,      "id": "exdef5",// [default:1]
              "durationmetabolic": 15
  0.6, // [default:1]
       },       "epoc": 0.6 // [default:1]
{             "id": "exdef3"},
            "durationmuscleStress": 10{
          },    "upper": 10, // [default:1]
   {             "idlower": "exdef1",10, // [default:1]
              "duration": 5core": 10 // [default:1]
            }
        ],  }
      "stress": {  }
      }
   "strength": 0.2 },
    "exerciseDefs": { // Clients listen here permanently "cardio": 0.9for ChildAdded, ChildChanged and ChildRemoved
       "metabolicexdef1": 0.6,
{
         "epocbehaviour": 0.6
 1, // [default:1]
      },         "muscleStress": {
 "title": "Cruches", // [no default]
        "uppervideo": 10"01-Crunches.mp4", // [no default]
        "lowerimage": 10"abs", // [default:"default"]
        "coredesc": 10
        }
      }
    }
  }
} "A crunch begins with lying face up on the floor with knees bent. The movement begins by curling the shoulders towards the pelvis. The hands can be behind or beside the neck or crossed over the chest. Injury can be caused by pushing against the head or neck with hands.", // [default:null]
        "subtitle": "Target your abs for a balanced set of stomach muscles.", // [default:null]
        "calPerSec": 5, // [default:0]
        "skill": 0.2, // [default:0.5]
        "strength": 0.7, // [default:0.5]
        "cardio": 0.1, // [default:0.5]
        "epoc": 0.4, // [default:0.5]
        "metabolic": 0.4, // [default:0.5]
        "upper": 0.5, // [default:0.5]
        "core": 0.5, // [default:0.5]
        "lower": 0.5, // [default:0.5]
        "needsHalfwaySwap": false // [default:false]
      },
      "exdef2": {
        "behaviour": 1,
        "title": "Squats",
        "video": "02-Squats.mp4",
        "image": "abs",
        "desc": "Squats are an excellent exercise for training the lower body and core muscles, if done regularly they help to define thighs and buttocks.",
        "subtitle": "Train your lower body and core.",
        "calPerSec": 4,
        "skill": 0.2,
        "strength": 0.6,
        "cardio": 0.3,
        "epoc": 0.4,
        "metabolic": 0.6,
        "upper": 0.5,
        "core": 0.5,
        "lower": 0.5,
        "needsHalfwaySwap": true
      }
    },
    "journeyTriggers": {
      "forAfterburner": {
        "trigger01": {
          "category": "achievement",
          "triggerType": "activeDaysInWeeks",
          "condition1": 4, // 4 active days
          "condition2": 8, // every week for 8 weeks
          "actions": [
            {"actionType":"postArticle","articleId":"article_id_01","data":"e.g. url parameters"},
            {"actionType":"unlockWorkout","workoutDefId":"workoutDef_id_01","articleId":"article_id_02","data":""}
          ]
        },
        "trigger02": {
          "category": "education",
          "triggerType": "totalActivities",
          "condition1": 10, // 10 activities
          "condition2": 0, // Not used
          "actions": [
            {"actionType":"postArticle","articleId":"article_id_01","data":"e.g. url parameters"}
          ]
        }
      },
      "for7MW": {
        "trigger01": {
          "category": "achievement",
          "triggerType": "activeDaysInWeeks",
          "condition1": 4, // 4 active days
          "condition2": 8, // every week for 8 weeks
          "actions": [
            {"actionType":"postArticle","articleId":"article_id_01","data":"e.g. url parameters"},
            {"actionType":"unlockWorkout","workoutDefId":"workoutDef_id_01","articleId":"article_id_02","data":""}
          ]
        },
        "trigger02": {
          "category": "education",
          "triggerType": "totalActivities",
          "condition1": 10, // 10 activities
          "condition2": 0, // Not used
          "actions": [
            {"actionType":"postArticle","articleId":"article_id_01","data":"e.g. url parameters"}
          ]
        }
      }
    }
    "timedNotifs": {
      "forAfterburner": {
        "notif01": {
          "deltaHours": 24, // Delta after APN token reg that the notif is delivered [no default]
          "seqVersion": 0, // Sequence version to allow future updates without flooding existing users [default:0]
          "title": "Title of notification", // [default:""]
          "body": "Body of notification" // [no default]
        },
      },
      "for7MW": {
        "notif01": {
          "deltaHours": 24, 
          "seqVersion": 0, 
          "title": "Title of notification",
          "body": "Body of notification"
        },
      }
    }
  },
  "receipts": {
    "user_id_01": {
      "receipt_auto_id_01": {
        "receipt": "receipt_data", // Written by the client after an IAP purchase
        "validation": { // Written by the server after the receipt has been processed
          "validationDate": 3456789, // Timestamp [default:0]
          "isValid": true [default:false]
        }
      }
    }
  },
}

Client-Side Data Validation & Error Handling

We apply the following process to validate data on the client and to handle the errors appropriately:

SituationActions
  • Property is missing or is wrong type
  • Property has a default defined in the model schema.
  • Log error to crashlytics.
  • Handle silently and apply default value.
  • Property is missing or is wrong type
  • Property doesn't have a default defined.
  • Log error to crashlytics.
  • Throw exception (catch the exception according to object-specific rules, see below).
  • Entire object is missing
  • Log error to crashlytics.
  • Throw exception (catch the exception according to object-specific rules, see below).

Data Validation Exception Handling

EntityChecksAction
visibleWorkoutDef
  • Missing properties without defaults.
  • Missing or invalid workout definition.
Hide from user.
exerciseDefinition
  • Missing properties without defaults.
Tell user via alert view.
timelineArticle
  • Missing properties without defaults.
Hide from user.
activity
  • Missing properties without defaults.
Tell user via alert view.
result
  • Missing properties without defaults.
Tell user via alert view.
afterburn
  • Missing properties without defaults.
Tell user via alert view.
userN/A (all properties have defaults)None