AB#2576 adds CategoryItem.PrefetchCount to the GetDocuments response: when set, the
app silently auto-downloads the top N downloadable documents in that category so they're cached
on-device ahead of a member ever tapping them. That silent behavior is exactly the problem —
nothing in the UI tells the member it happened. A code audit of the whole
Presentation layer while scoping AB#2576 found DataManager.IsDocumentDownloaded
consumed only as an internal implementation detail:
IsDocumentDownloaded, "downloaded", "offline", or "cached" in any
.razor/.razor.cs file.DocumentRow.razor shows exactly two indicators today — an unread dot and a
favorite heart — no download/offline/cloud icon.DocumentItem and DocumentRowViewModel expose no
IsDownloaded-style bindable property at all.alpa-components.css has no downloaded/offline badge class for documents (the only
"offline" classes, .alpa-kcm-map-offline*, belong to the unrelated KCM map feature).DocumentOpenPage.razor.cs downloads/opens a document unconditionally on open — it
never branches UI on whether the file was already cached.This is not a native-vs-Blazor parity gap. Every other doc in this hub compares an existing native screen against its undesigned Blazor counterpart. There is no native precedent here — PrefetchCount and the concept of a visible "document cache" are new to this app entirely. The template below is adapted accordingly: there is no side-by-side native screenshot section, because there is no native side to capture.
| Aspect | Current state |
|---|---|
| Download indicator | None. IsDocumentDownloaded only gates two internal decisions: whether
SharedActionsService shows a "you're offline" alert before attempting a download,
and which of GetDocumentDownloadFromFileAsync vs. the network download path
DataManager.GetDocumentDownloadAsync takes. |
| Favorites page layout | Single flat list (alpa-fav-list) under one static "SAVED ITEMS" section
label. No tabbing/pill-switch UI exists on this page today. |
| Favorites data model | Favorite.ItemTypeId (FavoriteItemTypes): MenuItem, Document,
NotificationCenterMessage, DocumentSet — all backed by the real Favorites API, all
member-initiated ("I saved this"). Auto-downloaded documents are not member-initiated and have
no representation in this model. |
| Pill/segmented-tab precedent | Shared, subsystem-neutral alpa-btn-pill-group / alpa-btn-pill
(D46), already used on the Notifications page to switch Comms vs. Flight Finder lists — a
directly reusable component, independent of any particular page or data model. |
| Notifications ↔ Favorites precedent for "related but separate" | Confirmed by code audit: separate @page routes (/favorites,
/notifications), separate Application-layer ports
(IFavoritesQueries vs. INotificationsQueries, no shared base beyond
the generic scaffold marker-interface pattern every port uses), separate scaffold routers
(FavoritesQueriesRouter / NotificationsQueriesRouter in
ScaffoldDataSourceRouters.cs), separate domain models, no shared LiteDB collection.
The only place they're "affiliated" is the UI entry point: sibling icon buttons
(topnav.favoritesButton2, topnav.notificationsButton3) in the same
right-hand cluster of TopNav.razor, and a shared component (the pill
control) — never a shared page, route, or data model. |
The original direction on this page (a second, pill-switched list living inside the Favorites page/data model) is rejected. Jose's correction: build Document Cache the way Notifications and Favorites relate to each other today — two different mechanisms, affiliated by function, not one mechanism wearing two hats. Favorites' data model is exclusively member-initiated saves; folding a system-initiated cache list into it would be exactly the kind of modeling mismatch flagged in the prior draft's Open Question 1.
Applying the confirmed Notifications/Favorites separation pattern (see table above) to Document Cache:
@page (e.g. /document-cache),
not a query-string mode of /favorites.IDocumentCacheQueries) alongside — not extending — IFavoritesQueries,
mirroring how INotificationsQueries sits beside it today.FavoritesViewModel — Notifications itself has no such base either
(NotificationsPage.razor.cs talks straight to its port, no intermediate ViewModel
class on the Blazor side).TopNav.razor (open question below — that cluster is currently a fixed 4-slot layout
with no obvious fifth slot), and/or reuse of the pill component or the
DocumentRow/CardSmall row treatment already used elsewhere — never a
shared page, route, or data model.Two candidate data sources remain open regardless of where the UI lives:
IsDocumentDownloaded checks) and resolve each back to a
DocumentItem via GetDocumentByFileId. Simple, always accurate to what's
actually on disk, but not queryable/sortable without a filesystem scan.DataManager.PrefetchDocumentAssetsAsync (AB#2576) already knows exactly which
documents it downloaded and when — persisting that list gives a proper queryable data source (for
sort, "downloaded on" display, eviction later) at the cost of a new store to keep in sync with the
filesystem.
Either path needs a new bindable property (e.g. DocumentRowViewModel.IsDownloaded or
similar) to actually render a per-row indicator — the existing view-model has no such property
(see "What exists today" above).
| # | For | Question |
|---|---|---|
| 1 | Design | Where does the Document Cache entry point live? Candidates: a
fifth icon in the TopNav cluster (currently a fixed 4-slot layout — avatar, heart,
bell, disabled search), a link from Document Center (where these documents actually live), or a
link from Favorites (functionally adjacent per Jose's direction, even though it's a separate
mechanism). No Figma frame exists for any of these. |
| 2 | Design | Copy and iconography for "Document Cache" as a page title/nav label and as a per-row indicator (a downloaded document still visible in its normal Document Center location needs some marker too, not just in this new list) — no Figma frame exists for either. |
| 3 | Design | Should a member be able to remove a document from the cache (free local storage) from this list, or is it read-only / self-managed by whatever eviction policy PrefetchCount ends up needing? |
| 4 | Product | Should Document Cache show only PrefetchCount
auto-downloads, or every downloaded document regardless of how it got there (e.g. a document a
member manually opened once, which is also cached per IsDocumentDownloaded)? These
are behaviorally identical on disk today — deciding to distinguish them is a product call, not an
engineering one. |
| 5 | Engineering | Data source for the list — read the cache directory live vs. a persisted "prefetched" record (see Proposed direction above). Affects whether this needs a new LiteDB collection. |
ALPAMobile/Services/DataManager.cs — PrefetchDocumentAssetsAsync,
SelectDocumentsToPrefetch, IsDocumentDownloaded (AB#2576)ALPAMobile.Presentation/Components/Pages/FavoritesPage.razor,
ALPAMobile.Presentation/ViewModels/FavoritesViewModel.cs,
ALPAMobile.Domain/Data/Models/Favorite.cs — current Favorites list/data shapeALPAMobile.Application/Abstractions/Favorites/IFavoritesQueries.cs,
ALPAMobile.Application/Abstractions/Notifications/INotificationsQueries.cs — the two
independent Application-layer ports this doc's "own mechanism" direction mirrorsALPAMobile/Services/ScaffoldDataSourceRouters.cs — FavoritesQueriesRouter,
NotificationsQueriesRouter — confirms zero shared base class between the two mechanismsALPAMobile.Presentation/Components/TopNav.razor — the shared icon cluster
(topnav.favoritesButton2, topnav.notificationsButton3) that is the actual
"affiliated by function" mechanism between Favorites and Notifications todayALPAMobile.Presentation/Components/Pages/NotificationsPage.razor,
NotificationsPage.razor.cs — the pill-tab precedent (alpa-btn-pill-group /
alpa-btn-pill, D46, Figma 4245:5754 / 5048:13576)ALPAMobile.Presentation/Components/Library/DocumentRow.razor,
DocumentRowViewModel.cs — current per-row indicator set (unread dot, favorite heart)