Skip to content

Marvin Data Types

Mark edited this page Mar 1, 2023 · 40 revisions

When you access or modify the data from your database, you can use the following documentation to know what the fields mean.

Tasks

See Recurrence for information about how recurring tasks, saved tasks, and pinned tasks work.

/**
 * @typedef {Object} Task
 * @property {String} _id - The task's unique ID.  For tasks generated from recurring tasks, this is of the form `${date}-${id}` where date is YYYY-MM-DD and id is the recurring task's id.
 * @property {Number} createdAt - Date.now() when the task was created.
 * @property {Number} updatedAt - Date.now() when the task was last updated.
 * @property {Number} workedOnAt - Date.now() when the task was last worked on (e.g. a subtask was completed).
 * @property {String} title - The task's title, like "Go to market".
 * @property {String} parentId - ID of parent project or category, or "unassigned".
 * @property {String} dueDate - When this project should be completed, formatted as "YYYY-MM-DD". Or null if no dueDate.
 * @property {String} startDate - When this task can be started, formatted as "YYYY-MM-DD". Or null if no start date.
 * @property {String} endDate - When this task should be completed (soft deadline), formatted as "YYYY-MM-DD". Or null if no end date.
 * @property {String} day - Which day the task is scheduled, in the format "YYYY-MM-DD", or "unassigned".  Guaranteed to be "YYYY-MM-DD" if the task is done.
 * @property {String} firstScheduled - Which day the task was first assigned to, formatted as "YYYY-MM-DD" or "unassigned" if it was never scheduled yet. Used to calculate how many !!! in procrastination strategy.
 * @property {String} plannedWeek - Which week the task is planned for. Date of the Monday of the ISO week (Mon-Sun) formatted as "YYYY-MM-DD"
 * @property {String} plannedMonth - Which month the task is planned for. "YYYY-MM"
 * @property {String} sprintId - The task's sprint, null if nothing
 * @property {Number} rank - The task's sort order in the day view.
 * @property {Number} masterRank - The task's sort order within the master list.  Having two ranks is necessary since scheduled tasks are shown in the master list, just grayed out.  And completed tasks within a project are shown crossed out.
 * @property {Boolean} done - True if this task has been completed.
 * @property {Number|null} completedAt - Date.now() when this task was completed.
 * @property {Number} duration - How long the user worked on this task (in ms). As of 1.18.0, only set when the task is done.
 * @property {Number[]} times - Array of Date.now() when time tracking started (odd indexes) and stopped (even indexes).  Updated when time tracking stops and when the task is marked done (or when manually edited by user).
 * @property {Number} firstTracked - When this task was first tracked (Date.now()).
 * @property {Number} doneAt - When this task was completed (Date.now()).
 * @property {Boolean} isReward - True if this task is a reward task.
 * @property {Boolean} isStarred - Used for priorities strategy. 3=red, 2=orange, 1=yellow (or true from old version).
 * @property {Boolean} isFrogged - True if this task has been frogged for eatThatFrog. 1=normal, 2=baby, 3=monster.
 * @property {Boolean} isPinned - Whether this task has been pinned to the master list.  In other words, scheduling it will just schedule a copy, and this task will remain in the master list.
 * @property {String} pinId - The pinned task that this task was copied from.
 * @property {Boolean} recurring - True if this task was generated via a recurring task.
 * @property {String} recurringTaskId - The recurring task that generated this task.
 * @property {Boolean} echo - True if this is an "echo" task (from RecurringTask type="echo").
 * @property {String} echoId - ID of task used to create this task (from RecurringTask type="echo").
 * @property {String} link - System-created tasks can have links, i.e. to "/braindump".  This is in the link target.
 * @property {Object.<String,Subtask>} subtasks - ID => Subtask.
 * @property {String} colorBar - One of null, "red", "yellow", "green" or "blue". No longer used.
 * @property {String[]} labelIds - The IDs of labels assigned to the task.  Any labelId that doesn't correspond to an existing label in strategySettings.labels should be ignored.
 * @property {Number} timeEstimate - How long the user thinks the task will take, in ms.
 * @property {String} note - Task note for "notes" strategy.
 * @property {String} email - Email HTML used to create note via "email" strategy.
 * @property {String} dailySection - Section used in dailyStructure, one of "Morning", "Afternoon", or "Evening".
 * @property {String} bonusSection - Section used in bonusStructure, either "Bonus" or "Essential".
 * @property {String} customSection - Section used in customStructure (ID of a custom section stored in strategySettings.customStructure).
 * @property {String} timeBlockSection - Section used in plannerStructure (ID of a time block).
 * @property {Object.<String,Boolean>} dependsOn - ID => true. Task and project IDs of items that have to be completed before this item can be worked on.
 * @property {Boolean} backburner - Tasks created in the backburner are given this property if they don't get the backburner status from their parent. Tasks can also be in the backburner due to a label, dependency, start date, or inheritance without having backburner=true.
 * @property {String} reviewDate - Date when user wants to review a task, formatted as "YYYY-MM-DD".
 * @property {Number} itemSnoozeTime - Date.now() until when task is snoozed.  While snoozed the task is hidden everywhere except the master list.
 * @property {String} permaSnoozeTime - Time (HH:mm) until when task is snoozed (NOT cleared on reschedule).
 * @property {String} calId - ID (from Marvin) of calendar this task has been created from / assigned to.
 * @property {String} calURL - Unique URL of this task in the calendar.
 * @property {String} etag - Calendar etag to determine when an update is needed.
 * @property {String} calData - Calendar data.  This string is modified and sent to server to update when tasks in Marvin change.
 * @property {Number} generatedAt - Date.now() when this task was created as a recurring task instance.
 * @property {Number} echoedAt - Date.now() when this task was created by the completion/deletion of a "repeat after X days" recurring task instance.
 * @property {Number} deletedAt - Date.now() when this task was added to the trash.
 * @property {Number} restoredAt - Date.now() when this task was restored from the trash.
 * @property {Boolean} onboard - Set to true if this task is an onboarding task (i.e. one that Marvin created when the account was created).
 * @property {Boolean} imported - Set to true if this task was imported in the Importer.
 *
 * Gamification
 * @property {Number} marvinPoints - How many kudos you got for this task.
 * @property {String[]} mpNotes - Notes on how Marvin awarded you kudos when you completed the task.
 * @property {Number} rewardPoints - How many reward points this task awards.
 * @property {Number} rewardId - ID of attached reward. Earned on completion.
 *
 * Goals
 * @property {Boolean} g_in_GOALID - If true, then a task is in a goal. It can also be in a goal from inheritance (i.e. if parent project is in goal).
 * @property {String} g_sec_GOALID - The ID of the section/phase of the goal this task lives in. If not given, then the task goes in the first section.
 * @property {Number} g_rank_GOALID - The rank of the task within its goal section.
 *
 * NEW REMINDER FORMAT
 * @property {String} taskTime - "HH:mm" time extracted from title
 * @property {Number} reminderOffset - Reminder offset, either manually set or taken from default at reminder creation.
 * @property {String} reminderTime - The unix timestamp (seconds) of the first reminder (i.e. before any snoozes), computed with taskTime and reminderOffset (or defaultOffset)
 * @property {Number} snooze - Snooze duration, either manually set or taken from default at reminder creation.
 * @property {Number} autoSnooze - Whether to autoSnooze, either manually set or taken from default at reminder creation.
 *
 * OLD REMINDER FORMAT
 * @property {String} remindAt - Time when user should be reminded, "YYYY-MM-DD HH:mm".
 * @property {Object} reminder - How remindAt was chosen, so that if the task is renamed, the reminder can be updated.
 * @property {String} reminder.time - Event time that was used to create the event.
 * @property {Number} reminder.diff - Number of ms before reminder.time when remindAt is scheduled.
 */

