Frontend: case membership UI and access-denied handling #70

Closed
opened 2026-05-23 01:35:59 +00:00 by Mark · 2 comments
Owner

Parent Issue: #36 (Case-level access control) / #53

Scope

Frontend updates to support case-level access control.

Background

Once the backend enforces case membership, the frontend needs to:

  1. Only show cases the user has access to
  2. Show membership management UI
  3. Handle 403 errors gracefully
  4. Show access denied states instead of empty data

Acceptance Criteria

  • Case list only shows cases where user is a member
  • Case detail page shows "Access Denied" state when user lacks access
  • Case settings/members tab: list members, add member, remove member, change role
  • Only owners see the members management UI
  • API 403 responses show user-friendly error messages (not just blank pages)
  • "Share case" or "Invite to case" action available to owners
  • Viewer role users see read-only UI (no edit/delete buttons)

Dependencies

  • #64 (backend membership management endpoints must exist first)

Implementation Notes

  • Start by handling 403 errors gracefully — this can be done in parallel with backend work
  • Member management UI can follow existing settings page patterns
  • Role display: use badges (Owner=red, Editor=blue, Viewer=grey)
## Parent Issue: #36 (Case-level access control) / #53 ## Scope Frontend updates to support case-level access control. ## Background Once the backend enforces case membership, the frontend needs to: 1. Only show cases the user has access to 2. Show membership management UI 3. Handle 403 errors gracefully 4. Show access denied states instead of empty data ## Acceptance Criteria - [ ] Case list only shows cases where user is a member - [ ] Case detail page shows "Access Denied" state when user lacks access - [ ] Case settings/members tab: list members, add member, remove member, change role - [ ] Only owners see the members management UI - [ ] API 403 responses show user-friendly error messages (not just blank pages) - [ ] "Share case" or "Invite to case" action available to owners - [ ] Viewer role users see read-only UI (no edit/delete buttons) ## Dependencies - #64 (backend membership management endpoints must exist first) ## Implementation Notes - Start by handling 403 errors gracefully — this can be done in parallel with backend work - Member management UI can follow existing settings page patterns - Role display: use badges (Owner=red, Editor=blue, Viewer=grey)
Author
Owner

⏸ Needs Decision

Blocking factors:

  • Didn't meet auto-approve criteria — scope=medium, risk=low, spec=aligned

Scope: medium Risk: low Spec: aligned Type: feature
Summary: Frontend updates to filter case list by membership, add member management UI to case settings, handle 403 errors gracefully, and enforce role-based read-only views.
Suggestion: Phase approach: (1) API client 403 interceptor + AccessDenied component, (2) member list/management sub-pages on case settings following existing settings patterns, (3) role badge components and conditional rendering for viewer vs editor vs owner, (4) case list filtering hook. Dependency note: #64 (backend membership endpoints) must be merged first or mocked.
Rationale: Medium scope because it introduces a new UI subsystem (member management tab, role-based rendering, 403 interceptor) across ~5-10 files rather than a simple tweak, but no backend or infra changes. Low risk because it's additive frontend-only work with fallback states (403 error screens) that degrade gracefully. Aligned with spec as it directly implements the case-level access control parent issues #36/#53. Type is feature: new capability, not bug fix or refactor. The phased dependency-aware approach avoids blocking on #64 by starting with the 403 handling piece which can be built independently.

Action: Review each blocking factor above. Remove blocked:needs-decision label to route back to triage.

## ⏸ Needs Decision **Blocking factors:** - **Didn't meet auto-approve criteria** — scope=medium, risk=low, spec=aligned --- **Scope:** medium **Risk:** low **Spec:** aligned **Type:** feature **Summary:** Frontend updates to filter case list by membership, add member management UI to case settings, handle 403 errors gracefully, and enforce role-based read-only views. **Suggestion:** Phase approach: (1) API client 403 interceptor + AccessDenied component, (2) member list/management sub-pages on case settings following existing settings patterns, (3) role badge components and conditional rendering for viewer vs editor vs owner, (4) case list filtering hook. Dependency note: #64 (backend membership endpoints) must be merged first or mocked. **Rationale:** Medium scope because it introduces a new UI subsystem (member management tab, role-based rendering, 403 interceptor) across ~5-10 files rather than a simple tweak, but no backend or infra changes. Low risk because it's additive frontend-only work with fallback states (403 error screens) that degrade gracefully. Aligned with spec as it directly implements the case-level access control parent issues #36/#53. Type is feature: new capability, not bug fix or refactor. The phased dependency-aware approach avoids blocking on #64 by starting with the 403 handling piece which can be built independently. **Action:** Review each blocking factor above. Remove `blocked:needs-decision` label to route back to triage.
Author
Owner

