Skip to content

DailyExecution / Client Mobile / Daily Agenda

Today View is the client's execution dashboard for the current local day.

The V1 baseline Today view gathers workouts, meals, check-ins, informational reminders, measurements, supplements, and lightweight daily actions into one ordered mobile agenda. It owns the daily task projection, informational card projection, offline cache contract, task status lifecycle, and adherence events while routing task-specific work to the owning feature screens.

Tags: DailyExecution, Client mobile, Offline cache, Task projection, Adherence updates

Boundary decision

Today View does not own nutrition plans, form definitions, program prescriptions, chat messages, or progress records. It owns dated task instances, Today informational card snapshots, completion state, sync cursors, and normalized daily adherence facts.

Note

Client mobile should render cached Today data immediately, then reconcile with the server projection. The user should always know whether a completed action is accepted, queued, syncing, or needs attention.

Note

Shared mobile sync mechanics for device registration, local outbox operations, receipts, conflict states, cache purge, and pruning follow the Offline Sync Protocol. Today owns only the dated task projection and source-aware task status rules.

Presentation decision (July 2026)

The multi-item agenda in this doc is the projection — the API contract, offline cache, and coach surfaces. Client mobile presents that projection one card at a time: the top-ranked task is the single card, the rest reveal sequentially as tasks resolve, and repeatable-value habits live in a tray below the card (background: the guided Today-first direction). Materialization, task lifecycle, and offline sync are unchanged. The one addition is the coach focus pin — a new ordering input whose coach-side authoring is specced with the coach-facing work; the agenda response exposes the pin marker and its one-line note. See the Client Mobile section for the presentation rules.

Today View Flows

The core flow starts at app open, then hands off to task-specific execution surfaces without losing daily status.

Client Opens Today

  1. Client launches the app and the mobile shell resolves the active relationship, local date, timezone, locale, and cached agenda version.
  2. Client mobile renders the latest SQLite Today snapshot immediately, including any queued local completions.
  3. API materializes or refreshes the requested date window, then returns task instances, display snapshots, task actions, status counts, and sync cursors.
  4. Client replaces stale local rows by server version while preserving local pending operations that have not been accepted yet.
  5. Tasks are ordered by urgency, the optional coach focus pin, scheduled time, coach priority, dependency, and stable fallback order so refreshes do not jump the list unnecessarily.

Client Completes Daily Work

  1. Client taps a workout, meal, check-in, measurement, supplement, or habit task from Today.
  2. Simple tasks can complete from Today when the action schema allows quick completion.
  3. Structured tasks open their owning screen, such as workout logging, meal detail, form submission, or measurement upload.
  4. Completion writes an idempotent task status transition and emits a normalized adherence event after backend acceptance.
  5. Coach dashboards, client timeline, streaks, risk flags, and progress summaries consume the accepted daily facts.

Offline And Weak Signal

  1. Client mobile prefetches the current local day only for V1 baseline, including the task and informational-card snapshots needed to open today's workouts and forms with weak signal.
  2. Local completions and status changes are written to SQLite with client operation ids and queued in the mobile outbox.
  3. Today shows pending local state separately from accepted server state, including queued, syncing, accepted, rejected, and conflict markers.
  4. Bulk sync merges by relationship, task id or source reference, client operation id, and expected task revision.
  5. Server returns canonical task statuses, rejected operations, updated agenda versions, and refresh hints for affected dates.

Source Plan Changes

  1. Program, nutrition, form, reminder, and coach workflow events invalidate future daily task projections for affected relationships.
  2. Materializer refreshes pending future tasks but does not rewrite completed historical task snapshots.
  3. If a coach changes today's plan while the client is offline, client mobile receives a conflict or superseded marker on reconnect.
  4. Completed task history remains tied to the source snapshot that was visible when the client performed the work.
  5. Coach-facing views explain whether the client completed an old version, current version, skipped task, or superseded task.

Domain Model

Today View belongs to DailyExecution and references source contexts through stable external ids and snapshots.

