Skip to content

Nutrition / DailyExecution / Client Mobile

Supplement schedule turns coach-prescribed supplement plans into dated adherence tasks.

The V1 baseline lets coaches prescribe relationship-scoped supplement schedules with dose, unit, timing, meal relation, day-type rules, reminders, and instructions. Clients can mark taken, partial, skipped, or missed from Today, including offline. Coaches review adherence trends without treating supplement entries as food columns or automated clinical advice.

Page status

  • Nutrition
  • Schedule items
  • Dose logging
  • Reminders
  • Adherence review

Boundary decision

Boundary decision: Nutrition owns supplement definitions, schedule items, intake logs, adherence rollups, and coach review semantics. DailyExecution owns dated Today task instances and quick-log item state. Notifications owns push delivery. ProgressAnalytics consumes accepted supplement events for trends, flags, and weekly recaps.

Product decision

Product decision: supplements are adherence tasks by default. Protein powders, meal replacements, or similar nutrition-bearing products may contribute to tracked totals only when the coach explicitly marks them as count-toward-nutrients. Creatine, magnesium, vitamins, minerals, and similar supplements remain adherence-only in Public V1 unless explicitly re-scoped later.

Supplement Flows

The schedule must support simple daily supplements, multi-dose timing, day-type variants, reminders, and correction without rewriting history.

Coach Builds Schedule

  1. Coach chooses a system, workspace, or newly created supplement definition with name, form, dose unit, optional ingredient notes, and client-facing label.
  2. Coach sets dose amount, dose unit, frequency, day types, optional days of week, timing hint, meal relation, instructions, and reminder policy.
  3. Schedule items can live inside a meal plan version, nutrition template, or relationship-level nutrition prescription when the client does not have a fixed meal plan.
  4. Publish validation checks duplicate schedule keys, invalid dose units, hidden archived definitions, impossible timing windows, and reminder settings outside the plan dates.
  5. Publishing emits schedule change events that refresh future Today tasks without changing completed historical intake logs.

Client Follows Today

  1. Today materializes supplement tasks from the active nutrition snapshot for the client's relationship timezone and local date.
  2. Client sees supplement label, dose, form, timing hint, meal relation, instructions, and reminder state from the published snapshot.
  3. Client can mark taken, record a partial dose, skip with reason when required, undo within the configured window, or open the nutrition detail screen for notes.
  4. Client mobile writes a local intake operation first, updates optimistic Today state, and syncs with stable client ids when online.
  5. Backend accepts the canonical supplement intake log, updates DailyExecution task state, returns a sync receipt, and recalculates adherence rollups.

Coach Reviews Adherence

  1. Daily nutrition review shows taken, partial, skipped, missed, and pending supplement occurrences separately from meal and macro totals.
  2. Coach can filter by supplement, schedule item, day type, adherence status, skip reason, date range, and repeated misses.
  3. Missed supplement patterns can create coach task inbox items or risk flags only when configured by the coach or workspace policy.
  4. Coach can message the client, adjust future schedule items, pause a supplement, or publish a replacement plan version.
  5. Historical adherence remains tied to the schedule snapshot active on that date.

Schedule Changes

  1. Coach edits create a draft and publish a new schedule version or plan version; published schedule snapshots are immutable.
  2. Future pending Today tasks refresh from the new version. Completed, skipped, or missed tasks keep the old visible label, dose, and instructions.
  3. Pausing or ending a supplement cancels future pending occurrences instead of deleting them from history.
  4. If a client logs while offline against an old snapshot, sync can accept the old occurrence, reject a superseded occurrence, or request review depending on timing policy.
  5. Notifications are rescheduled from the same schedule change event so reminders do not outlive the active prescription.

Domain Model

Supplements are prescribed schedule items plus append-friendly intake facts, not nutrients hidden inside meal totals.

