Files
service-finder/docs/profile_ui_identity_docs_password_implementation.md

4.9 KiB

Profile UI Refactor + Identity Docs + Change Password Implementation

Overview

Full-stack implementation of Profile page UI/UX improvements, identity documents (identity_docs) display/editing, and secure password change functionality.

Backend Changes

1. backend/app/schemas/user.py — PersonUpdate Schema

  • Added identity_docs: Optional[Any] = None field to PersonUpdate class (line 79)
  • Created new ChangePasswordRequest class (lines 93-96) with:
    • current_password: str — the user's existing password for verification
    • new_password: str — the desired new password

2. backend/app/api/v1/endpoints/users.py — PUT /me/person

  • Updated imports to include ChangePasswordRequest, AuthService, verify_password, get_password_hash
  • Added identity_docs merge logic (lines 219-227):
    • If identity_docs is provided and not null, merges with existing docs using dict.update()
    • Preserves fields not sent in the update payload (e.g., if only LICENSE is sent, ID_CARD is preserved)
    • Falls back to direct assignment if either value is not a dict

3. backend/app/api/v1/endpoints/users.py — PUT /me/password (New Endpoint)

Complete password change flow:

  1. Current password verification (line 273): Uses verify_password() to check the provided current password against the stored hash
  2. New password ≠ old password check (line 280): Prevents reusing the same password
  3. Complexity validation (line 287): Calls AuthService._validate_password_complexity() which reads dynamic rules from SystemParameter (min length, uppercase, digits, special chars)
  4. Hash and save (line 290): Uses get_password_hash() to bcrypt-hash the new password and commits to DB
  5. Error handling (lines 292-297): Rollback on SQLAlchemyError, returns 500 with detail

Frontend Changes

1. frontend/src/stores/auth.ts — PersonData Interface

  • Added identity_docs: Record<string, any> | null (line 28)
  • Added ice_contact: Record<string, any> | null (line 29)

2. frontend/src/stores/auth.ts — changePassword Action

New Pinia action that:

  • Calls PUT /users/me/password with { current_password, new_password }
  • Returns { status: string, message: string } on success
  • Throws with error message on failure

3. frontend/src/views/ProfileView.vue — Complete Rewrite

UI Design (Dark Card Theme)

  • Card backgrounds: bg-black/40 backdrop-blur-xl with border border-white/10
  • Data text: text-white font-medium (bold white for readability)
  • Labels: text-white/50 text-sm (muted gray labels)
  • Accent color: #00E5A0 (green) used only for buttons and active states
  • Input fields: bg-white/5 border-white/10 with focus state border-[#00E5A0]/50
  • Close button: Top-right X button with hover:text-red-400

Identity Docs Section (lines 214-309)

  • Read mode: Displays ID_CARD (number, expiry_date) and LICENSE (number, expiry_date, categories) in bordered sub-cards
  • Edit mode: Input fields for all identity doc fields, organized in sub-sections
  • Payload construction (buildIdentityDocsPayload(), lines 636-663): Only sends identity_docs if at least one field is filled; constructs nested JSON { ID_CARD: { number, expiry_date }, LICENSE: { number, expiry_date, categories } }

Change Password Modal (lines 431-528)

  • Teleport to body: Renders outside the component tree for proper z-index stacking
  • 3 fields: Current password, new password, confirm new password
  • Frontend validation (submitPasswordChange(), lines 713-751):
    • All fields required
    • New password must match confirmation
    • Minimum 6 characters
  • API call: Calls authStore.changePassword() on success
  • Success feedback: Green success message with auto-close after 2 seconds (setTimeoutclosePasswordModal())
  • Error feedback: Red error message from backend detail or fallback string

Testing Results

Test Result
Backend syntax check (user.py, users.py) Pass
Backend module imports (PersonUpdate, ChangePasswordRequest) Pass
Backend router routes (PUT /me/person, PUT /me/password) Pass
Frontend Vite build (112 modules) Pass
ProfileView chunk size 27.26 kB

Security Considerations

  1. Password never returned in responses — the ChangePasswordRequest is input-only
  2. Bcrypt hashingget_password_hash() uses bcrypt with work factor
  3. Dynamic complexity rules_validate_password_complexity reads from SystemParameter table, allowing admin to change rules without code deploy
  4. No password logging — the endpoint never logs the password values
  5. Identity docs merge — preserves existing data when partial updates are sent