Aggregates & Entities

  • DailyTaskInstance: aggregate root for one relationship, local date, source reference, task kind, status, due window, ordering, snapshot, and action schema.
  • TodayAgenda: server-side projection for one relationship and local date, assembled from active task instances, local timezone rules, and accepted sync state.
  • TodayInformationalCard: non-completable agenda item for coach-defined custom reminders and source notices that should not affect adherence scoring.
  • TaskAction: route contract that tells mobile whether the task opens workout logging, form submission, meal detail, measurement upload, messaging, or a quick completion action.
  • TaskStatusTransition: append-only record of status changes such as pending, in progress, completed, skipped, missed, canceled, and superseded.
  • DailyAdherenceEvent: normalized fact used by dashboards, streaks, risk flags, weekly recaps, and progress projections.
  • TodaySyncReceipt: server receipt for idempotent offline operations from client mobile.

Value Objects & Rules

  • LocalDay: date plus IANA timezone. All Today queries must be anchored to the client's relationship timezone, not server time.
  • TaskKind: WORKOUT, MEAL, CHECK_IN, MEASUREMENT, PHOTO, SUPPLEMENT, HABIT, REMINDER, and future system-supported task types.
  • TaskSourceRef: source context, source type, source id, source revision, optional child key, and a normalized non-null source key for idempotent materialization.
  • TaskStatus: PENDING, IN_PROGRESS, COMPLETED, SKIPPED, MISSED, CANCELED, SUPERSEDED.
  • ActionSchema: mobile-safe JSON contract for available CTAs, quick-complete eligibility, destination route, required payload, and offline capability.
  • Coach-defined custom reminders are projected as informational cards in Public V1, not as client-completable tasks, message prompts, or adherence facts.
  • Task materialization must be idempotent by relationship, local date, task kind, and source reference.
  • Completed or skipped tasks retain the visible snapshot even when the source plan changes later.
  • Quick completion is allowed only when the task action schema has no required domain-specific payload beyond completion metadata.

Implementation note (M1)

Shipped Execute records anchor on the client-supplied local date alone: workout_logs has no timezone column and the server derives none. The device timezone travels as sync operation metadata and is retained on the receipt rather than stored on the record.

ModelOwned ByImportant MethodsEmits
DailyTaskInstanceDailyExecutionmaterialize(), refreshSnapshot(), start(), complete(), skip(), markMissed(), supersede()DailyTaskMaterialized, DailyTaskCompleted, DailyTaskMissed
TodayInformationalCardDailyExecution projectionproject(), expire(), toAgendaItem()TodayInfoCardProjected
TodayAgendaDailyExecution projectionassemble(), sortTasks(), summarize(), markStale()TodayAgendaProjected
TaskStatusTransitionDailyExecutionrecord(), deduplicateClientOperation(), toAdherenceEvent()DailyTaskStatusChanged
TodaySyncReceiptDailyExecution infrastructureaccept(), reject(), mapCanonicalIds()MobileTodaySyncAccepted

Table Structure

Persist task instances and append-only status facts in PostgreSQL, with a compact mirrored subset in client SQLite.

Implementation note (M1)

No task-projection table exists yet. The only materialized daily fact today is the workout log itself — one row per relationship, assignment, program day, and local date, whose status (IN_PROGRESS, COMPLETED, SKIPPED) stands in for the workout task status — and offline receipts live in the shared sync_operation_receipts table rather than a Today-specific one. Everything below is the V1 target.

