# DATA-002: ListView column changes persist on server

**Status: REPRODUCED + A/B EXCLUDED** — Both SF and NexusCRM use localStorage; this is a frontend issue

## Environment Setup

### Backend A — NexusCRM

1. Configure and start frontend:
   ```bash
   cd frontend
   echo "REACT_APP_BACKEND_URL=https://nexuscrm.pingcap.com" > .env
   npm run dev  # starts on localhost:5173
   ```

2. Get a JWT token:
   ```bash
   curl -s -X POST "https://nexuscrm.pingcap.com/services/oauth2/token" \
     -H "Content-Type: application/x-www-form-urlencoded" \
     -d "grant_type=client_credentials&client_id=test-gosf-client&client_secret=test-gosf-secret-123" \
     | python3 -c "import sys,json; print(json.load(sys.stdin).get('access_token',''))"
   ```

3. Login via JavaScript console:
   ```javascript
   localStorage.setItem('auth_token', '<JWT token from step 2>');
   localStorage.setItem('instance_url', 'https://nexuscrm.pingcap.com');
   location.reload();
   ```

### Backend B — Salesforce (via Vite proxy)

1. Configure and start frontend:
   ```bash
   cd frontend
   echo "REACT_APP_BACKEND_URL=https://pingcap--partialcop.sandbox.my.salesforce.com" > .env
   npm run dev  # starts on localhost:5173
   ```

2. Login via Backend mode → Advanced Options → Token:
   - Token: `00D...` (valid SF session token)
   - **CRITICAL**: instance_url must be `http://localhost:5173` (NOT the SF URL).
     This forces all API requests through the Vite proxy, bypassing CORS.
   - Click Login

## Steps (verified 2026-03-25)

1. Navigate to `http://localhost:5173/object/Account`
2. Account list loads with columns: Name, External Id C, Industry, Portal Id C
3. Click "Columns" button (labeled "Select Fields to Display")
4. **Observation**: Dialog shows AVAILABLE FIELDS (12), SELECTED (0) — selected count
   is 0 even though 4 columns are visible. This means the default column set is not
   stored as a ListView configuration.
5. Select "Industry" and "Name" from available fields → they move to SELECTED (2)
6. Click "Apply Changes"
7. List view now shows only 2 columns: Industry, Name (change applied)
8. Hard refresh (Cmd+Shift+R)
9. List view still shows Industry, Name — **appears to persist**
10. Check localStorage: `localStorage.getItem('nexuscrm_columns_Account')`
    Returns: `["Industry","Name"]`

## Actual Result (NexusCRM backend)

- Column changes are stored in **browser localStorage** (`nexuscrm_columns_Account`)
- Changes survive page refresh because localStorage persists
- Changes will **NOT survive**:
  - Switching to a different browser
  - Clearing browser data
  - Using incognito/private mode
  - Logging in from a different device
- The server has no record of the user's column preferences

## Expected Result (Salesforce behavior)

- Column changes saved to the server (on the ListView record or user preferences)
- Changes persist across browsers, devices, and sessions
- Opening the column picker shows SELECTED fields matching the current display

## A/B Comparison (verified 2026-03-25)

| Aspect | SF Backend | NexusCRM Backend |
|--------|-----------|-----------------|
| Column picker SELECTED count | **(0)** — same as NexusCRM | **(0)** |
| Column storage | localStorage | localStorage |
| Available fields | 234 | 12 |

**Both backends exhibit SELECTED(0) behavior.** The ListView column picker
stores selections in `localStorage` on BOTH backends. This is a **frontend
issue**, not a backend compatibility problem. The NexusCRM frontend does
not persist column selections to the server regardless of which backend
it connects to.

## Root Cause

The frontend stores column selections in `localStorage` under the key
`nexuscrm_columns_{ObjectName}`. No API call is made to persist the selection
on the server. The `_System_ListView` table exists in the backend but the
frontend does not write to it when columns are changed.

Additionally, the column picker opens with SELECTED (0) even when 4 columns
are displayed — this means the initial column set comes from a default (possibly
all non-system fields) rather than from a stored ListView configuration.

## Failure Indicators

- Column changes lost after clearing browser data
- Column changes not visible on another device/browser
- Column picker shows SELECTED (0) when columns are visible (state mismatch)
- `localStorage.getItem('nexuscrm_columns_{Object}')` exists (client-only storage)

## Related

- DATA-005 (API): ListView PATCH returns 400 "not found" — server-side update broken
