Org topbar working tabs
The org topbar is a shell-level working set, not a second navigation tree. It combines temporary work, resumable drafts, durable record shortcuts, and live activity while keeping each state owner explicit.
The authoritative desired behavior is
../product/org-working-tabs-lifecycle-spec.md.
It defines stable insertion order, retention, dialog dismissal, lifecycle
handoff, persistence, and acceptance criteria.
The implemented consolidation architecture is
org-working-tabs-architecture.md. It
defines the single lifecycle engine, pure policy/reducer boundary, feature
adapter contract, persistence coordinator, and remaining feature-payload
adapter boundaries.
The comprehensive dialog and lifecycle inventory is maintained in
org-working-dialog-lifecycle-audit.md.
That audit defines feature coverage. This document records the current
architecture and migration boundary; current behavior described here is not a
substitute for the product specification.
Current state classes
| State | Owner | Lifetime | Close behavior |
|---|---|---|---|
| Create session | Lifecycle engine plus OrgCreateIntentProvider payload adapter | User and organization scoped; pinned or meaningful drafts survive minimize and reload | Leaving closes untouched sessions and minimizes pinned or meaningful sessions; X discards the exact draft session |
| Quick-note session | Lifecycle engine plus OrgQuickNoteProvider payload adapter | User and organization scoped; seven-day draft lifetime | Leaving closes an untouched note and minimizes a pinned or meaningful note; X discards only unsaved content |
| Active timer | useActiveTimer | User and organization scoped; survives reload | Explicit discard confirmation |
| Temporary record tab | Lifecycle engine plus OrgWorkspaceTabsProvider live handle adapter | Current browser tab session | Confirms removal from the topbar without deleting the record |
| Pinned record | Lifecycle engine plus OrgPinnedWorkProvider backend adapter | Durable backend preference, re-authorized on read | Confirms removal from the topbar; also closes an overlapping temporary tab without deleting the record |
| Edit or preview dialog tab | Lifecycle engine plus OrgEditDialogTabsProvider live handle adapter | Temporary while open; its record pin can survive route changes | X closes the temporary dialog tab; pin/unpin changes only durable topbar membership |
Create sessions currently remain local drafts, but create dialogs whose saved result has a canonical record adapter expose a pin-after-save control. Selecting it pins that exact lifecycle immediately; successful creation hands the same identity and immutable position to the saved record. Opening an existing record in edit or preview mode creates its temporary tab immediately. Its dialog pin promotes that same visible tab to durable topbar membership without rendering a duplicate.
Current implementation invariants
- Every shell-local storage key is scoped by organization ID and viewer email. No draft or working-tab content is read before that identity scope resolves.
- Temporary record tabs use
sessionStorage; durable pins use backend preferences. - Create and quick-note sessions use
localStoragebecause they contain recoverable work. - Canonical records never use shell browser storage as their source of truth. Manual calendar events and active timers are backend-backed; their remaining browser reads exist only to import and remove legacy data.
- Pin writes are optimistic, serialized in interaction order, and held until the corresponding backend
updatedAtrevision reaches the subscription. - A delayed close or minimize always captures and targets the exact session ID that initiated it.
- At most one create session, quick-note session, or edit dialog is active at a time; minimized siblings remain resumable.
- Leaving a create surface or quick note removes it immediately when it is untouched and keeps it resumable only after the user enters meaningful content.
- Saving a create session always removes the create tab. It pins the resulting record only when the user selected pin before saving and the result has a canonical saved-record adapter.
- Supported create dialogs and new quick-note editors expose an icon-only pin-after-save control. Existing-record edit/preview dialogs expose the same position as a direct pin/unpin control. Creates without a canonical saved-record adapter do not show a misleading pin.
- Note-level Starred state organizes Notes and is independent from shell pinning. Starred and Recent note rows expose the shell pin/unpin action; the action never mutates the note's Starred state.
- An action pin from an older release is cleanup-only. New create flows never persist draft action IDs to backend preferences.
- A record shown both as a durable pin and a temporary tab renders once. Closing the durable instance unpins it and removes the overlapping temporary tab.
- Unpinning an open edit or preview dialog returns its tab to temporary status; it does not close the dialog or delete the record.
- Route-backed edit and preview dialogs use the shared
useWorkingRecordRouteDialogcontroller. Closing records an intentional dismissal before removing the URL parameter, so a stale query cannot reopen the dialog. - Clicking a topbar tab never navigates or replaces the underlying page. It resumes a shell-owned create/editor/preview surface in place. Navigation is allowed only through a separate, explicit action inside that surface.
- Reminder launch rows and reminder working tabs use the same compact shell
preview.
Open reminderis the only quick-view action that transitions to the durable reminder detail route; Edit remains an explicit dialog action. - Pinned projects open an on-demand compact resume preview rather than a reporting modal. Open blockers lead, followed by viewer-assigned, unassigned, then team-assigned tasks, with due state and priority breaking ties. Inline completion and timer start stay bounded; task creation and explicit project/task links hand larger work back to its owning route.
working-record-registry.tsowns canonical record tab IDs and every route-backed record query parameter. Features pass a record type to the route controller and use the registry href builder; they do not construct these identifiers or query strings themselves.ModalDialogderives an existing record's tab ID from its type, ID, and edit/preview mode. A caller-provided temporary ID is used only when no saved record exists.- Every topbar tab trigger uses
WORKING_TAB_TRIGGER_CLASS; feature-specific chips may change content and behavior, but not their width contract. - Disabled escape or outside-click dismissal must not call the dialog close request.
- Icon-only controls expose localized accessible names and pressed-state controls use
aria-pressed.
Ownership boundaries
The shell owns create dialogs, quick notes, record tabs, pinned records, and the active timer, so they remain stable across org route navigation. Edit and preview tabs are adapters over route-owned dialogs: their forms, validation, dirty baselines, and save behavior remain with the owning feature. When their route unmounts, the temporary dialog adapter unregisters; if the user pinned it, the durable record tab remains and opens a shell-owned preview without changing the current route.
Adding a new topbar state requires choosing one state class above. Do not add another persistence mechanism or encode a temporary draft as a backend pin. New record pins must also be covered by backend visibility filtering.
Required migration outcome
The existing providers must converge on the shared lifecycle behavior without losing valid persisted work:
- one immutable cross-owner added order
- newly added lifecycles first
- no reordering on view, resume, pin, unpin, save, autosave, or stage change
- immediate pin retention for untouched creates
- engagement retained independently from dirty state
- atomic create-to-record identity and pin handoff at the same position
- exact create/edit-stage recovery across organization route navigation
- one canonical item across preview and edit
Migration and new tests must follow the product acceptance scenarios and the feature coverage audit. The consolidation architecture is the required implementation boundary; do not add another lifecycle state owner.
Validation
Lifecycle coverage lives in:
apps/app/tests/org/create-intent-context.test.tsxapps/app/tests/org/quick-note-context.test.tsapps/app/tests/org/pinned-work-context.test.tsapps/app/tests/org/workspace-tabs-context.test.tsapps/app/tests/org/edit-dialog-tabs-context.test.tsxapps/app/tests/org/working-record-route-dialog.test.tsapps/app/tests/org/working-record-route-coverage.test.tsapps/app/tests/org/working-record-registry.test.tsapps/app/tests/org/working-tab-style-coverage.test.tsapps/app/tests/org/working-quick-view-strip.test.tsapps/app/tests/org/reminders-quick-view.test.tsxapps/app/tests/org/reminder-quick-view-content.test.tsxapps/app/tests/org/working-project-quick-view.test.tsxapps/app/tests/ui/modal-dialog.test.tsxpackages/backend/tests/org/workspace-pinned-work.test.tspackages/backend/tests/org/project-workflow.test.ts