Aggregates & Entities

  • SupplementDefinition: system or workspace catalog row with display name, form, default dose unit, category, source, and archival lifecycle.
  • SupplementScheduleItem: immutable published prescription row attached to a plan version, target set, nutrition template, or relationship schedule.
  • SupplementOccurrence: derived occurrence for one local day and dose window, identified by a stable occurrence key for Today and offline sync.
  • SupplementIntakeLog: canonical accepted fact for one occurrence, with taken, partial, skipped, missed, corrected, and needs-review states.
  • SupplementScheduleException: relationship-scoped pause, one-off cancellation, or date-specific timing override for future pending occurrences.
  • SupplementAdherenceSummary: rebuildable projection for daily and weekly coach review, task inbox rules, and progress charts.
  • SupplementReminderPolicy: value object describing reminder channel, offset, quiet hours, repeat behavior, and client snooze policy.

Value Objects & Rules

  • Dose: decimal amount, unit, form, display label, optional maximum precision, and optional coach-visible ingredient metadata.
  • ScheduleCadence: daily, selected days, day type, every-n-days, training-day, rest-day, or custom rules resolved by the active plan timezone.
  • TimingHint: morning, afternoon, evening, bedtime, with meal, before meal, after meal, with training, or custom text.
  • MealRelation: optional link to a meal slot key, not a hard dependency on the client completing that meal first.
  • SupplementIntakeStatus: PENDING, TAKEN, PARTIAL, SKIPPED, MISSED, CORRECTED, NEEDS_REVIEW.
  • Every occurrence key is stable across materialization retries and includes plan version, schedule key, local date, and dose index.
  • Partial doses require a dose taken value and count separately from taken or skipped in adherence scoring.
  • Supplements can carry optional nutrient metadata, but food nutrient totals include it only for coach-marked nutrition-bearing items such as protein powder or meal replacements; creatine, magnesium, vitamins, and minerals remain adherence-only in Public V1.
  • The product stores reminders and adherence facts; it does not automatically diagnose deficiency, toxicity, contraindications, or treatment needs.
ModelOwned ByImportant MethodsEmits
SupplementDefinitionNutritioncreateWorkspaceDefinition(), rename(), archive(), restore()SupplementDefinitionCreated
SupplementScheduleItemNutritionpublish(), resolveOccurrences(), pauseFrom(), replaceWith(), toTodaySnapshot()SupplementSchedulePublished, NutritionScheduleChanged
SupplementIntakeLogNutritionrecordTaken(), recordPartial(), skip(), markMissed(), correct()SupplementIntakeRecorded, SupplementIntakeCorrected
SupplementAdherenceSummaryNutrition projectionrebuildForDay(), compareToSchedule(), summarizeTrend()SupplementAdherenceSummaryUpdated

Table Structure

Keep catalog data, published schedule snapshots, daily intake facts, and reminder receipts separate.