Subtasks

Subtasks live directly within the Task document in an Object where the key is the ID of the Subtask, and its value is an Object with the following shape:

/**
 * @typedef {Object} Subtask
 * @property {String} _id - The subtask's unique ID, which is the same as the key in the task's "subtasks" object.
 * @property {String} title - The subtask title, like "Carrots".
 * @property {Boolean} done - Whether the subtask is complete.
 * @property {Number} rank - Rank within parent task.
 * @property {Number} timeEstimate - Subtasks can have their own duration estimates.
 *
 * Reminders as in Tasks (see above).
 */
Example Task JSON with Subtasks
{
  "createdAt": 1612975446890,
  "db": "Tasks",
  "title": "Example task",
  "parentId": "unassigned",
  "day": "2021-02-10",
  "subtasks": {
    "3JTpZf4WnWvrK": {
      "_id": "3JTpZf4WnWvrK",
      "title": "Subtask 1",
      "done": false,
      "rank": 1
    },
    "eM93my8kteDMw": {
      "_id": "eM93my8kteDMw",
      "title": "Subtask 2",
      "done": false,
      "rank": 2
    }
  },
  "_id": "dKG245maqNRkn58Z9SyT",
  "_rev": "7-f2f224e38fd775ab49774cad0455559a"
}

Categories (and projects)

Marvin has infinite nesting of categories and projects. Main categories have parentId="root", and nested categories/projects have parentId equal to the _id of their parent. This storage format makes cycles and orphans a possibility, and Marvin does its best to gracefully handle these cases. If you restart Marvin then you will find orphans in your Inbox. Any orphan/cycle problems you inadvertantly create can be fixed by following this guide.

The Inbox doesn't live inside the couchdb as its own document. Tasks and Projects that live inside the Inbox have parentId="unassigned". The color of the Inbox is stored in a Profile Item, specifically inboxColor.

Both Projects and Categories have the field db="Categories". Projects are marked with type="project". There are several differences between Categories and Projects. Projects can be scheduled, given due dates and priorities, and marked done. And whereas both Categories and Projects can have child Tasks and Projects, only Categories can have child Categories.

See Recurrence for information about how recurring projects and saved projects work.

