journeys night planning - fahadahmed/jamaal-app GitHub Wiki
Status: reshaped to the design's five steps โ draft, needs review. Review today โ Carry forward โ Build tomorrow โ Check the load โ Close the day. Session state machine and supporting models are in rules-engine.md (module 4).
A guided end-of-day flow: look back at the day, decide what happens to what's unfinished, build tomorrow around its fixed commitments, check the load, close the day. It's a state machine, and its session is persisted (synced via CloudKit), so closing the app mid-flow resumes at the same step โ even on another device.
On phone the five steps are five screens in a full-screen modal with a progress bar; Back is available from step 2 onward and Close is always available. On wide layouts (iPad, Mac, Duo unfolded) they are five stops on one canvas โ a step rail beside a working area โ so the user always sees where they are without losing the step they're on.
The five steps as designed:
![]() NP-01 review today |
![]() NP-02 carry forward |
![]() NP-03 build tomorrow |
![]() NP-04 check the load |
![]() NP-05 close the day |
The same flow as a state machine (with the skip and reopen paths) is in Diagrams; the wide iPad layout is in the Screen gallery.
- The fixed evening notification (user-set time, default 20:00), set up during onboarding.
- User-opened any time from Today.
- If notifications are denied: an in-app banner at planning time ("Start evening planning โ").
The plan is always for a specific date, shown at the top: the first date whose working-day start is still in the future. At 23:00 that is tomorrow; at 00:30 with a midnight rollover it is today's new date (the day the user is about to wake into), with yesterday as the day under review. Rules and edge cases: The day boundary.
What happened today, read-only: tasks completed vs. incomplete, habit windows completed / partial / missed (counted habits shown honestly, e.g. "2/3 water"), Anchor attendance, and time actually spent against what was estimated (from focus sessions), stated plainly with no praise or blame.
Nothing is asked of the user here: there is no mood line or other self-reporting. Wellbeing is derived from the behaviour this step shows.
On a user's first day the review is minimal (see app-flow.md).
Each incomplete task gets one of:
| Choice | Effect |
|---|---|
| Keep | Moves to tomorrow. Counts as a deferral (deferralCount += 1, DeferralRecord). |
| Later | Opens the date picker โ Later this week / Next week / Someday / a specific date. Counts as a deferral. Someday is hidden for medium/high tasks. |
| Drop |
droppedAt set. The task leaves Today for good; history is kept. |
From a task's 3rd deferral onwards, Keep also opens the date picker with reason chips (Too much on / Not ready / No longer relevant) and the companion says "This one keeps slipping. Pick a day that actually works." If the task was medium/high, it is first eased to low (and the companion says so), which also makes Someday available. From the 5th, the companion suggests dropping it. Choices apply immediately and are undoable until the day is closed.
The wide layout uses the same three choices per task โ leftovers are not silently sent to the backlog. Skipped automatically when there is nothing incomplete.
The step opens on the shape of tomorrow, before any task is offered:
- Tomorrow's working day (start to the day's end, default 19:00) with its fixed commitments drawn in โ recurring Anchors and one-offs, such as the school run or an appointment. An Add one-off Anchor action is available, since planning often surfaces "dentist at 3".
- The free gaps between them, named by what surrounds them: "before the school run ยท 2h 40m free", "between the school run and Maghrib ยท 3h 05m", "after Maghrib". With no fixed commitments the day is one gap. Edge rules: gaps under 20 minutes aren't shown (they still count as free time); a day that begins with a commitment has no "before" gap, and one that ends with a commitment has no "after" gap; names use the composed Anchor titles (Fajr, School run ยท Drop-off); the longest gap is the one used for fit checks. Phone shows the gaps as a list; wide layouts show a proportional timeline so the size of each gap is visible. Only commitments inside the working day count, so prayers after the day's end don't create gaps.
Below that are tomorrow's tasks and tomorrow's habits. Tasks can be pulled in (backlog and later-dated suggestions, which sets their due date to tomorrow) and pushed out (to a later date โ rescheduling, never a deferral), and a new task or one-off Anchor can be added, defaulting to tomorrow; tasks have no manual order. Habits are shown read-only: they are scheduled, not chosen (paused ones don't appear), and their minutes count in free time. Tasks are not assigned to gaps: they are a plain ordered list, and the planner flags any task that won't fit in any gap ("the 90-minute review is longer than tomorrow's longest gap"). It is a flag, never a block.
This is where importance gets set: each task starts at low and can be raised to medium or high; choosing medium or high reveals a due date pre-filled with tomorrow. If the plan has five or more tasks and fewer than two are medium/high, the companion prompts the user to pick one or two that matter most (a prompt, not a block). Suggested candidates come from the hidden Eisenhower lens โ important-but-not-urgent (schedule) tasks are surfaced, since this is the moment to schedule them.
Set tomorrow's capacity โ low / medium / high, pre-selected to that weekday's default; the choice is written to tomorrow's DayPlan the moment it is made, so it survives leaving the app mid-flow. The step shows what tomorrow leaves (total free time and the longest gap) and the engine may suggest a level ("about 2 hours free โ low might suit"); the user decides. It then shows budget used ("2h 15m of 3h", with the load state light / balanced / full / overloaded / exhausting) and, only when relevant, overflow past the day's end ("40 min past 19:00").
When the day is overfull the companion offers one specific move โ "Groceries could wait until Wednesday. Want me to move it?" โ with Move and Keep as planned. The suggestion is the lowest-ordered movable task (never a doFirst one) moved to the nearest of the next seven days whose load would stay under 100%; if none fits, the user is asked for a date. Move is rescheduling, not a deferral. Overflow is soft: named, never blocked, one tap to move. It only ever suggests deferring tasks (fixed commitments and habits can't be). If some items have no duration, a quiet note says how many. At most once in a while (never within 28 days of a "Not now") a single quiet line may offer to update the user's normal day from their actual focus time โ "You usually do about 2h 40m โ set your normal day to that?" Never blocks.
Locks tomorrow's plan, writes the DayPlan (capacity, planned task minutes, free minutes, load score) and schedules tomorrow's notifications. The done screen says plainly what was planned ("Tomorrow is ready. Three tasks, 3h exactly. Put the phone down."), with a plain count of nights planned (not a streak) and a "Good night" button.
- Starting: the evening notification, the banner, or the Plan tomorrow action in Today's toolbar (after Add). After the planning time, if tonight isn't planned or skipped, Today also shows a quiet row for it, and the all-done state carries the action.
-
Re-opening a night that already has a session resumes that session: a closed one reopens at Build so the user can adjust (re-closing rewrites the
DayPlansnapshot), and a skipped one clearsskippedAtand starts again at Review.
Skip tonight is available at every step. It closes the flow without a plan:
- A session left unfinished at the day rollover ends as skipped, so the morning card can offer the plan. Nothing is lost: incomplete dated tasks auto-defer at rollover as usual (see task.md), and carry-forward choices already made stay applied.
- No
DayPlanis written; tomorrow simply uses that weekday's default level (UserSettings.weekdayLevels; weekends arelow, other daysmediumunless changed). -
If no plan was confirmed for today, the morning list shows one quiet card โ "No plan for today โ two minutes to pick?" โ that opens a shortened flow for today: a session with
forDate = todaythat starts at Build, then Load, then Close (Review and Carry are skipped; the day's leftovers were already settled at rollover). No guilt, no missed-night count, no streak, and the card doesn't repeat if dismissed. - Tonight's prompt stops once that night is closed or skipped, and is never repeated; the banner on Today stays until it is planned or skipped.
review โ carry โ build โ load โ close, plus a skipped end state. Each step's answers persist as the user moves forward, so backing up doesn't lose data.
- Every step is required unless the whole night is skipped (above).
- Steps with nothing to do (no incomplete tasks in Carry forward) are passed through.
- Not doing Night Planning at all never loses a task.
- Late nights and rollover time โ resolved by the day boundary: the plan's target date is the first date whose working-day start is in the future, and a user-set rollover keeps a late evening on the same logical day. The one remaining edge is planning after a custom rollover has passed (say 03:30 with a 03:00 rollover): that counts as the new day, and the morning card path covers it.
- Undo scope: carry-forward choices are undoable until the day is closed; confirm this persists if the wizard is closed but not finished (it should โ they're already applied to tasks).




