2026.06.05 frontend javítgatás és új belépési logika megvalósítva
This commit is contained in:
89
docs/profile_ui_identity_docs_password_implementation.md
Normal file
89
docs/profile_ui_identity_docs_password_implementation.md
Normal file
@@ -0,0 +1,89 @@
|
||||
# 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`](backend/app/schemas/user.py:68) — 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`](backend/app/api/v1/endpoints/users.py:179) — 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`](backend/app/api/v1/endpoints/users.py:260) — 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`](frontend/src/stores/auth.ts:19) — 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`](frontend/src/stores/auth.ts:430) — 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`](frontend/src/views/ProfileView.vue:1) — 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** (`setTimeout` → `closePasswordModal()`)
|
||||
- **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 hashing** — `get_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
|
||||
Reference in New Issue
Block a user