/**
 * @typedef {Object} Task
 * @property {String} _id
 * @property {String} title - The category/project's title, like "Work".
 * @property {String} type - Either "project" or "category".
 * @property {Number} updatedAt - Date.now() when updated.  This includes adding a task.
 * @property {Number} workedOnAt - Date.now() when last worked on.  That means completing a task within it.
 * @property {String} parentId - ID of parent project or category, or "unassigned" or "root".
 * @property {Number} rank - Sort rank within parent.
 * @property {Number} dayRank - Sort rank within day.
 * @property {String} day - Schedule date or null/undefined. Only projects can be scheduled. This might also be "unassigned", so check for both. See https://github.com/amazingmarvin/MarvinAPI/issues/11
 * @property {String} firstScheduled - Which day the project was first assigned to, formatted as "YYYY-MM-DD" or "unassigned" if it was never scheduled yet. Used to calculate how many !!! in procrastination strategy.
 * @property {String} dueDate - Date when project is due, formatted as "YYYY-MM-DD".
 * @property {String[]} labelIds - The IDs of labels assigned to the Project.  Any labelId that doesn't correspond to an existing label in strategySettings.labels should be ignored.
 * @property {Number} timeEstimate - How long the user thinks the project will take, in ms. When shown in Marvin this is added to the child tasks' time estimates.
 * @property {String} startDate - When this task can be started, formatted as "YYYY-MM-DD".
 * @property {String} endDate - When this task should be completed (soft deadline), formatted as "YYYY-MM-DD".
 * @property {String} plannedWeek - Which week the task is planned for. Date of the Monday of the week (Mon-Sun) "YYYY-MM-DD"
 * @property {String} plannedMonth - Which month the task is planned for. "YYYY-MM"
 * @property {String} sprintId - The project's sprint. Not used yet.
 * @property {Boolean} done - Whether the project has been marked as done.
 * @property {String} doneDate - If done, then this was the date the project/subproject (previously called milestone) was finished.
 * @property {String} priority - Project only: one of "low", "mid", or "high". Used when priorities strategy is enabled. Why not isStarred like tasks? These used to be different strategies.
 * @property {String} color - Color chosen by clicking icon in master list "#222222" (rrggbb).
 * @property {String} icon - Icon chosen by clicking icon in master list.
 * @property {String} note - note for "notes" strategy.
 * @property {Boolean} recurring - True if it's a recurring project.
 * @property {String} recurringTaskId - ID of RecurringTask creator.
 * @property {Boolean} echo - True if created by RecurringTask with type="echo".
 * @property {Boolean} isFrogged - True if this project has been frogged for eatThatFrog. 1=normal, 2=baby, 3=monster.
 * @property {String} reviewDate - Date when user wants to review a project.
 * @property {Number} marvinPoints - How many kudos you got for this project. Always 500.
 * @property {String[]} mpNotes - Notes on how Marvin awarded you kudos when you completed the project. Always ["PROJECT"].
 */

MIPs

- Warning! This will probably change in the future. 
Click for current documentation.

The IDs of MIPs are stored in profile.MIP:

GET /api/doc?id=MIP
=>
[
  "afh310hf12f213",
  "f1n02nksaljfi0",
]

Notes:

  • Each string in this array is a project ID
  • This document might be missing if no MIPs have been added yet.
  • This document may contain completed project IDs, which are no longer considered MIPs within Marvin
  • In the future this document will be ignored and project.mip=true or project.isMip=true or something like that.

RecurringTasks

Recurring Task and Project instances are created based on a separate item in the database with db="RecurringTasks". See Recurrence for more information.

/**
 * Collection for recurring tasks and sequences (recurring tasks with subtasks).
 *
 * To keep track of how far into the future recurring task instances have been
 * generated, the date is stored in the profile:
 * profile.createdUpTo.recurringTaskId => date
 *
 * @typedef {Object} RecurringTask
 * @property {String} _id - Unique ID
 * @property {String} recurringType - One of "task", "sequence" (no longer used), or "project"
 * @property {String} title - Title of generated task.
 * @property {String} parentId - ID of Category/Project where tasks will be placed.
 * @property {String} type - One of "daily", "weekly", "monthly", "n per week", "repeat", "repeat week", "repeat month", "repeat year", "echo", "onOff", or "custom".
 * @property {Number} day - "weekly" only... specifies which day of the week the task is assigned to by default.  0=Sunday.
 * @property {Number} date - "monthly" only... specifies which date of the month the task is assigned to by default.  1=1st.  29/30/31 will go to last day of the month if the month has fewer days.
 * @property {Number[]} weekDays - "n per week" only.  Which days of week the task is generated.  0=Sunday.
 * @property {Number} repeat - How often to repeat, 2=every other day for "repeat" or every other X for "repeat X".
 * @property {String} repeatStart - "repeat" and "repeat X" only, date when to start repeating.
 * @property {Boolean} limitToWeekdays - If true, then only schedule on weekdays, pushing to Friday if necessary.  Only available for "monthly" and "repeat month".
 * @property {Task[]} subtaskList - A list of subtasks to be added to the task.
 * @property {String} section - Default generated task section, like "Afternoon".
 * @property {Number} timeEstimate - Time estimate in ms.
 * @property {String[]} labelIds - IDs of labels attached to recurringTask.
 * @property {Number} dueIn - How far ahead (in days) to make project due (recurringType="project" only).
 * @property {String} autoPlan - If given, then set plannedWeek/plannedMonth (recurringType="project" only).  Possible values are "plannedWeek" and "plannedMonth".
 * @property {Number} echoDays - "echo" only... another task is scheduled this many days after a task is completed.
 * @property {Number} onCount - "onOff" only. Number of days "on".
 * @property {Number} offCount - "onOff" only. Number of days "off".
 * @property {String} customRecurrence - Human-readable text like (every) "month on the 2nd last Friday". This uses the toText format from rrule, but extended for a few extra rules that Marvin supports.
 * @property {String} endDate - YYYY-MM-DD, no longer generated after this date.
 */

