OnALead · Discovery Brief · Item I9

Back-Office Packet Selection & the Entitlements Question

A pre-build machine sweep for prior artifacts on packet selection and user entitlements — plus the state of the parked Inventory Snapshot dashboard and where the five wireframe directions land against it.

DirectiveI9 · "write it up before any build" PriorityP2 · soon StatusDiscovery complete Scope riskEntitlements spiral
01

Executive Summary

The feature — letting a back-office user see and select available packets from inside the agent app — is closer to done than it looks. Most of what it needs already exists in OnALead's back office; the real work is exposure and a disciplined entitlement boundary, not net-new domain logic.

Three findings shape everything below:

  • Packets are built twice. OnALead (the back office) owns the authoritative Agent.Packet model and already has server-side "available packets" and assignment operations. The AgentApp only exposes an agent's own packets and offers — read-mostly, no pool, no assignment.
  • The entitlement model already exists — in the wrong app. OnALead has a full hierarchical privilege/security-group system including a LeadPacket privilege. The AgentApp has only admin/non-admin string checks plus impersonation. The containment play is to reuse OnALead's privileges through the existing security-group bridge, not invent an entitlement layer inside the agent app.
  • The Snapshot dashboard is built and parked. A Phase-1 prototype (mock data) sits on a parked branch with KPI strip, charts, card grid, and table view already implemented — the wireframe round is refining something real, not starting from zero.
One-paragraph recommendation Ship the feature as a thin exposure layer: surface OnALead's existing GetOpenPackets() / AssignAgentToPacket() through new AgentApp endpoints, gate them on the existing OnALead.Leads.LeadPacket[.Approve] privilege read via the security-group bridge, and reuse the parked Snapshot shell for the UI. Hold the line on scope: no field-level masking, no new admin screens, no trust/profitability dependency in v1 — those are the spiral.
02

Packet Domain Today

"Packet" is a real, mature concept — a named bundle of leads assigned to an agent, with a status lifecycle and two types. It exists end-to-end in OnALead and partially in the AgentApp.

● OnALead — authoritative (back office)
  • Agent.Packet table, temporal/system-versioned, FK to PacketStatus & PacketType
  • PacketType ∈ {BackOffice, Referral}
  • Lifecycle: Created → OutToAgent → Accepted / Rejected → Retracted / Deleted
  • Already in IAgentService: GetPackets(), GetOpenPackets(), AssignAgentToPacket(), Finalize / Retract / Delete
  • 18-month expiration window from SentToAgentDate
● AgentApp — agent-facing (read-mostly)
  • PacketsController / OffersController expose only the agent's own packets
  • Agents can accept / reject offered packets and act on leads (phone, door-knock)
  • missing available-packet pool listing
  • missing assignment endpoint
  • missing any back-office / CSR view
The load-bearing insight The thing the feature is "missing" — a way to list unassigned packets and assign them — is not missing from the system, only from the agent app. OnALead.ServiceLibrary\Agent\IAgentService.cs already implements GetOpenPackets() and AssignAgentToPacket(). The build is exposure + UI, not new domain modeling.

Design intent already on record

Two in-repo specs define the UX philosophy and should anchor any build:

  • OnALead\docs\Harrison-CSR-Leadpacet.md — encodes the CSR's manual packet-building as a system. Its governing principle: "Design for selection, not submission" — present pre-built packets to choose from, don't make the user assemble carts.
  • OnALead\docs\# Natural Language Feature Handof Lead Packetsf.md — the trust/profitability matrix, lead lifecycle color-coding (Green 0-31 / Yellow 32-61 / Orange 62-92 / Red 93+), and an inventory-snapshot drill-down concept (sections 5–6).
03

Entitlements & the Containment Strategy

This is where I9 warned the work "can spiral." The good news: the spiral is avoidable because the entitlement model is already built — it just lives in OnALead, not the agent app.