TablePurposeImportant ColumnsConstraints & Indexes
daily_task_instancesMaterialized task shown in Today for a relationship and local date.id, workspace_id, relationship_id, local_date, timezone, task_kind, source_context, source_type, source_id, source_revision, source_child_key, source_key, status, priority, sort_key, starts_at, due_at, snapshot jsonb, action_schema jsonb, completion_summary jsonb, generated_at, completed_at, canceled_at, superseded_atUnique (relationship_id, local_date, task_kind, source_key); index (relationship_id, local_date, status); index (source_context, source_id).
today_agenda_snapshotsVersioned projection metadata for client cache reconciliation.id, relationship_id, local_date, timezone, projection_version, task_count, completed_count, missed_count, agenda_checksum, projected_at, invalidated_atUnique (relationship_id, local_date, projection_version); index latest by (relationship_id, local_date, projected_at desc).
today_informational_cardsNon-completable cards shown in Today, including coach-defined custom reminders.id, workspace_id, relationship_id, local_date, timezone, source_context, source_id, source_revision, card_key, priority, sort_key, display_from, display_until, snapshot jsonb, generated_at, expired_atUnique (relationship_id, local_date, card_key); index active by (relationship_id, local_date, expired_at).
daily_task_status_eventsAppend-only status transitions for audit, replay, and analytics projection rebuilds.id, daily_task_instance_id, relationship_id, from_status, to_status, reason, actor_user_id, device_id, client_operation_id, metadata jsonb, occurred_atUnique nullable (relationship_id, device_id, client_operation_id); index (daily_task_instance_id, occurred_at).
daily_adherence_eventsNormalized facts consumed by coach dashboards, risk flags, streaks, and recap jobs.id, daily_task_instance_id, relationship_id, local_date, task_kind, event_type, score, source_context, source_id, metadata jsonb, occurred_atUnique idempotency key from task id, accepted transition id, and event type; index (relationship_id, local_date desc).
mobile_today_sync_receiptsServer receipts for offline Today status operations.id, relationship_id, device_id, client_operation_id, operation_type, daily_task_instance_id, accepted_status, accepted_revision, rejection_reason, accepted_atUnique (relationship_id, device_id, client_operation_id); supports idempotent retries and client reconciliation.

Offline storage

SQLite mirrors daily_task_instances, today_informational_cards, latest agenda metadata, pending status operations, sync receipts, and compact source snapshots. It should not mirror full nutrition plans, full form definitions, or full program builder data unless the owning feature explicitly exposes an offline snapshot.

Lifecycle Policy

Today tasks are operational records. Preserve accepted history, refresh future tasks, and explain stale or superseded work clearly.

Task Lifecycle

  • New materialized tasks start as PENDING unless the source event explicitly creates an in-progress state.
  • A task becomes IN_PROGRESS when the client starts a structured task such as a workout, form, meal detail, or measurement upload.
  • Accepted task completion transitions to COMPLETED and records completion metadata, actor, source device, and adherence event details.
  • Scheduled overdue jobs mark tasks MISSED only after a fixed one-local-day grace window and source-specific policy checks.
  • Source cancellation, pause, deletion, or replacement marks future pending tasks CANCELED or SUPERSEDED instead of deleting rows.
  • Coaches cannot override missed-task grace windows per relationship in Public V1; retiring, deleting, or replacing the source plan changes future task projection instead.

History And Retention

  • Completed, skipped, and missed task records stay visible in client history and coach timeline for the relationship retention window.
  • Future pending task snapshots can refresh when source plans change; completed task snapshots must not be rewritten.
  • Agenda snapshots are cache metadata and can be pruned after the mobile sync retention window when status events remain available.
  • Closed relationships follow CoachClientManagement retention and privacy rules; sensitive snapshots are anonymized before any hard purge.

Caution

Do not use destructive delete for ordinary plan changes. The product needs to distinguish "not assigned anymore" from "client missed it" and "client completed an older visible version."

API Contracts

Client endpoints optimize for fast app launch, offline reconciliation, and source-aware task routing.

Implementation note (M1)

None of the Today routes below are built yet. Client mobile currently reads its day from the Execute pull, GET /api/v1/coach-client-relationships/{relationshipId}/sync, which returns the current active assignment with its full program tree, the relationship's workout logs with sets, the newest sync receipts for the device, and the relationship scope state. Only an ACTIVE assignment reaches that pull.

