Skip to content

DailyExecution / Client Mobile / Low-Friction Completion

Quick-log Daily Tasks turns Today items into fast, validated mobile actions.

The V1 baseline quick-log contract lets clients complete simple tasks, tick itemized meals and supplements, record lightweight values such as steps, and launch structured logging when a task requires richer data. It reduces daily friction without bypassing task ownership, offline sync rules, or coach-visible adherence history.

Tags: DailyExecution, Client mobile, Item-level completion, Offline outbox, Adherence facts

Boundary decision

Today View owns the dated task projection. Quick-log owns allowed action execution, item-level completion state, lightweight value capture, undo/skip semantics, and mobile operation receipts. Structured payloads still belong to their owning contexts, such as Workout Logging, Forms, Nutrition, Progress, and future integrations.

Note

Quick-log must never mark complex work complete just because the client tapped a button. The action schema decides whether the task can be completed directly, needs item-level values, or must open the owning feature screen.

Note

Quick-log operation payloads remain feature-specific, but device ids, client operation ids, receipts, replay, conflict categories, and local cache pruning follow the Offline Sync Protocol.

Quick-log Flows

The client interaction should feel instant while the backend remains idempotent, auditable, and source-aware.

Client Completes A Simple Task

  1. Client opens Today and sees a task with a quick action supplied by the task action schema.
  2. Client taps complete, skip, or undo from the task card or task detail screen.
  3. Client mobile writes an optimistic local operation with a stable client_operation_id, expected task revision, actor timestamp, and device id.
  4. When online, the API validates relationship access, task mutability, action eligibility, and expected revision before accepting the operation.
  5. Accepted operations update task state, item state if present, adherence events, Today counters, and coach summary projections.
  6. Rejected operations remain visible on the device with a clear reason and a refresh hint for the affected date.

Itemized Meals And Supplements

  1. Nutrition assignment events materialize a meal or supplement task with item rows and display snapshots.
  2. Client can tick individual items, untick within the configured undo window, or use complete-all when every item is eligible.
  3. Complete-all creates one parent operation and deterministic child item transitions, not multiple unrelated requests.
  4. Each item stores source keys, visible labels, completion timestamps, and whether completion came from an explicit tap or bulk action.
  5. Daily adherence can calculate partial completion from accepted item state rather than treating the whole meal block as binary.

Workout Quick Actions

  1. Workout tasks expose quick actions only through the Workout Logging adapter, because set rows, values, RPE/RIR, skips, and substitutions belong to workout execution.
  2. Client can tick a set or tick all only when required set values are already known, optional, or supplied by the action payload.
  3. If an exercise requires weight, reps, duration, distance, effort, or pain notes, the quick action opens the structured workout logger or displays the required inline fields.
  4. Accepted workout quick actions create or update a WorkoutSession revision and then update the matching Today task state.
  5. Quick-log never fabricates performance values for analytics, PR detection, or coach review.

Offline And Reconciliation

  1. Every tap writes to SQLite first and enters the mobile outbox with the action payload, task revision, and local sort timestamp.
  2. Today renders pending, syncing, accepted, rejected, and conflicted states separately so the client does not mistake a queued tap for accepted history.
  3. Bulk sync sends operations in client order, but the server validates each operation against canonical task revisions and source ownership.
  4. Server returns accepted receipts, rejected operation ids, updated item states, agenda version changes, and required refetch dates.
  5. Client keeps accepted receipts to make retries safe after crashes, app restarts, and weak-signal duplicate submits.

Domain Model

Quick-log belongs to DailyExecution and delegates structured details through explicit adapters.

Aggregates & Entities

  • DailyTaskInstance: parent task projected by Today View and mutated by accepted quick-log transitions when the action schema allows it.
  • DailyTaskCheckItem: itemized child for meals, supplements, habits, reminders, or other simple sub-tasks with source keys and display snapshots.
  • QuickLogOperation: append-only command record for one client action, including action kind, scope, payload, idempotency key, status, and validation result.
  • QuickLogValueEntry: normalized lightweight value capture for tasks such as manual steps, water, bodyweight prompts, or future simple metrics.
  • QuickLogReceipt: server receipt returned to mobile for accepted or rejected offline operations.
  • QuickLogAdapter: owning-context boundary that validates structured actions for workout, nutrition, form, progress, or integration-backed tasks.

