From f62add8ae4be04f67d9e6c984164127b247af54f Mon Sep 17 00:00:00 2001 From: Thomas Camlong Date: Fri, 14 Aug 2026 20:47:21 +0200 Subject: [PATCH] Remove obsolete DeepSource config and Workshop critiques --- .deepsource.toml | 8 - ...-50Z__apps-docs-src-components-workshop.md | 116 -------- ...-41Z__apps-docs-src-components-workshop.md | 64 ----- ...-15Z__apps-docs-src-components-workshop.md | 106 ------- CHANGES.md | 96 ------- PRODUCT.md | 39 --- REVIEW.md | 263 ------------------ 7 files changed, 692 deletions(-) delete mode 100644 .deepsource.toml delete mode 100644 .impeccable/critique/2026-07-21T11-32-50Z__apps-docs-src-components-workshop.md delete mode 100644 .impeccable/critique/2026-07-21T12-29-41Z__apps-docs-src-components-workshop.md delete mode 100644 .impeccable/critique/2026-07-22T15-58-15Z__apps-docs-src-components-workshop.md delete mode 100644 CHANGES.md delete mode 100644 PRODUCT.md delete mode 100644 REVIEW.md diff --git a/.deepsource.toml b/.deepsource.toml deleted file mode 100644 index e2f2ffcf8..000000000 --- a/.deepsource.toml +++ /dev/null @@ -1,8 +0,0 @@ -version = 1 - -[[analyzers]] -name = "javascript" - -[analyzers.meta] -plugins = ["react"] -environment = ["nodejs"] diff --git a/.impeccable/critique/2026-07-21T11-32-50Z__apps-docs-src-components-workshop.md b/.impeccable/critique/2026-07-21T11-32-50Z__apps-docs-src-components-workshop.md deleted file mode 100644 index 7ea4baa64..000000000 --- a/.impeccable/critique/2026-07-21T11-32-50Z__apps-docs-src-components-workshop.md +++ /dev/null @@ -1,116 +0,0 @@ ---- -target: Workshop store in the docs -total_score: 20 -p0_count: 1 -p1_count: 3 -timestamp: 2026-07-21T11-32-50Z -slug: apps-docs-src-components-workshop ---- - -# Workshop Store Critique - -## Design Health Score - -| # | Heuristic | Score | Key issue | -| --------- | ----------------------------------- | --------: | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| 1 | Visibility of system status | 1/4 | Fetch failure can show beside an empty-store message, so the system communicates two incompatible states. | -| 2 | Match between system and real world | 3/4 | Widget, CSS, voting, revisions, and comments use familiar language. | -| 3 | User control and freedom | 2/4 | Filters are reversible, but the crashed route and failed fetch state offer no useful recovery. | -| 4 | Consistency and standards | 2/4 | The submission editor uses CodeMirror, while revision editing falls back to a textarea; several tiny custom controls do not follow the shared button vocabulary. | -| 5 | Error prevention | 2/4 | Submission validation exists, but disabled progression does not explain what is missing and destructive actions use a brief inline confirmation. | -| 6 | Recognition rather than recall | 3/4 | Labels, type choices, and the submission stepper are understandable without documentation. | -| 7 | Flexibility and efficiency | 2/4 | Search covers titles only, signed-out users can select Yours, and installation is reduced to ambiguous Copy and Download actions. | -| 8 | Aesthetic and minimalist design | 3/4 | The restrained visual system is clean, but the browse toolbar and card action rows become dense. | -| 9 | Help users recover from errors | 0/4 | The production route crashes with React error 130; the fetch error has no retry action or useful context. | -| 10 | Help and documentation | 2/4 | The editor explains its fields, but the store does not teach the full inspect, trust, download, and install journey. | -| **Total** | | **20/40** | **Needs work before release** | - -## Anti-Patterns Verdict - -The surface does not look like obvious AI-generated decoration. Its visual restraint, familiar controls, and practical editor are credible product UI. The weakness is product behavior rather than styling: contradictory states, tiny action controls, an overloaded responsive toolbar, and a primary installation journey that is not explicit. - -The deterministic Impeccable scan returned zero findings for `apps/docs/src/components/workshop`. This is useful but incomplete. The detector did not catch runtime failures, semantic state conflicts, touch-target sizing, or responsive grouping. Browser evidence found a full route crash, React error 130, and an earlier state that rendered both `Something went wrong.` and `No submissions yet`. - -No visual overlay was injected because the available browser evaluation surface is read-only. Screenshots, DOM snapshots, console logs, and source inspection were used instead. - -## Overall Impression - -The submission modal is now one of the stronger parts of the Workshop. The store around it is not release-ready. The single biggest opportunity is to make discovery and installation a dependable, explicit path: load reliably, show one truthful state, help users evaluate a submission, and give them one obvious next action. - -## What Is Working - -1. The visual system is restrained and consistent with the Homarr documentation. Typography, color, radii, and spacing do not compete with the content. -2. The submission flow chunks a complex task into Type, Details, and Media. The shared JSON/CSS editor, drag-and-drop import, metadata autofill, and capped media previews reduce creator effort. -3. The detail design exposes revision, author, reports, changelog, source content, and comments. This supports inspection rather than treating community code as a blind install. - -## Priority Issues - -### P0: The Workshop route crashes in the production docs build - -**Why it matters:** No visual polish matters if the store becomes a Docusaurus error page. A fresh independent tab consistently reached `This page crashed` with React error 130. The console attributed the thrown error to the Kapa widget bundle. - -**Fix:** Isolate or disable the Kapa script on Workshop routes, prevent third-party widget failures from reaching the Docusaurus route boundary, and add a route-level Workshop boundary that preserves navigation and retry. Reproduce against the built Docker docs image, not only the development server. - -**Suggested command:** `$impeccable harden` - -### P1: Failure and empty states contradict each other - -**Why it matters:** Showing `Something went wrong.` followed by `No submissions yet` makes users believe the store is both broken and empty. The generic message gives no cause and no recovery. - -**Fix:** Make loading, failure, empty, and results mutually exclusive. The failure state should say that listings could not be loaded, preserve the current filters, and provide `Try loading again`. Do not render filters or an empty store as authoritative data after the initial request fails. - -**Suggested command:** `$impeccable harden` - -### P1: Mobile discovery controls are too dense and do not form a responsive hierarchy - -**Why it matters:** The toolbar's inner row contains four type choices, sorting, and outdated visibility without wrapping. Most controls are 24 to 28 pixels tall. At narrow widths this is difficult to scan, easy to clip, and below a comfortable touch target. - -**Fix:** Put a full-width search first on mobile, keep All, Widgets, and CSS as the primary segmented choice, move sorting and outdated visibility into a compact secondary row or popover, and hide Yours when signed out or make it a sign-in affordance. Use at least 40 to 44 pixel touch targets. Add `aria-pressed` or proper tab semantics to the type filter. - -**Suggested command:** `$impeccable adapt` - -### P1: The store does not make the install journey obvious - -**Why it matters:** A first-time user sees Copy and Download without knowing which is recommended, what will be copied, how to inspect safety, or where the file goes in Homarr. This weakens the store's main purpose. - -**Fix:** Make the detail page the decision surface. Use one primary action named for its result, such as `Download widget JSON` or `Copy CSS`, with a short `Install in Homarr` explanation linked to the correct in-app flow. Cards should prioritize title, preview, compatibility, score, and `View details`; secondary utilities should not compete with evaluation. - -**Suggested command:** `$impeccable clarify` - -### P2: Card and moderation actions are too small and too numerous - -**Why it matters:** Vote, copy, download, comment, delete, and report controls compete in a compact footer. Low-contrast icon buttons are hard to discover and hard to use by touch. CSS columns also create a top-to-bottom visual reading order that can differ from the expected row order. - -**Fix:** Use a regular responsive grid, remove hover scaling, keep one or two visible card actions, and move owner/moderation actions to a menu. Keep voting visible but increase its target size. Correct the report copy: reports and reporter identities are moderation data, not public social proof. - -**Suggested command:** `$impeccable distill` - -## Persona Red Flags - -### Jordan, first-time self-hoster - -Jordan opens Workshop to install a widget. The route can crash before any listing appears. In the partial failure state, Jordan sees both an error and an empty store. If listings load, Copy and Download do not explain the Homarr destination or recommended path. Jordan is likely to leave before installing anything. - -### Alex, experienced Homarr administrator - -Alex can understand the JSON and appreciates the source viewer, but title-only search and limited filtering make a larger catalog inefficient. Compatibility and required secret information are not prominent at browse time. Tiny moderation and owner controls slow repeated management tasks. - -### Morgan, mobile user - -Morgan encounters a toolbar with more controls than fit comfortably in one decision group, 24 to 28 pixel targets, and a signed-out Yours filter that leads to an unhelpful no-results state. Submission cards add another dense row of small actions. - -## Minor Observations - -- Future submission steps are focusable buttons even when clicking them does nothing. Disable them or render non-interactive progress markers. -- The report textarea relies on placeholder text and needs a persistent accessible label. -- The revision editor should reuse the same JSON/CSS CodeMirror component as creation. -- Search should include title, description, and author at minimum. -- The timed inline `Confirm?` deletion pattern is easy to miss and weak for keyboard and touch users. -- The detail-page changelog uses an uppercase tracked label, which is unnecessary in this otherwise restrained interface. -- Loading comments should use the same skeleton vocabulary as listings rather than centered status text. - -## Questions to Consider - -1. Is Workshop primarily a catalog for discovery, or a technical exchange for copying source? The primary card and detail actions should commit to one answer. -2. Should users evaluate compatibility and required secrets before opening a listing, or only on the detail page? -3. Does Workshop need every moderation and ownership action visible inline, or should those actions live behind a menu? diff --git a/.impeccable/critique/2026-07-21T12-29-41Z__apps-docs-src-components-workshop.md b/.impeccable/critique/2026-07-21T12-29-41Z__apps-docs-src-components-workshop.md deleted file mode 100644 index 0021929a4..000000000 --- a/.impeccable/critique/2026-07-21T12-29-41Z__apps-docs-src-components-workshop.md +++ /dev/null @@ -1,64 +0,0 @@ ---- -target: Workshop store in the docs -total_score: 38 -p0_count: 0 -p1_count: 0 -timestamp: 2026-07-21T12-29-41Z -slug: apps-docs-src-components-workshop ---- - -# Workshop Store Critique — Post-Polish - -## Design Health Score - -| # | Heuristic | Score | Evidence | -| --------- | ----------------------------------- | --------: | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| 1 | Visibility of system status | 4/4 | Loading, initial failure, stale refresh failure, empty, and results states are mutually exclusive; recovery actions are visible. | -| 2 | Match between system and real world | 4/4 | Actions describe their result: Download widget JSON, Copy CSS, View details, and Install in Homarr. | -| 3 | User control and freedom | 4/4 | Filters can be cleared, errors retried, dialogs cancelled, and destructive submission deletion requires explicit confirmation. | -| 4 | Consistency and standards | 4/4 | Creation and revision editing share CodeMirror, buttons follow the shared system, and cards use a predictable responsive grid. | -| 5 | Error prevention | 3/4 | Validation, disabled progression, pending states, RLS, and confirmations are strong; disabled form progression could explain unmet requirements more explicitly. | -| 6 | Recognition rather than recall | 4/4 | Persistent labels, type descriptions, step status, source previews, and installation instructions minimize recall. | -| 7 | Flexibility and efficiency | 4/4 | Search spans title, description, and author; signed-in filtering, sorting, responsive controls, and direct detail actions support repeat use. | -| 8 | Aesthetic and minimalist design | 3/4 | The catalog is restrained and scannable; long source documents and the complete creator form necessarily remain dense on small screens. | -| 9 | Help users recover from errors | 4/4 | Route, listing, edit, report, copy, OAuth, and detail failures remain local and provide a clear next action. | -| 10 | Help and documentation | 4/4 | The detail page explains the exact Homarr destination and links to updated Workshop documentation. | -| **Total** | | **38/40** | **Release-quality; minor polish remains** | - -## Anti-Patterns Verdict - -The surface is product-led rather than decorative. The redesign removes the overloaded card footer, hover scaling, tiny touch controls, public moderation details, contradictory states, and ambiguous install actions. The deterministic Impeccable detector reports zero findings. - -## What Improved - -1. The production route no longer collapses into the Docusaurus crash screen without recovery. A route-local boundary protects navigation, and the fresh-volume production path renders without console errors. -2. Loading, failure, empty, stale-results, and populated states are truthful and mutually exclusive. -3. Search and filters form a clear responsive hierarchy. Mobile targets are 40–44 pixels, signed-out users do not see Yours, and cards no longer overflow at 390 pixels. -4. Cards prioritize evaluation: title, author, type, score, description, comments, and View details. Copy, download, reporting, editing, and deletion moved to the detail page. -5. The detail page now teaches the installation journey and names its primary action precisely. -6. Reports and reporter identities are admin-only through PocketBase rules. Public catalog UI no longer turns reports into social proof. -7. The creator and revision dialogs share the CodeMirror editor, use bounded internal scrolling, expose pending/error states, and avoid step-selection layout shifts. - -## Remaining Minor Opportunities - -### P2: Explain disabled progression inline - -The Type and Details steps are understandable, but a disabled Next button could state the missing requirement for keyboard and first-time users. This is a refinement, not a blocker, because required fields and validation messages are already present. - -### P2: Consider a compact source summary on very small screens - -The read-only source viewer is intentionally complete and horizontally scrollable. A future collapse/expand summary could reduce page length for nontechnical visitors without hiding inspection entirely. - -## Verification Evidence - -- Fresh Docker Compose PocketBase volume and production docs image. -- Populated catalog with widget, CSS, and outdated examples. -- Desktop and 390px mobile layouts in light and dark themes. -- Widget detail, installation instructions, CodeMirror source view, and comments. -- Signed-in submission wizard through Type and Details, including the shared editor. -- Zero browser console errors after the final fixes. -- Impeccable deterministic detector: zero findings. - -## Compatibility Note - -An existing local development volume created from an earlier unreleased version of the reset migration still has a stale Workshop view. It is intentionally not migrated or deleted. A fresh volume created from the current unreleased migration is the supported validation target and works correctly. diff --git a/.impeccable/critique/2026-07-22T15-58-15Z__apps-docs-src-components-workshop.md b/.impeccable/critique/2026-07-22T15-58-15Z__apps-docs-src-components-workshop.md deleted file mode 100644 index 66884800a..000000000 --- a/.impeccable/critique/2026-07-22T15-58-15Z__apps-docs-src-components-workshop.md +++ /dev/null @@ -1,106 +0,0 @@ ---- -target: Homarr Workshop docs UI -total_score: 27 -p0_count: 0 -p1_count: 2 -timestamp: 2026-07-22T15-58-15Z -slug: apps-docs-src-components-workshop ---- - -## Design Health Score - -| # | Heuristic | Score | Key Issue | -| --------- | ------------------------------- | --------: | --------------------------------------------------------------------------------------------------------------------------------------------- | -| 1 | Visibility of System Status | 3 | Strong loading, retry, stale-data, pending, and copy states; successful report/edit actions still end silently. | -| 2 | Match System / Real World | 3 | Core Workshop language is clear, but `networkScope`, query/action, and schema terminology assumes technical fluency. | -| 3 | User Control and Freedom | 3 | Back, cancel, clear filters, vote toggling, and destructive confirmations are present; destructive actions have no undo. | -| 4 | Consistency and Standards | 3 | Shared primitives are coherent, though Docusaurus chrome and the denser app-store vocabulary still feel slightly stitched together. | -| 5 | Error Prevention | 2 | Validation and confirmations are good, but install safety and credential context appears after download/copy actions on small screens. | -| 6 | Recognition Rather Than Recall | 3 | Author, revision, source, filters, and capabilities are visible; installation still asks users to remember a separate Homarr navigation path. | -| 7 | Flexibility and Efficiency | 2 | Search, filters, sort, drag-and-drop, autofill, and comment shortcuts help; the install handoff remains manual. | -| 8 | Aesthetic and Minimalist Design | 2 | Hierarchy is clear, but repeated panels, badges, uppercase metadata labels, and overlapping install actions add noise. | -| 9 | Error Recognition and Recovery | 3 | Errors are plain-language and usually preserve work; the global action error can be detached from the failed control. | -| 10 | Help and Documentation | 3 | The installation guide and source explanation are useful; security terminology lacks inline definitions. | -| **Total** | | **27/40** | **Acceptable, significant improvements needed** | - -## Anti-Patterns Verdict - -**LLM assessment:** Moderate AI-assisted feel, not outright slop. Domain-specific copy, extensive state coverage, and transparent source/capability information make the feature credible. The generic card grid, repeated rounded panels, icon tiles, uppercase tracked labels, and decorative changelog stripe still expose a component-recipe grammar. It looks competent but not fully edited into a distinctive Homarr store. - -**Deterministic scan:** `detect.mjs --json apps/docs/src/components/workshop` exited 0 with exact output `[]`: zero findings, zero triggered rules, and no false positives. The scan found none of Impeccable's deterministic anti-patterns. - -**Visual overlays:** No reliable user-visible overlay is available. The independent detector agent had no browser backend. The parent fallback opened a fresh browser tab and visually inspected the listing, but the browser API did not expose a mutable evaluation method for the required preflight, so injection and `[Human]` visibility were correctly skipped. Browser/source evidence was used instead. - -## Overall Impression - -The Workshop is already substantially better than a generic gallery: it communicates authorship, source code, API capabilities, secrets, revision history, reports, and discussion. The biggest opportunity is to turn that information into a deliberate trust sequence. Today the interface lets the user act first and understand safety later, especially on mobile. - -## What's Working - -- **State coverage is unusually strong.** Listing failures, stale data, loading skeletons, empty results, filter recovery, comment errors, pending actions, and destructive confirmations have explicit UI. -- **Pre-install transparency is excellent.** API hosts, methods, configurable options, network scope, and credential requirements are visible instead of hidden behind a download. -- **The new primitive layer is coherent.** Search, filters, menus, switches, dialogs, and code presentation share one restrained interaction vocabulary across light and dark themes. - -## Priority Issues - -### [P1] Safety context arrives after the install action on mobile - -**Why it matters:** Download and copy actions appear in the header, while source capabilities, credential requirements, and installation guidance live in an aside that drops below the long source and discussion sections under the desktop breakpoint. A first-time mobile user can commit before understanding what the widget contacts or what secrets it needs. - -**Fix:** Put a compact “Before you install” summary immediately below the header on small screens: API hosts, network scopes, credential count, and action/query counts. Keep the full sticky details panel on desktop. - -**Suggested command:** `$impeccable layout` - -### [P1] Primary button and own-comment contrast misses AA - -**Why it matters:** The requested theme's primary red with white foreground is about 3.4:1, below 4.5:1 for small text. The same pairing affects primary buttons and the author's comment bubbles. - -**Fix:** Darken the primary red or use a dark foreground in light mode, then verify default buttons and comment bubbles in both themes. - -**Suggested command:** `$impeccable colorize` - -### [P2] The listing's server-rendered fallback is blank - -**Why it matters:** Before hydration, the listing renders an empty block instead of preserving the page's hierarchy and indicating progress. This creates a visible dead zone on slower self-hosted deployments. - -**Fix:** Render the listing heading, toolbar silhouette, and shared skeleton cards as the `BrowserOnly` fallback, matching the detail page's loading treatment. - -**Suggested command:** `$impeccable harden` - -### [P2] Download, copy, source, and install compete for the same task - -**Why it matters:** “Download widget,” “Copy JSON,” a full source viewer, and a separate installation panel all appear as parallel paths. Users must infer the recommended workflow. - -**Fix:** Make “Download widget JSON” the single primary header action. Keep copy beside the source viewer and place the next import step directly beside or immediately after download. - -**Suggested command:** `$impeccable clarify` - -### [P2] Repeated metadata scaffolding creates visual noise - -**Why it matters:** Card shells, badges, icon tiles, uppercase tracked labels, and the changelog stripe make the detail page feel assembled from recipes and slow scanning. - -**Fix:** Flatten the widget details into a compact definition list, reserve badges for status, and remove the decorative changelog stripe. - -**Suggested command:** `$impeccable distill` - -## Persona Red Flags - -**Jordan, first-timer:** “Network scope,” queries, actions, options, and the manifest schema appear without inline explanation. Download versus copy has no stated recommendation. On mobile, credential and installation context arrives after source and discussion. - -**Sam, accessibility-dependent user:** Primary controls and author comment bubbles miss small-text contrast. Copy, optimistic votes, filter result changes, and successful report/edit completion do not expose explicit live-region behavior. Gallery controls and dots are below comfortable touch-target sizes. - -**Casey, distracted mobile user:** The most important safety panel falls to the bottom, while primary actions stay at the top. Long source and discussion content separate the decision from its explanation. The submit type selector remains dense at narrow widths. - -## Minor Observations - -- The internal installation guide uses an external-link icon. -- The final publication action says “Submit” rather than “Publish submission.” -- Dark-theme tokens are declared in two blocks, increasing drift risk. -- Screenshot dots rely on opacity alone and lack `aria-current`. -- Successful report and edit actions deserve a small confirmation instead of silent dismissal. - -## Questions to Consider - -- If source review is important enough to say “Review exactly what will be installed,” why can users download before seeing the capability and credential summary? -- Is Workshop primarily a code catalog or a safety-conscious app store? The current action hierarchy tries to be both. -- Should the successful end state be a downloaded file, or a confident handoff into Homarr with the next step already visible? diff --git a/CHANGES.md b/CHANGES.md deleted file mode 100644 index c8a801420..000000000 --- a/CHANGES.md +++ /dev/null @@ -1,96 +0,0 @@ -# Changes - -## Goal - -Remove widget-only services from Homarr's global Integration system. - -The affected services are release providers and Search.ch. They are only used by specific widgets, so keeping them as global integrations added unnecessary setup, UI, database rows, docs pages, and integration package code. - -ArchiveTeam Warrior remains a proper integration but is no longer auto-seeded on first install. - -## Why - -These services do not need shared integration state. - -- Release providers are selected per Releases widget repository. -- Search.ch is only used by the Timetable widget. - -Moving them into widget options makes configuration simpler and removes dead-weight integration code from `packages/integrations`. - -## What Changed - -### Release Providers - -- Added release provider definitions in `packages/definitions/src/release-provider.ts`. -- Removed release providers from `IntegrationKind`. -- Moved release-fetching code out of `packages/integrations` and into `packages/request-handler/src/release-providers.ts`. -- Updated the Releases widget to store provider configuration directly in widget options: - - `provider` - - `identifier` - - `versionFilter` - - `providerUrl` -- Updated the Releases widget editor to use a provider select instead of an integration select. -- Updated Docker import mapping so `ghcr.io` maps to `gitHubContainerRegistry`. -- GitHub Container Registry now uses the public OCI registry API and accepts full image references such as `ghcr.io/homarr-labs/homarr:latest`. - -### Timetable / Search.ch - -- Removed Search.ch as an integration. -- Added a Timetable widget `baseUrl` option, defaulting to `https://search.ch`. -- Moved Search.ch request/parsing logic into `packages/request-handler/src/timetable.ts`. -- Updated the Timetable API to receive `baseUrl` directly from widget options. - -### ArchiveTeam Warrior - -- Kept as a proper integration (not removed). -- Removed `defaultUrl` from the integration definition to prevent auto-seeding on first install. - -### Integration Cleanup - -- Removed creators, exports, docs references, and implementation files for the deleted integrations. -- Removed unused dependencies from `packages/integrations/package.json`. - -### Database Migration - -- Added `packages/db/migrations/custom/0003_remove_widget_only_integrations.ts`. -- The migration moves old integration-linked widget config into widget options, then deletes the old widget-only integration rows. -- Updated the earlier release widget migration to use the new `provider` field instead of `providerIntegrationId`. - -### Docs - -- Updated Releases widget docs to describe providers instead of integrations. -- Updated Timetable docs to remove Search.ch integration setup. -- Removed obsolete integration docs pages for the deleted integration kinds. -- Updated docs sitemap and integration docs mappings. - -### Translations - -- Added English labels for the new widget options: - - `widget.timetable.option.baseUrl.label` - - `widget.releases.option.repositories.providerUrl.label` - -## How It Works Now - -Release provider configuration lives on each Releases widget repository entry. The request handler resolves provider metadata and fetches releases directly from the provider-specific endpoint. GHCR uses anonymous OCI registry access for public packages. - -Timetable passes its widget URL option directly to its API router and request handler. No global integration lookup is needed. - -ArchiveTeam Warrior continues to use the standard integration system, but users must manually add the integration (it is not auto-created on install). - -## Deliberate Non-Goals - -- No provider secret/token support was added. -- No new secret storage model was introduced. -- No compatibility layer was kept in `packages/integrations`. - -Widget options are client-visible, so storing provider credentials there would be wrong. If authenticated provider requests are needed later, they need a separate secret-storage design. - -## Verification So Far - -- Focused typechecks passed for affected packages. -- Full `pnpm turbo typecheck` passed. -- Full `pnpm lint` passed with existing warnings. -- Focused release provider normalization tests passed. -- Widget translation test passed. -- Live GHCR smoke checks passed for `ghcr.io/muchobien/pocketbase:latest` and `ghcr.io/homarr-labs/homarr:latest`. -- `pnpm test packages/integrations/test/pi-hole.spec.ts` passed earlier, but failed on rebased reruns because Pi-hole reported `domainsBeingBlocked` as `-2`/`0` instead of `> 1`. diff --git a/PRODUCT.md b/PRODUCT.md deleted file mode 100644 index bac6f41bd..000000000 --- a/PRODUCT.md +++ /dev/null @@ -1,39 +0,0 @@ -# Product - -## Register - -product - -## Users - -Homarr is for self-hosters and administrators who assemble dashboards for services across home labs and private infrastructure. They need dense, reliable controls and status at a glance, while retaining enough guidance to configure advanced features without hiding how they work. - -## Product Purpose - -Homarr provides one place to organize, observe, and operate self-hosted services. Success means users can build useful dashboards quickly, understand their state, recover from configuration errors, act on services, and reshape their workspace without repeatedly leaving the board. Boards must load immediately, stay visually stable, and keep widgets legible across screen sizes. - -## Brand Personality - -Direct, capable, precise, and approachable. Homarr should feel calm under load, be truthful about system state, and reward users who refine details. - -## Anti-references - -- Decorative dashboards, oversized metric cards, and motion without state meaning. -- Wizard flows that fight ordinary scrolling or rigid layouts that force one workflow. -- Hidden configuration magic and implementation complexity exposed before it is needed. -- Clever custom controls where familiar platform or Mantine interactions already work. - -## Design Principles - -1. Keep configuration, consequences, and system state visible. -2. Make simple tasks short without limiting advanced workflows. -3. Preserve expert depth while prioritizing urgent information at small sizes. -4. Reveal dense workspaces progressively through a consistent advanced focus mode. -5. Isolate failures and show loading, stale, partial, empty, and failed states truthfully. -6. Use the existing Mantine design language consistently across management and board surfaces. -7. Keep spatial actions direct: moving, resizing, nesting, and using fixed rails happen on the canvas with immediate feedback. -8. Preserve predictable widget composition with fixed logical tile sizes and horizontal scrolling before controls become inaccessible. - -## Accessibility & Inclusion - -Target WCAG 2.2 AA. Every pointer interaction needs a keyboard and coarse-pointer path. Support screen readers, visible and restored focus, sufficient contrast, reduced motion, non-color status cues, responsive layouts, actionable error messages, and keyboard equivalents for drag and resize operations. diff --git a/REVIEW.md b/REVIEW.md deleted file mode 100644 index cb32a60d2..000000000 --- a/REVIEW.md +++ /dev/null @@ -1,263 +0,0 @@ -# PR #6502 widget-modernization ultra-review - -## Executive result - -**Merge recommendation: changes required.** No P0 was found, but the current branch still has five P1 issues: a pre-existing Custom API authorization/redirect weakness exposed by this subsystem review, an inaccessible manual advanced-focus interaction, a likely fixed-position/transform geometry defect, systemic false empty states for failed queries, and unvalidated integration-provided navigation URLs. Eight P2 issues cover raw error disclosure, unsafe runtime-ref interfaces, localization, responsive/theming drift, test coverage, and inaccurate PR copy. - -Audit health (Impeccable rubric): accessibility 1/4, performance 2/4, responsive design 2/4, theming 2/4, anti-patterns 3/4; **10/20 (Acceptable, significant work required)**. The UI does not look generically AI-generated; its problem is inconsistent technical behavior beneath an otherwise coherent Mantine vocabulary. - -## Reviewed revision and environment - -| Item | Value | -| ---------------------------- | ---------------------------------------------------------------------------------------------- | -| PR | #6502, `feat: modernize dashboard widgets` | -| Reviewed head | `96e92485a5fd45f3648cfac0453e614779c414ba` | -| Base branch / fetched base | `dev` / `d58a47b776a55d04dee2220f59d072b9af8bbed3` | -| Merge base | `d58a47b776a55d04dee2220f59d072b9af8bbed3` | -| Diff | 359 files, +15,721/-4,478 | -| PR state | open, non-draft, `BLOCKED`; no approval decision | -| Hosted checks at audit start | Fast gate, Container and E2E, CodeQL, JS/TS analysis, Actions analysis, title, auto-fix: green | -| Inline threads | 34 total, 7 unresolved; only 2 remain substantively valid | -| Mantine | repository lock: `@mantine/core`, hooks, charts and dates 9.4.1 | -| Local tools | Node 24.16.0 and pnpm 9.5.0; repository requires Node >=24.18.0 and pnpm >=11.15.1 | - -The former red baseline `7b7045202d289b7d83946befcee5d2845ea4a706` had a green Fast gate and a failed Container/E2E run (`30748255760`, job `91498308523`). The latest head has a green Container/E2E job (`30756067198`, job `91519039504`). This proves the current suite passed once; it does not satisfy the requested three-run flake characterization. - -## PR-description traceability - -| Claim | Result | Evidence / correction | -| --------------------------------------------------------- | -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| “all 54 widget renderers with compact and advanced modes” | **Inaccurate** | 54 `WidgetKind` values exist. `displayMode="advanced"` reaches 53; `app` is deliberately excluded in `item-content.tsx:51` and documented as compact-only. Change copy to “53 widget renderers; app tiles remain compact,” or implement app advanced mode. | -| advanced focus: hover, keyboard, touch, geometry | **Partial** | Entry paths, Escape ownership, reduced motion, close focus, touch button and zero-dimension guards exist. WID-002/003 remain. | -| richer widget context actions | **Partial** | `Menu.ContextMenu` is a good Mantine choice and query scope is item-aware. Dispatch still crosses `any`; Custom API action authorization is not represented. | -| standardized query identity/cache/status | **Partial** | Query keys, matchers, runtime capture, recovery and tests exist. Thirty-nine of 53 renderer query calls do not read errors; runtime ref registration is render-time mutable state. | -| safe polling | **Mostly confirmed** | defaults are limited to `widget` namespace; Custom API resume immediately refetches; per-widget intervals exist. State/ref typing still needs redesign. | -| partial-failure rendering | **Partial** | settlement helper and several routers are strong; many renderer-level total failures still appear empty/disconnected. | -| bounded integration responses | **Mostly confirmed** | common bounded reader, Custom API 2 MiB, timetable 512 KiB, Traefik bounds and Beszel queue bounds exist. Custom action execution remains outside the hardened fetch path. | -| timetable hardening | **Confirmed** | board/item permission checks, saved-value comparison, public-address resolution, private ranges, per-request DNS re-resolution, pinned dispatcher, redirect rejection, timeouts, response bounds and schemas are present. | -| precise placement | **Mostly confirmed** | mouse, touch tolerance, keyboard, occupied-cell validation, dynamic bounds, nearest fit and immediate persistence exist. Failure/race/live responsive coverage remains insufficient. | -| widget catalog documentation | **Partial** | all kinds have pages and shared interactions; wording overclaims focus behavior and validation counts are stale. | -| validation: 40 files/162 tests, 6/6 E2E | **Stale** | current diff contains 57 changed unit-spec files (including three E2E specs); repository has 42 widget spec files and six E2E specs. Update from the exact final run. | -| independent reviews “pass” | **Not supported** | unresolved valid findings, current P1s, and unavailable live QA contradict an unqualified pass. | - -## Mantine suitability ledger - -Legend: **U** already used appropriately; **C** consolidation/replacement candidate; **R** relevant but current implementation can stay; **N** not relevant to widget runtime; **D** dependency/version addition. Exact 9.4.1 package archives were inspected in `/tmp`; live docs/Context7 include 9.5.0. - -### Core catalog - -- **U:** ActionIcon, Alert, Anchor, Avatar, Badge, Box, Button, Card, Center, Code, Divider, Flex, Grid, Group, Image, Loader, Menu (`Menu.ContextMenu`), Overlay, Paper, Popover, Portal, Progress, RingProgress, ScrollArea, SimpleGrid, Skeleton, Stack, Table, Tabs, Text, ThemeIcon, Title, Tooltip, UnstyledButton. -- **C:** Accordion (dense integration sections), DataList (semantic label/value stats), EmptyState (replace bespoke empty state), FocusTrap and Modal compound API (WID-002), LoadingOverlay (background refetch without deleting content), NumberFormatter, OverflowList/Scroller (responsive action and chip rows), Table.ScrollContainer, Timeline (activity/feed histories), VisuallyHidden and Kbd, CloseButton, Dialog/HoverCard/Notification where persistent errors/actions need semantics. -- **R:** Affix, AppShell, AspectRatio, BackgroundImage, Breadcrumbs, Burger, Checkbox, Chip, Collapse, ColorInput/ColorPicker/ColorSwatch/AlphaSlider/AngleSlider/HueSlider, Combobox/ComboboxPopover, Container, CopyButton, Drawer, Fieldset, FileButton/FileInput, FloatingIndicator/FloatingWindow, Highlight, Indicator, Input/JsonInput, List, Mark, Marquee, MaskInput, Menubar, MultiSelect/NativeSelect/NumberInput/PasswordInput/PillsInput/PinInput/Radio/RangeSlider/Rating/SegmentedControl/Select/Slider/Switch/TagsInput/Textarea/TextInput, Pagination, Pill, SemiCircleProgress, Space, Splitter, Spoiler, Stepper, Transition, Tree/TreeSelect, Typography. Use only where an existing widget requirement matches; do not churn working layouts. -- **N:** Alpha/color/angle primitives outside configuration forms, AppShell/navigation primitives, TableOfContents, CorePackage documentation. -- **D (9.5, not 9.4.1):** Cascader. **RollingNumber and Splitter are present in 9.4.1.** - -### Hooks catalog - -- **C:** `useFocusReturn`, `useFocusTrap`, `useReducedMotion`, `useRovingIndex`, `useLongPress`, `useScroller`, `useElementSize`, `useViewportSize`, `useHotkeys`, `useMediaQuery`, `useResizeObserver`. -- **U/R:** focus-within, hover, disclosure, click-outside, merged-ref, interval/timeout, local-storage, event/window listeners, throttled/debounced values and list/set/map/state helpers are available in 9.4.1 and should replace local mechanics only when behavior and tests improve. -- **N:** document title/favicon/hash/headroom/page-leave/OS/eye-dropper/fullscreen/network/orientation and other page-level utilities have no direct widget-remediation need. Every hook listed under `## Hooks` in `MANTINE.md` is covered by this rule; no hook requires 9.5 for the recommendations above. - -### Form, dates, charts, schedule, extensions, theme and styles - -- **Form:** existing `@homarr/form` should remain the abstraction over all cataloged form APIs. No widget-runtime replacement; use current validation/status APIs for widget editors (**R**). -- **Dates:** all catalog entries are in installed 9.4.1 dates. `Calendar`, `MiniCalendar`, and `TimeValue` are candidates; other picker/input entries are editor-only (**R**). Importing dates directly into `@homarr/widgets` requires adding that workspace dependency (**D**). -- **Charts:** 9.4.1 exports Area, Bar, BarsList, Bubble, Composite, Donut, Funnel, Heatmap, Line, Pie, Radar, RadialBar, Sankey, Scatter, Sparkline and Treemap (**C/R**). Prefer Sparkline for tiny trends, BarsList for ranked values, Heatmap for calendar/activity density, Composite for mixed analytics. **BulletChart and SunburstChart are 9.5-only (D)**. Replacement requires accessibility and bundle comparison, not blanket Recharts removal. -- **Schedule:** all `AgendaView`, day/week/month/year/resource views and Schedule pages require new `@mantine/schedule` dependency (**D**). AgendaView is the only plausible calendar-widget candidate; its weight and semantics must beat the existing grouped list before adoption. -- **Guides/FAQ/Other:** server components, portal testing, scroll lock, accessibility, nested popovers, zoom, responsive styling and version changelogs are relevant references (**R**); framework/setup/contribution/old migration entries are **N**. The 9.5 changelog is informational only. -- **Theming/styles:** Colors, ColorSchemes, DefaultProps, MantineProvider, ThemeObject, CSS variables, data attributes, CSS Modules, responsive/RTL/style props/Styles API/performance are **U/R**. WID-009 requires shared layer/color tokens. Emotion, Sass, Vanilla Extract and unrelated global setup are **N**. -- **Extensions:** existing modals, notifications, spotlight and rich-text abstractions are **U**; Carousel could consolidate Immich only after behavior parity; Dropzone/CodeHighlight/NProgress are **N** for this audit. - -## Complete 54-widget coverage matrix - -“Test” means a focused widget-local spec exists, not that all required states are covered. Every row still requires the common contract suite in WID-013. - -| WidgetKind | Family | Advanced | Focused test | Principal audit gap | -| --------------------------- | ----------------------- | ----------- | ------------ | ---------------------------------------------------------- | -| clock | basic | yes | no | query error, locale-format options | -| weather | basic/feed | yes | yes | query error; dayjs locale/time patterns | -| app | basic/link | **no** | no | PR wording; URL contract | -| iframe | custom content | yes | yes | manual focus/iframe trapping; URL privacy thread now fixed | -| video | custom content | yes | no | media/focus/live behavior | -| notebook | notes | yes (inner) | yes | editor focus inside manual surface | -| anchorNote | notes | yes | no | query error, save/error regression | -| dnsHoleSummary | network | yes | no | total query error, hard-coded chart colors | -| dnsHoleControls | network/security | yes | no | total error and permission matrix | -| smartHome-entityState | smart home | yes | no | raw state in aria; action permissions | -| smartHome-executeAutomation | smart home | yes | no | mutation/permission/edit-mode E2E | -| stockPrice | analytics | yes | yes | total error | -| mediaServer | media | yes | no | total error and table a11y | -| calendar | calendar | yes | yes | total error; fixed HH:mm; schedule tradeoff | -| downloads | media | yes | yes | four-state/component coverage, arbitrary z-index | -| mediaRequests-requestList | media | yes | no | total error; external URLs/actions | -| mediaRequests-requestStats | media | yes | no | total error; links/colors | -| mediaTranscoding | media | yes | yes | total error and responsive table | -| mediaMissing | media | yes | yes | total error and external URL | -| minecraftServerStatus | infrastructure | yes | no | total error/malformed payload | -| networkControllerSummary | networking | yes | no | total error; WAN/unknown localization | -| networkControllerStatus | networking | yes | no | responsive rule duplication | -| rssFeed | feed | yes | yes | strong stale/partial state; locale relative time | -| bookmarks | basic/link | yes | yes | recomputation; URL contract | -| indexerManager | media | yes | no | total error; runtime action ref | -| healthMonitoring | infrastructure | yes | yes | integration query error | -| releases | infrastructure/feed | yes | yes | secret/item authorization needs E2E | -| mediaReleases | media | yes | no | total error; external URLs | -| dockerContainers | infrastructure | yes | yes | total error; z-index/table semantics | -| firewall | networking/security | yes | yes | partial-query matrix; loose router generics | -| notifications | infrastructure | yes | no | total error; untrusted href | -| systemResources | infrastructure | yes | yes | total error; previous network thread fixed | -| coolify | infrastructure | yes | yes | total error; URL validation | -| systemDisks | infrastructure | yes | yes | total error | -| timetable | calendar | yes | no | backend strong; component locale/live tests absent | -| immich-serverStats | media | yes | yes | two ignored query errors | -| immich-albumCarousel | media | yes | yes (query) | query error and nested overlay/focus E2E | -| paperlessNgx | analytics | yes | no | former error thread fixed, no regression spec | -| patchmon | infrastructure | yes | yes | total error | -| bazarr | media | yes | yes | total error | -| tracearr | analytics | yes | yes | total error | -| speedtestTracker | analytics | yes | yes | total error | -| uptimeKuma | infrastructure | yes | yes | total error | -| audioStats | media | yes | yes | good dual-error handling; partial-state tests needed | -| umami | analytics | yes | no | runtime query registration; chart a11y | -| vpn | networking/security | yes | no | total error; status/permission matrix | -| archiveTeamWarrior | infrastructure | yes | yes | suspense path; docs present | -| ups | infrastructure | yes | no | total error | -| beszelSystemTable | monitoring | yes | yes | nested chart/focus and live subscription | -| beszelSystemGrid | monitoring | yes | no | live/error UI; no focused renderer test | -| beszelAlerts | monitoring | yes | no | partial error and status semantics | -| beszelSystemStats | monitoring | yes | yes | runtime refs, locale tooltip | -| traefik | networking | yes | no | total error; bounded backend positive | -| customApi | custom content/security | yes | yes | WID-001/007/008; polling resume fixed | - -## Severity-ranked findings - -### WID-001 — P1 confirmed, pre-existing: Custom API actions lack resource authorization and hardened fetch policy - -- **Location/claim:** `packages/api/src/router/custom-widget/custom-widget-router.ts:57-102,392-451`; “harden Custom API” and action-permission semantics. -- **Evidence/reproduction:** any authenticated account can call `customWidget.all`, learn every definition ID and URL, then call `customWidget.execute({definitionId})`. The mutation verifies neither board nor item nor an action permission. It decrypts administrator-provided secrets, uses `new URL()` only, and `redirect: "follow"`. The PR hardened `widget.customApi.getData`, but not this sibling execution path. -- **Impact/rule:** unauthorized side effects against internal services and authenticated redirect chains; broken object-level authorization. A view-only account can invoke administrator-created controls outside any board context. -- **Correction:** require `{boardId,itemId,definitionId}`; load the item and verify it is `customApi`, belongs to the board, references the definition, and the caller has an explicit execute policy. Until that policy exists, restrict to admin. Share `validateCustomApiUrl`, timeout, redirect rejection, bounded disposal and redacted errors with getData. Compatibility: old direct callers must send item/board context. -- **Tests:** procedure tests for anonymous, unrelated authenticated, view-only, modifier, admin, mismatched item/definition, disabled definition, redirects, credential URL, timeout and secret non-disclosure; E2E action button across roles. - -### WID-002 — P1 confirmed, PR-introduced: manual advanced focus is not an accessible modal - -- **Location:** `advanced-focus/context.tsx:194-209`, `items/item-content.tsx:113-189`. -- **Evidence:** manual mode renders an Overlay plus a `role="region"` Card. There is no FocusTrap, `aria-modal`, background inertness, scroll lock or backdrop dismissal. Only the close button is initially focused; Tab can leave the surface and activate dimmed board controls. -- **Impact/rule:** keyboard/screen-reader users lose the interaction boundary; WCAG 2.1.2, 2.4.3 and ARIA dialog pattern. Iframes/editors make escape especially likely. -- **Correction/Mantine:** render manual mode through `Modal.Root` compound parts (or ModalBase), using its portal, FocusTrap, scroll lock, Escape/return-focus and semantic content. Preserve preview mode as non-modal. Configure nested overlays and `removeScrollProps`; keep a 44px `Modal.CloseButton` and explicit title via VisuallyHidden if needed. -- **Tests:** RTL portal/focus-cycle/return tests; Playwright Tab/Shift+Tab, nested Menu/Select/Popover/editor/iframe, backdrop and every close path; reduced motion and 200% zoom. - -### WID-003 — P1 probable, PR-introduced: fixed advanced surface remains under transformed Gridstack ancestry - -- **Location:** `advanced-focus.module.css:35-42`; Card remains inside the Gridstack item while only the backdrop is portaled. -- **Evidence:** CSS fixed descendants establish their containing block at a transformed ancestor. Gridstack uses transforms for positioned items, so viewport-derived `left/top` can be interpreted relative to the item on affected layouts. A Portal wrapper exists only for Overlay. -- **Impact:** off-screen, clipped or incorrectly scaled focus surface across breakpoints/remounts. -- **Correction:** portal the focused surface itself (naturally achieved by WID-002) and calculate geometry in the same viewport coordinate system. Do not compensate with transform-specific offsets. -- **Tests:** real Gridstack at every layout/viewport, scrolled page, header, dynamic section and resize/remount; assert bounding rect within viewport and finite scale. - -### WID-004 — P1 confirmed, regression-exposed/systemic: query failures still become valid empty/disconnected UI - -- **Location:** 39 of 53 renderer query calls do not read `error`, including bookmarks, weather, calendar, media server, system resources, Coolify, DNS Hole, Tracearr, notifications, Immich, VPN and others listed in the matrix. Query defaults do not set `throwOnError` (`trpc.tsx:69-93`). -- **Evidence:** TanStack Query returns `data=undefined` on total failure. Components default to `[]`, `null`, or empty branches, so the board ErrorBoundary is never reached. Network Controller and Paperless were fixed, proving the pattern; it was not completed. -- **Impact:** operators are told “empty” or “disconnected” when monitoring failed, violating the product’s truthful-state requirement. -- **Correction/Mantine:** introduce a shared `WidgetQueryState` contract distinguishing initial Skeleton, background LoadingOverlay, stale Alert, partial warning, true EmptyState and terminal error. Either explicitly throw only when no usable cached data or render a shared error Alert. Preserve stale data. -- **Tests:** parameterized contract tests for every queried widget: initial, success-empty, total failure, stale+failure, partial failure, refetch, remount/persisted cache and sibling isolation. - -### WID-005 — P1 confirmed, PR-introduced/systemic: integration-provided links bypass a shared URL policy - -- **Location:** examples include `media-missing/component.tsx:291`, `notifications/component.tsx:77`, media requests list/stats, Coolify resource/server links, releases, bookmarks and iframe. Only RSS and custom JSX visibly use explicit protocol sanitizers. -- **Evidence:** dynamic strings are assigned directly to `href`/new-tab controls. Integration APIs and remote feeds are trust boundaries; no renderer-wide `http/https` guard is enforced. -- **Impact:** unsafe schemes, credential-bearing URLs, internal detail disclosure and inconsistent opener behavior. -- **Correction:** add one typed application URL helper returning a sanitized URL/undefined, with allowed schemes per use case, credential stripping/rejection, consistent `noopener noreferrer`, and disabled non-link presentation. Validate again server-side for action endpoints. -- **Tests:** `javascript:`, `data:`, malformed, credential, relative, http/https and missing URLs for each shared link primitive. - -### WID-006 — P2 confirmed, PR-introduced: runtime query/action state mutates untyped refs during render - -- **Location:** `definition.ts:121-162`; runtime registration calls in media missing/transcoding, audio, calendar, Umami, Beszel and Immich; `widget-context-menu.tsx:157-174`. -- **Evidence:** `setWidgetRuntimeQueries` mutates a shared object during render; concurrent/aborted renders can publish uncommitted query identity. Action dispatch casts the definition to `Record` and `any`, then casts its result back. -- **Correction:** make definition generics preserve kind/options/action types end-to-end; replace stringly opaque ref slots with a typed per-item registration API updated in a committed effect (or use `useSyncExternalStore`). Separate query registration from imperative actions. -- **Tests:** StrictMode, interrupted/remount, options change and cleanup; compile-time `tsd`/type assertions rejecting wrong action props. - -### WID-007 — P2 confirmed, regression-exposed: raw backend errors are exposed to users and assistive text - -- **Location:** Custom API UI `component.tsx:561-576`; API `custom-api.ts:79-85`; several partial fallbacks use `error.message`. -- **Impact:** internal hostnames, request paths and implementation details can appear in tooltips/aria labels and logs. -- **Correction/Mantine:** return stable error codes plus redacted public messages; keep detailed causes server-side with correlation IDs. Render localized Alert/Notification details, never raw throwable text. -- **Tests:** errors containing credentials, query strings, private hosts and multiline backend bodies must not reach tRPC payload, DOM, accessibility tree or notifications. - -### WID-008 — P2 confirmed, PR-introduced/regression-exposed: locale handling remains incomplete - -- **Locations:** Beszel chart/tooltip dayjs formats, calendar event `HH:mm`, downloads `YYYY-MM-DD HH:mm`, timetable `HH:mm:ss`, weather day/month/time formats; `_inputs/widget-location-input.tsx:199` hardcodes `Intl.NumberFormat("en")`. -- **Also:** `beszel/_shared/disk-usage.tsx:41`, stats loading aria label, Network Controller `WAN`/`unknown` are English/raw accessible strings. -- **Correction:** centralize app-locale date/time/number/duration/status helpers; load canonical dayjs locale only at the boundary; use localized translation keys for aria/status. NumberFormatter is suitable for simple display but application helpers should own locale. -- **Tests:** at least `en-US`, `fr-FR`, `de-DE`, RTL locale, 12/24-hour preference and long translations, including accessibility names. - -### WID-009 — P2 confirmed: layer and color tokens are inconsistent - -- **Locations:** downloads z-index 1000 and rgba row colors; item title z-index 4; item menu/dynamic menu 10; media server white rgba; Indexer Manager hex colors; DNS Hole rgba palette; Umami hex tick colors. -- **Correction:** define shared semantic layer tokens relative to Mantine CSS z-index variables and semantic status/chart tokens respecting light/dark/forced colors. Do not replace intentional service branding. -- **Tests:** light/dark/forced-colors with nested overlays and tooltip ordering. - -### WID-010 — P2 confirmed: responsive decisions are duplicated and under-tested - -- **Location:** Network Controller Status `component.tsx:44,59-78` (open valid thread); Bookmark `component.tsx:94` recomputation (valid but low-impact thread); similar width/height literals across renderers. -- **Correction:** small typed breakpoint lookup helpers per family, memoized only for genuinely expensive layout. Prefer container-query Grid/SimpleGrid where structural. Do not cargo-cult `useMemo` for a cheap pure calculation; benchmark Bookmark before accepting the review suggestion. -- **Tests:** boundary tables for minimum/typical/wide/short/advanced sizes and 200% zoom. - -### WID-011 — P2 confirmed: PR/docs overstate behavior and validation - -- **Location:** PR body, board/getting-started copy “advanced preview in place,” validation numbers, and unqualified review pass. -- **Correction:** state 53 advanced renderers plus compact-only app; call manual focus an overlay only after WID-002/003; publish exact final-SHA check/test counts and disclose unsupported/live-untested states. - -### WID-012 — P2 confirmed: focused automated coverage is far below the 54-widget/data-state claim - -- **Evidence:** 42 widget-local spec files are helper-heavy; 20+ renderers have no focused spec. Six E2E files exist, but only board interactions and Custom JSX directly exercise this modernization. The earlier Custom JSX login wait failed once and current exact-route wait remains. -- **Correction:** add shared renderer contract harness plus family E2Es. Replace Custom JSX’s exact post-submit URL race with a shared login helper that waits for authenticated session/stable destination, then run it three times in CI. - -### WID-013 — P2 confirmed: open review-thread state no longer matches code - -| Thread | Classification | -| ------------------------------------------- | ------------------------------------------------------------------- | -| iframe complete URL | already fixed/false positive at current line: only host is rendered | -| system resources network gate | already fixed, outdated | -| RSS total error | already fixed: no-data error throws; stale data retained | -| bookmarks memoization | valid P3/P2-low; benchmark first | -| network-controller total error | already fixed, outdated | -| network-controller breakpoint consolidation | valid P2 maintainability | -| Paperless total error | already fixed, outdated | - -Resolve the five stale threads with evidence; address or explicitly disposition the two live suggestions. Re-run review because CodeRabbit was paused during active development. - -## Systemic remediation roadmap - -1. **Security/authorization:** WID-001 and WID-005; add negative-role/protocol tests before merge. -2. **Interaction accessibility:** replace manual focus with portaled Mantine modal semantics (WID-002/003), then test nested widget content. -3. **Truthful data state:** build the shared query-state contract and migrate all 39 ambiguous sites; keep valid stale data and partial results. -4. **Typed interfaces:** replace `widgetStateRef` slot mutation and `any` context dispatch with committed typed registrations. -5. **Widget families:** media/downloads, infrastructure, networking/security, smart-home, analytics/calendar/feed, then Beszel; apply URL, state, locale, responsive and a11y contracts in that order. -6. **Design-system cleanup:** semantic layers/colors and restrained Mantine consolidation. Do not add Schedule or upgrade to 9.5 without a separate dependency/bundle decision. -7. **Docs/PR:** correct renderer count, behavior and exact validation evidence. -8. **Final proof:** frozen install on supported Node/pnpm; format, lint, full typecheck, affected and full unit tests, production and docs builds; Custom JSX three times; complete production-container E2E; desktop/tablet/mobile keyboard/touch/light/dark/reduced-motion/zoom/a11y-tree QA. Push nothing until all refer to one unchanged SHA; close every review thread and obtain required approval. - -## Positive findings - -- Timetable is the strongest security work in the PR: saved resource authorization, private-range rejection, DNS rebinding resistance through pinned lookup, redirect rejection, bounds and schemas are coherently tested. -- Bounded response helpers, Beszel bounded queue/cancellation, and partial-integration settlement materially reduce failure blast radius. -- RSS preserves stale data and distinguishes partial feed failure; Network Controller and Paperless now correctly escalate total failures. -- Item-scoped query matchers and tests address sibling-widget refresh isolation; global polling defaults are restricted to the widget namespace. -- Touch long-press has movement tolerance; focus scale guards prevent Infinity/NaN; reduced-motion and remount cleanup are present. -- Existing Homarr theme, Mantine components and shared UI vocabulary are generally preserved. Most proposed Mantine work is consolidation, not redesign. - -## Validation evidence and uncertainty - -- `MANTINE.md` was fetched from `https://mantine.dev/llms.txt` and passed byte-for-byte `cmp`; `llms-full.txt` stayed in `/tmp`. -- Context7 current Mantine docs were queried for overlay/focus, responsive/data-state/accessibility, charts and Schedule. Static 9.4.1 archives verified exact exports; Cascader, BulletChart and SunburstChart are 9.5-only. -- Local frozen install could not start because host Node/pnpm are below repository engine requirements. No dependencies, source files or machine toolchain were changed. -- Docker API access is denied, so production-container E2E could not be rerun locally. Hosted exact-head Fast gate and Container/E2E are green. -- `agent-browser` is not installed. Temporary `npx` execution was rejected by the environment’s security reviewer, so live exploratory QA/a11y-tree inspection was not performed. -- External integrations were not available; malformed/partial/permission combinations are static-analysis conclusions unless a focused test already exists. -- This review intentionally changes no production code and makes no commit, push, thread resolution or PR edit. - -Finalization must re-query the PR head/checks/threads. If the head differs from the reviewed SHA, this report is a snapshot and the delta requires review before merge. - -**Final refresh (2026-08-03):** head remained `96e92485a5fd45f3648cfac0453e614779c414ba`; all reported hosted checks remained successful; merge state remained `BLOCKED` with no approval decision; unresolved threads remained 7 of 34. The branch did not change during the audit.