TablePurposeImportant ColumnsConstraints & Indexes
supplement_definitionsSystem and workspace supplement catalog.id, workspace_id, code, display_name, form, default_dose_unit, category, source, is_system, created_by_user_id, archived_atUnique active (workspace_id, code); system rows have null workspace; archive rather than delete when referenced.
supplement_nutrient_factsOptional nutrient metadata for supplement definitions.id, supplement_definition_id, nutrient_definition_id, amount_per_dose, unit, source, confidence, enabled_for_totalsUnique (supplement_definition_id, nutrient_definition_id); disabled for nutrient totals by default and enabled only for coach-marked nutrition-bearing items.
supplement_schedule_itemsPublished supplement prescription item attached to a plan, target set, template, or relationship.id, workspace_id, relationship_id, plan_version_id, target_set_id, template_id, supplement_definition_id, schedule_key, label_snapshot jsonb, dose_amount, dose_unit, dose_form, cadence jsonb, day_type, timing_hint, meal_slot_key, reminder_policy jsonb, instructions, sort_order, client_visibleUnique (plan_version_id, schedule_key) when attached to a plan; index active relationship schedule by (relationship_id, plan_version_id); published rows are immutable.
supplement_schedule_exceptionsFuture pause, cancellation, or one-off override for a schedule item.id, schedule_item_id, relationship_id, local_date, exception_type, replacement_timing_hint, reason, created_by_user_id, created_atUnique (schedule_item_id, local_date, exception_type); only affects pending future occurrences.
supplement_intake_logsCanonical daily intake facts for supplement occurrences.id, client_intake_id, daily_nutrition_log_id, relationship_id, schedule_item_id, occurrence_key, local_date, status, dose_taken, taken_at, skip_reason, note, source_device_id, supersedes_log_id, accepted_atUnique (relationship_id, client_intake_id); unique active (schedule_item_id, occurrence_key); corrections supersede rather than update accepted facts.
supplement_adherence_daily_summariesRebuildable daily adherence projection.id, relationship_id, local_date, plan_version_id, scheduled_count, taken_count, partial_count, skipped_count, missed_count, adherence_score, flag_summary jsonb, calculated_atUnique (relationship_id, local_date); index by relationship and date descending for coach review.
supplement_reminder_receiptsNotification scheduling and delivery receipts for supplement reminders.id, schedule_item_id, occurrence_key, relationship_id, notification_job_id, scheduled_for, delivery_status, delivered_at, canceled_atUnique (schedule_item_id, occurrence_key, notification_job_id); canceled when schedule version is superseded.
mobile_nutrition_sync_receiptsExisting Nutrition receipt table for replay-safe supplement operations.relationship_id, device_id, client_operation_id, operation_type, canonical_record_id, accepted_revision, payload_checksum, accepted_atUse operation_type = SUPPLEMENT_INTAKE; unique (relationship_id, device_id, client_operation_id).

Note

Client SQLite mirrors active supplement schedule snapshots, pending local intake operations, reminder metadata, accepted receipts, and recent adherence state. It should not mirror hidden coach notes or full support audit data.

Lifecycle Policy

Published prescriptions are immutable, daily facts are append-friendly, and future reminders follow active schedule versions.

Definitions And Schedules

  • System supplement definitions are seeded and versioned by migrations. Workspace definitions are coach-created and workspace-scoped.
  • Definitions can be archived when no longer selectable, but historical schedule items keep label and dose snapshots.
  • Published schedule items are immutable. Edits create a draft and then a replacement schedule or plan version.
  • Pauses, date-specific cancellations, and timing overrides apply only to future pending occurrences.
  • Reminder jobs are created, rescheduled, or canceled from schedule events, not from direct notification writes in the Nutrition domain.

Intake And Corrections

  • Client intake starts as local draft or queued operation, then becomes canonical only after backend acceptance.
  • Taken, partial, skipped, missed, and corrected facts are retained for audit and trend rebuilds.
  • Corrections create a new intake log that supersedes the prior accepted fact; adherence projections rebuild from active facts.
  • Missed status is assigned by a timezone-aware job after the configured grace window and pending offline work check.
  • Closed relationships follow CoachClientManagement retention rules; supplement notes and raw sync payloads are anonymized before hard purge.

Note

Do not hide supplement history when a coach removes a supplement from the current plan. The product needs to explain whether a client completed an older prescription, skipped it, missed it, or never had it assigned.

API Contracts

Coach endpoints manage catalog and schedules; client endpoints fetch snapshots and record occurrence-level intake idempotently.

