Repository source: docs/plans/archive/forte_activity_feed_step2_feature_description.md
Forte Activity Feed Step 2 Feature Description
Problem
Forte has no way to see classic's technical/administrative activity log (source file paths, commit SHAs, signature-verification status, and identity/bootstrap/approval/content events across 5 filtered views) without leaving Forte for classic's /activity/. Per Step 1's Decision, the fix is a genuine three-pane paned view mirroring forte_board.php's own structure, not a simplified reader-only list.
User Stories
As a Forte user, I want to open an "Activity" view from the board toolbar, so I can see the same category breadth and technical detail classic's
/activity/provides, without leaving Forte.As a user reviewing activity, I want a left-hand filter pane offering the same five categories classic offers (All/Content/Identity/Bootstraps/Approvals), so I can narrow to the events I care about.
As a user auditing activity, I want a selected item's detail pane to show its source file path, commit SHA, and signature-verification status, so I can verify technical provenance at the same fidelity classic offers.
As a user browsing content-related activity, I want post/reply-kind items to link into the board using the existing permalink pattern, so I can jump straight to the discussion the event refers to.
As a keyboard user, I want the filter list and item list to be Tab-reachable and arrow-key navigable, matching every other paned Forte view already shipped.
Core Requirements
New route (e.g.
/forte/activity/) with arenderForteActivity(string $view)controller inApplication.php, following the samerenderStandalonePage(..., 'paned-reader-body', [...], ['/assets/forte.css'])conventionrenderForteBoard()/renderForteUserDirectory()already use.Left pane: activity-type filter list, structurally the same as
paned_folder_tree.php, with the five existing view keys (all/content/identity/bootstrap/approval) as entries. Selected filter is carried in a?view=query param, defaulting toall.Top-right pane: list of activity items for the selected filter, produced by calling the existing
fetchActivity($view)(which appliesactivityViewSql()'s per-view SQL WHERE fragment plus the matching PHP-sidehasBoardTag/hidden-post filter) verbatim — zero new query or filter logic, sameACTIVITY_ITEM_LIMITandcreated_at DESC, post_id DESC, id DESCordering classic uses.Bottom pane: detail view of the selected item, showing
kind,label,created_at, the "Author: reply-agent" badge when applicable, and the full technical metadata classic'ssource_metadata.phprenders — source path (+ link), commit SHA (+ link, truncated to 12 chars, or "commit unavailable"), and signature-verification status (sourceSignatureLink()/sourceSignatureStatus()) — same fields, same values, not a paraphrase or subset.Items whose classic destination is a board post/thread render their link using the existing
forte_post_permalinkshape (/forte?selected={threadId}&created_post_id={postId}#post-{postId}) so clicking them lands in the Forte board with that thread selected and the post highlighted; items whose classic destination is elsewhere (e.g. the feature-flags tool) keep that original destination.A new "Activity" toolbar icon button is added to
forte_board.php's toolbar, immediately after the existing "Users" button, using the identical pattern committed in e0eb3b7 (<span class="paned-toolbar-sep">+<a class="paned-toolbar-btn">with a 16×16 stroke-onlycurrentColorSVG +<span>label), linking to the new route. The new Activity page itself gets a way back to the board (a back link/button, matching howforte_users.phpreturns to the board).Filter selection and selected item are reflected in the URL (
?view=&selected=) and reproduced by the server on first load — same pre-resolution conventionresolveForteBoardSelection()already uses for the board, so a shared/reloaded Activity link reproduces the same server-rendered state instead of relying on JS correction alone.Filter list and item list are Tab-reachable and arrow-key navigable, matching the roving-tabindex convention
paned_folder_tree.php/paned_board_thread_list.phpalready use elsewhere in Forte.
Shared Component Inventory
fetchActivity(),activityViewSql(),sourcePathHref(),sourceCommitHref(),sourceSignatureLink(),sourceSignatureStatus()(all inApplication.php) — reused verbatim for both the item list and the detail-pane technical metadata; no new backend query or enrichment logic.templates/partials/paned_folder_tree.phpconvention — reused structurally for the activity-type filter left pane, swapping tag groups for the five activity views.templates/partials/paned_board_thread_list.php/paned_board_content_pane.phpconventions (data-paned-*attributes, one-visible-article-at-a-time detail pane) — reused structurally for the new list/detail panes.public/assets/forte.css's existing paned-* classes (.paned-window,.paned-toolbar-btn,.paned-toolbar-sep,.paned-board-layout,.paned-folder-tree,.paned-list-pane,.paned-content-pane,.paned-highlight-new) — reused verbatim; only a new toolbar icon and any activity-specific row/detail styling get added.The "Users" toolbar button markup from commit e0eb3b7 — exact structure replicated for the new "Activity" button.
The
forte_post_permalink/forte?selected=&created_post_id=#post-URL shape and its.paned-highlight-newrestore-on-load behavior inpaned_board_reader.js— reused verbatim for post/reply-kind activity items linking into the board.renderStandalonePage()plus theforte_users.php+renderForteUserDirectory()pair — reused as the scaffolding convention for the new route/controller/template.A new small JS file (sibling to, not a modification of,
paned_board_reader.js) following the samedata-paned-*attribute,URLSearchParams, and restore-on-load conventions — needed because this page's selection state (activity view + item) is a different shape than thread selection, so the existing script isn't reused directly.
Simple User Flow
From the Forte board, the user clicks the new "Activity" toolbar button.
The Activity page opens in the same paned chrome, defaulting to the "All" filter, with the most recent item selected and its detail shown in the bottom pane.
The user clicks "Content" in the left filter pane; the list re-renders to show only content-view activity items (the same set classic's
/activity/?view=contentalready shows).The user clicks an item in the list; the detail pane updates to show that item's source path, commit SHA, and signature-verification status.
For a reply/post-kind item, the user clicks its board link and lands back in the Forte board with that thread selected and the specific post highlighted, via the existing permalink mechanism.
The user reloads or shares the Activity page's URL; the same filter and selected item are reproduced by the server.
Success Criteria
The five activity-type filters (All/Content/Identity/Bootstraps/Approvals) are available in the left pane, and each shows exactly the same set of items as classic's corresponding
/activity/?view=filter — same underlying SQL/PHP filter logic, unchanged.Selecting any item shows its full technical metadata (source path, commit SHA, signature-verification status) in the detail pane, matching classic's fidelity exactly.
Post/reply-kind items link into the Forte board via the existing permalink pattern and correctly select and highlight the target post.
A new "Activity" toolbar button on the Forte board opens this page; the new page provides a way back to the board.
Filter selection and item selection are reflected in the URL and reproduced by the server on reload or when shared, consistent with
forte_board.php's existing convention.No new database tables or fields; the new page issues zero new SQL beyond what
fetchActivity()already runs.