ConcernOnALead (back office)AgentApp (agent portal)
ModelHierarchical Privilege (CRUD / visible / enabled / scope bits), SecurityGroup, PrivilegeSecurityGroupsGroup-name string checks only
Packet privilegeOnALead.Leads.LeadPacket & .Approve (among 100+ generated PrivilegeNames)None
EnforcementISecurityService.GetUserAccess() resolves effective privileges"Administrators" / "On A Lead Manager" + impersonation block
GranularityPer-privilege, per-group, scopedBinary admin / non-admin
Containment strategy Gate the new feature on the existing OnALead.Leads.LeadPacket[.Approve] privilege, surfaced through the security-group bridge the AgentApp already calls (GetUserSecurityGroupsAsync). That's one new repository read and zero new entitlement schema — the agent app asks "does this user hold the packet privilege?" and never grows its own parallel permission model.

Explicitly out of scope for v1 (the spiral)

  • defer Field-level masking — the 2024 user story ("so JE can create lead packets without seeing Lead Thumbnail, address, and age") is a real future requirement, noted but not built now.
  • defer New admin/role-management UI — groups and privileges are administered in OnALead; the agent app only consumes them.
  • defer Trust/profitability matrix — the access-classification system from the Natural-Language spec is a separate, larger effort; the packet-selection feature must not take a dependency on it.
04

Inventory Snapshot — State of Play

JJ asked to fold in the Inventory Snapshot work. It is not hypothetical: a working Phase-1 prototype is parked on a branch, and its mock data traces directly back to existing Excel count files.

The parked prototype

Branch parking/snapshot-phase-1-prototype in the onboard repo (commit 8cabed7 — "Park: snapshot inventory dashboard Phase 1 prototype (mock data)"). It already contains:

