Gratitude Field

Gratitude Field gives you one job: find something good today. That's it. Do it every day and your brain starts doing it automatically. Toby is your accountability partner. He's very serious about this.

Complete Logging Flow

One gratitude per day. One tag per day. Small actions, cosmic ripples.

Home (ready to log)
tap i
Info Sheet
Log it (empty)
Error: Empty
Log it (<3 chars)
Error: Too Short
Log it (3+ chars)
Success
Tag a Friend
Already Tagged
Return same day (already logged)
Already Logged (Return State)

Home: Ready to Log

The default landing state. Users can only log once per day -- on load the app reads lastGratitudeMillis to decide which state to show. If they haven't logged today, this is where they land.

Home Page Page
🐶 Toby: Idle / curious
👆
Tap i button
Info sheet slides up (Screen 0)
👆
Tap "Log it" with empty field
Error state: Empty (Screen 1a). Input highlights red, error message appears.
👆
Tap "Log it" with 1-2 characters
Error state: Too Short (Screen 1b). Input highlights red, error message appears.
👆
Tap "Log it" with 3+ characters
Success! Transitions to Screen 2. Gratitude is saved, streak increments.
DB Annotation 📦 DB: reads Users.lastGratitudeMillis on load → determines which home state to show

Info Sheet

Triggered by tapping the (i) button. A purely informational overlay -- no data is read or written. Dismisses by tapping outside or dragging down.

Info Sheet Sheet
🌙 Visual: Moon/planet illustration
👆
Tap outside sheet or drag down
Dismisses sheet, returns to home

Error: Empty Input

Client-side validation only. No data is written. The error clears as soon as the user starts typing.

Error State: Empty Error
🐶 Toby: Idle (unimpressed blink)
You didn't type anything. Toby blinks at you.

Everything else stays the same. User can keep typing and resubmit.

✏️
User types in field
Error clears. Input border returns to normal. Can resubmit.

Error: Too Short

Same as above. Minimum length is 3 characters. Two separate error states exist so the message can be specific.

Error State: Too Short Error
🐶 Toby: Idle (slight tilt)
Tell us more. At least 3 characters.

Everything else stays the same. User can keep typing and resubmit.

✏️
User types in field
Error clears. Input border returns to normal. Can resubmit.

Success: Just Logged

Shown immediately after a successful log. Streak increments, gratitude is written to Firestore. The milestone message rotates based on streak count.

Success Page Page
🐕 Toby: Happy / celebrate
StreakMessage
Days 1-3Day [X]. Toby's watching. Keep it up.
Days 4-6You're on a roll. Toby tilts his head, curious.
Day 7Seven days. Toby does a slow barrel roll in approval.
Day 14Two weeks. Even Toby's raising an eyebrow now.
Day 30A full month. Toby removes his helmet in respect. (He puts it back on immediately.)
Day 100100 days. Toby has no words. Just vibes.

For the spec demo, streak starts at 1 and increments each time the demo is "logged."

👆
Tap "Tag a friend"
Tag a Friend sheet opens (Screen 3)
🔀
User already tagged today and returns
Shows Screen 4 (Already Tagged) instead
DB Annotation 📦 DB writes on successful log: Gratitudes collection → new document (gratitudeText, authorId, authorName, createdAt, chainId) Users collection → lastGratitudeMillis = now, streak++, longestStreak (if new high)

Tag a Friend Sheet

One tag per day. The availability logic is real -- a user can only be tagged if they haven't logged today and have no pending chain. Jamie Lee is hardcoded as unavailable in this demo to show the logic.

Tag a Friend Sheet
🐶 Toby: Idle (patient, waiting)
NameAvatarStatus
Casey JordanProfile photoAvailable. Tag button
Jamie LeeProfile photo (greyed)Not available. Not available label, greyed out
River SmithEmpty avatar circleAvailable. Tag button
Dakota JonesProfile photoAvailable. Tag button
Marcus T.Profile photoAvailable. Tag button

Jamie Lee is intentionally unavailable. They've already logged or been tagged today. This demonstrates the availability logic.

👆
Tap "Why are some people not available? i"
Inline tooltip bubble appears below the link
👆
Tap anywhere else
Tooltip dismisses
👆
Tap "Tag" next to available name
Snackbar + sheet closes → Already Tagged state (Screen 4)
Drag sheet down or tap outside
Sheet dismisses, back to Success screen
Toby sent the signal. [Friend Name] has 24 hours to respond.
DB Annotation (search/load) 📦 DB: real app queries Users collection, filters by displayName Excludes current user Greyed out when: lastGratitudeMillis = today OR pendingChainId exists Spec: hardcoded list, Jamie Lee hardcoded as unavailable
DB Annotation (on tag) 📦 DB writes on tag: Gratitudes doc → taggedFriendUserId, taggedUserName, expiresAt (now + 24h), chainStatus = "waiting" Chains doc → currentTaggedUserId, currentTaggedUserName, expiresAt, isActive = true Friend's Users doc → pendingChainId, pendingChainExpiresAt (now + 24h) Current user's Users doc → lastTaggedMillis = now

Already Tagged

The resting state for the remainder of the day after tagging. No further actions available until midnight resets the clock.

Already Tagged State
🐾 Toby: Content / satisfied
🔀
This is the resting state
No interactions. User is done for the day.
DB Annotation 📦 DB: reads Users.lastTaggedMillis on load → if today, shows this state instead of Tag CTA

Already Logged (Return State)

Shown when the user opens the app after already logging today. Input is hidden. Tag CTA shows if they haven't tagged yet, Already Tagged copy shows if they have.

Return State State
🐕 Toby: Happy / celebrate (same as success)
🔀
Haven't tagged yet
"Tag a friend" button is visible. Tapping opens Screen 3.
🔀
Already tagged
Shows Already Tagged body copy. No CTA button.
DB Annotation 📦 DB: on app load, reads Users.lastGratitudeMillis → if today, skips input and shows this state

Interaction Summary

Complete map of user actions, screen results, and database operations across the logging flow.

User ActionResultDB Operation
Open app, not logged todayScreen 1: Ready to logread lastGratitudeMillis
Open app, already logged, not taggedScreen 5 with Tag CTAread lastGratitudeMillis, lastTaggedMillis
Open app, already logged + taggedScreen 4: Already taggedread lastGratitudeMillis, lastTaggedMillis
Tap i on homeScreen 0: Info sheet slides upNo DB
Dismiss info sheetReturns to homeNo DB
Tap Log it, empty fieldError 1a, stay on Screen 1No write
Tap Log it, 1-2 charsError 1b, stay on Screen 1No write
Tap Log it, 3+ charsScreen 2: Successwrite Gratitudes + Users
Tap Tag a FriendSheet opens (Screen 3)read Users for search
Tap "Why not available?"Inline tooltip appearsNo DB
Tap Tag on available friendSnackbar + Screen 4write Gratitudes, Chains, Users (x2)
StateWhen UsedDescription
Idle / curiousHome, Tag sheetFloating, blinking, looking around
Happy / celebrateSuccess, Already loggedSubtle bounce or slow spin
Content / satisfiedAlready taggedStill, calm, done for the day