Saved Items

Templates for the "Saved Items (Templates)" strategy. These items have db="SavedItems". See Recurrence for more information.

 * Collection for saved tasks, task groups, and projects.
 *
 * @typedef {Object} SavedItem
 * @property {String} _id - Unique ID
 * @property {String} itemType - One of "task", "taskGroup", or "project"
 * @property {String} title - Item title (same as task title if itemType is "task").
 * @property {Number} rank - Order in organizer.
 * @property {Object[]} tasks - Always has length=1 if itemType="task"
 * @property {String} defaultParentId - Which category/project to load into by default.

Labels

/**
 * @typedef {Object} Label
 * @property {String} _id - Unique ID like "qoq4xtw653fGv", used in task.labelIds array
 * @property {String} title - Label name like "quick"
 * @property {String} groupId - ID of label group (see below)
 * @property {Number} createdAt - Date.now() when created, like 1595057624899
 * @property {String} color - Label color, like "#29224a"
 * @property {String} icon - Label icon, like "inbox"
 * @property {String} showAs - One of "text", "icon", or "both".
 * @property {Boolean} isAction - If true, then this is an action label. Removing the label creates a task.
 * @property {Boolean} isHidden - If true, then this label won't show in task/project metadata.  Still useful for smart lists, etc.
 */

Label Groups

/**
 * @typedef {Object} LabelGroup
 * @property {String} _id - Unique ID like "qoq4xtw653fGv", used in label.groupId
 * @property {String} title - Group name like "Example group"
 * @property {Number} rank - Like 1, order within label organizer
 * @property {Number} createdAt - Date.now() when created, like 1595057624899
 * @property {Boolean} isExclusive - If true, then a task/project can only have one label from this group at a time
 * @property {String} color - Label color, like "#29224a"
 * @property {String} icon - Label icon, like "inbox"
 * @property {Boolean} isMenu - No longer used.  Use hover button strategy settings instead.
 */

Time Tracking

The master for time tracking data is the account database at serv.amazingmarvin.com, not the couchdb database. But this data is cached in task.times (in the couchdb database) whenever you stop time tracking or mark the task done.

/**
 * @property {Number[]} task.times - Array of Date.now() when time tracking started (odd indexes) and stopped (even indexes).  Updated when time tracking stops and when the task is marked done (or when manually edited by user).
 */

Basically the current unix timestamp (in milliseconds) is appended to this array whenever you start and stop time tracking. So if an odd number of numbers are in the array, this should be the task you are currently tracking. If you add up the difference between each consecutive pair of numbers, you should get the total time track duration of the task, in milliseconds.

Timers

Timers don't live in Marvin's database, just in its app state. But knowing the structure may help you if you are using Marvin's timer webhooks.

Regular timers

/**
 * A timer starts with elapsed=0 and progress=0 and runs up to elapsed=duration
 * and progress=1.
 *
 * @typedef {Object} Timer
 * @property {Number} elapsed - Number of milliseconds that have elapsed so far.
 * @property {Number} progress - Timer progress between 0 and 1.
 * @property {Number} duration - Total timer duration in milliseconds.
 * @property {String} taskId - The ID of the task this timer is linked to. This can happen when there's a time in the task's title, like "30m" and you click on it.
 * @property {Number} beepCount - How many times this task should beep.
 * @property {Boolean} done - Set to true when the timer has finished.
 */

Tomato timers

/**
 * A tomato timer starts with elapsed=0, progress=0, and isWork=true. Once
 * elapsed runs up to workDuration and progress up to 1, then elapsed and
 * progress are both set to 0 and isWork is set to false.
 *
 * @typedef {Object} TomatoTimer
 * @property {Number} elapsed - How long into the current work or break cycle the timer is, in milliseconds.
 * @property {Number} progress - Timer progress between 0 and 1.
 * @property {Number} workDuration - How long the work session is, in milliseconds.
 * @property {Number} breakDuration - How long the break is, in milliseconds.
 * @property {Number} cycle - For repeating timers. This is 0 the first session, then 1, etc.
 * @property {Number} repeat - The total number of repeat cycles configured.
 * @property {Number} beepCount - How many times this task should beep.
 * @property {Boolean} isWork - Set to true during the work session, then false during the break session.
 * @property {Boolean} done - Set to true when the work session and break are both completed. If repeat, then only set to true when ALL work sessions and breaks are completed.
 */

mpNotes values

The following values are possible in the mpNotes array and describe how Marvin awarded you kudos when completing the task/project.

