# Frontend UI + Data RLS + Multi-User Test Plan

**Scope:** Verify folder permissions, data-level RLS, and multi-user isolation from the end-user perspective.

**Prerequisites:**
- Backend running at localhost:8079 (branch `ian-security-test`)
- Frontend running at localhost:8082 (or localhost:5173 via Vite)
- TiDB Cloud branch with real Salesforce-synced data (3277 accounts, 6969 contacts, 316 folders, 140 users)

---

## Test Users

| User | Email | Profile | Role | Purpose |
|---|---|---|---|---|
| Max Liu | liuqi@pingcap.com | System Administrator | Management | Admin — sees everything |
| Shen Li | shenli@pingcap.com | Sales | NA & EMEA Region | Non-admin — subject to RLS |
| ReadOnly Agent | readonly-agent@nexus.agent | Standard User | (none) | API agent with api.read scope |
| ReadWrite Agent | readwrite-agent@nexus.agent | Standard User | (none) | API agent with api scope |

## Data Context

| Object | OWD | Record Shares | Implication |
|---|---|---|---|
| Account | PublicRead | 14,259 shares | All users can READ all accounts; write restricted by shares |
| Opportunity | Private | 6,039 shares | Only owner + shared users can see |
| Contact | ControlledByParent | — | Access follows parent Account |
| Lead | Private | — | Only owner + shared users can see |
| Case | Private | 1 share | Only owner + shared users can see |

---

## Scenario 1: Frontend UI (Chrome browser tests)

Test the permission features from a real browser session. Uses Chrome MCP tools.

### UI-1: Login as Admin → verify full folder visibility
```
1. Navigate to localhost:8082
2. Login as liuqi@pingcap.com (admin)
3. Navigate to Reports tab
4. Verify: folder sidebar shows all folders (public + personal)
5. Verify: can see admin's personal folders
```
- [ ] Tested
- [ ] Passed

### UI-2: Login as Sales user → verify limited folder visibility
```
1. Login as shenli@pingcap.com (Sales profile)
2. Navigate to Reports tab
3. Verify: folder sidebar shows ONLY:
   - Public folders (with Organization View share)
   - Personal folders (My Personal Custom Reports / My Personal Dashboards)
   - NOT admin's personal folders
4. Verify: total folders < admin's total
```
- [ ] Tested
- [ ] Passed

### UI-3: Dashboard page → folder picker shows accessible folders only
```
1. As Sales user, navigate to Dashboards
2. Click "New Dashboard" (or equivalent create action)
3. Verify: folder picker dropdown shows only accessible dashboard folders
4. Verify: admin's private dashboard folders NOT in picker
```
- [ ] Tested
- [ ] Passed

### UI-4: Connected App Manager Setup page
```
1. Login as admin
2. Navigate to Setup → Connected Apps (/setup/connected-apps)
3. Verify: page loads, shows existing apps (test-gosf-client, etc.)
4. Verify: can see Name, Scopes, IsActive columns
5. Verify: can toggle activate/deactivate
```
- [ ] Tested
- [ ] Passed

### UI-5: Folder Sharing Manager Setup page
```
1. Navigate to Setup → Folder Sharing (/setup/folder-sharing)
2. Verify: page loads, shows folder list
3. Click a folder → verify shares panel loads
4. Verify: can add a share (User/View)
5. Verify: can remove a share
```
- [ ] Tested
- [ ] Passed

### UI-6: Report list filtered by folder permissions
```
1. As admin: create a report in a private folder
2. As Sales user: navigate to Reports
3. Verify: the private folder's reports are NOT visible
4. As admin: share the folder with Organization at View
5. As Sales user: refresh → folder's reports now visible
```
- [ ] Tested
- [ ] Passed

### UI-7: Personal folder auto-creation on first visit
```
1. Login as a user who has never visited Reports before
2. Navigate to Reports
3. Verify: "My Personal Custom Reports" appears in folder list
4. Navigate to Dashboards
5. Verify: "My Personal Dashboards" appears
```
- [ ] Tested
- [ ] Passed

---

## Scenario 2: Data-Level RLS (API tests)

Test record-level security — do users only see records they're authorized to see?

### RLS-1: Account (PublicRead) — all users can read, write restricted
```
# As Sales user (shenli):
GET /query?q=SELECT Id,Name FROM Account LIMIT 5

Expected: 200, records returned (PublicRead = everyone can read)
```
- [ ] Tested
- [ ] Passed

