Some things happen on a timetable and are tedious to log by hand: a shift at work, a standing appointment, a daily supplement. A Schedule logs them for you. Each one names a trackable, the days it applies to and the times, and on those days its entry appears without anyone logging it, as an entry logged for you (Logged for You): marked as such, yours once you change it, and never brought back once deleted.

Schedules are their own page, /schedules, in the navigation after the Rundown. The model is packages/core/src/schedule.ts; schedules are stored in schedule and synced after the Rundown’s layers.

A schedule

  • Name and the trackable it logs. A trackable that a source fills (Weather) and a Routine are not offered.
  • Which days: the Rundown’s own rules (The Rundown): every day, days of the week, every N days, every N weeks on chosen weekdays, particular dates, or the day after a day with or without an entry of a trackable. Picked for the day is not offered, since a schedule runs whether or not the app is opened. One rule language serves both, through one rule picker.
  • When: for an interval, a Start and an End, in seconds into the day; an end at or before the start is the next day’s, so a night shift runs past midnight. For a moment, a Time.
  • The entry’s values and its item, filled in once.
  • Logs itself or asks.

Days on hold are skipped (dueDays): a day a Disruption holds, a holiday or the flu, gets no entry from a schedule, though one can still be logged by hand.

Logging itself

While the app is open, a runner (useScheduleRunner, mounted in the app shell) checks the schedules every minute and on any change, through core’s logDueSchedules (packages/core/src/schedule-runner.ts):

  • A due day gets its entry once its start has passed, catching up on days the app was not open, back to the day the schedule was made or two weeks at most. The day it was made is read as a local day, since the database stamps it in UTC.
  • An interval starts itself at its start, open, and is shown in the running bar with when it ends and how long is left (“Work · ends 5:00 PM · 3h 54m left”, scheduledEnd in packages/core/src/schedule.ts). It ends itself at its end, unless it was changed by hand first: once changed it is yours, the runner leaves it alone, and the running bar says since when, as for any open interval.
  • A moment is logged at its time.
  • A day already logged or deleted is left alone. Each day’s entry has the id schedule:<schedule>:<day>, so two devices running the same schedule make one row, and a deleted day is known by its id and not logged again.

Asking

A schedule that asks does not log itself. On its days it takes its place in the Rundown’s order by its start, among the questions (inDayOrder in components/capture/check-in.ts): listed in its section, and when its turn comes the card is the schedule’s, with Log, which logs it as planned from its start, and Not today, which lets it go for that day. Skip for now puts it aside as it does a question. It is not counted in the Rundown’s progress, which counts its questions. One that asks and is logged is ended at its end like any other.

Its entries

An entry from a schedule names it, with a link to this page, and follows the rules every entry logged for you does (Logged for You).

In the demo profiles

Chad has three: Work, 9:00 to 17:00 on weekdays, logging itself on days he was not ill and now and then ended late by hand; Therapy, every other Wednesday from 17:00 to 17:50, logging itself; and Vitamin D, asking every morning at 8:00.

Logged for You · The Rundown · Intervals · Weather