Value Objects & Rules

  • QuickLogActionKind: COMPLETE_TASK, COMPLETE_ITEM, COMPLETE_ALL_ITEMS, RECORD_VALUE, SKIP, UNDO, OPEN_STRUCTURED_LOG.
  • CompletionScope: task-level, item-level, group-level, or owning-feature scope with a stable source reference.
  • InputRequirement: required fields, units, defaulting rules, validation range, and offline eligibility for a quick action.
  • BulkCompletionPolicy: controls whether complete-all is allowed, requires confirmation, applies existing values, or must open a detail screen.
  • UndoWindow: relationship and task-kind specific time window where a client action can be reversed by a compensating operation.
  • Every quick-log operation is idempotent by relationship, device id, and client operation id.
  • Task completion is derived from accepted item/value state and owning adapter receipts, not from optimistic client UI alone.
  • Undo and skip create new operations; they do not delete historical completion records.
ModelOwned ByImportant MethodsEmits
DailyTaskCheckItemDailyExecutionmaterializeFromSource(), complete(), skip(), undo(), refreshSnapshot()DailyTaskItemCompleted, DailyTaskItemSkipped
QuickLogOperationDailyExecutionaccept(), reject(), deduplicate(), toReceipt(), toAdherenceDelta()QuickLogOperationAccepted, QuickLogOperationRejected
QuickLogValueEntryDailyExecutionrecord(), validateUnit(), replaceByCorrection(), toProgressFact()QuickLogValueRecorded
QuickLogAdapterOwning context boundarycanApply(), validatePayload(), apply(), summarizeResult()Context-specific accepted or rejected events.

Table Structure

Persist item state, operations, and lightweight values separately from Today projection metadata.

TablePurposeImportant ColumnsConstraints & Indexes
daily_task_check_itemsItemized child rows for quick-log eligible tasks.id, daily_task_instance_id, relationship_id, local_date, item_kind, source_context, source_id, source_item_key, sort_order, label_snapshot jsonb, input_schema jsonb, status, completion_source, completed_at, skipped_at, latest_operation_idUnique (daily_task_instance_id, source_item_key); index (relationship_id, local_date, status); preserve snapshots after completion.
quick_log_operationsAppend-only server record for every accepted or rejected quick action.id, workspace_id, relationship_id, daily_task_instance_id, daily_task_check_item_id, device_id, client_operation_id, action_kind, scope, expected_task_revision, payload jsonb, operation_status, rejection_reason, actor_user_id, client_recorded_at, accepted_atUnique (relationship_id, device_id, client_operation_id); index (daily_task_instance_id, accepted_at desc); append-only except receipt metadata.
quick_log_value_entriesLightweight metric values captured directly from quick-log actions.id, quick_log_operation_id, relationship_id, daily_task_instance_id, metric_kind, value_numeric, unit, value_text, source_type, source_device_id, recorded_at, superseded_by_entry_idIndex (relationship_id, metric_kind, recorded_at desc); corrections supersede rather than update the prior row.
quick_log_sync_receiptsCompact receipts returned to mobile for replay-safe reconciliation.id, relationship_id, device_id, client_operation_id, quick_log_operation_id, accepted_task_revision, accepted_item_revision, receipt_status, agenda_refresh_date, created_atUnique (relationship_id, device_id, client_operation_id); supports idempotent retry and offline refetch hints.
quick_log_adherence_deltasNormalized deltas consumed by daily adherence projections.id, quick_log_operation_id, relationship_id, local_date, task_kind, delta_type, score_delta, metadata jsonb, created_atUnique (quick_log_operation_id, delta_type); index (relationship_id, local_date desc).

Note

Client SQLite mirrors daily task item rows, current item states, queued quick-log operations, sync receipts, and compact action schemas. Server PostgreSQL remains canonical after an operation is accepted.

Action Schemas

Each Today task exposes only the quick actions that are valid for that task kind, source snapshot, and offline state.