EndpointPurposeRequestResponse
GET /api/v1/client/today?date=YYYY-MM-DDReturn one day's agenda for the active relationship.Local date, timezone, optional agenda checksum, optional since cursor.Agenda version, task list, informational cards, status summary, action schemas, offline cache hints, stale-source warnings.
GET /api/v1/client/today/range?from=YYYY-MM-DD&to=YYYY-MM-DDFetch compact agenda changes for explicit date ranges; V1 baseline mobile calls it with from and to set to the same current local day.Date range, timezone, cached checksums.Compact agendas, informational cards, changed dates, removed/superseded task ids, next sync cursor.
POST /api/v1/client/today/tasks/{taskId}/startMark a structured task as in progress and return destination metadata.Device id, client operation id, expected task revision, started at.Task status, accepted revision, destination route, source snapshot checksum.
POST /api/v1/client/today/tasks/{taskId}/completeQuick-complete a simple task when allowed by action schema.Device id, client operation id, expected task revision, completion metadata, completed at.Accepted task status, adherence summary, updated agenda counters, sync receipt.
POST /api/v1/client/today/tasks/{taskId}/skipSkip a task with a source-aware reason.Device id, client operation id, reason, note, skipped at.Accepted task status, adherence effect, coach-review hint if needed.
POST /api/v1/client/today/syncBulk sync offline Today operations.Device id, ordered operations, client operation ids, task ids or source refs, expected revisions.Accepted operations, rejected operations, canonical task ids, latest agenda versions, refresh hints.
GET /api/v1/coach/relationships/{relationshipId}/daily-summaryCoach reads daily task status for review surfaces.Date range, task kind filter, status filter.Daily summaries, task breakdowns, completion events, missed/superseded explanation.
POST /api/v1/internal/daily-execution/materializeInternal job endpoint or service boundary for materializing affected task windows.Relationship ids, source context, source ids, date window, reason.Materialized count, changed dates, projection versions, outbox events.

Key Code Snippets

Implementation sketches show the task and informational-card projection shape, Today fetch boundary, and access policy.

Drizzle schema shape

apps/api/src/daily-execution/db/today-view.schema.ts

ts
export const dailyTaskInstances = pgTable("daily_task_instances", {
  id: uuid("id").primaryKey().defaultRandom(),
  workspaceId: uuid("workspace_id").notNull(),
  relationshipId: uuid("relationship_id").notNull(),
  localDate: date("local_date").notNull(),
  timezone: text("timezone").notNull(),
  taskKind: text("task_kind").$type<TaskKind>().notNull(),
  sourceContext: text("source_context").notNull(),
  sourceType: text("source_type").notNull(),
  sourceId: uuid("source_id").notNull(),
  sourceRevision: integer("source_revision"),
  sourceChildKey: text("source_child_key"),
  sourceKey: text("source_key").notNull(),
  status: text("status").$type<TaskStatus>().notNull().default("PENDING"),
  priority: integer("priority").notNull().default(0),
  sortKey: text("sort_key").notNull(),
  startsAt: timestamp("starts_at", { withTimezone: true }),
  dueAt: timestamp("due_at", { withTimezone: true }),
  snapshot: jsonb("snapshot").$type<DailyTaskSnapshot>().notNull(),
  actionSchema: jsonb("action_schema").$type<TaskActionSchema>().notNull(),
  completionSummary: jsonb("completion_summary").$type<CompletionSummary>(),
  completedAt: timestamp("completed_at", { withTimezone: true }),
  supersededAt: timestamp("superseded_at", { withTimezone: true }),
}, (table) => ({
  sourceUnique: uniqueIndex("daily_task_instances_source_unique")
    .on(table.relationshipId, table.localDate, table.taskKind, table.sourceKey),
  relationshipDateStatusIdx: index("daily_task_instances_relationship_date_status_idx")
    .on(table.relationshipId, table.localDate, table.status),
}));

export const todayInformationalCards = pgTable("today_informational_cards", {
  id: uuid("id").primaryKey().defaultRandom(),
  workspaceId: uuid("workspace_id").notNull(),
  relationshipId: uuid("relationship_id").notNull(),
  localDate: date("local_date").notNull(),
  timezone: text("timezone").notNull(),
  sourceContext: text("source_context").notNull(),
  sourceId: uuid("source_id").notNull(),
  sourceRevision: integer("source_revision"),
  cardKey: text("card_key").notNull(),
  priority: integer("priority").notNull().default(0),
  sortKey: text("sort_key").notNull(),
  displayFrom: timestamp("display_from", { withTimezone: true }),
  displayUntil: timestamp("display_until", { withTimezone: true }),
  snapshot: jsonb("snapshot").$type<TodayInfoCardSnapshot>().notNull(),
  generatedAt: timestamp("generated_at", { withTimezone: true }).notNull(),
  expiredAt: timestamp("expired_at", { withTimezone: true }),
}, (table) => ({
  cardUnique: uniqueIndex("today_informational_cards_unique")
    .on(table.relationshipId, table.localDate, table.cardKey),
  relationshipDateActiveIdx: index("today_informational_cards_relationship_date_active_idx")
    .on(table.relationshipId, table.localDate, table.expiredAt),
}));

