Files
cve-dashboard/.kiro/specs/user-profile/tasks.md

8.4 KiB
Raw Blame History

Implementation Plan: User Profile

Overview

This plan implements the user profile feature in three phases: backend API routes first (profile endpoint and password change endpoint on the existing auth router), then the frontend components (UserProfilePanel modal and UserMenu theming/integration), and finally wiring everything together. Each task builds incrementally on the previous one, and testing tasks are placed close to the code they validate.

Tasks

  • 1. Add backend profile and password change routes to routes/auth.js

    • 1.1 Add GET /api/auth/profile route

      • Add a new route inside createAuthRouter that queries the users table for id, username, email, user_group, created_at, last_login using the session user's ID
      • Return { id, username, email, group, created_at, last_login } on success
      • Return 401 if the account is inactive (with is_active = 0), clearing the session cookie
      • Use the existing requireAuth(db) middleware for authentication
      • Requirements: 4.1, 4.2, 4.3
    • 1.2 Add POST /api/auth/change-password route with rate limiting

      • Add express-rate-limit middleware scoped to this route: 5 requests per 15-minute window, keyed by req.cookies.session_id
      • Validate request body has currentPassword and newPassword fields; return 400 if missing
      • Validate newPassword is at least 8 characters; return 400 if too short
      • Query the user's password_hash and is_active from the database; return 401 if account is inactive
      • Use bcrypt.compare to verify currentPassword; return 401 if incorrect
      • Hash the new password with bcrypt.hash(newPassword, 10) and update the password_hash column
      • Call logAudit with action password_change, entityType auth
      • Return { message: 'Password changed successfully' } on success
      • Return 429 with appropriate message when rate limit is exceeded
      • Requirements: 2.2, 2.3, 2.7, 2.8, 5.1, 5.2, 5.3, 5.4
    • 1.3 Write property tests for password change round-trip (backend)

      • Property 3: Password change round-trip — For any valid current password and any new password of 8+ characters, after a successful change, bcrypt.compare(newPassword, storedHash) returns true
      • Validates: Requirements 2.2, 2.7
    • 1.4 Write property tests for incorrect password rejection (backend)

      • Property 4: Incorrect current password is always rejected — For any password string that does not match the user's current password, the endpoint returns 401 and the stored hash remains unchanged
      • Validates: Requirements 2.3
    • 1.5 Write property tests for short password rejection (backend)

      • Property 6 (server-side): Short passwords are rejected — For any string of length 07, POST /api/auth/change-password returns 400 and the stored hash remains unchanged
      • Validates: Requirements 2.5, 5.4
  • 2. Checkpoint — Verify backend routes

    • Ensure all tests pass, ask the user if questions arise.
  • 3. Create UserProfilePanel.js frontend component

    • 3.1 Create the UserProfilePanel modal component

      • Create frontend/src/components/UserProfilePanel.js
      • Accept isOpen and onClose props
      • On open, fetch GET /api/auth/profile with credentials: 'include' and display loading state
      • Render profile info section showing: username, email, group, created_at (formatted), last_login (formatted)
      • Use dark theme inline styles matching the design system (intel-card gradient background, accent borders, light text colors from DESIGN_SYSTEM.md)
      • Include a close button (X icon from lucide-react) and click-outside-to-close behavior
      • Display error state with retry option if profile fetch fails
      • Use icons from lucide-react (User, Mail, Shield, Calendar, Clock)
      • Requirements: 1.1, 1.2, 1.3, 1.4
    • 3.2 Add password change form to UserProfilePanel

      • Add a password change section below the profile info with three fields: current password, new password, confirm new password
      • Implement client-side validation: new password must match confirm password; new password must be >= 8 characters
      • Display inline validation errors below the relevant fields
      • On submit, call POST /api/auth/change-password with { currentPassword, newPassword }
      • Handle API error responses (401 wrong password, 429 rate limited, 400 validation, 500 server error) and display appropriate messages
      • On success, show success message and clear all form fields
      • Style the form with dark theme inline styles (intel-input styling, intel-button-primary for submit)
      • Requirements: 2.1, 2.2, 2.3, 2.4, 2.5, 2.6
    • 3.3 Write property test for profile panel field rendering

      • Property 1: Profile panel displays all required fields — For any valid profile object with arbitrary username, email, group, created_at, and last_login values, rendering UserProfilePanel displays all five values in the output
      • Validates: Requirements 1.2
    • 3.4 Write property test for mismatched password confirmation

      • Property 5: Mismatched password confirmation is rejected client-side — For any two distinct strings used as newPassword and confirmPassword, the form displays a validation error and does not submit a request
      • Validates: Requirements 2.4
    • 3.5 Write property test for short password client-side rejection

      • Property 6 (client-side): Short passwords are rejected — For any string of length 07, the form displays a minimum-length validation error and does not submit a request
      • Validates: Requirements 2.5
  • 4. Checkpoint — Verify frontend component

    • Ensure all tests pass, ask the user if questions arise.
  • 5. Modify UserMenu.js for dark theming and profile integration

    • 5.1 Convert UserMenu.js from light theme to dark theme

      • Replace Tailwind light-theme classes with inline dark-theme style objects
      • Button: hover:bg-gray-100rgba(14, 165, 233, 0.1) hover background
      • Username text: text-gray-900#F8FAFC (design system --text-primary)
      • Group label text: text-gray-500#E2E8F0 (design system --text-secondary)
      • Chevron icon: text-gray-500#E2E8F0
      • Dropdown panel: bg-white → intel-card gradient background; border-gray-200rgba(14, 165, 233, 0.3)
      • Dropdown items: text-gray-700#F8FAFC; hover:bg-gray-50rgba(14, 165, 233, 0.1)
      • Sign out text: text-red-600#F87171; hover:bg-red-50rgba(239, 68, 68, 0.1)
      • Dropdown header: text-gray-900#F8FAFC; text-gray-500#94A3B8; border-gray-100rgba(14, 165, 233, 0.2)
      • Retain existing group badge color-coding logic
      • Requirements: 3.1, 3.2, 3.3, 3.4, 6.1, 6.2, 6.3, 6.4, 6.5
    • 5.2 Add "My Profile" menu item and wire UserProfilePanel

      • Import UserProfilePanel component
      • Add showProfile state variable
      • Add a "My Profile" menu item with User icon between the dropdown header and the admin-only actions
      • On click, close the dropdown and set showProfile to true
      • Render <UserProfilePanel isOpen={showProfile} onClose={() => setShowProfile(false)} /> in the component output
      • Requirements: 1.1, 1.3
    • 5.3 Write property test for profile API data completeness

      • Property 2: Profile API returns complete user data matching database — For any active user record, a GET request to /api/auth/profile with that user's valid session returns an object with id, username, email, group, created_at, and last_login fields matching the database
      • Validates: Requirements 4.1
  • 6. Final checkpoint — Ensure all tests pass

    • Ensure all tests pass, ask the user if questions arise.

Notes

  • Tasks marked with * are optional and can be skipped for faster MVP
  • Each task references specific requirements for traceability
  • Checkpoints ensure incremental validation
  • Property tests use fast-check (already installed in frontend/package.json as a devDependency)
  • Backend tests for properties 3, 4, and 6 (server-side) will need fast-check added to the root package.json devDependencies
  • The existing express-rate-limit package (already in root package.json) is used for the password change rate limiter
  • No database migrations are needed — the existing users table has all required columns
  • All styling follows the dark theme design system documented in DESIGN_SYSTEM.md