# Issue #358: Build frontend credential management pages

## Objective

Create frontend credential management pages at `/settings/credentials` with full CRUD operations, following PDA-friendly design principles and existing UI patterns.

## Backend API Reference

- `POST /api/credentials` - Create (encrypt + store)
- `GET /api/credentials` - List (masked values only)
- `GET /api/credentials/:id` - Get single (masked)
- `GET /api/credentials/:id/value` - Decrypt and return value (rate-limited)
- `PATCH /api/credentials/:id` - Update metadata only
- `POST /api/credentials/:id/rotate` - Replace value
- `DELETE /api/credentials/:id` - Soft delete

## Approach

### 1. Component Architecture

```
/app/(authenticated)/settings/credentials/
  └── page.tsx (main list + modal orchestration)

/components/credentials/
  ├── CredentialList.tsx (card grid)
  ├── CredentialCard.tsx (individual credential display)
  ├── CreateCredentialDialog.tsx (create form)
  ├── EditCredentialDialog.tsx (metadata edit)
  ├── ViewCredentialDialog.tsx (reveal value)
  ├── RotateCredentialDialog.tsx (rotate value)
  └── DeleteCredentialDialog.tsx (confirm deletion)

/lib/api/
  └── credentials.ts (API client functions)
```

### 2. UI Patterns (from existing code)

- Use shadcn/ui components: `Card`, `Button`, `Badge`, `AlertDialog`
- Follow personalities page pattern for list/modal state management
- Use lucide-react icons: `Plus`, `Eye`, `EyeOff`, `Pencil`, `RotateCw`, `Trash2`
- Mobile-first responsive design

### 3. Security Requirements

- **NEVER display plaintext in list** - only `maskedValue`
- **Reveal button** requires explicit click
- **Auto-hide revealed value** after 30 seconds
- **Warn user** before revealing (security-conscious UX)
- Show rate-limit warnings (10 requests/minute)

### 4. PDA-Friendly Language

```
❌ NEVER                    ✅ ALWAYS
─────────────────────────────────────────
"Delete credential"       "Remove credential"
"EXPIRED"                 "Past target date"
"CRITICAL"                "High priority"
"You must rotate"         "Consider rotating"
```

## Progress

- [x] Read issue details and design doc
- [x] Study existing patterns (personalities page)
- [x] Identify available UI components
- [x] Create API client functions (`lib/api/credentials.ts`)
- [x] Create dialog component (`components/ui/dialog.tsx`)
- [x] Create credential components
  - [x] CreateCredentialDialog.tsx
  - [x] ViewCredentialDialog.tsx (with reveal + auto-hide)
  - [x] EditCredentialDialog.tsx
  - [x] RotateCredentialDialog.tsx
  - [x] CredentialCard.tsx
- [x] Create settings page (`app/(authenticated)/settings/credentials/page.tsx`)
- [x] TypeScript typecheck passes
- [x] Build passes
- [ ] Add navigation link to settings
- [ ] Manual testing
- [ ] Verify PDA language compliance
- [ ] Mobile responsiveness check

## Implementation Notes

### Missing UI Components

- Need to add `dialog.tsx` from shadcn/ui
- Have: `alert-dialog`, `card`, `button`, `badge`, `input`, `label`, `textarea`

### Provider Icons

Support providers: GitHub, GitLab, OpenAI, Bitbucket, Custom

- Use lucide-react icons or provider-specific SVGs
- Fallback to generic `Key` icon

### State Management

Follow personalities page pattern:

```typescript
const [mode, setMode] = useState<"list" | "create" | "edit" | "view" | "rotate">("list");
const [selectedCredential, setSelectedCredential] = useState<Credential | null>(null);
```

## Testing

- [ ] Create credential flow
- [ ] Edit metadata (name, description)
- [ ] Reveal value (with auto-hide)
- [ ] Rotate credential
- [ ] Delete credential
- [ ] Error handling (validation, API errors)
- [ ] Rate limiting on reveal
- [ ] Empty state display
- [ ] Mobile layout

## Notes

- Backend API complete (commit 46d0a06)
- RLS enforced - users only see own credentials
- Activity logging automatic on backend
- Custom UI components (no Radix UI dependencies)
- Dialog component created matching existing alert-dialog pattern
- Navigation: Direct URL access at `/settings/credentials` (no nav link added - settings accessed directly)
- Workspace ID: Currently hardcoded as placeholder - needs context integration

## Files Created

```
apps/web/src/
├── components/
│   ├── ui/
│   │   └── dialog.tsx (new custom dialog component)
│   └── credentials/
│       ├── index.ts
│       ├── CreateCredentialDialog.tsx
│       ├── ViewCredentialDialog.tsx
│       ├── EditCredentialDialog.tsx
│       ├── RotateCredentialDialog.tsx
│       └── CredentialCard.tsx
├── lib/api/
│   └── credentials.ts (API client with PDA-friendly helpers)
└── app/(authenticated)/settings/credentials/
    └── page.tsx (main credentials management page)
```

## PDA Language Verification

✅ All dialogs use PDA-friendly language:

- "Remove credential" instead of "Delete"
- "Past target date" instead of "EXPIRED"
- "Approaching target" instead of "URGENT"
- "Consider rotating" instead of "MUST rotate"
- Warning messages use informative tone, not demanding

## Security Features Implemented

✅ Masked values only in list view
✅ Reveal requires explicit user action (with warning)
✅ Auto-hide revealed value after 30 seconds
✅ Copy-to-clipboard for revealed values
✅ Manual hide button for revealed values
✅ Rate limit warning on reveal errors
✅ Password input fields for sensitive values
✅ Security warnings before revealing

## Next Steps for Production

- [ ] Integrate workspace context (remove hardcoded workspace ID)
- [ ] Add settings navigation menu or dropdown
- [ ] Test with real OpenBao backend
- [ ] Add loading states for API calls
- [ ] Add optimistic updates for better UX
- [ ] Add filtering/search for large credential lists
- [ ] Add pagination for credential list
- [ ] Write component tests