EndpointPurposeRequestResponse
GET /api/v1/coach/supplementsSearch system and workspace supplement definitions.Query, form, category, include archived flag, pagination cursor.Definition results, default dose units, source labels, archived state.
POST /api/v1/coach/supplementsCreate a workspace supplement definition.Name, code, form, default dose unit, category, optional nutrient facts, source note.Created definition dto and validation warnings.
POST /api/v1/coach/relationships/{relationshipId}/nutrition/supplement-schedulesCreate or publish a relationship-level supplement schedule when no meal plan draft owns it.Effective dates, timezone, schedule items, reminder policies, visibility, idempotency key.Published schedule snapshot, version, affected Today window.
POST /api/v1/coach/relationships/{relationshipId}/nutrition/plansPublish meal or macro plan with embedded supplement schedule items.Existing plan payload plus supplement schedule items and reminder policies.Published plan version, schedule item ids, snapshot checksum, materialization hints.
GET /api/v1/client/nutrition/today?date=YYYY-MM-DDReturn today's nutrition snapshot including supplement occurrences and accepted intake state.Local date, timezone, optional snapshot checksum, optional sync cursor.Meal tasks, supplement tasks, hydration target, current intake logs, reminder metadata, outbox hints.
POST /api/v1/client/nutrition/logs/{logId}/supplementsRecord taken, partial, skipped, or corrected supplement occurrence.Device id, client operation id, schedule item id, occurrence key, status, dose taken, taken at, skip reason, note, expected revision.Accepted intake log, canonical ids, adherence summary, Today task update, sync receipt.
POST /api/v1/client/nutrition/syncBulk sync offline nutrition operations, including supplement intake.Device id, ordered operations, client ids, expected revisions, payload checksums.Accepted operations, rejected stale operations, canonical id map, updated adherence summaries, refetch hints.
GET /api/v1/coach/relationships/{relationshipId}/nutrition/supplement-adherenceCoach reviews supplement adherence by date range.Date range, schedule item id, status filter, day type, pagination cursor.Daily summaries, occurrence details, skip reasons, repeated miss flags, schedule version labels.
POST /api/v1/internal/nutrition/supplements/materializeInternal materialization boundary for affected supplement task windows.Relationship ids, schedule item ids, date window, reason.Created, refreshed, canceled, and skipped occurrence counts.

Key Code Snippets

Implementation sketches show the schema shape, intake use case, Today materialization adapter, and access policy.

Drizzle schema shape

apps/api/src/nutrition/db/supplement-schedule.schema.ts

ts
export const supplementDefinitions = pgTable("supplement_definitions", {
  id: uuid("id").primaryKey().defaultRandom(),
  workspaceId: uuid("workspace_id"),
  code: text("code").notNull(),
  displayName: text("display_name").notNull(),
  form: text("form").$type<SupplementForm>().notNull(),
  defaultDoseUnit: text("default_dose_unit").notNull(),
  category: text("category"),
  source: text("source").$type<SupplementDefinitionSource>().notNull(),
  isSystem: boolean("is_system").notNull().default(false),
  archivedAt: timestamp("archived_at", { withTimezone: true }),
}, (table) => ({
  activeCodeUnique: uniqueIndex("supplement_definitions_active_code_unique")
    .on(table.workspaceId, table.code)
    .where(isNull(table.archivedAt)),
}));

export const supplementScheduleItems = pgTable("supplement_schedule_items", {
  id: uuid("id").primaryKey().defaultRandom(),
  workspaceId: uuid("workspace_id").notNull(),
  relationshipId: uuid("relationship_id").notNull(),
  planVersionId: uuid("plan_version_id"),
  targetSetId: uuid("target_set_id"),
  supplementDefinitionId: uuid("supplement_definition_id").notNull(),
  scheduleKey: text("schedule_key").notNull(),
  labelSnapshot: jsonb("label_snapshot").$type<SupplementLabelSnapshot>().notNull(),
  doseAmount: numeric("dose_amount", { precision: 10, scale: 3 }).notNull(),
  doseUnit: text("dose_unit").notNull(),
  cadence: jsonb("cadence").$type<SupplementCadence>().notNull(),
  timingHint: text("timing_hint"),
  mealSlotKey: text("meal_slot_key"),
  reminderPolicy: jsonb("reminder_policy").$type<SupplementReminderPolicy>().notNull(),
  clientVisible: boolean("client_visible").notNull().default(true),
}, (table) => ({
  planScheduleKeyUnique: uniqueIndex("supplement_schedule_items_plan_key_unique")
    .on(table.planVersionId, table.scheduleKey),
  relationshipPlanIdx: index("supplement_schedule_items_relationship_plan_idx")
    .on(table.relationshipId, table.planVersionId),
}));