{
  SLOW_DOWN: { type: "Slow Down!", reason: "You hit the point cap for today. Save some for the rest of us! Try adding time estimates or tracking time if you do lots of small tasks." },
  HIGH_WEIGHT: { type: "Good One", reason: "Great task!", modifierType: 1 },
  DREADED: { type: "Congrats", reason: `You did something you dreaded.`, modifierType: 1 },
  IMPORTANT: { type: "Congrats", reason: `You did something important.`, modifierType: 1 },
  COMBO: { type: "Combo", reason: "Multiple tasks completed today.", modifierType: 1 },
  STREAK: { type: "Streak", reason: `Tasks completed multiple days in a row!`, modifierType: 1 },
  NO_PROC: { type: "Impressive", reason: "You didn't procrastinate :).", modifierType: 1 },
  PROC: { type: "Oops", reason: "You procrastinated :(.", modifierType: -1 },
  WAY_EARLY: { type: "Great", reason: "You completed the task way early!", modifierType: 1 },
  EARLY: { type: "Great", reason: "You completed the task early!", modifierType: 1 },
  ON_TIME: { type: "Great", reason: "You met the deadline.", modifierType: 1 },
  MISSED_DEADLINE: { type: "Oops", reason: "You missed the deadline.", modifierType: -1 },
  SOFT_ON_TIME: { type: "Great", reason: "You met the soft deadline.", modifierType: 1 },
  MISSED_SOFT: { type: "Oops", reason: "You missed the soft deadline.", modifierType: 1 },
  SHORT: { type: "Short", reason: "Nice and quick.", modifierType: 0 },
  LONG: { type: "Long", reason: "That was a long one.", modifierType: 0 },
  DOUBLE: { type: "Wow", reason: "Marvin smiles! 2x kudos!", modifierType: 1 },
  TRIPLE: { type: "Wow!", reason: "Marvin winks! 3x kudos!", modifierType: 1 },
  BONUS: { type: "Bonus", reason: "Marvin gave you 500 bonus kudos! Good tasks are most likely to get a bonus.", modifierType: 1 },
  FROG_BONUS: { type: "Bonus", reason: "Marvin gave you 500 bonus kudos for eating the frog first!", modifierType: 1 },
  PROJECT: { type: "Project", reason: "500 kudos for completing a project.", modifierType: 0 },
}

Goals

/**
 * Habits, Tasks, and Projects are attached to goals using g_in_GOAL_ID=true,
 * g_sec_GOAL_ID="xyz" of the section/phase they're in, and g_rank_GOAL_ID=2 to
 * determine their sort order.
 *
 * @typedef {Object} Goal
 * @property {String} _id - The goal's unique ID.
 * @property {String} title - The goals's title, like "Reach 10MRR".
 * @property {String} note - The goal's note.
 * @property {Boolean} hideInDayView - If true, then don't show it in the DailyTasks GoalItems.
 * @property {String} parentId - A goal can get a category (for grouping).
 * @property {Number} isStarred - Priority.
 * @property {String[]} labelIds - Labels.
 * @property {Number} importance - How important is this Goal, 1-5 stars in Commitment Contract.
 * @property {Number} difficulty - How difficult is this Goal, 1-5 stars in Commitment Contract.
 * @property {String[]} motivations - Why the user wants to do this.
 * @property {Challenge[]} challenges - What challenges does the user anticipate.
 * @property {Boolean} committed - User clicked checkbox saying they are really committed.
 * @property {Number} expectedTasks - Number of tasks done each week.
 * @property {Number} expectedDuration - Number of minutes of work expected each week.
 * @property {Number} expectedHabits - Expectation Habit success (e.g. "B-").
 * @property {Boolean} checkIn - True if check-in enabled.
 * @property {Number[]} checkIns - An array of numbers. Each 4 numbers determines a check-in. First the date, then the confidence 1-5, then the motivation 1-5, then how it's going 1-5.
 * @property {String} lastCheckIn - Last check-in (YYYY-MM-DD).
 * @property {Number} checkInWeeks - Number of weeks between check-ins.
 * @property {String} checkInStart - First check-in (YYYY-MM-DD).
 * @property {Object[]} checkInQuestions - Questions user wants to answer during a check-in. An array of { _id, title }.
 * @property {String} status - The goal's status: "backburner", "pending", "active", "done"
 * @property {Number} startedAt - Date.now() when the goal was made "active". Fallback to createdAt since this was added after 1.58.2!
 * @property {String} color - Color used for this goal
 * @property {String} dueDate - When this goal should be achieved, formatted as "YYYY-MM-DD". This is null for ongoing goals.
 * @property {Boolean} hasEnd - Whether this goal is and "End goal" (true) or Ongoing (false).
 * @property {GoalSection[]} sections - Each goal has its own sections, and each section can have trackers, habits, and tasks/projects. Trackers/habits/tasks/projects are attached to a Goal using g_in_GOAL_ID = true and a section using g_sec_GOAL_ID. Order within section is g_rank_GOAL_ID = 2.
 * @property {Boolean} taskProgress - If true, then task/project completion should count toward goal progress.
 * @property {Boolean} trackerProgress_$ID - If true, then the tracker with _id=$ID is used in progress calculation.
 *
 * @typedef {Object} Challenge
 * @property {String} _id
 * @property {String} challenge
 * @property {String} action - What user will do if challenge comes up.
 *
 * @typedef {Object} GoalSection
 * @property {String} _id - ID of section.
 * @property {String} title - Name of section.
 * @property {String} note - The section's note.
 */

