From 4873a22f9b605849b3f8b193eb74c47f7fb67ad3 Mon Sep 17 00:00:00 2001 From: curo1305 Date: Fri, 26 Jun 2026 20:45:20 +0200 Subject: [PATCH] docs(14.1-ui): define cloud local parity contract --- .../14.1-UI-SPEC.md | 223 ++++++++++++++++++ 1 file changed, 223 insertions(+) create mode 100644 .planning/phases/14.1-cloud-local-file-parity-hardening/14.1-UI-SPEC.md diff --git a/.planning/phases/14.1-cloud-local-file-parity-hardening/14.1-UI-SPEC.md b/.planning/phases/14.1-cloud-local-file-parity-hardening/14.1-UI-SPEC.md new file mode 100644 index 0000000..a6ff014 --- /dev/null +++ b/.planning/phases/14.1-cloud-local-file-parity-hardening/14.1-UI-SPEC.md @@ -0,0 +1,223 @@ +--- +phase: 14.1 +slug: cloud-local-file-parity-hardening +status: draft +shadcn_initialized: false +preset: none +created: 2026-06-26 +--- + +# Phase 14.1 — UI Design Contract + +> Visual and interaction contract for frontend phases. Generated by gsd-ui-researcher, verified by gsd-ui-checker. + +--- + +## Design System + +| Property | Value | +|----------|-------| +| Tool | none | +| Preset | not applicable | +| Component library | none — custom Vue components styled with Tailwind utilities | +| Icon library | local `AppIcon` stroke set plus existing inline loading spinner | +| Font | Tailwind default sans / system UI stack | + +--- + +## Spacing Scale + +Declared values (must be multiples of 4): + +| Token | Value | Usage | +|-------|-------|-------| +| xs | 4px | Icon gaps, inline badge spacing | +| sm | 8px | Compact control spacing, pill padding | +| md | 16px | Default control gaps, card padding increments | +| lg | 24px | Section padding, header/action separation | +| xl | 32px | Page gutters on desktop detail views | +| 2xl | 48px | Major section separation | +| 3xl | 64px | Reserved for full-page spacing only | + +Exceptions: `36px` minimum dense icon-button targets inside `StorageBrowser.vue` rows; `44px` minimum for modal and confirmation actions; sticky browser headers keep `12px` vertical padding with `16px` mobile and `24px` desktop horizontal padding. + +--- + +## Typography + +| Role | Size | Weight | Line Height | +|------|------|--------|-------------| +| Body | 14px | 400 | 1.5 | +| Label | 12px | 600 | 1.4 | +| Heading | 18px | 600 | 1.2 | +| Display | 24px | 600 | 1.2 | + +--- + +## Color + +| Role | Value | Usage | +|------|-------|-------| +| Dominant (60%) | `#F9FAFB` | App background, empty areas, muted surfaces | +| Secondary (30%) | `#FFFFFF` | Cards, sticky browser header, detail panels, sidebars | +| Accent (10%) | `#4F46E5` | Primary actions, active navigation, focus rings, selected states | +| Destructive | `#DC2626` | Delete and irreversible confirmations only | + +Accent reserved for: primary preview/open/analyze controls, active breadcrumb/tree states, selection highlights, inline links, and focus indicators. Provider identity uses `providerColor()` / `providerBg()` only in compact metadata chips or icons; it must never recolor the whole detail surface. + +Warning and stale states use the existing amber family (`amber-50/200/500/800`), success uses green, and failure uses red. These semantic colors stay secondary to the indigo accent. + +--- + +## Copywriting Contract + +| Element | Copy | +|---------|------| +| Primary CTA | `Analyze file` when no analysis exists; otherwise the first content action is `Preview` or `Open` and analysis becomes `Re-analyze` | +| Empty state heading | `No analysis yet` | +| Empty state body | `Analyze this file to extract text and topics.` Follow with a subtle source note for cloud files: `Preview, download, and analysis still run through DocuVault.` | +| Error state | `This file could not be fully analyzed.` Follow with the next step: `Retry analysis or re-analyze to refresh the result.` | +| Destructive confirmation | `Re-analyze this file? Existing extracted text and topics stay visible until the new analysis finishes.` | + +Visible copy rule: user-facing text must say `Re-analyze` everywhere. `Re-classify` is not allowed in rendered UI. + +--- + +## Registry Safety + +| Registry | Blocks Used | Safety Gate | +|----------|-------------|-------------| +| shadcn official | none | not applicable | +| Third-party registries | none | no third-party registry use is permitted for this phase | + +--- + +## Shared Surface Contract + +| Surface | Contract | +|---------|----------| +| Browser | `StorageBrowser.vue` remains the single file browser for local and cloud rows/cards. No parallel grid, card stack, or cloud-only action strip may be introduced. | +| Detail | Extract a shared detail surface from `DocumentView.vue`; local and cloud detail routes become thin data providers that pass props and handle emitted actions. | +| Source metadata | Cloud ownership is communicated only through subtle metadata: provider chip, location line, and current/stale status. The cloud detail view must not look like a separate product surface. | +| Status translation | `cloudConnections.translateAnalysisStatus()` is the single analysis-status translation source. Components do not translate statuses locally. | + +--- + +## Route And Navigation Contract + +1. Local document navigation stays at `/document/:id`. +2. Cloud rows open a dedicated detail route, named `cloud-file-detail` or an equivalent explicit named route under `/cloud/:connectionId/...`. +3. Cloud route params use `connectionId` plus opaque provider item identity. Vue Router handles encoding; frontend code must not split or infer structure from provider IDs. +4. Clicking a cloud row opens detail first. It does not auto-preview and does not auto-download. +5. Preview/Open and Download are explicit actions from the detail header and any mirrored row action slots. + +--- + +## Browser Parity Contract + +| Element | Rule | +|--------|------| +| Row click | Local and cloud file rows both navigate to a detail view. | +| File title area | Filename on the first line, topic badges directly beneath when present, action affordance inline with the title row. | +| Analysis affordance | Analyze / Re-analyze / Retry analysis occupies the same relative slot for local and cloud rows. Cloud-specific affordances stay inline in the name cell rather than moving into a separate cloud-only toolbar. | +| Status badges | Current, stale, queued, working, failed, and skipped badges appear in the same relative zone across local and cloud rows. Use green for current, amber for stale/skipped, blue or violet for active work, red for failure. | +| Disabled actions | Unsupported preview/download/analyze actions stay in the same action positions and use shared disabled styling plus a backend-provided reason. | +| Selection styling | Cloud multi-select keeps the existing violet selection treatment. Introducing a second color language for cloud parity is not allowed. | + +Row density stays unchanged: text remains `14px`, metadata remains `12px`, and icon buttons keep the existing dense treatment. + +--- + +## Detail Layout Contract + +The shared detail surface uses this section order for both local and cloud files: + +1. Back navigation +2. Header block: filename, metadata line, subtle source metadata, primary action cluster +3. Status and source notice area +4. Topics section +5. Extracted text section +6. Secondary controls and inline error/help copy + +Header rules: + +- Display title uses `24px` semibold with wrapping allowed for long filenames. +- Metadata line stays `12-14px` muted gray and includes date, size, and MIME/type information. +- Cloud-specific source metadata is a low-emphasis secondary line or compact chip group below the metadata line. +- Primary action cluster aligns right on desktop, stacks below the title on narrow screens, and keeps the content action before analysis actions. + +Card rules: + +- Detail sections stay white with `border-gray-200` and `rounded-xl`. +- Internal section padding is `20-24px`. +- Section headings use `18px` semibold for top-level detail sections and `14px` semibold for compact labels. + +--- + +## Detail State Contract + +| State | Required UI | +|-------|-------------| +| Not analyzed | Show the shared detail shell, `Analyze file` as the primary analysis CTA, empty topics copy, and empty extracted-text copy. Cloud source metadata is still visible. | +| Queued / downloading / extracting / classifying | Show a working status badge and progress copy. Existing extracted text/topics remain visible if they already exist. Do not blank the page while work runs. | +| Indexed / current | Show topics, extracted text, content actions, and a secondary `Re-analyze` action. | +| Stale | Keep prior extracted text and topics visible, add an amber stale badge/banner, and promote `Re-analyze` to the primary analysis action. | +| Partial result | Render any successful section normally and place the failure message plus `Retry analysis` beside the failed section. Example: extracted text present, topics section failed. | +| Failed with no usable data | Show the shared error treatment inside the detail surface and expose `Retry analysis` in the same action slot used by `Analyze file` / `Re-analyze`. | + +--- + +## Preview, Download, And Unsupported-State Contract + +1. Preview and Download stay adjacent in the detail header action cluster. +2. If preview is supported, `Preview` or `Open` is the first content action. +3. If preview is unsupported but download is supported, Preview remains visible but disabled, with helper copy `Preview unavailable` plus the backend reason. Download remains active. +4. Preview never triggers an automatic download. +5. No cloud UI may expose provider URLs, provider hostnames, raw tokens, or cache object keys. +6. Any content action copy that differs between local and cloud must be justified by ownership or capability, not by layout convenience. + +--- + +## Re-Analyze And Retry Contract + +1. `Re-analyze` is the label for explicit refresh of an already-analyzed file in both local and cloud detail/browser surfaces. +2. Re-analyzing a current cloud file requires confirmation using the copy in the Copywriting Contract. +3. `Retry analysis` is reserved for failed work. It must not be used for current or stale-but-readable results. +4. `Analyze file`, `Retry analysis`, and `Re-analyze` occupy one shared action slot per surface; they swap by state instead of accumulating as separate buttons. +5. When a retry or re-analyze starts, the previous extracted text and topics remain visible until new results replace them. + +--- + +## Accessibility And Feedback Contract + +1. Dense row icon buttons may use `36px` targets; modal, footer, and primary actions use `44px` minimum targets. +2. Disabled actions must remain keyboard-focusable only when they can surface an explanatory reason; otherwise they are non-interactive and accompanied by inline explanatory text. +3. Status banners use semantic color plus icon plus text; color alone is insufficient. +4. Focus indicators use the indigo ring pattern already present in the app. +5. Long filenames, provider locations, and error reasons must wrap instead of truncating inside the detail header and status areas. + +--- + +## Verification Anchors + +The implementation must be testable against these UI outcomes: + +- Paired local/cloud browser assertions verify identical row title structure, topic placement, status placement, and analysis-action slots. +- Paired local/cloud detail assertions verify identical section order, action order, and stale/partial/failed rendering rules. +- Cloud row click opens detail instead of immediate preview/download. +- Unsupported preview keeps Download active and never auto-downloads from the Preview trigger. +- No rendered output or API-fed UI state leaks provider URLs, credentials, or cache object keys. +- Visible UI contains `Re-analyze` and no surviving `Re-classify` copy. + +--- + +## Checker Sign-Off + +- [ ] Dimension 1 Copywriting: PASS +- [ ] Dimension 2 Visuals: PASS +- [ ] Dimension 3 Color: PASS +- [ ] Dimension 4 Typography: PASS +- [ ] Dimension 5 Spacing: PASS +- [ ] Dimension 6 Registry Safety: PASS + +**Approval:** pending