Repository source: docs/plans/archive/forte_users_three_pane_step2_feature_description.md
Forte Users Three-Pane Layout — Step 2: Feature Description
Problem
The Forte Users page is a flat list of names, unlike Board and Activity's filter + listing + detail layout, so admins can't filter or inspect a user without leaving the page.
User Stories
As an admin, I want to filter the Users list (e.g., by role/status) so that I can quickly find the users I'm looking for.
As a viewer, I want to select a user from the list and see their details in a side pane so that I don't have to navigate to a separate page.
As an admin, I want the Users page to look and behave consistently with Board and Activity so that navigation feels familiar across the app.
Core Requirements
Filter pane (left) listing filter categories, mirroring the Board/Activity filter-pane pattern.
Listing pane showing the filtered set of users as selectable rows, with selection state kept in the URL like Board/Activity.
Detail pane showing the selected user's profile in place, without a full-page navigation.
Shared toolbar/layout chrome (
paned_toolbar.php,paned-window/paned-board-layoutCSS) reused unchanged, with "Users" as the active tab.No database schema changes; the existing approved user directory data source is reused as-is.
Shared Component Inventory
Toolbar —
paned_toolbar.php: existing, reused unchanged (activeView: 'users').Layout chrome —
paned-window/paned-board-layout/paned-panes-stackCSS classes inforte.css: existing, reused; no new layout system introduced.Detail data source —
/api/forte_user_detail(new, added in Step 4 Stage 1): a fragment endpoint mirroring the existing/api/forte_commit_detailpattern (renderFragment+{status, html}), not/api/get_profile— that endpoint is keyed by a singleprofile_slugand returns plain text, which doesn't fit theusername_token-aggregated directory.Filter/listing partials — no existing partial fits;
paned_folder_tree.php(tags) andpaned_activity_filter_list.php(fixed activity views) are shaped for their own domains. New partials are needed:paned_users_filter_list.php,paned_user_list.php,paned_user_detail_pane.php, following the same markup/URL-state conventions as Board/Activity.JS controller — no existing controller covers Users; new
paned_users_reader.jsneeded, mirroring the URL-state pattern inpaned_board_reader.js/paned_activity_reader.js.
Simple User Flow
User navigates to
/forte/users/.Page loads with filter pane, listing pane (approved user directory), and "Users" active in the shared toolbar.
User applies a filter, narrowing the listing pane.
User clicks a row; selection updates the URL and highlights the row.
Detail pane fetches and displays the selected user's profile via
/api/get_profile.
Success Criteria
/forte/users/visually matches Board/Activity's filter + listing + detail chrome.Selecting a user updates the detail pane without a full page reload.
Applying a filter narrows the listing without a full page reload.
Board and Activity are unchanged and unaffected.
No database schema changes.
Addendum: Semantic Filter Categories (post-Step-4 revision)
Step 4 Stage 2 originally shipped an alphabetical A-Z filter (the only schema-free option identified in Step 1, since no role/status field existed). After shipping, the user requested semantic categories instead. This addendum supersedes the alphabetical filter.
Revised filter categories (membership flags, not a mutually-exclusive partition — mirrors Activity's data-paned-activity-view-* pattern, since a user can match more than one at once):
All Users — approved users, baseline (unchanged from today)
New — NOT (
thread_count >= 1ANDpost_count - thread_count >= 1)Established —
thread_count >= 1ANDpost_count - thread_count >= 1(at least one thread started and one reply made;post_countincludes replies,thread_countcounts only root posts)No Threads —
thread_count = 0(its own category, kept separate from "New" even though every "No Threads" user is also "New")Recently Active — any authored post/thread within the last 7 days
Not Approved — fully separate/disjoint bucket; unapproved users appear only here, never counted in "All Users" or any of the above
New data needed:
A per-
username_tokenlast-activity timestamp (MAX(posts.created_at)across all identities sharing that token) — no existing query computes this; new but schema-free.Pending/unapproved profiles, via the existing
fetchPendingUserDirectoryProfiles()method (already powers the classic/users/pending/page) — new to this directory's data source, but not a new query.
Core requirement change: the filter pane is no longer alphabetical; the listing/filter-pane/JS-controller stages (originally Step 4 Stages 2/4/5) are being reworked rather than extended. Detail pane behavior for a "Not Approved" row still needs defining — pending profiles don't have the same visible-threads/posts data an approved user does.