Skip to content
Draft
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 keyboard-only mode: [Shortcuts](./acceptance/shortcuts.md), [Feature File Map](./development/feature-file-map.md#keyboard-shortcuts)
- Onboarding tour after Start Now: [Feature File Map](./development/feature-file-map.md#onboarding-tour), [Frontend Runtime Flow](./frontend/frontend-runtime-flow.md#welcome-and-onboarding-tour)
- 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
56 changes: 44 additions & 12 deletions docs/acceptance/shortcuts.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,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)
- spatially focusing events with arrow keys
- toggling event-jump chips (Shift tap) and keyboard-only mode (Shift-Shift)
- 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 @@ -47,18 +49,21 @@ 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 |
| `Shift` `Shift` | Global | Toggle keyboard-only 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 |
| `Shift` | Day view | Toggle event jump keys |
| `Shift` | 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` | Day view | Focus previous/next event spatially |
| `ArrowLeft` / `ArrowRight` | Day / Week | Focus nearest event on previous/next column/day (skip empty) |
| `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 @@ -78,9 +83,9 @@ Helpful notes:
| `A` | Week view | Create all-day event |
| `I` | Week view | Focus sidebar |
| `U` | Week view | Focus first calendar event |
| `Shift` | Week view | Toggle event jump keys |
| `Shift` | 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 |
| `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 @@ -173,16 +178,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, Undo last change, Redo last change, Restart onboarding tour, 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 @@ -351,7 +357,32 @@ Tapping `Shift` toggles event-jump mode (activation waits briefly so Shift-Shift

---

## Scenario 13: Shortcuts Do Not Fire While Typing In Inputs
## Scenario 13: Shift-Shift Enters Keyboard-Only Mode

### UX

Two quick `Shift` taps toggle keyboard-only mode. While active, pointer clicks are blocked (scroll and hover still work) so the user practices keyboard navigation. A persistent indicator shows how to exit. Mode is not persisted across refresh.

### Steps

1. Navigate to `/week` with at least one event visible.
2. Tap `Shift` twice quickly (not a held 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 tap `Shift` `Shift` again.

### Expected Results

- A “Keyboard only” indicator appears after the double tap.
- Clicks do not open events or focus controls; the indicator may pulse on a blocked click.
- Keyboard shortcuts continue to work.
- If a modal, floating layer, or event form is open, `Esc` dismisses that owner first; a later `Esc` exits keyboard-only mode.
- Exiting clears the indicator. Reloading the page also clears the mode.
- A single Shift tap still toggles event-jump chips; a following quick second Shift cancels jump mode and enters keyboard-only instead.

---

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

### UX

Expand Down Expand Up @@ -380,15 +411,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, ArrowUp/ArrowDown stay on the same day; ArrowLeft/Right jump to the time-nearest event on the previous/next non-empty day.
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; bare `E` alone does nothing.
15. Tapping Shift toggles event jump chips; a day letter + digit focuses that event; fast Shift+J does not toggle the mode.
16. Shift-Shift enters keyboard-only mode (clicks blocked, indicator visible); Esc or another Shift-Shift exits.
30 changes: 30 additions & 0 deletions docs/development/common-change-recipes.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,36 @@ 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. 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/`
3. If the shortcut shares Shift with event-jump or keyboard-only mode, go through
`packages/web/src/shortcuts/shift-tap-gesture.ts` instead of a private
keydown listener — single-tap vs Shift-Shift coexistence depends on one bus.
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).
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.
- **Private Shift listeners** — bypassing `shift-tap-gesture` reintroduces
jump-mode flashes on Shift-Shift or blocks keyboard-only entry.
- **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
43 changes: 40 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,42 @@ 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 shared gesture behavior 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`
- Global shell shortcuts (sidebar `]`, palette, settings, navigation): `packages/web/src/shortcuts/useGlobalShortcuts.ts`
- Shared Shift-tap gesture (single tap vs Shift-Shift): `packages/web/src/shortcuts/shift-tap-gesture.ts`
- Event-jump chips (Shift tap): `packages/web/src/shortcuts/shift-hint/`
- Keyboard-only mode (Shift-Shift; clicks inert until Esc / Shift-Shift): `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 + keyboard-only hooks: `packages/web/src/components/RootShell/RootShell.tsx`
- Acceptance runbook: [Shortcuts](../acceptance/shortcuts.md)

## Onboarding Tour

Interactive coachmarks after Welcome **Start Now**. Not an app-lock modal —
calendar shortcuts stay live so each step can advance by doing the action.

- Steps (order + copy): `packages/web/src/components/OnboardingTour/onboarding.tour.steps.ts`
- Store + start/skip/finish: `packages/web/src/components/OnboardingTour/onboarding.tour.store.ts`
- Seen flag (browser storage): `packages/web/src/components/OnboardingTour/onboarding.tour.storage.ts`
- Progress listeners (advance on C / save / palette / `?`): `packages/web/src/components/OnboardingTour/useOnboardingTourProgress.ts`
- UI: `packages/web/src/components/OnboardingTour/OnboardingTour.tsx`
- Started from Welcome **Start Now**: `packages/web/src/components/WelcomeModal/WelcomeModal.tsx`
- Restart from command palette (“Restart onboarding tour”): `packages/web/src/components/CommandPalette/navigation.cmd.constants.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 +123,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
34 changes: 34 additions & 0 deletions docs/frontend/frontend-runtime-flow.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,40 @@ Important behavior:

This is the shell for the main desktop app experience.

## Welcome And Onboarding Tour

Files:

- `packages/web/src/components/RootShell/RootShell.tsx`
- `packages/web/src/components/WelcomeModal/WelcomeModal.tsx`
- `packages/web/src/components/OnboardingTour/`

`RootShell` mounts the welcome modal, onboarding tour, global navigation /
calendar-shell shortcuts, and keyboard-only mode.

Welcome → tour contract:

- **Start Now** starts the interactive tour when
`compass.onboarding.has-seen-onboarding-tour` is not yet set
- backdrop dismiss / Escape / Log In / Sign Up mark the tour skipped without
starting it (same seen flag) so the coachmarks do not appear later by surprise
- the tour is **not** an app-lock modal: shortcuts underneath stay live so each
step advances when the user performs the hinted action (`C`, save, Cmd+K /
Escape, `?`)
- step order and copy live in `onboarding.tour.steps.ts` (single source of truth)
- users can reopen it anytime from the command palette (“Restart onboarding tour”)

Keyboard-only mode (`Shift` `Shift`, also mounted from `RootShell`):

- blocks pointer clicks while active; scroll and hover remain
- exits via Escape when nothing higher owns Escape, another Shift-Shift, or refresh
- shares the Shift-tap gesture bus with event-jump chips so a second quick Shift
cancels jump mode and enters keyboard-only instead

See [Shortcuts](../acceptance/shortcuts.md) for acceptance coverage and
[Feature File Map](../development/feature-file-map.md#keyboard-shortcuts) for
file pointers.

## Session Runtime

File:
Expand Down
Loading