Habits

/**
 * @typedef {Object} Habit
 * @property {String} _id - The habit's unique ID.
 * @property {String} title - The habit's title, like "Drink water".
 * @property {String} note - Rich text note.
 * @property {String} color - Color used for icon, etc.
 * @property {String} parentId - ID of parent project or category, or "unassigned".  null doesn't work because of pouchdb-find.
 * @property {String[]} labelIds - IDs of labels.
 * @property {Number} isStarred - Habits can be starred.
 * @property {Number} isFrogged - Habits can be frogged.
 * @property {Number} timeEstimate - Habits can have estimated durations. How long it will take to do it once.
 * @property {String} startDate - Date ("YYYY-MM-DD", or null) when user will start tracking.
 * @property {String} endDate - Date ("YYYY-MM-DD", or null) when user will stop tracking.
 * @property {String} units - Custom units, like "miles" if the habit is "Run".
 * @property {String} period - One of "day", "week", "month", "quarter", or "year".
 * @property {Number} target - Target number for the period.
 * @property {Boolean} isPositive - If true then we want >= target. Otherwise <= target.
 * @property {String} recordType - Value type. Could be "boolean", "number". If "boolean", then clicking increases by 1. Otherwise you're prompted for a number.
 * @property {Boolean} showInDayView - If true then the habit is shown in the day view.
 * @property {Boolean} showInCalendar - If true then the habit is shown in the calendar.
 * @property {Number[]} askOn - Which days of the week to show in the day view.
 * @property {String} startTime - What time to start showing in the day view.
 * @property {String} endTime - What time to stop showing in the day view.
 * @property {String} time - Time when the habit is shown in the calendar.
 * @property {Boolean} showAfterSuccess - If false, then hide in the day view after hitting the target for this period.
 * @property {Boolean} showAfterRecord - If false, then hide in the day view after recording once in a day.
 * @property {Boolean} done - Once the user feels done with a habit, they can mark it as done, i.e. archived.
 * @property {Number[]} history - Array of [time1, val1, time2, val2, ...]
 * @property {String} dismissed - Date ("YYYY-MM-DD") when habit was last dismissed for the day. It can be found in All Habits or Open Habits (maybe) tomorrow.
 */

Trackers

/**
 * @typedef {Object} Tracker
 * @property {String} title - Name of the tracker.
 * @property {String} trackerType - One of "number" or "rating".
 * @property {Number} startValue - Initial value for "number" type.
 * @property {Number} targetValue - Target value for "number" type.
 * @property {Number} isCumulative - For "number" trackerType. If true, then user will be prompted to add to current value (rather than set).
 * @property {String} units - For "number" type.
 * @property {Number} minRating - A number, like 1, for "rating" type.
 * @property {Number} maxRating - A number, like 5, for "rating" type.
 * @property {Number} minLabel - Label for min rating, for "rating" type.
 * @property {Number} maxLabel - Label for max rating, for "rating" type.
 * @property {String} symbol - For "rating" type. Normally null when numbers are input, but user can also choose "heart" or "star".
 * @property {String} dueDate - Deadline formatted as "YYYY-MM-DD". Only for targets which aren't in a Goal with its own dueDate.
 * @property {String} askType - One of "n per week", "monthly".
 * @property {Number[]} askOn - Which days of the week to ask on, like [1, 7] for Monday and Sunday. For "n per week" only.
 * @property {Number} askDate - Day of the month when to ask. For "monthly" only.
 * @property {Boolean} askWeekdays - If true, then only ask on weekdays (for askDate).
 * @property {Boolean} showAfterRecord - If true, then prompt even after having recorded.
 * @property {Boolean} startTime - If given, time in the day when user should be prompted.
 * @property {Boolean} endTime - If given, time in the day when user should be no longer prompted.
 * @property {Boolean} showAs - Either "graph" or "progress". The value "progress" only works if trackerType==="number".
 * @property {Number[]} history - Array of [time1, val1, time2, val2, ...]
 */

Calendars

// @typedef {Object} Calendar
// @property {String} _id - Calendar ID (randomly generated by Marvin).
// @property {Boolean} twoWay - If true, then local changes will be propagated to calendar.
// @property {String} provider - one of "icloud", "google", "outlook", "caldav", "pubfeed", or "yahoo"
// @property {String} displayName - Calendar name, from provider. Can be changed while adding to Marvin.
// @property {String} url - Calendar api url, returned from getCalendars
// @property {String} username - User's caldav username.
// @property {String} password - the encrypted OTP, also returned from getCalendars
// @property {String} itemType - "task", "event", "timeBlock"
// @property {String} ctag - the last synced ctag. Only used for caldav/icloud/yahoo since gcal's ctag only updates when you change calendar properties.
// @property {String} parentId - parentId automatically applied to tasks created by sync, and used to determine which tasks will be sent to the calendar
// @property {String[]} labelIds - Label(s) automatically applied to tasks created by sync, and used to determine which tasks will be sent to the calendar
// @property {String} calendarId - For google, e.g. "user@gmail.com"
// @property {String} color - Calendar color, like "#9fc6e7"
// @property {String} accessRole - "reader", "writer", or "owner"
// @property {Number} rank - Index in list.  This is important now that we can have two-way sync without label/parent.
// @property {Number} timeZoneFix - Default timeZoneFix for events synced with this calendar. See Events for more info.