FileRoleLines
src/pages/snapshot/SnapshotPage.jsxPage shell — view-type tabs, filters, layout toggle267
SnapshotKpiStrip.jsxStatus-count tiles52
SnapshotCharts.jsxAging + SCF charts78
SnapshotCardGrid.jsxRegion cards, expand-in-place163
SnapshotTable.jsxDense table view79
store/slices/snapshotSlice.jsRedux state — filters, sort, expansion141
services/snapshotApi.jsMock API (planned real endpoints noted inline)220
Mock, not wired snapshotApi.js returns mock regions. Its header documents the planned real endpoints — GET /api/v1/inventory/snapshot, /:id, /kpi — which do not exist in the backend yet. Reviving this for production means building those endpoints in OnALead.WebApi (per the repo's stored-procedure convention in CLAUDE.md).

Data lineage — mock fields trace to real spreadsheets

The prototype's region shape (SCF / territory / county / route grouping; lead-type counts OAL, OAIC, PHI, SVQ, CSL, CSN, OTR, CLM, T65, MIX; aging buckets; response rate; premium YTD; CPA; close rate) mirrors the working count files in D:\repos\SnapShot\Counts\: target list counts.xlsx, analytics.xlsx, counts MS.xlsx, and JJ Penetration Data - Jan 2026.xlsx, plus the Issued and Not Taken NBR Blend Production extracts. Older UX references survive in LM system design notes\LEAD Packet App\ (the Binder PDF and Lead Assignment Layout) and the Nov-2025 back-office snapshot screenshot.

05

Wireframe Directions — Evaluation

Scoring the five Round-v1 directions against four constraints: distance from the parked prototype, data already available, the D3/D4 decisions (maps live in the back office; build order is matching → mapping → geography selector → snapshot), and the Harrison-CSR "design for selection" principle.

B Sidebar filters + dense rows Target shell

Why: Strongest team-lead fit. The permanent filter rail (grouping, status, age, lead-type, agent, saved quick views) maps almost one-to-one onto the filters already in snapshotSlice.js. Row-cards show eight regions at once, and an inline Assign control is exactly the "design for selection" move from Harrison-CSR.

Cost: Moderate — rebuild the card grid as rows + add the rail; the slice and data layer largely carry over.

D Heatmap matrix Phase-2 companion

Why: Best single view for triage — SCF × age-bucket, intensity = volume, hue = dominant status. It's literally the two charts we already have, crossed. But it's a companion to a region list, not a replacement, so it rides on top of Direction B rather than competing with it.

Cost: Additive — a second view mode once the data endpoints are real.

A Classic, refined Cheapest increment

Why: The parked prototype is already direction-A shaped (KPI strip → charts → expand-in-place cards). If the goal is the smallest shippable step, tighten what exists. Weakness the summary itself flags: expand-in-place blocks side-by-side region comparison — which is the team lead's core job.

Cost: Lowest — a polish pass on existing components.

C Map-first Defer

Why deferred: Decision D3 already places maps in the back office (React), and real SCF boundaries are a meaningful build. Per D4, mapping MVP precedes the snapshot in sequence — so geography-led snapshot UI should wait for that foundation rather than duplicate it.

E Assignment command-center Defer

Why deferred: Purpose-built for the highest-value action (drag region → agent lane, capacity bars), but it's a whole new page and it presumes assignment endpoints are already exposed to the app. Sequence it after Direction B proves the exposure layer and the entitlement gate.

Net recommendation B as the target shell, D as a phase-2 companion view. A is the fallback if only a polish increment is wanted; C and E are deferred behind the mapping MVP (D3/D4) and the assignment-exposure layer respectively.
06

Suggested Build Sequence

Not this taskThis is the path after the write-up is accepted — included so the discovery points somewhere concrete. No code is being written now.

  1. Backend snapshot endpoints. Build GET /api/v1/inventory/snapshot[, /:id, /kpi] in OnALead.WebApi over stored procedures (per CLAUDE.md — no inline SQL), backed by the existing Counts data model.
  2. Revive the parked branch. Bring parking/snapshot-phase-1-prototype forward and swap snapshotApi.js mocks for the real endpoints.
  3. Reshape to Direction B. Filter rail + row-cards + saved quick views, reusing the existing slice filters.
  4. Add the entitlement gate. Surface OnALead's LeadPacket privilege through the security-group bridge; show packet-selection affordances only to holders.
  5. Wire packet-selection actions. Connect Manual Order / Request Leads / Assign to the existing IAgentService operations (GetOpenPackets, AssignAgentToPacket).
  6. Phase 2. Layer the Direction-D heatmap as a companion view once regions render reliably.
07

Artifact Index

Load-bearing artifacts surfaced by the sweep. Binary files (xlsx / docx / pdf) are flagged where manual extraction is still needed.

Packet domain — OnALead
OnALead.Database\Agent\Tables\Agent.Packet.sql— table, temporal, FK status/type
OnALead.ServiceLibrary\Agent\IAgentService.cs— GetOpenPackets / AssignAgentToPacket
OnALead.ServiceLibrary\Models\Agent\PacketStatus.cs · PacketType.cs— enums
Packet domain — AgentApp
Agent.App.Api\Controllers\PacketsController.cs · OffersController.cs— agent-own only
agent-app-web\src\pages\packets\PacketList.jsx · PacketDetails.jsx— agent UI
Entitlements
OnALead.ServiceLibrary\Models\Authorization\Privilege.cs · PrivilegeNames.cs— LeadPacket privilege
OnALead.ServiceLibrary\Security\ISecurityService.cs— GetUserAccess
Agent.App.Api\Controllers\AuthorizationController.cs · BaseUserController.cs— group checks + impersonation
Design intent
OnALead\docs\Harrison-CSR-Leadpacet.md— "design for selection"
OnALead\docs\# Natural Language Feature Handof Lead Packetsf.md— matrix, lifecycle, snapshot §5-6
Inventory Snapshot — code
onboard @ parking/snapshot-phase-1-prototype : src/pages/snapshot/*— parked prototype
…/store/slices/snapshotSlice.js · services/snapshotApi.js— state + mock API
Inventory Snapshot — data & UX (binary)
SnapShot\Counts\target list counts.xlsx · analytics.xlsx · counts MS.xlsx⚠ xlsx
SnapShot\Counts\JJ Penetration Data - Jan 2026.xlsx⚠ xlsx
LM system design notes\LEAD Packet App\Binder -- LEAD Packet App.pdf⚠ pdf
OnALead\docs\SnapShot\Screenshot 2025-11-17 094650 (backoffice).png⚠ png
Historical entitlement references (binary)
LM system design notes\User Roles for Entire System plus Lead Packets - AS OF 2014_12_06.xlsx⚠ xlsx
LM system design notes\GroupPrivileges*.xlsx⚠ xlsx
LM system design notes\Agent App user story Q4 - 2024 v2.docx⚠ docx
LM system design notes\notes user stories 2024-05-24.txt— field-masking story
Origin
KnowledgeWorks\handoffs\2026-06-standup-6-triage\HANDOFF.md · TRIAGE-BRIEF.md— I9 directive, D3/I5 context