Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ Internal documentation for engineers and agents working in the Compass repo.
- Event shape or recurrence behavior: [Event Domain Model](./architecture/event-domain-model.md), [Common Change Recipes](./development/common-change-recipes.md#change-recurring-event-behavior)
- Event caching, reads, or optimistic writes: [Event Caching](./frontend/event-caching.md)
- Dragging/resizing events on the week grid: [Week Drag Interaction](./frontend/week-drag-interaction.md)
- Keyboard shortcuts, event jump, or Hardcore Mode: [Shortcuts](./acceptance/shortcuts.md), [Feature File Map](./development/feature-file-map.md#keyboard-shortcuts)
- Welcome, Shortcut Showcase, or onboarding checklist: [Feature File Map](./development/feature-file-map.md#welcome-showcase-and-checklist), [Frontend Runtime Flow](./frontend/frontend-runtime-flow.md#welcome-showcase-and-checklist)
- Breakpoints, sidebar collapse, or layout at different viewport sizes: [Responsive Layout](./frontend/responsive-layout.md)
- Local-first or storage behavior: [Offline Storage And Migrations](./features/offline-storage-and-migrations.md)
- Backend routes and API behavior: [Backend Route Map](./backend/README.md), [Backend Request Flow](./backend/backend-request-flow.md), [Backend Error Handling](./backend/backend-error-handling.md)
Expand Down
61 changes: 46 additions & 15 deletions docs/acceptance/shortcuts.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,13 @@ Use this guide to validate:
- navigating between views with the keyboard (D, W)
- navigating between days in Day view (J, K, T)
- navigating between weeks in Week view (J, K, T)
- opening and using the command palette (Cmd+K)
- opening and using the command palette (Cmd+K), including undo/redo rows
- creating events with keyboard shortcuts (C, A in both Day and Week view)
- editing events with the same keys in Day and Week (Delete, Shift+arrows, draft arrows)
- focusing events with arrow keys (chronological in Day, spatial in Week)
- toggling event-jump chips (`S`) and Hardcore Mode (`H`)
- toggling the sidebar (])
- undoing with the keyboard (Cmd+Z / Ctrl+Z)
- undoing / redoing with the keyboard (Cmd+Z / Cmd+Shift+Z)
- confirming that shortcuts do not fire while typing in inputs

Do not use this guide to validate:
Expand Down Expand Up @@ -50,19 +52,20 @@ Helpful notes:
| `W` | Global | Navigate to Week view |
| `Cmd+K` / `Ctrl+K` | Global | Open command palette |
| `]` | Global | Toggle sidebar |
| `?` | Global | Toggle shortcuts legend |
| `Cmd+Z` / `Ctrl+Z` | Global | Undo last event action |
| `Cmd+Shift+Z` / `Ctrl+Shift+Z` | Global | Redo last undone event action |
| `H` | Global | Toggle Hardcore Mode |
| `J` | Day view | Previous day |
| `K` | Day view | Next day |
| `T` | Day view | Go to today |
| `I` | Day view | Focus sidebar |
| `U` | Day view | Focus first calendar event |
| `S` | Day view | Toggle event jump keys |
| `H` | Day view | Toggle Hardcore Mode |
| `S` | Day view | Toggle event jump keys |
| `C` | Day view | Create timed event |
| `A` | Day view | Create all-day event |
| `Delete` | Day view | Delete focused event |
| `ArrowUp` / `ArrowDown` | Day view | Focus previous/next event |
| `ArrowUp` / `ArrowDown` / `ArrowLeft` / `ArrowRight` | Day view | Focus previous/next event chronologically |
| `Arrow keys` | Day view | Move open draft event |
| `Enter` | Day view | Open focused event |
| `E` then `T` | Day view | Edit focused event title |
Expand All @@ -83,10 +86,10 @@ Helpful notes:
| `A` | Week view | Create all-day event |
| `I` | Week view | Focus sidebar |
| `U` | Week view | Focus first calendar event |
| `S` | Week view | Toggle event jump keys |
| `H` | Week view | Toggle Hardcore Mode |
| `S` | Week view | Toggle event jump keys |
| `Delete` | Week view | Delete focused event |
| `ArrowUp` / `ArrowDown` | Week view | Focus previous/next event |
| `ArrowUp` / `ArrowDown` | Week view | Focus previous/next event on the same day |
| `ArrowLeft` / `ArrowRight` | Week view | Focus time-nearest event on previous/next non-empty day |
| `Arrow keys` | Week view | Move open draft event |
| `Enter` | Week view | Open focused event |
| `E` then `T` | Week view | Edit focused event title |
Expand Down Expand Up @@ -180,16 +183,17 @@ Pressing Cmd+K opens the command palette from any view, including while a text i
2. Press Cmd+K (or Ctrl+K on Windows).
3. Observe the palette contents.
4. Use the search/filter to type "event".
5. Select "Create Event" from the palette.
5. Select "Create event" from the palette.
6. Press Cmd+K again and then Escape.

### Expected Results

- The command palette opens immediately.
- Items include: Create Event, Create All-Day Event, Go to Today, Log Out.
- Items include: Create event, Create all-day event, Go to Today, Toggle Hardcore Mode, Practice shortcuts, Show welcome guide, Undo last change, Redo last change, Log Out.
- Undo / Redo rows show their keycaps and stay disabled when there is no history.
- Google Calendar connection status and actions appear in the sidebar, not the command palette.
- Typing filters the list.
- Selecting "Create Event" opens the event creation form.
- Selecting "Create event" opens the event creation form.
- Pressing Escape closes the palette without taking action.
- Cmd+K works even when a text input elsewhere has focus.

Expand Down Expand Up @@ -360,7 +364,33 @@ Pressing `S` shows event-jump chips. Week view chips use day prefixes (`SU`/`M`/

---

## Scenario 13: Shortcuts Do Not Fire While Typing In Inputs
## Scenario 13: H Enters Hardcore Mode

### UX

Bare `H` toggles Hardcore Mode (keyboard-only). While active, pointer clicks are blocked (scroll and hover still work) so the user practices keyboard navigation. A persistent “Hardcore Mode · Esc” indicator shows how to exit. Mode is not persisted across refresh. Shift alone does not enter this mode.

### Steps

1. Navigate to `/week` with at least one event visible.
2. Press `H` (not a chord).
3. Try clicking an event with the mouse.
4. Use `U` / arrows / `Enter` to open an event with the keyboard.
5. Press `Esc` (with no modal/form open) or press `H` again.

### Expected Results

- A “Hardcore Mode · Esc” indicator appears.
- Clicks do not open events or focus controls; the indicator may pulse on a blocked click.
- Clicks inside onboarding UI (`[data-onboarding-ui]`) still work.
- Keyboard shortcuts continue to work.
- If a modal, floating layer, or event form is open, `Esc` dismisses that owner first; a later `Esc` exits Hardcore Mode.
- Exiting clears the indicator. Reloading the page also clears the mode.
- Event-jump chips (`S`) clear when Hardcore enters. Shift alone / Shift-Shift do not toggle Hardcore Mode.

---

## Scenario 14: Shortcuts Do Not Fire While Typing In Inputs

### UX

Expand Down Expand Up @@ -389,15 +419,16 @@ If time is limited, run these checks before shipping shortcut-related changes:
1. `D`, `W` navigate to the correct views from any starting view.
2. `J` and `K` navigate days in Day view and weeks in Week view.
3. `T` returns to today from any offset in both Day and Week view.
4. Cmd+K opens the command palette; Escape closes it without action.
4. Cmd+K opens the command palette; Escape closes it without action; Undo/Redo rows are present.
5. `C` opens a timed event form and `A` an all-day event form, in both Day and Week view.
6. `]` toggles the sidebar in both Week and Day view.
7. Delete removes a focused event in Day and Week view and shows an undo toast.
8. Cmd+Z / Ctrl+Z undoes the last event action; Cmd+Shift+Z / Ctrl+Shift+Z redoes it.
9. No shortcuts fire inside a focused text input except Cmd+K.
10. Shift+ArrowLeft/Right move a focused event by one day in both Day and Week view.
11. Arrow keys reposition an open draft in both Day and Week view.
12. With a focused event and no draft open, ArrowUp/ArrowDown move focus to the previous/next event chronologically.
12. With a focused event and no draft open: in Week view ArrowUp/ArrowDown stay on the same day and ArrowLeft/Right jump to the time-nearest event on the previous/next non-empty day; in Day view all four arrows move chronological focus.
13. Cmd+D / Ctrl+D duplicates a focused event in Day and Week view.
14. With a focused event, `E` then `T` opens the form with the title focused; `E` then `A` / `C` jump to account / color; bare `E` alone does nothing.
15. Pressing `S` shows event jump chips; a day letter + digit focuses that event; Shift+Tab does not show chips. `H` toggles Hardcore Mode.
15. Pressing `S` shows event jump chips; a day letter + digit focuses that event; Shift+Tab does not show chips.
16. `H` enters Hardcore Mode (clicks blocked, indicator visible); Esc or another `H` exits. Shift-Shift does not.
33 changes: 33 additions & 0 deletions docs/development/common-change-recipes.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,39 @@ consistent.
2. Verify auth-state implications in `packages/web/src/auth/compass/session/SessionProvider.tsx` and auth-state helpers.
3. Test both never-authenticated and previously-authenticated behavior.

## Add Or Change A Keyboard Shortcut

1. Add or update the entry in `packages/web/src/shortcuts/shortcuts.registry.ts`
(id, keys, label, section, optional `when`). The `?` legend and overlay
sections read from this registry — do not hard-code a second label list.
2. If the Shortcut Showcase teaches the binding, also update
`packages/web/src/shortcuts/keymap.ts`. `keymap.test.ts` fails if the
registry row and keymap disagree.
3. Register the key in the owning hook:
- global / shell: `packages/web/src/shortcuts/useGlobalShortcuts.ts`
- week: `packages/web/src/views/Week/hooks/shortcuts/useWeekViewShortcuts.ts`
(+ behavior in `useWeekShortcutOwner.ts`)
- day: `packages/web/src/views/Day/hooks/shortcuts/useDayViewShortcuts.ts`
- shared grid edit/focus: `packages/web/src/grid/shortcuts/`
- event jump (`S`): `packages/web/src/shortcuts/shift-hint/`
- Hardcore Mode (`H`): `packages/web/src/shortcuts/keyboard-only/`
4. Respect `app-lock`, `escape-ownership`, and “do not fire while typing in
inputs” (use the existing `useAppShortcut` helpers; do not attach bare
`window` listeners for new app shortcuts). Bare-letter shortcuts (`S`, `H`,
`E`…) must yield to an armed edit sequence.
5. Add or update registry/data tests and the owning hook tests. Update
[Shortcuts acceptance](../acceptance/shortcuts.md) when user-visible
behavior changes.

Common pitfalls:

- **Legend-only change** — updating the registry without a handler (or the
reverse) ships a lie in the `?` overlay.
- **Showcase drift** — remapping a taught shortcut in the handler but not
`keymap.ts` leaves the practice calendar teaching the old keycaps.
- **App-lock blind spots** — shortcuts that fire while Auth/Settings/Welcome
own the UI feel broken; follow the helpers that already gate on lock state.

## Change A Shared Hotkey Dialog (Day + Week)

Use this for overlays mounted in both `WeekView` and `DayViewContent` (for example Dedication).
Expand Down
41 changes: 38 additions & 3 deletions docs/development/feature-file-map.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,12 @@ Use this document to find the first files to inspect for common Compass changes.

- Day view route and content: `packages/web/src/views/Day/view`
- Day view header (includes sidebar toggle control): `packages/web/src/views/Day/components/Header/Header.tsx`
- Day keyboard shortcuts: `packages/web/src/views/Day/hooks/shortcuts/useDayViewShortcuts.ts`
- Sidebar toggle (`]`): `packages/web/src/views/Week/hooks/shortcuts/useGlobalShortcuts.ts`
- Day keyboard shortcuts (thin key registration): `packages/web/src/views/Day/hooks/shortcuts/useDayViewShortcuts.ts`
- Week keyboard shortcuts (thin key registration): `packages/web/src/views/Week/hooks/shortcuts/useWeekViewShortcuts.ts`
- Week shortcut owner (draft create/nav/focus + bus): `packages/web/src/views/Week/hooks/shortcuts/useWeekShortcutOwner.ts`
- Shared grid edit/focus shortcuts: `packages/web/src/grid/shortcuts/useGridEventEditShortcuts.ts`, `focus-adjacent-grid-event.ts`
- Day column set when Google is connected (hides local Compass column): `packages/web/src/views/Day/components/Calendar/dayCalendarColumns.util.ts`
- All-day event color wash on day columns: `packages/web/src/grid/utils/allDayColumnTint.util.ts`
- Day view hooks: `packages/web/src/views/Day/hooks`
- Week view: `packages/web/src/views/Week`
- Responsive layout controller (auto-collapse on breakpoint crossings): `packages/web/src/components/AuthenticatedLayout/useResponsiveLayout.ts`
Expand All @@ -48,11 +52,40 @@ Use this document to find the first files to inspect for common Compass changes.
- week view: `packages/web/src/views/Week/WeekView.tsx`
- day view: `packages/web/src/views/Day/view/DayViewContent.tsx`

## Keyboard Shortcuts

Authoritative legend data and taught bindings live under
`packages/web/src/shortcuts`. View owners register keys; do not duplicate
labels outside the registry.

- Registry (source of truth for `?` legend): `packages/web/src/shortcuts/shortcuts.registry.ts`
- Overlay sections derived from the registry: `packages/web/src/shortcuts/data/shortcuts.data.ts`
- Taught bindings (handlers + Shortcut Showcase keycaps): `packages/web/src/shortcuts/keymap.ts`
- Global shell shortcuts (sidebar `]`, palette, settings, navigation): `packages/web/src/shortcuts/useGlobalShortcuts.ts`
- Event-jump chips (`S`): `packages/web/src/shortcuts/shift-hint/`
- Hardcore Mode (`H`; clicks inert until Esc / `H` / refresh): `packages/web/src/shortcuts/keyboard-only/`
- Escape ownership (modals/form before lower handlers): `packages/web/src/shortcuts/escape-ownership.ts`
- App lock (suppress shortcuts while a modal owns the UI): `packages/web/src/shortcuts/app-lock.ts`
- Mount point for global + Hardcore Mode hooks: `packages/web/src/components/RootShell/RootShell.tsx`
- Acceptance runbook: [Shortcuts](../acceptance/shortcuts.md)

## Welcome, Showcase, And Checklist

Anonymous calendar onboarding is three stacked surfaces, all mounted from
`RootShell` except on `/life` (see `isLifePathname`).

- Welcome modal (**Start Now** / Escape both hand off to the showcase): `packages/web/src/components/WelcomeModal/WelcomeModal.tsx`
- Shortcut Showcase (takeover practice calendar): `packages/web/src/components/ShortcutShowcase/` (`showcase.steps.ts` is the taught-step order)
- Post-showcase checklist over real events: `packages/web/src/components/OnboardingChecklist/`
- Replay from the command palette (“Practice shortcuts”, “Show welcome guide”): `packages/web/src/components/CommandPalette/navigation.cmd.constants.ts`
- Legacy tour seen-flag is honored once so established users are not ambushed: `packages/web/src/components/ShortcutShowcase/showcase.storage.ts`

## Sidebar

- Shared sidebar shell: `packages/web/src/components/Sidebar/Sidebar.tsx`
- Month picker: `packages/web/src/components/Sidebar/MonthPicker/MonthPicker.tsx`
- Account identity/sync indicator: `packages/web/src/components/Sidebar/CalendarList/CalendarListHeader.tsx`
- Shared account sync-status + CTA labels: `packages/web/src/components/Sidebar/CalendarList/useAccountHeaderStatus.ts`
- Account identity/sync indicator: `packages/web/src/components/Sidebar/CalendarList/CalendarListHeader.tsx`, `AccountSectionHeader.tsx`
- Sidebar actions and shortcuts overlay: `packages/web/src/components/Sidebar/SidebarActions/SidebarActions.tsx`, `packages/web/src/components/Sidebar/ShortcutsOverlay/ShortcutsOverlay.tsx`
- Week mount point: `packages/web/src/views/Week/WeekView.tsx`
- Day mount point: `packages/web/src/views/Day/view/DayViewContent.tsx`
Expand Down Expand Up @@ -88,6 +121,8 @@ see [Google Sync And SSE Flow](../features/google-sync-and-sse-flow.md) for
the full picture.

- Service entrypoint + internal routes: `packages/sync/src/app.ts`, `packages/sync/src/server/`
- Failed-job self-heal sweep: `packages/sync/src/domain/failed-job-requeue.service.ts` (wired from `packages/sync/src/app.ts`)
- Operator CLI for exhausted jobs: [CLI](./cli.md#manage-exhausted-sync-jobs)
- Diagnostics / retention / principal purge: `packages/sync/src/server/diagnostic.routes.ts`, `packages/sync/src/domain/connection-retention.service.ts`, `packages/sync/src/domain/principal-purge.service.ts`
- Sync DB backup/restore CLI: `packages/scripts/src/commands/sync-backup.ts`, `sync-restore.ts`

Expand Down
23 changes: 23 additions & 0 deletions docs/features/google-sync-and-sse-flow.md
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,29 @@ remember to click **Refresh calendar**.
4. User initiates re-consent via the OAuth flow (proxied to Sync).
5. Sync completes the OAuth exchange; the backend's next metadata fetch/change-feed poll picks up the reconnected state.

## Failed Job Self-Heal (Sync Operator Path)

Sync workers mark a job `failed` after its per-attempt retry ladder is spent.
Nothing else requeues that row unless the **failed-job self-heal** sweep runs
(`failedJobRequeue` in `packages/sync/src/app.ts`, logic in
`packages/sync/src/domain/failed-job-requeue.service.ts`):

1. After a ~30 minute cooldown, the sweep requeues cooled-down failed jobs with
a fresh attempt budget (up to `FAILED_JOB_MAX_REQUEUES`, currently 3).
2. Jobs that keep failing past that budget are **exhausted** and need an
operator — see [manage-failed-jobs](../development/cli.md#manage-exhausted-sync-jobs).
3. Exhausted jobs whose connection already has a durable provider read-failure
marker (`lastReadFailureAt`, for example Google `notACalendarUser`) are
**auto-cleared** so their coalescing key no longer blocks rediscovery /
reconnect enqueue. Health already surfaces those provider errors; keeping
the failed row only adds log noise.

Watch sync logs for:

- `Sync self-heal sweep requeued N failed job(s)`
- `Sync self-heal sweep cleared N exhausted job(s) blocked by durable provider read failure`
- `Sync self-heal sweep: N failed job(s) exhausted their requeue budget and need operator attention`

## Rules Of Thumb For Changes

- New realtime behavior usually needs changes in `core`
Expand Down
Loading