Skip to content

UX Definitions

What is this?

The presentation rules that govern the user's view, including the "4 AM Rule" for time boundaries and the dynamic grouping of meals into time blocks.

This document defines the User Experience (UX) rules and Presentation Logic that govern how data is displayed to the user. These are distinct from the Data Model (how data is stored) but must be consistent with it.


1. Time Domains & The "User Day"

While the Data Model defines the "User Day" (04:00 AM - 04:00 AM) for storage and aggregation, the UX layer interprets this for display.

The "4 AM Rule" (Display)

  • Logic: Any activity between 00:00 and 03:59 belongs to the previous calendar day.
  • Example: A snack at 2 AM on Tuesday is displayed as "Monday Night" (or just part of Monday's list).
  • Date Selector: When a user selects a date, they are selecting a "User Day".
    • Selecting "Jan 5" means viewing the range Jan 5 04:00 to Jan 6 04:00.

2. Meal Grouping (Breakfast / Lunch / Dinner)

To structure the daily feed, meals are grouped into three fixed time blocks based on their time relative to the User Day.

Time Blocks

These blocks are purely presentational.

Period Start Time (Local) End Time (Local) Note
Breakfast 04:00 11:30 Starts at the "User Day" boundary.
Lunch 11:30 17:00
Dinner 17:00 04:00 (+1) Extends into the next calendar morning.

Empty States

  • Behavior: If a time block contains no meals, it is still rendered (or a placeholder is shown) to give the user a sense of the day's structure.
  • Visual: "Nothing logged" or a subtle dash.

3. Date & Time Selection

Default State ("Now")

  • Behavior: The meal logger defaults to "Now".
  • Logic: The timestamp is generated at the moment of submission.
  • Indicator: A "Clock" icon or text indicating live mode.

Manual Selection

  • Behavior: Users can select a specific past or future time.
  • Granularity: Date + Time (e.g., "Jan 4, 12:30 PM").
  • Reset: A clear action must exist to return to "Now" mode.

Timestamp Persistence

  • Submission: The selected timestamp is passed explicitly to the backend.
  • Aggregation: The backend calculates the UserDate based on this timestamp, ensuring it falls into the correct "User Day" bucket (respecting the 4 AM rule).

Relog Behavior

  • Intent: Relogging is treated as a new log event, not a replay of the original timestamp.
  • Default: When a user clicks Relog and confirms without selecting a time, the meal is logged at the current submission time ("Now").
  • Override: If the user selects a manual timestamp before confirming, that explicit timestamp is used.
  • Scope Note: This relog rule is specific to the relog UX flow. Explicitly backdated JSON/log payloads may still carry createdAt and should be honored when the user is intentionally importing historical entries.

4. Daily Totals Hierarchy & Nutrient Display

Primary vs Secondary Signal

The Daily Totals tracker is explicitly hierarchical:

  • Primary (always expanded): Calories.
    • Full label and value/target are always visible.
    • This row is visually emphasized and intended to be the first-read metric.
  • Secondary: Protein, Carbs, Fat, and extended nutrients.
    • These rows provide supporting context and must not visually compete with calories.

Secondary Compact Mode

  • Default state: Expanded (secondary rows show labels and numeric values).
  • Controls: Two independent compact toggles are displayed in the Daily Totals header near settings:
    • Compact macros: Protein, Carbs, Fat.
    • Compact nutrients: Extended nutrients from the registry.
  • Collapsed behavior (for whichever group is compacted):
    • Bars remain visible (color + progress preserved).
    • Labels and numeric text are hidden.
    • Rows collapse to a dense, no-gap stack for quick visual scanning.
    • Expand/collapse transitions animate to reduce layout jank.
  • Bar style: Daily Totals bars are rounded in expanded mode. When a section is collapsed, only those compact bars switch to a right-angled edge.
  • Persistence: Preferences are stored per user scope in local storage:
    • daily_totals_macro_compact_v1:<scope>
    • daily_totals_extended_compact_v1:<scope>

Extended Nutrient Inclusion Rules

  • Extended nutrients render when either condition is true:
    • The nutrient is ACTIVE in the registry.
    • The nutrient has a non-zero total for the selected day.
  • Archived nutrients with non-zero totals remain visible for historical context and are visually muted with an (Archived) label suffix.

5. First-Log Journey (Onboarding)

To achieve "Friction Zero" retention, the journey from landing to value must be instantaneous.

The "Try Before You Buy" Flow

  1. Landing Page: Clear value prop with a "Start Logging Now" (Guest Mode) button.
  2. Instant Access: No account required. The dashboard loads immediately in "Guest Mode" (IndexedDB storage).
  3. The "Aha!" Moment: User logs their first meal via AI or Paste.
  4. Soft Registration:
    • After the first meal is logged, a subtle "Save your progress" banner or toast appears.
    • User continues to log.
    • Hard Trigger: If the user attempts to log from a different device OR has > 10 meals, emphasize the importance of Cloud Sync.

Promotion UX (Guest -> Cloud)

  • New User (Sign Up): Silent Sync. Guest data is automatically promoted to the new cloud account without interrupting the flow.
  • Returning User (Log In): Confirmation Sync. If the cloud account already has data, a ConfirmationModal asks to "Merge" or "Discard" the local guest session.
  • Visual Feedback: A "Migrating..." indicator is shown if the sync takes > 200ms.