Skip to content

feat(service): restore the personal My Open Cases by Priority widget - #1957

Merged
os-warren merged 3 commits into
mainfrom
claude/issue-510-my-open-cases-widget
Sep 25, 2026
Merged

os-warren merged 3 commits into
mainfrom
claude/issue-510-my-open-cases-widget

Conversation

@objectstack-fleet

@objectstack-fleet objectstack-fleet Bot commented Sep 25, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #510

What this does

Restores the personal case table on the Customer Service dashboard (service_dashboard), the card's own closing condition:

  • widget open_cases_by_priority → my_open_cases_by_priority, title Open Cases by Priority → My Open Cases by Priority, filter { is_closed: false } → { is_closed: false, owner_id: '{current_user_id}' } (owner_id, not owner, per the card's warning);
  • the four locale packs retitled under the new widget id;
  • the now-false "analytics resolves no user token / proven 0" notes removed from src/sales/apps/crm.app.ts (My Work group, and the nav_my_calendar note) and from the dashboard itself;
  • test/view-references.test.ts: the analytics-path token rule accepted date macros only; it now accepts the same user tokens as the list path, and its docblock records why.

Status: complete at 5089afd3 (surface extended per #510 comment 5832389289)

  • Surface extension (9 files): test/dashboard-agent-global-filter.test.ts gains a viewer context and a new section 7 pinning the personal widget; test/dashboard-date-range-window.test.ts runs as a signed-in viewer with owner_id fixtures. No existing assertion was removed or loosened. The six docs pages (content/docs/analytics/dashboards*, content/docs/service/index*) name My Open Cases by Priority and say it ignores the Agent filter. The my_open_cases docblock in src/service/views/case.view.ts is rewritten.
  • filterBindings: { owner_id: false } on my_open_cases_by_priority, measured in the console before commit:
    • With an Agent pick of another user, the personal widget keeps showing the viewer's own cases.
    • Control: the bound KPI widgets re-query and change (22 → 0, 5 → 0, 3 → 0).
    • Ablation: without the opt-out, the widget empties to "No data yet".
  • Gates at 5089afd3: validate · typecheck · lint · lint:i18n-gate · hygiene · hygiene:tokens · build · test — all exit 0; 172 test files, 3687 passed, 1 skipped. CI green on this head.

Two-user measurement (the acceptance step)

Local dev server on the 17.4.0 pin, pnpm demo:staff run, then five open cases handed out as admin: service.agent owns 3 (critical, medium, low), service.manager owns 2 (critical, medium), admin owns none; the other 25 open cases have no owner.

Console door (headless Chromium, each user signed in, service_dashboard opened, the widget's POST /api/v1/analytics/dataset/query captured). The widget rendered for each user:

viewer widget rows runtimeFilter sent
A service.agent Medium 1 · Low 1 · Critical 1 (3 cases) owner_id = A's own id
B service.manager Medium 1 · Critical 1 (2 cases) owner_id = B's own id
admin "No data yet" (0) owner_id = admin's id

Note: the console substitutes the viewer's id into the filter before sending, so on this door the server receives a literal id.

Server door: the same selection replayed with the literal {current_user_id} token, plus a team-wide control:

viewer owner_id: '{current_user_id}' control { is_closed: false } '{current_user}' misspelling
A HTTP 200, 3 cases HTTP 200, 22 (RLS-visible) HTTP 400 FILTER_TOKEN_UNKNOWN (suggests {current_user_id})
B HTTP 200, 2 cases HTTP 200, 9 HTTP 400 FILTER_TOKEN_UNKNOWN
admin HTTP 200, 0 HTTP 200, 30 HTTP 400 FILTER_TOKEN_UNKNOWN

The control shows admin's 0 is a real result: admin can see 30 open cases and owns none. A and B each saw only their own rows, and the rows differ. The generated SQL carried owner_id = $2 as a bound parameter, alongside the RLS predicate (owner_id = $5 OR id IN (...)). That RLS predicate is the actual access boundary: {current_user_id} only scopes what the widget shows.

Gates at 065af37

gate exit
pnpm validate 0
pnpm typecheck 0
pnpm lint 0
pnpm lint:i18n-gate 0
pnpm hygiene 0
pnpm hygiene:tokens 0: src/service interaction layer ~6,228 → ~6,239, src/service total ~21,127 → ~21,138, src/sales total ~99,340 unchanged
pnpm build 0
pnpm test 1: 12 failed / 3673 passed, all in the four out-of-surface files above

Generated by Claude Code

…510)

The analytics path resolves {current_user_id} on the 17.4.0 pin
(objectstack#12230). Widget filter now scopes to owner_id; stale
'proven gap' notes in crm.app.ts and the analytics token rule in
view-references.test.ts are corrected.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01X8U3asekbiC7yWoEPWR4Dg
@vercel

vercel Bot commented Sep 25, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated
hotcrm Ignored Ignored Sep 25, 2026 12:37pm UTC

Request Review

@github-actions github-actions Bot added ci/cd CI plumbing and the verification pipeline metadata Declarative metadata — schema, security posture, UI surfaces labels Sep 25, 2026
@github-actions github-actions Bot added the documentation Improvements or additions to documentation label Sep 25, 2026
@os-warren
os-warren marked this pull request as ready for review September 25, 2026 12:44
@os-warren
os-warren added this pull request to the merge queue Sep 25, 2026
Merged via the queue into main with commit df49be2 Sep 25, 2026
11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci/cd CI plumbing and the verification pipeline documentation Improvements or additions to documentation metadata Declarative metadata — schema, security posture, UI surfaces

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Analytics/dashboard query path resolves no user token — personal ("my …") dashboard widgets are impossible

2 participants