Skip to content

feat(persona): extract organization data from detection extras#446

Merged
asithade merged 4 commits intomainfrom
feat/LFXV2-1475
Apr 14, 2026
Merged

feat(persona): extract organization data from detection extras#446
asithade merged 4 commits intomainfrom
feat/LFXV2-1475

Conversation

@asithade
Copy link
Copy Markdown
Contributor

Summary

  • Extract organization data (Salesforce account ID, name) from board_member detection extras returned by the persona service and propagate through SSR and client-side flows
  • Merge detected organizations into the predefined ACCOUNTS list so organizations not in the hardcoded list appear in the dev toolbar selector
  • Always refresh persona data from API after hydration — cookie serves as backup for initial SSR render, not primary source
  • Delete unused organization-matcher.ts (dead code, never imported)

LFXV2-1475

Related

Generated with Claude Code

LFXV2-1475

Extract organization data (Salesforce account ID, name) from
board_member detection extras returned by the persona service and
propagate through the SSR and client-side flows.

- Add organizations field to PersonaApiResponse, SsrPersonaResult,
  and PersistedPersonaState interfaces
- Extract organizations from board_member detection extras in
  PersonaDetectionService
- Propagate organizations through SSR cookie and NATS paths
- Forward organizations to AccountContextService on client refresh
- Merge detected organizations into predefined ACCOUNTS list so
  organizations not in the hardcoded list appear in the selector
- Update dev toolbar to use dynamic account list from service
- Always refresh persona data from API after hydration
- Delete unused organization-matcher.ts