export const dailyTaskStatusEvents = pgTable("daily_task_status_events", {
  id: uuid("id").primaryKey().defaultRandom(),
  dailyTaskInstanceId: uuid("daily_task_instance_id").notNull(),
  relationshipId: uuid("relationship_id").notNull(),
  fromStatus: text("from_status").$type<TaskStatus>(),
  toStatus: text("to_status").$type<TaskStatus>().notNull(),
  actorUserId: uuid("actor_user_id"),
  deviceId: text("device_id"),
  clientOperationId: uuid("client_operation_id"),
  metadata: jsonb("metadata").$type<TaskTransitionMetadata>().notNull(),
  occurredAt: timestamp("occurred_at", { withTimezone: true }).notNull(),
});

Fetch Today use case

apps/api/src/daily-execution/use-cases/get-today-agenda.ts

ts
@Injectable()
export class GetTodayAgendaUseCase {
  constructor(
    private readonly materializer: TodayTaskMaterializer,
    private readonly tasks: DailyTaskInstanceRepository,
    private readonly cards: TodayInformationalCardRepository,
    private readonly agendaProjector: TodayAgendaProjector,
    private readonly policy: TodayViewPolicy,
  ) {}

  async execute(query: GetTodayAgendaQuery, actor: Actor): Promise<TodayAgendaDto> {
    this.policy.assertClientCanReadToday(actor, query.relationshipId);

    const localDay = LocalDay.from(query.localDate, query.timezone);
    await this.materializer.ensureWindow({
      relationshipId: query.relationshipId,
      from: localDay,
      to: localDay,
      reason: "CLIENT_TODAY_OPENED",
    });

    const taskRows = await this.tasks.findForLocalDay(query.relationshipId, localDay);
    const infoCards = await this.cards.findActiveForLocalDay(query.relationshipId, localDay);
    const agenda = this.agendaProjector.project(taskRows, infoCards, {
      cachedChecksum: query.cachedChecksum,
      sinceCursor: query.sinceCursor,
    });

    return TodayAgendaDto.fromProjection(agenda);
  }
}

Quick completion boundary

apps/api/src/daily-execution/use-cases/complete-daily-task.ts

ts
@Injectable()
export class CompleteDailyTaskUseCase {
  constructor(
    private readonly tasks: DailyTaskInstanceRepository,
    private readonly policy: TodayViewPolicy,
    private readonly receipts: TodaySyncReceiptRepository,
    private readonly tx: TransactionRunner,
    private readonly outbox: OutboxPort,
  ) {}

  async execute(command: CompleteDailyTaskCommand, actor: Actor): Promise<DailyTaskDto> {
    return this.tx.run(async () => {
      const existing = await this.receipts.findAccepted(command.idempotencyKey());
      if (existing) return this.tasks.getDto(existing.dailyTaskInstanceId);

      const task = await this.tasks.getForUpdate(command.taskId);
      this.policy.assertClientCanComplete(actor, task);
      task.assertQuickCompletionAllowed();
      task.complete(command.toCompletionMetadata());

      await this.tasks.save(task);
      await this.receipts.accept(command.toReceipt(task));
      await this.outbox.publish(task.pullDomainEvents());

      return DailyTaskDto.fromDomain(task);
    });
  }
}

Access policy

apps/api/src/daily-execution/policies/today-view.policy.ts

ts
export class TodayViewPolicy {
  assertClientCanReadToday(actor: Actor, relationshipId: string): void {
    actor.requireRole("CLIENT");
    actor.requireRelationshipParticipant(relationshipId);
  }

  assertClientCanComplete(actor: Actor, task: DailyTaskInstance): void {
    actor.requireRole("CLIENT");
    actor.requireRelationshipParticipant(task.relationshipId);
    task.assertClientMutable();
  }

  assertCoachCanReadSummary(actor: Actor, relationshipId: string): void {
    actor.requireRole("COACH");
    actor.requireCoachRelationshipAccess(relationshipId);
  }
}

Events & Background Jobs