export const supplementIntakeLogs = pgTable("supplement_intake_logs", {
  id: uuid("id").primaryKey().defaultRandom(),
  clientIntakeId: uuid("client_intake_id").notNull(),
  dailyNutritionLogId: uuid("daily_nutrition_log_id").notNull(),
  relationshipId: uuid("relationship_id").notNull(),
  scheduleItemId: uuid("schedule_item_id").notNull(),
  occurrenceKey: text("occurrence_key").notNull(),
  localDate: date("local_date").notNull(),
  status: text("status").$type<SupplementIntakeStatus>().notNull(),
  doseTaken: numeric("dose_taken", { precision: 10, scale: 3 }),
  takenAt: timestamp("taken_at", { withTimezone: true }),
  skipReason: text("skip_reason"),
  note: text("note"),
  supersedesLogId: uuid("supersedes_log_id"),
  acceptedAt: timestamp("accepted_at", { withTimezone: true }).notNull(),
}, (table) => ({
  clientIntakeUnique: uniqueIndex("supplement_intake_logs_client_unique")
    .on(table.relationshipId, table.clientIntakeId),
  occurrenceUnique: uniqueIndex("supplement_intake_logs_occurrence_unique")
    .on(table.scheduleItemId, table.occurrenceKey)
    .where(isNull(table.supersedesLogId)),
}));

Record intake use case

apps/api/src/nutrition/use-cases/record-supplement-intake.ts

ts
@Injectable()
export class RecordSupplementIntakeUseCase {
  constructor(
    private readonly dailyLogs: DailyNutritionLogRepository,
    private readonly schedules: SupplementScheduleRepository,
    private readonly receipts: NutritionSyncReceiptRepository,
    private readonly policy: SupplementSchedulePolicy,
    private readonly tx: TransactionRunner,
    private readonly outbox: OutboxPort,
  ) {}

  async execute(command: RecordSupplementIntakeCommand, actor: Actor): Promise<SupplementIntakeDto> {
    return this.tx.run(async () => {
      const duplicate = await this.receipts.findAccepted(command.idempotencyKey());
      if (duplicate) return this.dailyLogs.getSupplementIntakeDto(duplicate.canonicalRecordId);

      const dailyLog = await this.dailyLogs.getOrCreateForUpdate(command.dailyLogIdentity());
      const scheduleItem = await this.schedules.getPublishedItem(command.scheduleItemId);

      this.policy.assertClientCanRecord(actor, dailyLog, scheduleItem);
      dailyLog.assertExpectedRevision(command.expectedRevision);
      scheduleItem.assertOccurrenceAllowed(command.occurrenceKey, dailyLog.localDay);

      const intake = SupplementIntakeLog.record({
        scheduleItem,
        occurrenceKey: command.occurrenceKey,
        status: command.status,
        doseTaken: command.doseTaken,
        actorTimestamp: command.takenAt,
        note: command.note,
      });

      dailyLog.recordSupplementIntake(intake);
      await this.dailyLogs.save(dailyLog);
      await this.receipts.accept(command.toReceipt(intake.id, dailyLog.revision));
      await this.outbox.publish(dailyLog.pullDomainEvents());

      return SupplementIntakeDto.fromDomain(intake);
    });
  }
}

Today materialization adapter

apps/api/src/nutrition/adapters/supplement-task-source.ts

ts
export class SupplementTaskSource {
  toDailyTaskInput(item: SupplementScheduleItem, occurrence: SupplementOccurrence): DailyTaskInput {
    return {
      relationshipId: item.relationshipId,
      localDate: occurrence.localDate,
      taskKind: "SUPPLEMENT",
      sourceContext: "Nutrition",
      sourceType: "SupplementScheduleItem",
      sourceId: item.id,
      sourceRevision: item.planVersion,
      sourceChildKey: occurrence.occurrenceKey,
      sourceKey: `${item.planVersion}:${item.scheduleKey}:${occurrence.occurrenceKey}`,
      sortKey: occurrence.sortKey,
      startsAt: occurrence.startsAt,
      dueAt: occurrence.dueAt,
      snapshot: item.toTodaySnapshot(occurrence),
      actionSchema: {
        offlineEligible: true,
        actions: ["TAKEN", "PARTIAL", "SKIP", "UNDO"],
        requiresDoseForPartial: true,
      },
    };
  }
}