### RLS-2: Opportunity (Private) — only owner + shared see it
```
# As Sales user (shenli):
GET /query?q=SELECT Id,Name FROM Opportunity LIMIT 5

Expected: only opportunities owned by shenli or shared with him
# Verify: count < total opportunities
```
- [ ] Tested
- [ ] Passed

### RLS-3: Lead (Private) — same as Opportunity
```
# As Sales user:
GET /query?q=SELECT Id,Name FROM Lead LIMIT 5

Expected: only leads owned by shenli or shared with him
```
- [ ] Tested
- [ ] Passed

### RLS-4: Admin sees all records regardless of OWD
```
# As admin (liuqi):
GET /query?q=SELECT COUNT() FROM Opportunity
# As Sales user (shenli):
GET /query?q=SELECT COUNT() FROM Opportunity

Expected: admin count > sales user count (for Private OWD objects)
```
- [ ] Tested
- [ ] Passed

### RLS-5: Account write — non-owner blocked on Private
```
# Find an Account NOT owned by shenli
# As shenli: try to PATCH it

Expected: depends on OWD. Account is PublicRead, so PATCH should be
blocked unless shenli has Edit share or is the owner.
```
- [ ] Tested
- [ ] Passed

### RLS-6: Cross-object query — Contact follows parent Account
```
# Contact OWD = ControlledByParent
# As Sales user:
GET /query?q=SELECT Id,Name,Account.Name FROM Contact LIMIT 5

Expected: only contacts whose parent Account the user can access
```
- [ ] Tested
- [ ] Passed

### RLS-7: SOQL with WHERE clause respects RLS
```
# As Sales user:
GET /query?q=SELECT Id,Name FROM Opportunity WHERE StageName='Closed Won'

Expected: only shenli's closed won opportunities, not all closed won
```
- [ ] Tested
- [ ] Passed

### RLS-8: ViewAllRecords bypasses RLS
```
# Admin has ViewAllRecords on all objects
GET /query?q=SELECT COUNT() FROM Lead
# As admin vs as Sales user

Expected: admin sees all leads, Sales user sees only owned/shared
```
- [ ] Tested
- [ ] Passed

---

## Scenario 3: Multi-User Isolation (API + cross-verification)

Test that different users with different profiles/roles see different data.

### MU-1: Sales vs Pre-Sales — different Opportunity visibility
```
# Get tokens for two users with different roles
# Sales user (shenli, NA & EMEA Region)
# Find a Pre-Sales user in a different region

# Both query Opportunities
# Verify: different result sets (each sees their own + shared)
```
- [ ] Tested
- [ ] Passed

### MU-2: Manager sees subordinate's records (Role Hierarchy)
```
# Find a manager-subordinate pair in the role hierarchy
# Manager: query Opportunities
# Subordinate: query Opportunities

# Verify: manager's results include subordinate's owned records
# Verify: subordinate does NOT see manager's records
```
- [ ] Tested
- [ ] Passed

### MU-3: Folder visibility varies by user
```
# Admin, Sales user, and API agent each list folders
# Verify: three different result counts
# Admin > Sales user > API agent (or different compositions)
```
- [ ] Tested
- [ ] Passed

### MU-4: Record created by user A invisible to user B (Private OWD)
```
# As Sales user: create an Opportunity
# As a different Sales user (different role): query Opportunities
# Verify: the new opportunity NOT in the other user's results
# (unless shared via sharing rules)
```
- [ ] Tested
- [ ] Passed

### MU-5: Sharing rule grants cross-team visibility
```
# Check existing sharing rules
# Find a rule that shares Accounts/Opportunities between groups
# Verify: users matching the rule's criteria can see shared records
```
- [ ] Tested
- [ ] Passed

### MU-6: Admin revokes user → immediate session invalidation
```
# Get a token for a test user
# Deactivate the user (IsActive=0)
# Try using the token

Expected: 401 (session rejected for inactive user)
```
- [ ] Tested
- [ ] Passed

---

## Previously Verified (from Agent API Test Plan)

The following have been fully tested and passed in the API test session:

- All 38 Agent API tests (A1-A9, B1-B5, C1-C10, D1-D7, E1-E7, G1-G2, H1-H3)
- FolderShare CRUD via dedicated SQL (not Persistence)
- Scope enforcement (api, api.read, openid)
- Token lifecycle (introspect, revoke)
- Personal folder lazy creation + isolation
- Multi-agent folder isolation