Today View is event-fed by source contexts and emits normalized daily execution facts downstream.

Consumed Events

  • ProgramAssigned, ProgramPaused, ProgramResumed, and ProgramSuperseded create, pause, refresh, or supersede workout tasks.
  • MealPlanAssigned and NutritionScheduleChanged create meal, supplement, and macro-related daily tasks.
  • FormAssigned and CheckInScheduled create form and check-in tasks with due windows and reminder metadata.
  • MeasurementRequested and ProgressPhotoRequested create progress capture tasks.
  • CoachReminderCreated projects non-completable informational cards in Public V1; MessageFollowUpCreated creates lightweight tasks only when the system requires an explicit client action.

Emitted Events And Jobs

  • DailyTaskMaterialized: updates mobile sync hints and agenda snapshot versions.
  • DailyTaskCompleted: emits adherence facts and can resolve reminder or coach-review projections.
  • DailyTaskSkipped: feeds coach review and risk signal projectors when skipped reason is meaningful.
  • DailyTaskMissed: updates adherence, risk flags, and coach task inbox summaries after the fixed one-local-day grace window.
  • Daily materialization job keeps the current local day ready for mobile prefetch in Public V1.
  • Missed-task job runs timezone-aware checks for overdue tasks and avoids marking tasks missed while accepted or pending offline work exists.

Permissions & Access Rules

Today data is relationship-scoped and can reveal health, nutrition, communication, and progress context.

Client

  • Client can read Today only for relationships where they are the participant and the relationship is active or historically visible.
  • Client can complete, skip, or start only mutable tasks for their own relationship.
  • Client cannot complete a task that requires an owning feature payload unless that feature accepts the payload or the task action allows quick completion.
  • Client can sync offline operations only from registered devices and must send stable client operation ids.

Coach And Support

  • Coach can read daily summaries and task history for relationships they are authorized to manage.
  • Coach creates source plans, forms, reminders, and assignments through owning contexts rather than directly inserting Today tasks.
  • Coach-defined custom reminders appear as informational cards and cannot be completed, skipped, or scored by the client in Public V1.
  • Support/admin access to raw task snapshots and sync receipts requires explicit permission and audited reason.
  • Ended relationships follow CoachClientManagement visibility rules and must not leak future tasks after access ends.

Web, Coach Mobile, Client Mobile

Today is client-mobile-first, with coach surfaces consuming summaries and exceptions.

Coach Web

  • Client profile and timeline show daily completion, missed tasks, skipped reasons, and notable task exceptions.
  • Coach dashboard uses aggregated daily summaries rather than rendering the exact mobile Today screen.
  • Program, form, nutrition, and reminder changes show their projected effect on future client Today tasks when practical.
  • Coach and client surfaces expose the same adherence scoring in Public V1, while coach views can add management context and client views can add plain-language explanations.

Coach Mobile

  • Coach mobile can inspect a client's current daily status and message or follow up quickly.
  • Task exceptions such as missed check-ins, skipped workouts, and pain notes surface in compact review lists.
  • Coach mobile mutations still go through owning contexts, not direct Today task edits.

Client Mobile