Events

See Recurrence for more information about recurring events.

/**
 * @typedef {Object} Event
 * @property {String} _id - The event's unique ID.
 * @property {String} title - The event's title, like "Go to market".
 * @property {Boolean} isAllDay - True for all-day items.
 * @property {String} parentId - Imported events can live in a category.
 * @property {String[]} labelIds - Imported events can have labels.
 * @property {String} start - Event start as ISO string, like "2019-06-25T00:30:00.490Z".
 * @property {Number} length - Event duration, in milliseconds.
 * @property {String} calId - ID of Marvin calendar this event has been created from / assigned to.
 * @property {String} calURL - Unique URL of this event in the calendar.
 * @property {String} etag - Calendar etag to determine when an update is needed.
 * @property {String} calData - Calendar data.  This string is modified and sent to server to update when events in Marvin change. Its format depends on the calendar provider. It's a JSON object for gcal, some other JSON object for outlook, and ICS for everything else.
 * @property {Object} cancelDates - A lookup of YYYY-MM-DD => true, indicating dates for which this event has been deleted.
 * @property {Object} exceptions - A lookup of YYYY-MM-DD => { etag, calData, start, title, length } (YYYY-MM-DD is originalDate!). This is when there are changes to one instance of an event.
 * @property {String} note - A note ("description" in gcal, "DESCRIPTION" in caldav). This is HTML in gcal and outlook, and plain text in other calendars. On mobile it's shown as plain text even if the note was created as HTML, so probably in the future I'll convert to markdown and use a markdown editor everywhere in Marvin.
 * @property {Boolean} hidden - Set to true when hiding a read-only event.
 * @property {Number} timeZoneFix - Number of ms to adjust start time in case of time zone issues.
 */

Time Blocks

Note: time blocks have doc.db="PlannerItems" since this feature was originally called "Planner". Similarly, time block sections come from the "plannerStructure" strategy.

See Recurrence for more information about recurring time blocks.

/**
 * @typedef {Object} TimeBlock
 * @property {String} _id - The PlannerItems's unique ID.
 * @property {String} title - The title.
 * @property {String} date - Date formatted as "YYYY-MM-DD".
 * @property {String} time - Time block start time formatted as "HH:mm". This makes time blocks time zone independent!
 * @property {String} duration - Duration in minutes (determines height).
 * @property {Boolean} isSection - Set to false to not show as a day section.
 * @property {String} calId - ID of calendar this task has been created from / assigned to.
 * @property {String} calURL - Unique URL of this task in the calendar.
 * @property {String} etag - Calendar etag to determine when an update is needed.
 * @property {String} calData - Calendar data.  This string is modified and sent to server to update when timeBlocks in Marvin change.
 * @property {Object} cancelDates - A lookup of YYYY-MM-DD => true, indicating dates for which this time block has been deleted.
 * @property {Object} exceptions - A lookup of YYYY-MM-DD => { etag, calData, date, title, time, duration } (YYYY-MM-DD is originalDate!).
 * @property {any} recurrence - A Calendar-specific recurrence pattern, for recurring time blocks imported from calendar sync.
 * @property {String} note - The time block's note. This will soon be in Markdown format.
 *
 * Time Block colors are stored per-title in
 * profile.strategySettings.plannerColors. This is an object where the key is
 * the normalized title (see below), and the value is a hex-format color like
 * "#ff00ff".
 *
 * Time Block label/category/smart list is stored per-title in
 * profile.strategySettings.plannerSmartLists. This is an object where the key
 * is the normalized title (see below), and the value is the ID of a
 * category/label/smart list.
 *
 * Titles are normalized by removing non-word characters: /[^-_\p{L}0-9]/gu
 */

Rewards

/**
 * @typedef {Object} Reward
 * @property {String} _id - The reward unique ID.
 * @property {Number} isArchived - If true, then it's not shown in the organizer.
 * @property {Number} rank - Order in organizer.
 * @property {String} groupId - The group to which it belongs, from strategySettings.rewards.groups.
 * @property {String} title - The rewards's title, like "Drink water".
 * @property {String} note - Rich text note.
 * @property {Boolean} isPinned - pinned rewards can be repeatedly claimed
 * @property {Number} rewardPoints - How many reward points you have to spend to claim this
 * @property {Number[]} earned - Array of Date.now() when it was claimed/earned. If not pinned, has at most one entry.
 * @property {Number[]} spent - Array of Date.now() when it was spent. If not pinned, has at most one entry.
 */

ProfileItems

