docs: vault tab UI + session timeout design spec
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
154
docs/superpowers/specs/2026-04-27-relicario-vault-tab-design.md
Normal file
154
docs/superpowers/specs/2026-04-27-relicario-vault-tab-design.md
Normal file
@@ -0,0 +1,154 @@
|
||||
# Vault Tab UI + Session Timeout — Design Spec
|
||||
|
||||
**Date:** 2026-04-27
|
||||
**Scope:** New `vault.html` full-tab UI, shared session timeout, popup↔vault navigation
|
||||
|
||||
## Problem
|
||||
|
||||
Chrome extension popups close when focus leaves them (e.g., file picker dialogs). The popup is also too cramped for complex operations like editing identity/card items, managing attachments, or bulk vault operations. Currently we work around this with `popOutToTab()` which opens `popup.html` in a tab — a hack that reuses popup-sized UI in a full window.
|
||||
|
||||
Additionally, there's no session timeout — users must re-enter their passphrase every time they interact with the extension.
|
||||
|
||||
## Design
|
||||
|
||||
### Two entry points, one shared core
|
||||
|
||||
- **`popup.html`** — quick access: search, copy, autofill, add login/secure_note (without attachments)
|
||||
- **`vault.html`** — full "desktop" UI in a browser tab: sidebar + detail pane, handles everything including attachments, bulk operations, trash, devices, settings, field history
|
||||
|
||||
Both talk to the same service worker, share the same WASM session handle and unlock state.
|
||||
|
||||
### vault.html layout
|
||||
|
||||
Sidebar + detail pane, similar to 1Password's desktop app:
|
||||
|
||||
```
|
||||
┌──────────────────────────────────────────────────┐
|
||||
│ 🔒 relicario [lock] [settings] │
|
||||
├────────────────┬─────────────────────────────────┤
|
||||
│ [search...] │ │
|
||||
│ │ (detail view for selected │
|
||||
│ ── logins ── │ item, or form when │
|
||||
│ GitHub 🔑 │ adding/editing) │
|
||||
│ AWS 🔑 │ │
|
||||
│ │ │
|
||||
│ ── notes ── │ │
|
||||
│ Recovery 📝 │ │
|
||||
│ │ │
|
||||
│ │ │
|
||||
│ │ │
|
||||
├────────────────┤ │
|
||||
│ 🗑 trash │ │
|
||||
│ 📱 devices │ │
|
||||
│ ⚙ settings │ │
|
||||
└────────────────┴─────────────────────────────────┘
|
||||
```
|
||||
|
||||
- **Left sidebar (~240px):** vault name/lock status at top, search input, item list grouped by type, nav links at bottom (trash, devices, settings)
|
||||
- **Right pane:** detail view for selected item, or add/edit form. Empty state when nothing selected.
|
||||
- URL hash tracks current selection (`#item/abc123`, `#add/login`, `#trash`, etc.) for browser back/forward
|
||||
|
||||
### Session timeout
|
||||
|
||||
Lives in the **service worker**, not in any UI. Shared across popup and vault tab.
|
||||
|
||||
**Timer logic** — new `session-timer.ts` module alongside existing `session.ts`:
|
||||
- Holds a `setTimeout` ID, reads config from `chrome.storage.local`
|
||||
- Resets on every message routed through the SW (any popup or vault tab interaction)
|
||||
- When it fires: calls `clearCurrent()` to zero the WASM handle, then broadcasts `{ type: 'session_expired' }` via `chrome.runtime.sendMessage`
|
||||
- Both popup and vault tab listen for this broadcast and show the lock screen
|
||||
|
||||
**Config shape** in `chrome.storage.local`:
|
||||
```json
|
||||
{ "session_timeout": { "mode": "inactivity", "minutes": 15 } }
|
||||
```
|
||||
or:
|
||||
```json
|
||||
{ "session_timeout": { "mode": "every_time" } }
|
||||
```
|
||||
|
||||
Default: `{ mode: 'inactivity', minutes: 15 }`. This is a **per-device setting** (stored in `chrome.storage.local`, not in the encrypted vault) since different devices have different risk profiles.
|
||||
|
||||
**UI for timeout config:** In a "device settings" section, a simple toggle:
|
||||
- "Lock after inactivity" with a minutes dropdown (5, 15, 30, 60)
|
||||
- "Lock every time" (current behavior)
|
||||
|
||||
Changing the setting sends an `update_session_config` message to the SW which immediately applies the new timer.
|
||||
|
||||
### Navigation between popup and vault
|
||||
|
||||
**Popup → vault:**
|
||||
- "Open vault" link on the lock screen and item list toolbar
|
||||
- `Shift+F` keydown listener in popup — opens/focuses the vault tab
|
||||
- When navigating from popup with context (e.g., viewing an item), pass item ID via URL: `vault.html#item/abc123`
|
||||
- `popOutToTab()` now redirects to `vault.html` instead of `popup.html` for types that need it
|
||||
|
||||
**Global shortcut:**
|
||||
- `chrome.commands` manifest entry (default unbound, user configures in `chrome://extensions/shortcuts`)
|
||||
- SW listener opens or focuses existing vault tab
|
||||
|
||||
**Vault → popup:**
|
||||
- Not needed — vault tab is the superset
|
||||
|
||||
### Shared components
|
||||
|
||||
Form renderers (login, secure-note, identity, card, key, totp, document), field helpers, attachments disclosure, generator panel are currently in `popup/components/`. These get moved to `shared/components/` so both entry points can import them.
|
||||
|
||||
The popup wrappers conditionally hide attachments (via `isInTab()`); the vault versions always show everything.
|
||||
|
||||
### Keyboard shortcuts
|
||||
|
||||
| Key | Context | Action |
|
||||
|-----|---------|--------|
|
||||
| `/` | Popup list, vault sidebar | Focus search |
|
||||
| `+` | Popup list, vault sidebar | New item |
|
||||
| `↑↓` | Popup list, vault sidebar | Navigate items |
|
||||
| `Enter` | Popup list, vault sidebar | Open selected item |
|
||||
| `Escape` | Popup | Close popup |
|
||||
| `Escape` | Vault form/detail | Back to list |
|
||||
| `Shift+F` | Popup | Open/focus vault tab |
|
||||
| Global | Anywhere in Chrome | Open/focus vault tab (user-configured) |
|
||||
|
||||
### New files
|
||||
|
||||
```
|
||||
extension/
|
||||
├── src/
|
||||
│ ├── vault/
|
||||
│ │ ├── vault.ts # Entry point, state management, hash routing
|
||||
│ │ ├── vault-shell.ts # Layout container, sidebar/pane split
|
||||
│ │ ├── vault-sidebar.ts # Search, grouped item list, nav links
|
||||
│ │ └── vault-pane.ts # Detail/form/settings renderer
|
||||
│ ├── shared/
|
||||
│ │ └── components/ # Moved from popup/components/
|
||||
│ │ ├── types/ # login.ts, secure-note.ts, etc.
|
||||
│ │ ├── fields.ts
|
||||
│ │ ├── attachments-disclosure.ts
|
||||
│ │ └── generator-panel.ts
|
||||
│ ├── service-worker/
|
||||
│ │ └── session-timer.ts # Inactivity timeout logic
|
||||
│ └── popup/
|
||||
│ └── components/ # Thin wrappers that import from shared/
|
||||
├── vault.html # New entry point
|
||||
└── vault.css # Vault-specific layout styles (imports shared)
|
||||
```
|
||||
|
||||
### What stays in popup
|
||||
|
||||
The popup keeps its stacked-view navigation and compact layout. It imports form/detail components from `shared/` but wraps them in popup-specific chrome (back buttons, condensed headers). Login and secure_note forms render inline in the popup (without attachments); all other types redirect to `vault.html`.
|
||||
|
||||
### Messages
|
||||
|
||||
New message types:
|
||||
- `update_session_config` — popup/vault → SW, updates timeout settings
|
||||
- `get_session_config` — popup/vault → SW, reads current timeout settings
|
||||
|
||||
New broadcast:
|
||||
- `session_expired` — SW → all extension views, triggers lock screen
|
||||
|
||||
### Out of scope
|
||||
|
||||
- Grouping/tagging/export features (future work, mentioned as eventual goal)
|
||||
- Mobile-style responsive layout for vault tab
|
||||
- Theme customization
|
||||
- Multi-vault support
|
||||
Reference in New Issue
Block a user