Task TypeAllowed Quick ActionsRequired ValidationOwning Boundary
Meal taskComplete meal item, complete all eligible meals, undo, skip with reason.Meal item exists in active snapshot, item is mutable, complete-all does not include blocked items, optional note length.Nutrition supplies meal source snapshots; DailyExecution stores completion state.
Supplement taskComplete item, complete all, undo, skip.Supplement schedule item exists, dosage label snapshot is preserved, skip reason policy is satisfied.Nutrition supplies schedule; DailyExecution records daily execution.
Workout taskOpen logger, complete set, tick all eligible sets, undo within workout policy.Workout snapshot checksum, set value requirements, exercise modality, RPE/RIR requirement, substitution and skip policy.Workout Logging adapter owns session/set mutation.
Check-in or form taskOpen form, mark started, complete only when no answers are required.Published form version, required fields, submission state, due window.Forms owns answers and submission; DailyExecution records task state.
Steps or simple metricRecord value, replace latest manual value, undo correction, open detail history.Metric kind, unit, min/max range, source precedence against imported values, duplicate timestamp rules.DailyExecution for V1 baseline manual values; Integrations or Progress can consume facts later.
Reminder or habitComplete, skip, undo, snooze if configured.Reminder is actionable by client, due window, snooze limit, coach visibility policy.DailyExecution unless reminder was created by another owning context.

Note

The mobile UI renders from action schemas rather than hardcoding task kinds. A future task type can become quick-log eligible by exposing a validated action schema and adapter contract.

API Contracts

Endpoints optimize for one-tap mobile actions, explicit validation errors, and replay-safe offline sync.

EndpointPurposeRequestResponse
GET /api/v1/client/today?date=YYYY-MM-DDReturn tasks with quick-log action schemas and compact item rows.Local date, timezone, optional agenda checksum, optional item cursor.Task list, item summaries, allowed quick actions, offline cache hints, sync cursor.
GET /api/v1/client/quick-log/tasks/{taskId}Fetch full quick-log state for one task.Task id, optional cached task revision.Task, item rows, action schema, validation requirements, latest receipts.
POST /api/v1/client/quick-log/tasks/{taskId}/actionsApply one online quick-log action.Device id, client operation id, action kind, scope, payload, expected task revision, client recorded at.Accepted or rejected operation, task/item state, adherence summary, updated agenda counters, receipt.
POST /api/v1/client/quick-log/tasks/{taskId}/complete-allConvenience endpoint for eligible bulk completion.Device id, client operation id, expected task revision, optional values, confirmation flag.Accepted child transitions, skipped ineligible items, task completion summary, receipt.
POST /api/v1/client/quick-log/tasks/{taskId}/valuesRecord a simple metric value.Device id, client operation id, metric kind, value, unit, source type, recorded at.Accepted value entry, task state effect, progress/adherence hints, receipt.
POST /api/v1/client/quick-log/syncBulk sync offline quick-log operations.Device id, ordered operations, client operation ids, expected revisions, action payloads.Accepted operations, rejected operations, latest task/item states, receipts, refetch date hints.
GET /api/v1/coach/relationships/{relationshipId}/quick-logCoach reads quick-log history for review surfaces.Date range, task kind, status, item filter, pagination cursor.Operation summaries, item completion state, simple metric values, adherence deltas.

Key Code Snippets

Implementation sketches define the action contract, server use case, mobile outbox shape, and access policy.

Action schema contract

packages/contracts/src/daily-execution/quick-log.ts

ts
export type QuickLogActionKind =
  | "COMPLETE_TASK"
  | "COMPLETE_ITEM"
  | "COMPLETE_ALL_ITEMS"
  | "RECORD_VALUE"
  | "SKIP"
  | "UNDO"
  | "OPEN_STRUCTURED_LOG";

export interface QuickLogActionSchema {
  taskId: string;
  taskRevision: number;
  taskKind: TaskKind;
  offlineEligible: boolean;
  actions: Array<{
    kind: QuickLogActionKind;
    scope: "TASK" | "ITEM" | "GROUP" | "OWNING_FEATURE";
    requiresConfirmation?: boolean;
    requiresStructuredScreen?: boolean;
    requiredInputs: Array<{
      key: string;
      type: "number" | "text" | "choice" | "boolean";
      unit?: string;
      min?: number;
      max?: number;
      required: boolean;
    }>;
  }>;
}

Apply operation use case

apps/api/src/daily-execution/use-cases/apply-quick-log-operation.ts

ts
@Injectable()
export class ApplyQuickLogOperationUseCase {
  constructor(
    private readonly tasks: DailyTaskInstanceRepository,
    private readonly quickLogs: QuickLogOperationRepository,
    private readonly adapters: QuickLogAdapterRegistry,
    private readonly policy: QuickLogPolicy,
    private readonly tx: TransactionRunner,
    private readonly outbox: OutboxPort,
  ) {}

  async execute(command: QuickLogCommand, actor: Actor): Promise<QuickLogResultDto> {
    return this.tx.run(async () => {
      const duplicate = await this.quickLogs.findByClientOperation(command.idempotencyKey());
      if (duplicate) return QuickLogResultDto.fromOperation(duplicate);

      const task = await this.tasks.getForUpdate(command.taskId);
      this.policy.assertClientCanApply(actor, task, command);
      task.assertExpectedRevision(command.expectedTaskRevision);

      const adapter = this.adapters.forTask(task.taskKind);
      const result = await adapter.apply(task, command);

      const operation = QuickLogOperation.accept(command, result);
      await this.quickLogs.save(operation);
      await this.tasks.save(result.task);
      await this.outbox.publish(operation.pullDomainEvents());

      return QuickLogResultDto.fromOperation(operation);
    });
  }
}

Mobile outbox shape

apps/client-mobile/src/daily-execution/quick-log-outbox.ts

ts
export interface PendingQuickLogOperation {
  clientOperationId: string;
  deviceId: string;
  relationshipId: string;
  taskId: string;
  itemId?: string;
  actionKind: QuickLogActionKind;
  expectedTaskRevision: number;
  payload: Record<string, unknown>;
  localStatus: "QUEUED" | "SYNCING" | "ACCEPTED" | "REJECTED" | "CONFLICTED";
  clientRecordedAt: string;
  lastSyncAttemptAt?: string;
}

Access policy

apps/api/src/daily-execution/policies/quick-log.policy.ts

ts
export class QuickLogPolicy {
  assertClientCanApply(actor: Actor, task: DailyTaskInstance, command: QuickLogCommand): void {
    actor.requireRole("CLIENT");
    actor.requireRelationshipParticipant(task.relationshipId);
    task.assertClientMutable();
    task.assertActionAllowed(command.actionKind, command.scope);
  }

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

Events & Background Jobs

Quick-log consumes materialized task state and emits normalized completion/value facts.

Consumed Events

  • DailyTaskMaterialized creates or refreshes quick-log item rows when the task source exposes itemized actions.
  • MealPlanAssigned and NutritionScheduleChanged refresh meal and supplement quick-log eligibility for future dates.
  • WorkoutTaskMaterialized exposes workout quick actions through the Workout Logging adapter.
  • FormAssigned and CheckInScheduled expose open-form or no-payload completion actions.
  • StepsImported or future wearable events reconcile imported values against manual quick-log values by source precedence.

Emitted Events And Jobs

  • QuickLogOperationAccepted: updates task/item projections, mobile receipts, and Today agenda versions.
  • QuickLogOperationRejected: creates a receipt with reason and refetch hints without mutating accepted state.
  • DailyTaskItemCompleted: feeds itemized adherence, coach summaries, and client streak calculations.
  • QuickLogValueRecorded: feeds simple progress facts and future integration reconciliation.
  • Receipt pruning job keeps mobile receipts for the configured offline retry window and archives older rows by relationship retention policy.
  • Adherence projection job rebuilds daily summaries from accepted operations and owning-context completion events.

Permissions & Access Rules

Quick-log can expose nutrition, training, health, and coaching adherence data, so every operation stays relationship-scoped.

Client

  • Client can quick-log only active or historically mutable tasks for relationships where they are the participant.
  • Client cannot quick-complete a task when the action schema requires a structured payload that has not been supplied.
  • Client can sync offline operations only from registered devices with stable operation ids and expected revisions.
  • Client undo is allowed only inside the action-specific undo window and creates a compensating operation.

Coach And Support

  • Coach can read quick-log history and item completion for relationships they are authorized to manage.
  • Coach cannot mutate client quick-log rows directly; they change assignments, schedules, reminders, or review notes through owning contexts.
  • Support/admin access to raw payloads, rejected operations, and receipt tables requires explicit permission and an audited reason.
  • Ended relationships follow CoachClientManagement visibility and retention rules before any quick-log history is hidden or anonymized.

Web, Coach Mobile, Client Mobile

Quick-log is client-mobile-first, with coach surfaces focused on review and exceptions.

Coach Web

  • Client profile and timeline show item completion, skipped reasons, manual values, and rejected/conflicted operations when relevant.
  • Dashboard cards use accepted adherence facts rather than optimistic mobile state.
  • Nutrition, workout, and form review screens link back to the source task and accepted quick-log operation where useful.

Coach Mobile

  • Coach mobile sees compact daily completion and missed/skipped exceptions for quick review.
  • Push or inbox follow-ups can be created from repeated skips, conflicts, or low adherence patterns.
  • Coach mobile does not expose direct controls for changing client quick-log history in Public V1.

Client Mobile