Access policy

apps/api/src/nutrition/policies/supplement-schedule.policy.ts

ts
export class SupplementSchedulePolicy {
  assertCoachCanManageSchedule(actor: Actor, relationshipId: string): void {
    actor.requireRole("COACH");
    actor.requireCoachRelationshipAccess(relationshipId);
    actor.requirePermission("nutrition.plan.write");
  }

  assertClientCanRecord(
    actor: Actor,
    dailyLog: DailyNutritionLog,
    item: SupplementScheduleItem,
  ): void {
    actor.requireRole("CLIENT");
    actor.requireRelationshipParticipant(dailyLog.relationshipId);
    dailyLog.assertClientMutable();
    item.assertVisibleToClient();
    item.assertBelongsToRelationship(dailyLog.relationshipId);
  }

  assertCoachCanReadAdherence(actor: Actor, relationshipId: string): void {
    actor.requireRole("COACH");
    actor.requireCoachRelationshipAccess(relationshipId);
    actor.requirePermission("nutrition.log.read");
  }
}

Events & Background Jobs

Supplement events refresh Today tasks, reminders, adherence projections, and coach review signals.

Emitted Events

  • SupplementDefinitionCreated: updates workspace catalog search projections.
  • SupplementSchedulePublished: refreshes future Today supplement tasks and reminder schedules.
  • NutritionScheduleChanged: shared event for Today and Quick-log refresh when supplements change alongside meal plans.
  • SupplementIntakeRecorded: updates DailyExecution task state, adherence summaries, coach review, and mobile sync receipts.
  • SupplementIntakeCorrected: rebuilds daily adherence and emits a correction fact for audit and analytics.
  • SupplementAdherenceSummaryUpdated: feeds progress charts, risk flags, task inbox rules, and weekly recaps.

Jobs And Projectors

  • Rolling supplement materializer keeps today plus the configured future window ready for mobile prefetch.
  • Reminder scheduler creates or cancels notification jobs from published schedule snapshots and relationship timezone settings.
  • Missed supplement worker marks overdue occurrences after grace windows and skips dates with pending offline operations.
  • Adherence projector rebuilds daily summaries from active intake facts and the published schedule snapshot.
  • Repeated miss detector creates coach review signals only for coach-selected supplements or workspace rules.
  • Receipt retention job prunes mobile sync and reminder receipts after the configured retry and audit windows.

Permissions & Access Rules

Supplement data is relationship-scoped health behavior data and needs the same access discipline as food logs.

Client

  • Client can read only published supplement schedule snapshots visible to their own relationship.
  • Client can record, correct, or undo intake only until the coach reviews that nutrition day or 24 hours after submission, whichever comes first, and only for visible schedule items.
  • Client cannot create supplement definitions, change dose instructions, alter reminder policy beyond allowed snooze settings, or read hidden coach notes.
  • Client offline operations must include relationship id, device id, stable client operation id, occurrence key, and expected revision.

Coach And Support

  • Coach can create definitions, publish schedules, pause future items, and read adherence for relationships they manage.
  • Coach cannot rewrite accepted client intake history; corrections are explicit records with actor and reason metadata.
  • Coach mobile may support small schedule changes, but dense template authoring belongs to coach web for V1 baseline.
  • Support/admin access to raw supplement notes, rejected sync payloads, deleted definitions, or reminder receipts requires explicit permission and audited reason.

Web, Coach Mobile, Client Mobile

Coach surfaces emphasize schedule design and review; client mobile emphasizes low-friction completion with clear reminders and offline state.

Coach Web

  • Build supplement definitions, templates, relationship schedules, day-type variants, and reminder policies in the nutrition plan workflow.
  • Inspect schedule impact on Today tasks before publishing, including date ranges, dose windows, and notification previews.
  • Review daily and weekly adherence with filters for supplement, status, skip reason, day type, and repeated misses.
  • Adjust future schedules from review without mutating historical intake logs or completed Today snapshots.