Most of your configuration lives within the "profile" section of your sync database and can be read and manipulated using Database Access. So, for example, when the time block documentation above refers to profile.strategySettings.plannerColors, that means you will find a ProfileItem in your database with _id="strategySettings.plannerColors", and val={Work:"#ff00ff",...}. You can use Marvin API#read-any-doc to read these values one-at-a-time, or use Database Access to read and manipulate them with more power. Note: take care when editing these values as it would be easy to store something invalid and cause Marvin to crash on startup.

/**
 * @typedef {Object} ProfileItem
 * @property {String} _id
 * @property {*} val - The profile value.
 */

Profile

Some basic profile information is available at the /api/me endpoint (see Marvin API#Me). This is from your user account data stored in Marvin's central servers, and is confusingly different than the profile information that lives in your sync database. See ProfileItems above.

type Profile struct {
	UserId                  int64     `json:"userId,string"` // Your user ID, encoded as a string (since it may be more than 53 bits).
	Email                   string    `json:"email"` // Your signup email.
	ParentEmail             string    `json:"parentEmail"` // It's possible your account is linked with another for payment. If so this field is that account's email address.
	EmailConfirmed          bool      `json:"emailConfirmed"` // True if you confirmed your email address
	BillingPeriod           string    `json:"billingPeriod"` // One of "TRIAL", "MONTH", "YEAR", "ONCE", or "PAID"
	PaidThrough             time.Time `json:"paidThrough"` // Account paid through this date.
	IosSub                  bool      `json:"iosSub"` // True if you have a linked ios Sub
	MarvinPoints            int       `json:"marvinPoints"` // Total Marvin kudos
	NextMultiplier          int       `json:"nextMultiplier"` // If you complete a task, the next task might be worth more.
	RewardPointsEarned      float64   `json:"rewardPointsEarned"` // Total rewardPoints earned by this user
	RewardPointsSpent       float64   `json:"rewardPointsSpent"` // Total rewardPoints spent by this user
	RewardPointsEarnedToday float64   `json:"rewardPointsEarnedToday"` // Points earned today; based on Date provided by user when claiming/spending
	RewardPointsSpentToday  float64   `json:"rewardPointsSpentToday"` // Points spent today; based on Date provided by user when claiming/spending
	RewardPointsLastDate    string    `json:"rewardPointsLastDate"` // Date like "2020-08-25"; changes when the user claims/spends points; used to figure out whether RewardPointsEarned/SpentToday still valid
	Tomatoes                int       `json:"tomatoes"` // Lifetime work timers completed
	TomatoesToday           int       `json:"tomatoesToday"` // Work timers completed today. Check tomatoDate to see if it's actually still today.
	TomatoTime              int64     `json:"tomatoTime"` // Lifetime tomato work time (in ms)
	TomatoTimeToday         int64     `json:"tomatoTimeToday"` // Work time (in ms) today. Check tomatoDate to see if it's actually still today.
	TomatoDate              string    `json:"tomatoDate"` // Date like "2020-09-29". Changes when the user adds a tomato.
	DefaultSnooze           int       `json:"defaultSnooze"` // Default snooze duration, in minutes. 0=use default of 5 minutes
	DefaultAutoSnooze       bool      `json:"defaultAutoSnooze"` // Whether to autoSnooze by default. Defaults to false.
	DefaultOffset           int       `json:"defaultOffset"` // Default reminder offset, in minutes. Defaults to 0 which is to remind at the task time
	Tracking      string `json:"tracking"`      // ID of task the user is tracking
	TrackingSince int64  `json:"trackingSince"` // Date.now() when user started tracking task
	CurrentVersion          string    `json:"currentVersion"` // Current front-end version
	SignupAppVersion        string    `json:"signupAppVersion"` // The current Marvin version when you signed up
}

Reminders

These server-side Reminders are needed in order to get push notifications on your mobile device. Use the Reminder APIs to list, create, and delete them.

type Reminder struct {
	Time       int64  `json:"time"`                            // unix timestamp (seconds)
	Offset     int    `json:"offset" datastore:",noindex"`     // Minutes ahead of time that user wants to be reminded, -1=use default
	ReminderId string `json:"reminderId"`                      // Unique (per-user) ID of reminder; either taskId or a randId for reminders unrelated to tasks
	Type       string `json:"type"`                            // Careful: no longer than 10 characters! See below for types
	Title      string `json:"title" datastore:",noindex"`      // Task title which will be shown in notification.  Capped at 200 characters
	Snooze     int    `json:"snooze" datastore:",noindex"`     // Snooze duration, in minutes.
	AutoSnooze bool   `json:"autoSnooze" datastore:",noindex"` // Whether to auto-snooze the reminder
	CanTrack   bool   `json:"canTrack"`                        // True if user has trackTime strategy on; "Track Time" action can be shown instead of "Dismiss".
}

// Possible Reminder types
const (
	REM_TASK        = "T"  // A task with a time
	REM_MANUAL      = "M"  // User manually set a reminder not corresponding to a task/project
	REM_DUE_TASK    = "DT" // A task with a due date
	REM_DUE_PROJECT = "DP" // A project with a due date
	REM_TEST        = "t"
)