docs: define first alpha product UX
This commit is contained in:
parent
acabe340e9
commit
a6d349f188
|
|
@ -0,0 +1,242 @@
|
|||
# First Alpha Product UX Design
|
||||
|
||||
## Status and scope
|
||||
|
||||
This is the approved product-UX tranche for the first public alpha. It covers
|
||||
the Desktop application, official Activity, Journal and Browser Inbox plugins,
|
||||
and the browser extension. Release packaging, public repository documentation,
|
||||
licensing, and sync-server hardening are specified separately in the
|
||||
`alpha-release` tranche.
|
||||
|
||||
The user-visible Russian term is **Дело**. Existing platform and storage names
|
||||
such as `workspaceRootPath` remain internal compatibility details in this
|
||||
tranche.
|
||||
|
||||
This document supersedes conflicting decisions in the following older narrow
|
||||
designs:
|
||||
|
||||
- `2026-06-29-activity-worklog-suggestions-design.md` for candidate lifecycle
|
||||
and background availability;
|
||||
- `2026-06-29-browser-inbox-domain-binding-design.md` for the relation between
|
||||
bindings, global Inbox, and browser activity;
|
||||
- `2026-07-11-platform-localization-design.md` only where it would leave
|
||||
developer-facing plugin IDs visible in the normal user interface.
|
||||
|
||||
## Product decisions
|
||||
|
||||
- A new Дело is created **only** by an explicit user action. Browser Inbox,
|
||||
Activity, and Journal never create a case, candidate case, or implicit case.
|
||||
- A manual extension send is a Browser Inbox capture. Passive browsing activity
|
||||
is never an Inbox capture.
|
||||
- Passive browser activity records only a normalized hostname and measured
|
||||
duration. It never records a page URL, title, selection, page content,
|
||||
keystrokes, or browsing history.
|
||||
- Passive browser activity counts only the active tab in a focused browser
|
||||
window. Background tabs and unfocused browser windows contribute no time.
|
||||
- Activity can suggest a Journal record, but the user reviews and saves it.
|
||||
Journal entries are never created automatically.
|
||||
- An unassigned activity can be saved only after the user picks an existing
|
||||
Дело. Picking it for a single Journal entry does not silently create a domain
|
||||
binding.
|
||||
- The first alpha retains one optional Дело assignment per Browser Inbox
|
||||
capture, matching current product semantics. It does not introduce sharing a
|
||||
capture between several cases.
|
||||
|
||||
## Browser extension: manual capture and passive activity
|
||||
|
||||
### Manual capture
|
||||
|
||||
The existing explicit popup/context-menu actions remain the only way to create
|
||||
`browser.capture.*` events and Browser Inbox records. Their protocol and
|
||||
retry queue remain separate from passive activity data.
|
||||
|
||||
### Domain activity tracker
|
||||
|
||||
The extension adds a small persisted tracker:
|
||||
|
||||
1. When an HTTP(S) page becomes the active tab of a focused browser window,
|
||||
start timing its normalized lowercase hostname.
|
||||
2. On tab activation, hostname change, window focus loss, or a five-minute
|
||||
alarm, calculate elapsed time and add it to that hostname's local total.
|
||||
3. Ignore browser-internal pages, invalid URLs, and excluded hostnames. An
|
||||
exclusion `youtube.com` matches that hostname and every subdomain; the same
|
||||
rule applies to `x.com`.
|
||||
4. On a flush, send each accumulated hostname as a `browser.activity.domain`
|
||||
record. The payload contains a schema version, idempotency ID, observed
|
||||
period bounds, hostname, and `durationSeconds`; it contains no URL-like
|
||||
field.
|
||||
5. Remove a hostname's sent total only after Desktop confirms that particular
|
||||
idempotency ID. On failure, shutdown, or service-worker suspension, preserve
|
||||
the timestamp and totals in extension local storage and retry later.
|
||||
|
||||
The extension uses timestamp arithmetic rather than an in-memory interval, so
|
||||
the behaviour survives Chromium Manifest V3 service-worker restarts. Its
|
||||
manifest gains only the `windows` and `alarms` permissions needed for this
|
||||
flow; existing tab access is retained. Firefox uses the equivalent WebExtension
|
||||
events.
|
||||
|
||||
The settings page gets an **Excluded domains** list. It accepts one hostname per
|
||||
item, normalizes case and leading dots, rejects a scheme/path/query, and
|
||||
explains that a hostname excludes its subdomains. The default list is empty.
|
||||
|
||||
### Desktop receiver
|
||||
|
||||
Desktop exposes an authenticated activity receiver separate from the capture
|
||||
receiver. It validates a bounded hostname, positive bounded duration, ISO time
|
||||
fields, schema version, and idempotency ID before it publishes
|
||||
`browser.activity.domain`. Invalid and duplicate records do not enter Activity.
|
||||
The existing local pairing token gates the endpoint; the token is never placed
|
||||
in Activity storage or UI.
|
||||
|
||||
The receiver annotates a valid activity with an existing exact hostname-to-Дело
|
||||
binding when one exists. Bindings remain explicit: `client.example.com` does
|
||||
not imply `example.com` or the reverse. This is deliberately different from
|
||||
the exclusion-list suffix rule. Unbound activity is stored as global activity.
|
||||
|
||||
## Activity and Journal
|
||||
|
||||
### Background processing
|
||||
|
||||
Official plugins gain a lifecycle-safe background-service contribution. It is
|
||||
loaded when the plugin host starts, not only while the plugin view is mounted.
|
||||
The Activity service subscribes once to public events, normalizes and persists
|
||||
them, rebuilds candidates, and releases subscriptions on host teardown.
|
||||
|
||||
The platform provides unsubscribe-capable event subscriptions. Activity writes
|
||||
use the existing atomic plugin-settings update primitive, preventing concurrent
|
||||
browser/file events from overwriting each other. Command registration is also
|
||||
owned by the background service so commands remain available without opening
|
||||
the Activity view.
|
||||
|
||||
### Candidate rules
|
||||
|
||||
Activity presents chronological sessions rather than a raw log by default. A
|
||||
browser activity session displays, for example, `admin.client-site.ru · 1 ч
|
||||
32 мин`; it exposes no hidden URL/title data.
|
||||
|
||||
A candidate is scoped to one existing Дело and local calendar day. It is ready
|
||||
when either:
|
||||
|
||||
- meaningful events in its session cover at least ten minutes and include at
|
||||
least two events; or
|
||||
- it contains one or more browser-domain records totaling at least ten minutes.
|
||||
|
||||
`workspace.selected`, `file.opened`, and `note.opened` are diagnostic context,
|
||||
not meaningful work by themselves. Candidate identity is stable by case, local
|
||||
day, and source event IDs. Accepted and dismissed state is persisted, so an
|
||||
already handled candidate does not reappear after a restart.
|
||||
|
||||
The Journal review action opens the existing journal editor with candidate
|
||||
duration, date, and a concise domain/event summary. The user may edit all
|
||||
content and must explicitly save. For global/unassigned activity, the review
|
||||
requires choosing one existing Дело first. Missing or disabled Journal support
|
||||
produces a visible, actionable message rather than failing silently.
|
||||
|
||||
Activity has two clear views:
|
||||
|
||||
- **Сессии** — default, with candidate cards and activity summaries;
|
||||
- **События** — a secondary diagnostic stream for technical event inspection.
|
||||
|
||||
## Browser Inbox lifecycle
|
||||
|
||||
### Record state
|
||||
|
||||
A capture remains one canonical record with independent fields:
|
||||
|
||||
```text
|
||||
globalState: active | archived
|
||||
workspaceRootPath: optional existing Дело
|
||||
```
|
||||
|
||||
Existing records migrate to `globalState: active`; their current assignment is
|
||||
retained. The current test vault may be discarded, but the migration is
|
||||
non-destructive for an alpha user vault.
|
||||
|
||||
### Actions
|
||||
|
||||
- **Assign to Дело** retains the capture in global Inbox and shows it in the
|
||||
selected Дело's Inbox.
|
||||
- **Убрать из общих входящих** changes `globalState` to `archived`. It never
|
||||
removes the assignment, so an assigned capture remains available from its
|
||||
Дело.
|
||||
- **Открепить от дела** removes only `workspaceRootPath`. If the capture is
|
||||
still globally active it returns to the global Inbox; otherwise it remains in
|
||||
archive.
|
||||
- **Удалить везде** removes the canonical capture and its assignment. It is a
|
||||
separate destructive action and requires confirmation that names the affected
|
||||
Дело when assigned.
|
||||
- **Сохранить ссылку в деле** creates an independent `.url` file under the
|
||||
case's `Links/` directory, creating that directory first. Success does not
|
||||
depend on retaining the capture record; later Inbox deletion cannot remove
|
||||
the written file.
|
||||
|
||||
Bulk actions operate only on the visibly filtered capture set, show the count,
|
||||
and use archive rather than permanent deletion. Every permanent deletion and
|
||||
Journal deletion has a cancellation-safe confirmation dialog.
|
||||
|
||||
When a Дело is renamed, the Inbox service migrates its capture assignments and
|
||||
exact domain bindings from the old root to the new root. It does not migrate a
|
||||
binding that has been manually changed to another Дело during that operation.
|
||||
|
||||
## Alpha interface
|
||||
|
||||
- Use Russian product labels consistently: **Дела**, **Входящие**,
|
||||
**Активности**, and **Журнал**. User-facing dates use the local time zone.
|
||||
- The overview contains only useful, properly scoped items: continuation for
|
||||
the selected Дело, new Inbox records, Journal candidates, and real recent
|
||||
changes. It excludes repeated `file.changed`, `workspace.selected`, and
|
||||
unrelated-case events.
|
||||
- Empty states give a next action, not an empty pane.
|
||||
- Clear, delete, and archive actions name their scope and consequences.
|
||||
|
||||
Plugin IDs are diagnostic information. Normal tabs display the manifest's
|
||||
human title, such as `Заметки` or `Изображение`, never
|
||||
`verstak.default-editor.notes-markdown` or `verstak.file-preview.image`.
|
||||
|
||||
Add a persisted **Settings → Debug → Show plugin IDs** preference, defaulting
|
||||
to false. The Desktop application-specific `--debug` command-line argument
|
||||
enables the same display only for that run. When either is active, show the ID
|
||||
adjacent to the human title and in diagnostic errors. Neither mode alters data,
|
||||
plugin permissions, or release behaviour.
|
||||
|
||||
## Error handling and privacy
|
||||
|
||||
- A failed extension delivery keeps the accumulated hostname time locally and
|
||||
reports a non-blocking retry state in extension settings; it never falls back
|
||||
to Browser Inbox capture.
|
||||
- Receiver authentication/validation errors provide a safe status to the
|
||||
extension without echoing the pairing token or untrusted payload.
|
||||
- Activity never manufactures a case from missing assignment data.
|
||||
- User-visible errors explain the failed action and offer the next safe action.
|
||||
|
||||
## Verification
|
||||
|
||||
Automated checks must cover:
|
||||
|
||||
- browser tracker start/stop, focused-tab-only accounting, exclusions,
|
||||
coalescing, acknowledgement-only reset, retry persistence, and payload
|
||||
privacy;
|
||||
- Desktop activity receiver authentication, validation, idempotency, binding,
|
||||
and event publication;
|
||||
- atomic Activity persistence, background subscription lifecycle, candidate
|
||||
threshold/state, Journal handoff, local dates, and missing-Journal feedback;
|
||||
- assigning, archiving, unlinking, permanent deletion, `.url` creation,
|
||||
filtered bulk operations, and renaming an assigned Дело;
|
||||
- normal and debug-mode plugin tab labels;
|
||||
- the corrected frontend Wails mock, plus the end-to-end flows
|
||||
activity-to-Journal and Inbox-to-Дело.
|
||||
|
||||
Manual GUI smoke testing verifies Russian normal-mode labels, hidden plugin
|
||||
IDs, candidate review, Inbox preservation, and extension domain exclusions in
|
||||
the Linux Desktop build.
|
||||
|
||||
## Out of scope
|
||||
|
||||
- automatic creation of a Дело;
|
||||
- background-tab or browser-history tracking;
|
||||
- URL/content/title collection for passive activity;
|
||||
- shared/multi-case captures;
|
||||
- automated Journal saving, billing, or time-sheet generation;
|
||||
- browser-extension localization and a general analytics product;
|
||||
- release packaging, licensing, public GitHub README, and sync-server release
|
||||
security, which belong to the next alpha-release design.
|
||||
Loading…
Reference in New Issue