Coach Mobile

  • Read compact supplement adherence summaries, repeated-miss flags, and client notes.
  • Pause or restart simple future schedule items when validation is clean and relationship permissions allow it.
  • Message the client or create follow-up tasks from missed, skipped, or needs-review occurrences.
  • Defer complex template editing, ingredient metadata, and multi-day schedule authoring to web.

Client Mobile

  • Today renders supplement tasks from SQLite first with dose, timing, meal relation, instructions, reminder state, and accepted or pending intake status.
  • Task controls support taken, partial, skip, note, and undo states with optimistic UI clearly distinct from accepted server state.
  • Push reminders deep link to the matching occurrence and avoid duplicate prompts after the occurrence is accepted or canceled.
  • Arabic/English labels, RTL ordering, dynamic type, dark mode, screen-reader status text, and long supplement names are required for V1 baseline parity.

Test Scenarios & V1 Baseline Decisions

Supplement schedules touch prescription versioning, reminders, offline sync, and adherence scoring, so regressions can create misleading coach feedback.

Tests

  • Domain unit tests: dose validation, cadence resolution, day-type filtering, occurrence key stability, partial-dose rules, skip policy, and reminder policy validation.
  • Versioning tests: schedule publish freezes snapshots, edits create replacement versions, future Today tasks refresh, and historical intake remains tied to the old schedule.
  • API integration tests: coach creates definition, publishes schedule, client fetches Today, records taken, retries the same operation, and receives one accepted intake log.
  • Offline sync tests: queued supplement intake survives app restart, duplicate client ids deduplicate, stale superseded occurrences return refetch hints, and accepted receipts reconcile task state.
  • Reminder tests: schedule changes cancel old notification jobs, quiet hours are respected, delivered reminders stop after accepted intake, and timezone changes rematerialize future occurrences.
  • Projection tests: daily adherence rebuild handles taken, partial, skipped, missed, corrected, and canceled occurrences without double counting.
  • Access tests: clients cannot record another relationship's supplement, coaches cannot publish outside their workspace, and support raw payload access is audited.
  • Mobile E2E tests: open Today offline, mark a supplement partial with note, reconnect, sync once, and verify coach adherence summary updates.
  • Localization and accessibility tests: Arabic/English supplement names, RTL task ordering, dynamic type, screen-reader labels for pending/syncing/accepted/rejected, and dark mode contrast.

Resolved V1 Baseline Decisions

  • Public V1 does not support client snooze or per-occurrence rescheduling. Clients can mark taken, partial, or skipped and manage notification preferences; reminder timing changes come from coach schedule edits, quiet hours, or user-level reminder windows.
  • Default missed grace is 4 hours after a timed dose window. All-day or no-time occurrences remain open until 06:00 the next local day, and the missed worker skips dates with pending offline intake operations.
  • Seed skip reasons are forgot, ran out/unavailable, travel/schedule, fasting or meal timing, side effects, health concern, chose not to take, and other. Side effects, health concern, chose not to take, ran out/unavailable for coach-selected supplements, and repeated skip or miss patterns create coach inbox review items.
  • Supplement nutrient facts contribute to tracked totals only for coach-marked nutrition-bearing products such as protein powder or meal replacements; creatine, magnesium, vitamins, and minerals remain adherence-only in Public V1.
  • After a relationship ends, clients retain read-only access to their own supplement intake history and client-visible schedule instructions during the 30-day ended-relationship retention and export window. Future reminders stop immediately, hidden coach notes never display, and cleanup follows CoachClientManagement purge or anonymization policy.
  • Coach mobile may publish simple supplement-only schedules when the compact flow can capture definition, dose, unit, cadence, timing, reminders, and client-visible instructions. Multi-supplement templates, day-type-heavy rules, nutrient-bearing configuration, and complex edits remain web-first in V1.

CoachMe internal planning documentation.