Generated with [Claude Code](https://claude.ai/code)

Signed-off-by: Asitha de Silva <asithade@gmail.com>
Copilot AI review requested due to automatic review settings April 14, 2026 01:58
@asithade asithade requested a review from a team as a code owner April 14, 2026 01:58
Copy link
Copy Markdown

@claude claude bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude Code Review

This repository is configured for manual code reviews. Comment @claude review to trigger a review and subscribe this PR to future pushes, or @claude review once for a one-time review.

Tip: disable this comment in your organization's Code Review settings.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 14, 2026

Caution

Review failed

Pull request was closed or merged during review

Walkthrough

Extracts organizations from persona detections, persists them with persona state (cookies), surfaces them through SSR to the client, merges detected organizations with hardcoded accounts, and updates the dev toolbar selector to use the merged accounts signal.

Changes

Cohort / File(s) Summary
Shared Interfaces
packages/shared/src/interfaces/persona-detection.interface.ts, packages/shared/src/interfaces/persona.interface.ts
Added organizations: Account[] to PersonaApiResponse and optional organizations?: Account[] to SSR/persona persisted state.
Server: Persona Detection
apps/lfx-one/src/server/services/persona-detection.service.ts
Added extractOrganizations to derive unique Account objects from board_member detections; getPersonas now returns organizations; added parsing/debug logs.
Server: Persona Resolution / SSR
apps/lfx-one/src/server/server.ts, apps/lfx-one/src/server/utils/persona-helper.ts
Propagate organizations from persona resolution into SSR auth/context and include organizations in cookie/NATS resolution shapes.
Server Utilities Removed
apps/lfx-one/src/server/utils/organization-matcher.ts
Removed matchOrganizationNamesToAccounts implementation and export.
Client: Persona & Account Context
apps/lfx-one/src/app/shared/services/persona.service.ts, apps/lfx-one/src/app/shared/services/account-context.service.ts
Persist organizations in persona cookie state; setPersonas(..., organizations?); persona refresh now always runs and initializes accountContextService with detected organizations; availableAccounts now merges hardcoded ACCOUNTS with detected organizations (deduped).
Client: Dev Toolbar
apps/lfx-one/src/app/layouts/dev-toolbar/dev-toolbar.component.ts, apps/lfx-one/src/app/layouts/dev-toolbar/dev-toolbar.component.html
Switched selector data source to service-backed availableAccounts signal and updated template to call availableAccounts() for options; removed static ACCOUNTS import.
Docs
docs/architecture/backend/README.md
Removed reference to the organization-matcher.ts helper from backend utilities list.

Sequence Diagram

sequenceDiagram
    participant API as External API/NATS
    participant PDS as PersonaDetectionService
    participant Server
    participant Helper as PersonaHelper
    participant SSR as SSR Handler
    participant Client
    participant PS as PersonaService
    participant ACS as AccountContextService

    API->>PDS: detection payload
    PDS->>PDS: extractOrganizations() -> Account[]
    PDS-->>Server: PersonaApiResponse { personas, organizations }
    Server->>Helper: resolvePersonaForSsr()
    Helper-->>Server: SsrPersonaResult { persona, personas, organizations }
    Server->>SSR: populate auth + organizations
    SSR-->>Client: initial state (includes organizations)
    Client->>PS: hydrate
    PS->>PS: setPersonas(..., organizations)
    PS->>ACS: initializeUserOrganizations(organizations)
    ACS->>ACS: merge ACCOUNTS with detected organizations
    ACS-->>Client: availableAccounts() updated
    Client->>Client: dev toolbar selector renders merged accounts
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title directly reflects the main feature: extracting organization data from persona detection extras and propagating it through the system.
Description check ✅ Passed The description clearly explains the changes: extracting organization data from detection extras, merging into ACCOUNTS list, improving API refresh logic, and removing dead code.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/LFXV2-1475

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR wires organization metadata (Salesforce account id/name) from persona detection “extras” through the shared interfaces, SSR auth context, and the client-side persona/account flows, so the dev toolbar’s organization selector can include detected organizations beyond the hardcoded ACCOUNTS list.

Changes:

  • Extend shared persona/persona-detection interfaces to include organizations: Account[] where appropriate (API response, SSR result, persisted cookie state).
  • Extract unique organizations from board_member detection extras on the server and propagate them into SSR auth context and the /api/user/personas response.
  • Update the Angular account/persona/dev-toolbar flow to merge detected orgs into ACCOUNTS and always refresh persona data post-hydration; remove dead organization-matcher.ts.

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
packages/shared/src/interfaces/persona.interface.ts Adds organizations?: Account[] to persisted persona cookie state.
packages/shared/src/interfaces/persona-detection.interface.ts Adds organizations: Account[] to API response + SSR persona result.
apps/lfx-one/src/server/utils/persona-helper.ts Includes organizations in SSR resolution and persists them in persona cookie.
apps/lfx-one/src/server/utils/organization-matcher.ts Deletes unused org matching helper (dead code).
apps/lfx-one/src/server/services/persona-detection.service.ts Logs detection extras (debug) and extracts unique org accounts from board_member extras.
apps/lfx-one/src/server/server.ts Propagates SSR-detected organizations into AuthContext.
apps/lfx-one/src/app/shared/services/persona.service.ts Always refreshes persona post-hydration; forwards detected organizations to AccountContextService.
apps/lfx-one/src/app/shared/services/account-context.service.ts Merges detected orgs into ACCOUNTS for selection.
apps/lfx-one/src/app/layouts/dev-toolbar/dev-toolbar.component.ts Uses computed availableAccounts signal instead of static ACCOUNTS.
apps/lfx-one/src/app/layouts/dev-toolbar/dev-toolbar.component.html Updates template to call the accounts signal (availableAccounts()).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/lfx-one/src/app/shared/services/account-context.service.ts`:
- Around line 42-49: When a refresh returns an empty detected list, clear the
cached org state so stale orgs aren't shown: inside initializeUserOrganizations
(the code path that handles detected arrays) when detected.length === 0, call
the userOrganizations setter with an empty array (userOrganizations([])) and
update the initialized flag/state (via initialized()/its setter or
setInitialized(true)) so the service reflects that a refresh occurred and
availableAccounts will return ACCOUNTS instead of stale entries.

In `@apps/lfx-one/src/app/shared/services/persona.service.ts`:
- Around line 87-92: The persist call in setPersonas(primary: PersonaType, all:
PersonaType[], multiProject = false, multiFoundation = false, organizations?:
Account[]) overwrites stored organizations when callers (like setPersona) omit
the organizations arg; update setPersonas to use the service's existing
organizations state (or last-known organizations) when the organizations
parameter is undefined before calling persistToCookie, or maintain and always
read from a this.organizations property and pass that into persistToCookie so
switching personas does not drop the detected organizations; ensure
persistToCookie receives the preserved organizations value.
- Around line 125-128: The code only calls
this.accountContextService.initializeUserOrganizations(...) when
response.organizations has items, so an API response with organizations: []
never clears client state; change PersonaService to always sync organization
state when response.organizations is present (including empty arrays) — e.g.,
remove the length check and call
initializeUserOrganizations(response.organizations) unconditionally, or call a
new accountContextService.resetUserOrganizations() when the array is empty; also
update AccountContextService (the methods around initializeUserOrganizations and
the no-op behavior at lines 58-77) to accept an empty array and clear/reset
stored org list and selection accordingly so the client state matches the cookie
cleared at Line 122.

In `@apps/lfx-one/src/server/services/persona-detection.service.ts`:
- Around line 329-333: The code currently only validates organization.id before
creating an Account entry; update the logic around
detection.extra['organization'] (the org variable) to ensure both org.id and
org.name exist and are strings before calling seen.add and accounts.push, e.g.
narrow types with typeof checks (validate org?.id && typeof org.id === 'string'
&& org?.name && typeof org.name === 'string'), and only push Account objects
when both accountId and accountName are valid to avoid undefined accountName
values in accounts and maintain the seen set consistency.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 749abd03-ec66-4387-a75a-aecaab476e96

📥 Commits

Reviewing files that changed from the base of the PR and between d2f61da and 3c95153.

📒 Files selected for processing (10)
  • apps/lfx-one/src/app/layouts/dev-toolbar/dev-toolbar.component.html
  • apps/lfx-one/src/app/layouts/dev-toolbar/dev-toolbar.component.ts
  • apps/lfx-one/src/app/shared/services/account-context.service.ts
  • apps/lfx-one/src/app/shared/services/persona.service.ts
  • apps/lfx-one/src/server/server.ts
  • apps/lfx-one/src/server/services/persona-detection.service.ts
  • apps/lfx-one/src/server/utils/organization-matcher.ts
  • apps/lfx-one/src/server/utils/persona-helper.ts
  • packages/shared/src/interfaces/persona-detection.interface.ts
  • packages/shared/src/interfaces/persona.interface.ts
💤 Files with no reviewable changes (1)
  • apps/lfx-one/src/server/utils/organization-matcher.ts

Remove deleted file from the backend architecture doc file tree.

Signed-off-by: Asitha de Silva <asithade@gmail.com>
Address review comments from @MRashad26, copilot[bot], coderabbitai[bot]:

- persona-detection.service.ts: validate both org.id and org.name as
  strings before mapping to Account (per @MRashad26, copilot[bot],
  coderabbitai[bot])
- persona-detection.service.ts: sanitize debug log to only emit org
  id/name, not full detection extras (per copilot[bot])
- persona.service.ts: preserve organizations across persona switches
  via lastKnownOrganizations signal (per coderabbitai[bot])
- persona.service.ts: persist organizations to cookie even when
  personas.length === 0 (per @MRashad26)
- persona.service.ts: always sync organizations to AccountContextService
  including empty arrays to clear stale state (per coderabbitai[bot])
- persona.service.ts: document unconditional refreshFromApi trade-off
  with comment explaining NATS cache bounds (per @MRashad26)
- account-context.service.ts: clear org state on empty refresh and
  validate stored selection against merged ACCOUNTS + detected set
  (per copilot[bot], coderabbitai[bot])

Resolves 11 review threads.

Signed-off-by: Asitha de Silva <asithade@gmail.com>
@asithade
Copy link
Copy Markdown
Contributor Author

Review Feedback Addressed

Commit: 0aab7e6

Changes Made

  • persona-detection.service.ts: Sanitized debug log to only emit org id/name, not full detection extras (per copilot[bot])
  • persona-detection.service.ts: Validate both org.id and org.name as non-empty strings with typeof checks before mapping to Account (per @MRashad26, copilot[bot], coderabbitai[bot])
  • persona.service.ts: Added lastKnownOrganizations signal to preserve organizations across persona switches (per coderabbitai[bot])
  • persona.service.ts: Persist organizations to cookie even when personas.length === 0 (per @MRashad26)
  • persona.service.ts: Always sync organizations to AccountContextService including empty arrays to clear stale state (per coderabbitai[bot])
  • persona.service.ts: Documented unconditional refreshFromApi trade-off explaining NATS cache bounds (per @MRashad26)
  • account-context.service.ts: Clear org state on empty refresh and validate stored selection against merged ACCOUNTS + detected set (per copilot[bot], coderabbitai[bot])

No Change Needed

  • persona-helper.ts:82: Cookie size concern — board members typically have 1-3 organizations (~60 bytes each), well under the 4KB limit. The unconditional API refresh also means the cookie is a backup, not the sole source. (per copilot[bot])

Threads Resolved

11 of 11 unresolved threads addressed.

@asithade asithade requested a review from MRashad26 April 14, 2026 16:08
@asithade asithade merged commit 847f3ea into main Apr 14, 2026
11 of 12 checks passed
@asithade asithade deleted the feat/LFXV2-1475 branch April 14, 2026 16:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants