Skip to content

ADR 15: Web File Explorer (Miller Columns, Virtualization, Passport-Aware UX)

Status: Accepted
Date: 2026-05-16

Context

Authenticated users browse drives and large folder trees in apps/file-explorer. The UI must feel responsive at scale (thousands of entries), support familiar desktop patterns (multi-column navigation, list and grid views, multi-select), and surface security semantics from Passport Receipt metadata without inventing a parallel permission model. Identity is AT Protocol (did:plc) via existing session and API client wiring (ADR 12: AT Protocol Integration).

We need a single architectural stance on layout, performance primitives, selection, prefetch, and how metadata drives affordances (locks, context menus).

Decision

  1. Layout modes: Ship three first-class view modes, routed distinctly (e.g. split / list / grid): Miller columns for split navigation, and single-pane list or grid for the current folder. Column widths and view mode are persisted in the browser (e.g. localStorage) so layout survives reloads.

  2. Virtualization: Use @tanstack/virtual-core (framework-agnostic) with Mithril lifecycle hooks for windowed list and grid rendering. Only visible rows/tiles mount DOM; scroll observers drive Virtualizer updates and Mithril redraws.

  3. Resizing and global interaction: Column dividers use a dedicated panel resizer with pointer capture. While dragging, a body-level class disables text selection and problematic pointer targets (e.g. iframes) for predictable drag behavior.

  4. Selection: Centralize pointer semantics in a SelectionManager: plain click replaces selection; Ctrl/Cmd toggles membership; Shift extends a range from an anchor index. Marquee selection applies to grid view only, using drag rectangles intersecting tile geometry.

  5. Data loading: A FolderChildrenCache loads children per path through the same loader used for display; prefetch on directory hover warms the cache to reduce flicker when the user opens a folder. Until the gateway tree API is ubiquitous, the app may use a mock tree behind the same entry shape; production paths call @substratum/api-client with shared credentials.

  6. Passport-driven UI: Private vs shared affordances derive from Passport Receipt fields (e.g. access_control empty vs non-empty): context menu sections differ; encryption indicator maps to lock visuals (e.g. emphasized lock for private files). Do not hard-code business rules that contradict the schema. Context menu copy uses filesystem-native vocabulary (folder, file, drive, properties, move targets) and sharing vocabulary (people, groups, share link), not low-level protocol terms (e.g. “Access Control”) in user-visible strings. Prefer no encryption-specific menu items; optional lock or status affordances may still reflect private vs shared without exposing crypto jargon.

  7. Theming: Explorer-specific chrome (resizer, marquee, locks) uses CSS variables aligned with existing design tokens so themes switch without bespoke layout logic.

  8. Internationalization: User-visible strings follow ADR 14: Frontend Internationalization: explicit IDs, catalogs per locale, checklist in apps/file-explorer/AGENTS.md.

Consequences

  • Positive: Predictable performance at large folder sizes; OS-like navigation without abandoning Mithril; security and sharing semantics stay tied to Passport Receipts; cache + prefetch improve perceived latency.
  • Negative: More client complexity (virtualizer lifecycle, marquee hit-testing, selection invariants); mock vs real tree must stay behaviorally aligned until the API is complete; extra accessibility work for grid/marquee and column scrolling.