Files
stack/docs/scratchpads/358-credential-frontend.md
Jason Woltje 6521cba735
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
feat: add flexible docker-compose architecture with profiles
- Add OpenBao services to docker-compose.yml with profiles (openbao, full)
- Add docker-compose.build.yml for local builds vs registry pulls
- Make PostgreSQL and Valkey optional via profiles (database, cache)
- Create example compose files for common deployment scenarios:
  - docker/docker-compose.example.turnkey.yml (all bundled)
  - docker/docker-compose.example.external.yml (all external)
  - docker/docker.example.hybrid.yml (mixed deployment)
- Update documentation:
  - Enhance .env.example with profiles and external service examples
  - Update README.md with deployment mode quick starts
  - Add deployment scenarios to docs/OPENBAO.md
  - Create docker/DOCKER-COMPOSE-GUIDE.md with comprehensive guide
- Clean up repository structure:
  - Move shell scripts to scripts/ directory
  - Move documentation to docs/ directory
  - Move docker compose examples to docker/ directory
- Configure for external Authentik with internal services:
  - Comment out Authentik services (using external OIDC)
  - Comment out unused volumes for disabled services
  - Keep postgres, valkey, openbao as internal services

This provides a flexible deployment architecture supporting turnkey,
production (all external), and hybrid configurations via Docker Compose
profiles.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 16:55:33 -06:00

5.9 KiB

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

  • Read issue details and design doc
  • Study existing patterns (personalities page)
  • Identify available UI components
  • Create API client functions (lib/api/credentials.ts)
  • Create dialog component (components/ui/dialog.tsx)
  • Create credential components
    • CreateCredentialDialog.tsx
    • ViewCredentialDialog.tsx (with reveal + auto-hide)
    • EditCredentialDialog.tsx
    • RotateCredentialDialog.tsx
    • CredentialCard.tsx
  • Create settings page (app/(authenticated)/settings/credentials/page.tsx)
  • TypeScript typecheck passes
  • 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:

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