GSD VERIFY phase failed after 3 attempts.
═══ Gate: verify-passed (osint-hub#70) ═══
Mode: Tier 1 (functional only)

GATE OK: All gates up to 'implement' pass
── Tier 1: Functional ────────────────────────────────
Running tests...
❌ Tests failed (exit 4)
configfile: pyproject.toml
plugins: anyio-4.13.0, httpx-0.36.2, timeout-2.4.0, xdist-3.8.0, cov-7.1.0, split-0.11.0, asyncio-1.4.0
timeout: 60.0s
timeout method: signal
timeout func_only: False
asyncio: mode=Mode.STRICT, debug=False, asyncio_default_fixture_loop_scope=None, asyncio_default_test_loop_scope=function
collected 0 items

============================ no tests ran in 0.00s =============================
ERROR: file or directory not found: tests/

============================= test session starts ==============================
platform linux -- Python 3.11.14, pytest-9.0.3, pluggy-1.6.0
rootdir: /home/b/Projects/osint-hub
configfile: pyproject.toml
plugins: anyio-4.13.0, httpx-0.36.2, timeout-2.4.0, xdist-3.8.0, cov-7.1.0, split-0.11.0, asyncio-1.4.0
asyncio: mode=Mode.STRICT, debug=False, asyncio_default_fixture_loop_scope=None, asyncio_default_test_loop_scope=function
collected 0 items

============================ no tests ran in 0.00s =============================
Running linter...
✅ Lint clean
Running type checker...
✅ Types check clean
Previous test count: unknown

❌ GATE FAIL: verify-passed
- Tests failed with exit code 4
GATE FAIL: verify — blocked at 2026-05-26T22:19:55Z
Class: test-failure
Evidence: Verification failed: 1 failures
Git tag: osint-hub#70-gate-verify-fail-81125016dc8e (use gate-retry after fixing)

GSD VERIFY phase failed after 3 attempts. ═══ Gate: verify-passed (osint-hub#70) ═══ Mode: Tier 1 (functional only) GATE OK: All gates up to 'implement' pass ── Tier 1: Functional ──────────────────────────────── Running tests... ❌ Tests failed (exit 4) configfile: pyproject.toml plugins: anyio-4.13.0, httpx-0.36.2, timeout-2.4.0, xdist-3.8.0, cov-7.1.0, split-0.11.0, asyncio-1.4.0 timeout: 60.0s timeout method: signal timeout func_only: False asyncio: mode=Mode.STRICT, debug=False, asyncio_default_fixture_loop_scope=None, asyncio_default_test_loop_scope=function collected 0 items ============================ no tests ran in 0.00s ============================= ERROR: file or directory not found: tests/ ============================= test session starts ============================== platform linux -- Python 3.11.14, pytest-9.0.3, pluggy-1.6.0 rootdir: /home/b/Projects/osint-hub configfile: pyproject.toml plugins: anyio-4.13.0, httpx-0.36.2, timeout-2.4.0, xdist-3.8.0, cov-7.1.0, split-0.11.0, asyncio-1.4.0 asyncio: mode=Mode.STRICT, debug=False, asyncio_default_fixture_loop_scope=None, asyncio_default_test_loop_scope=function collected 0 items ============================ no tests ran in 0.00s ============================= Running linter... ✅ Lint clean Running type checker... ✅ Types check clean Previous test count: unknown ❌ GATE FAIL: verify-passed - Tests failed with exit code 4 GATE FAIL: verify — blocked at 2026-05-26T22:19:55Z Class: test-failure Evidence: Verification failed: 1 failures Git tag: osint-hub#70-gate-verify-fail-81125016dc8e (use gate-retry after fixing)
Mark 2026-05-30 04:32:11 +00:00
  • closed this issue
  • removed the
    quickfix
    label
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
Mark/osint-hub#70
No description provided.