# 2026-04-13 — Profile feature + input sanitization **Timestamp:** 2026-04-13T02:00:00 ## Summary Added shared input sanitization layer applied to all database-bound inputs, introduced the `profiles` table for personal information (position, phone, date of birth, address), and built the frontend profile page with inline editing and a shared nav bar (Dashboard | Profile | Logout). Admin role flag (`is_superuser`) confirmed hidden from API. Security check patterns strengthened. ## Files Added - `backend/app/core/sanitize.py` — shared helpers: `sanitize_str`, `normalize_email`, `validate_phone`, `validate_date_of_birth`; applied to every user-supplied string before it reaches the DB - `backend/app/models/profile.py` — `Profile` ORM model (profiles table): `user_id` FK, `phone`, `date_of_birth`, `position`, `address`, `updated_at` - `backend/app/schemas/profile.py` — `ProfileRead` / `ProfileUpdate` Pydantic schemas; all fields sanitized via shared helpers - `backend/app/routers/profile.py` — `GET /api/profile/me` (lazy-create), `PUT /api/profile/me` - `backend/alembic/versions/676084df61d1_add_profiles_table.py` — Alembic migration creating the profiles table - `frontend/src/components/Nav.tsx` — shared nav bar: Dashboard, Profile, Logout - `frontend/src/pages/ProfilePage.tsx` — profile view + inline edit form; uses TanStack Query for fetch/mutate ## Files Modified - `backend/app/schemas/user.py` — added `normalize_email` and `sanitize_str` validators to `UserCreate` - `backend/app/models/user.py` — added `Profile` back-reference; added admin-role comment on `is_superuser` - `backend/app/models/__init__.py` — export `Profile` - `backend/app/main.py` — register `/api/profile` router - `frontend/src/api/client.ts` — added `ProfileData`, `ProfileUpdate` types, `getProfile`, `updateProfile` - `frontend/src/App.tsx` — added `/profile` private route - `frontend/src/pages/DashboardPage.tsx` — replaced inline logout with `Nav` component - `scripts/security_check.py` — strengthened SQL injection patterns (f-string/format/% in execute, text() without bindparam); added SANIT category for raw request→DB patterns - `TODO.md` — frontend feature items marked complete - `README.md` — Current State updated