Client mobile renders the agenda projection one card at a time, per the adopted guided Today-first direction.

  • Today is the default post-onboarding landing screen and should render from SQLite before network refresh.
  • The screen shows one actionable card: the top task of the stable server ordering. The next task is revealed only after the current one is completed or skipped; the agenda is never rendered as a checklist. Work in progress keeps the slot — a started workout stays the card, and when its session is minimized it persists as the resumable-session dock rather than releasing the slot.
  • A coach can pin one existing materialized task as "today's focus" with an optional one-line note; the pin re-tops the ordering for that relationship and local date. A time-critical task (an expiring check-in, a pain follow-up) can still preempt the pin, and the pin cannot create a task — content authorship stays in the plan tools.
  • Tasks whose quick action is repeatable value capture never occupy the card. They render in a persistent quiet habit tray below the card, tappable all day. Water rides Nutrition's hydration goal and logging (see Nutrition Tracking); steps and simple metrics ride Quick-log RECORD_VALUE manual values; the tray's target ("3 of 8") comes from the source plan, not from Quick-log. HABIT and REMINDER tasks whose action schema is complete/skip stay ordinary cards.
  • Informational cards never enter the card sequence. Like the habit tray, they render outside the card slot — quiet context above or below the current card — and never gate the reveal of the next task.
  • The card exposes status, due time, progress, offline state, primary action, and compact coach context.
  • Empty and edge states are designed, not blank: "nothing due yet" points at the next scheduled item, and "all done" closes the card queue explicitly while the tray stays visible with any outstanding progress. Overdue-but-still-pending work within the one-local-day grace window is re-offered forward ("pick up where you left off") as one action, never a guilt backlog; tasks already marked MISSED on earlier local days appear in history only.
  • Informational cards expose coach reminders without completion controls, skip controls, or adherence score effects.
  • Clients cannot reorder or hide Today items in Public V1; stable server ordering remains the source of truth until the core flow is stable.
  • Clients see the same adherence score values as coaches in Public V1, with mobile-friendly labels and explanations.
  • The screen supports Arabic/English, RTL, dark mode, large tap targets, dynamic type, and accessible status labels.
  • Refreshes should preserve the current card and stable ordering unless task urgency or completion state genuinely changes.

Test Scenarios & V1 Baseline Decisions

Today View needs strong projection, timezone, offline, and permission coverage because it is the client's main entry point.

Tests

  • Domain unit tests: idempotent task materialization, status transitions, quick-complete eligibility, skips, missed windows, and superseded source handling.
  • API integration tests: Today fetch materializes missing tasks and informational cards, checksum responses avoid full payloads, same-day range fetch returns changed dates, and quick completion emits adherence facts once.
  • Offline sync tests: duplicate client operation retry, stale task revision rejection, server canonical status reconciliation, and pending local completion preserved during refresh.
  • Timezone tests: date boundary changes, daylight-saving transitions, travel timezone changes, and coach/client timezone mismatch.
  • Access tests: client cannot read or mutate another relationship's Today tasks, coach cannot read unauthorized summaries, support receipts require permission.
  • Mobile E2E tests: app opens offline with cached Today, completes a simple task offline, reconnects, syncs once, and updates coach summary.
  • Localization tests: Arabic/English labels, RTL ordering, long task names, dynamic type, screen-reader status text, and dark mode contrast.

V1 Baseline Decisions

  • Client mobile prefetches the current local day only for Today and workout execution in Public V1.
  • Coach-defined custom reminders are informational cards for now, not client-completable tasks or message prompts.
  • All task kinds use a fixed one-local-day missed-task grace window; coaches cannot override it per relationship.
  • Clients cannot reorder or hide low-priority Today tasks in Public V1; revisit after the core flow is stable.
  • Clients and coaches can see the same adherence scoring during V1 baseline, with role-appropriate context around the same values.
  • The one-card client presentation is a presentation policy over the unchanged agenda projection; coach web and coach mobile keep multi-item summaries. The client API contract changes only by exposing the coach focus pin marker and its note on the agenda response.
  • The coach focus pin is a small per-relationship, per-local-date marker referencing an existing materialized task plus an optional one-line note, preemptable by time-critical tasks. Its coach-side authoring surface and endpoint are specced with the coach-facing work, not here.
  • Repeatable-value habits surface only in the habit tray and are excluded from card sequencing. "All done" closes the card queue only; the tray keeps showing outstanding progress. At day close, a value task with at least one accepted entry completes — the entries carry the partial detail for the coach — while a task with zero entries follows the normal missed path.
  • The tray's value capture reuses the owning contexts as-is: Nutrition hydration for water, Quick-log manual values for steps and simple metrics. What the tray adds is presentation metadata on the action schema — the daily target from the source plan and whether taps accumulate (water) or replace the latest value (steps).
  • Today (and its session mode) is the only surface that tells the client what to do in Public V1. The coach Thread can ask, explain, or invite, but anything the client must complete resolves onto a Today card; messages carry no completable actions. External channels — push notifications, and any future linked-bot chat delivery — carry nudges that deep-link into Today and never present their own agenda. An OS-level notification action for habit-tray value capture ("log a glass") is a possible later enhancement — a remote control for the tray, never a place that decides what is due — and is not in the Public V1 baseline.

CoachMe internal planning documentation.