  • Quick-log controls appear on Today cards and task-specific screens only when the action schema permits them.
  • Tap targets must be large, optimistic state must be visually distinct from accepted state, and errors must keep the client's last input recoverable.
  • Bulk actions require confirmation when they could affect workouts, many items, or any value-bearing task.
  • The UI supports Arabic/English, RTL, dynamic type, dark mode, accessible labels, and offline status announcements.

Test Scenarios & Resolved Decisions

Quick-log needs strong coverage because it turns casual taps into source-of-truth adherence data.

Tests

  • Domain unit tests: action eligibility, complete-all policy, item state transitions, undo windows, skips, value validation, and idempotent operation replay.
  • API integration tests: duplicate client operation returns the same receipt, stale revisions reject cleanly, rejected operations do not mutate task state, and adherence deltas emit once.
  • Adapter contract tests: workout quick actions cannot omit required values, forms require submissions, nutrition item keys must match source snapshots.
  • Offline sync tests: queued operations survive app restart, conflicting task revisions request refetch, accepted receipts reconcile optimistic item state, and retries are safe.
  • Mobile E2E tests: complete a meal item offline, complete all eligible supplements, record manual steps, reconnect, sync once, and see coach summary update.
  • Localization tests: Arabic/English action labels, RTL item ordering, dynamic type, screen-reader labels for pending/syncing/accepted/rejected, and dark mode contrast.

Resolved V1 Baseline Decisions

  • Undo windows are source-aware and correction-only after the window closes. Pending offline operations can be canceled or replaced before sync. Accepted meal, supplement, habit, reminder, and simple metric quick-log actions can be undone until the coach reviews the relevant day or 24 hours after the accepted operation, whichever comes first. Workout quick actions follow Workout Logging policy: the client can correct the submitted workout until the end of the same local day, and coach-reviewed workouts become correction-request or clarification flows rather than direct undo. All undo actions create compensating operations and never delete historical records.
  • Workout tick-all requires confirmation for V1 baseline. Any workout COMPLETE_ALL_ITEMS action at exercise or session scope sets BulkCompletionPolicy.requiresConfirmation=true. The confirmation must summarize how many sets will change and call out value-bearing, PR-eligible, RPE/RIR, pain-note, substitution, or skip effects. Single set completion remains a direct item action when the adapter says required values are already present; bulk workout completion does not use a hidden threshold in Public V1.
  • Manual steps are the V1 baseline fallback; verified imports win later without double counting. Quick-log stores manual step values with source type, source device, local date, recorded timestamp, and supersession metadata. Before integrations, the latest accepted manual value is the daily step fact. Once Apple Health, Google Fit, or wearable imports exist, the canonical daily step total uses source precedence: verified imported daily aggregates replace manual totals for the same local date, manual rows remain visible as client-entered history, and the system never adds manual and imported steps together. Explicit manual correction of an imported total belongs in the future Progress or Integrations detail flow, not the quick-log button.
  • Ad hoc items stay in the owning feature, not Quick-log. Quick-log cannot create unplanned meals, foods, exercises, supplements, or source records in Public V1. It may deep link to Nutrition for unplanned food or meal logging, Workout Logging for extra sets on assigned exercises or approved alternatives, and other owning screens for rich capture. After the owning feature accepts and publishes the source fact, Today and Quick-log can refresh the visible task, timeline, or adherence summary.
  • Skipped reasons route only actionable exceptions into coach inbox. V1 baseline seed reasons are PAIN_OR_INJURY, ILLNESS, SIDE_EFFECT, FOOD_UNAVAILABLE, EQUIPMENT_UNAVAILABLE, PLAN_TOO_HARD, CONFUSED, REQUEST_HELP, BUSY, FORGOT, TRAVEL, NOT_HUNGRY, ALREADY_DONE_OUTSIDE_APP, and OTHER. Pain, injury, illness, side effect, confusion, and request-help reasons create or refresh one open coach inbox task immediately after backend acceptance. Food or equipment unavailable and plan-too-hard create or refresh a task after two occurrences in seven local days, unless the client adds a help note. Busy, forgot, travel, not hungry, already-done-outside-app, and other remain timeline/adherence facts unless repeated three times in seven local days. Dedupe uses one rolling open task per relationship, reason group, and source context, refreshing severity and latest occurrence instead of creating one task per skip.

Open Decisions

Open Decision

Whether values from the first set should auto-fill later sets remains open.

CoachMe internal planning documentation.