# 11 — User Profile Redesign

> **Goal**: Transform the user profile from a fragmented settings dump into a clean, social-first academic profile — the "LinkedIn for researchers" experience. Mobile-first, Arabic-first, minimal noise.

---

## Current State (Problems)

| Problem | Details |
|---------|---------|
| **4 redundant tabs** | Playground, Personal Info, Subscription, Credit — only visible to owner, confusing for visitors |
| **Credit page is legacy** | `/users/credit/{username}` — old download-credit system, no longer relevant |
| **Subscription shown twice** | `/users/subscribtion/{username}` (gold academic) AND `/users/playground/{username}` (AI credits) — user doesn't know which is which |
| **No public social feed on profile** | Posts exist (`/api/profile-posts/{username}`) but profile page only shows published research papers — no posts, no shares, no activity |
| **No unified settings page** | Photo, bio, password, privacy, notifications all scattered across inline modals on the profile page |
| **No notification preferences** | Only 3 booleans (`emailRecivedType`, `recommendationNewsletterEnabled`, `digestNewsletterEnabled`) — no per-event control |
| **No block system** | No entity, no API, no UI |
| **No "Ask" / wall posting** | Visitors cannot interact with the profile beyondFollow |
| **Not mobile-friendly** | `personal_info.html.twig` is 1031 lines of densely packed Bootstrap 3 grid with hardcoded widths |
| **No privacy granularity** | Only 1 toggle: entire profile public/private. No per-field visibility (email, birthdate, country) |

---

## Target Architecture

### Two Distinct Surfaces

1. **Public Profile** (`/users/{username}`) — What visitors see. Social-first: hero card + activity feed + academic info. Clean, minimal, mobile-friendly.
2. **Settings** (`/settings` or `/settings/{section}`) — Owner-only. Consolidated single page with sidebar sections. Replaces all current tabs (Playground, Subscription, Credit, Personal Info editing).

### URL Structure

| Route | Purpose | Access |
|-------|---------|--------|
| `/users/{username}` | Public profile (hero + feed + academic info) | Everyone (respects privacy) |
| `/users/{username}/followers` | Followers list | Everyone |
| `/users/{username}/following` | Following list | Everyone |
| `/settings` | Redirect to `/settings/profile` | Owner only |
| `/settings/profile` | Edit name, bio, photo, university, field, links | Owner only |
| `/settings/account` | Email, password, 2FA, language, delete account | Owner only |
| `/settings/privacy` | Per-field visibility, who can post on wall, block list | Owner only |
| `/settings/notifications` | Per-event notification toggles (in-app, email, push) | Owner only |
| `/settings/subscription` | AI Playground tier + legacy academic subscription | Owner only |

**Removed routes** (redirect to new equivalents):
- `/users/credit/{username}` → redirect to `/settings/subscription` (or remove entirely)
- `/users/subscribtion/{username}` → redirect to `/settings/subscription`
- `/users/playground/{username}` → redirect to `/settings/subscription`

---

## Implementation Phases

### Phase 1 — Public Profile Redesign (Foundation) ✅ COMPLETED (Mar 5, 2026)

**Goal**: Make `/users/{username}` a clean, social-first page that mirrors the feed experience.

**Status**: Fully implemented and deployed to production.

#### What Was Done

##### 1.1 New Profile Hero Card ✅
- Clean hero card with profile photo (larger, circular, camera overlay for owner to change)
- Full name, `@username`, study degree badge, work, study field, country — all in a compact tagline row
- Academic interests displayed as clickable tag chips below tagline (up to 5)
- Stats bar: followers count, following count, posts count, papers count, profile views (eye icon) — each clickable
- **Action buttons**: Follow/Unfollow for visitors, Edit Profile button for owner
- No cover photo — clean white card design per user feedback

##### 1.2 Profile Activity Feed (Inline) ✅
- Reuses existing `/api/profile-posts/{username}` endpoint
- Shows posts, shared papers, shared URLs in feed card layout (same design as `/feed`)
- Infinite scroll with "Load more" button
- Owner sees post composer at top of feed
- Post interactions: like, comment, share, edit, delete — all inline
- Tabs: "Posts" and "Papers" to switch between social feed and published research

##### 1.3 Profile Sidebar ✅
- **About** section — bio, degree, study field, work, country, email, join date
- Sidebar collapses below feed on mobile (responsive)
- **Removed**: Published research sidebar card (redundant with Papers tab)
- **Removed**: Interests sidebar card (moved to hero header)

##### 1.4 Tab Bar Removed ✅
- Old 4-tab bar (Playground, Personal Info, Subscription, Credit) completely removed
- `layout.html.twig` rewritten from ~203 lines to ~35 clean lines
- Visitors see: Hero → Feed/Papers → Sidebar. No tabs.

#### Files Modified
- `templates/Profile/show/personal_info.html.twig` — complete rewrite (hero + feed + sidebar + modals + JS)
- `templates/Profile/show/layout.html.twig` — rewritten to clean ~35-line shell
- `src/Controller/ProfileController.php` — passes `isOwner` and `postsCount` to template
- `translations/Social.ar.yml` — 20+ new profile translation keys
- `translations/Social.en.yml` — 20+ new profile translation keys
- `translations/FOSUserBundle.ar.yml` — added `back_to_profile` key
- `translations/FOSUserBundle.en.yml` — added `back_to_profile` key

#### Bug Fixes During Phase 1
- Fixed `profile.degree_phD` translation mismatch — DB stores `phD` (capital D), translations use `phd` (lowercase). Added `|lower` normalization in template.
- Fixed missing `profile.back_to_profile` translation on followers/following pages.
- Hidden `studyField` when value is "غير محدد" (undefined placeholder stored in DB).
- Removed green cover area per user feedback (too wide/distracting).
- Removed duplicate bio from hero card (bio kept only in sidebar).

#### Backup
- `templates/Profile/show/personal_info_backup.html.twig` — backup of original template before rewrite

---

### Phase 2 — Unified Settings Page ✅ COMPLETED (Mar 5, 2026)

**Goal**: One settings page at `/settings` replacing all current owner-only tabs.

**Status**: Fully implemented and deployed to production.

#### What Was Done

##### 2.1 Settings Layout ✅
- Left sidebar navigation with icons: Profile, Account, Subscription
- Active tab highlighted with green left border
- Main content area renders the active section (full page navigation, not SPA)
- Mobile responsive: sidebar becomes horizontal scrollable tabs
- Toast notification system (`showToast()`) for save/error feedback
- Full CSS variables system matching site theme (green primary, clean cards)
- Extends site's base `layout.html.twig` via `{% block body %}`

##### 2.2 Settings — Profile Section (`/settings/profile`) ✅
- **Avatar upload**: preview + change button, posts to `/api/user/profile/update-image`
- **Personal info form**: First name, Last name, Username (read-only), Bio (textarea with char counter, 500 limit), Gender (dropdown), Birthdate (date picker), Phone
- **Academic info form**: Study degree (dropdown: Student/Bachelor/Master/PhD/Professor), Field of study (dropdown from `Field` entity via dedicated `/settings/update-study-field` endpoint), Work, Country (dropdown from `CountryChoices` with Arab countries prioritized), Address
- **Social links form**: LinkedIn URL, Facebook URL
- **Academic interests**: Chip-based tag editor — Enter/comma to add, × to remove, saves via `/api/update-academic-interests`
- All forms save via AJAX to existing `/api/user/profile/update` endpoint (field+value pairs)

##### 2.3 Settings — Account Section (`/settings/account`) ✅
- **Email**: displayed read-only with hint to contact support
- **Password change**: current + new + confirm form, AJAX to `/settings/change-password` — validates current password, enforces 8+ chars with letter+number
- **Language toggle**: Arabic/English buttons, posts to `/api/user/profile/update-locale` then page redirect
- **Privacy toggle**: Public profile on/off switch
- **Notifications**: Recommendation newsletter toggle + Weekly digest toggle
- **Danger zone**: Delete account button linking to existing `/opt-out` route with confirmation

##### 2.4 Settings — Subscription Section (`/settings/subscription`) ✅
- **AI Playground**: Status badge (active/trial/inactive), tier label with color coding, valid-until date, credits remaining with visual progress bar, monthly usage stats table (action/count/tokens), upgrade button → playground page
- **Academic subscription**: Gold member badge, valid-until date, canceled status display
- Empty state when no subscription active

##### 2.5 Navigation Integration ✅
- **Header desktop**: Settings gear icon (`fa-cog`) added between avatar and logout
- **Header mobile**: Settings link added in sidebar Account section
- **Profile hero card**: "Settings" button added for profile owner (both template variants)

#### Files Created
- `src/Controller/SettingsController.php` — 6 routes: index (redirect), profile, account, subscription, change-password, update-study-field
- `templates/settings/layout.html.twig` — settings shell with sidebar nav + responsive CSS + toast JS
- `templates/settings/profile.html.twig` — avatar + personal/academic/social forms + interests editor
- `templates/settings/account.html.twig` — email + password + language + privacy + notifications + danger zone
- `templates/settings/subscription.html.twig` — AI playground credits + academic subscription display
- `translations/Settings.ar.yml` — ~100 translation keys (nav, toast, profile, account, subscription)
- `translations/Settings.en.yml` — ~100 translation keys

#### Files Modified
- `templates/header.html.twig` — added settings gear icon (desktop) + settings link (mobile sidebar)
- `templates/Profile/show/personal_info.html.twig` — added Settings button in hero card for owner
- `templates/Profile/show/personal_info_new.html.twig` — added Settings button in hero card for owner
- `src/Controller/ProfileController.php` — added `digestNewsletterEnabled` to allowed fields, fixed null-to-string type error for empty field values
- `translations/UserBundle.ar.yml` — added `settings` key
- `translations/UserBundle.en.yml` — added `settings` key
- `translations/Social.ar.yml` — added `settings_btn` key
- `translations/Social.en.yml` — added `settings_btn` key

#### Bug Fixes During Phase 2
- **Empty page fix**: Settings layout used `{% block page %}` but parent layout only defines `{% block body %}` — changed to correct block name.
- **Missing translations**: `{% trans_default_domain "Settings" %}` is NOT inherited by child Twig templates — added the directive to all three child templates (profile, account, subscription).
- **Profile update 500 error**: `$value ?: null` turned empty strings into `null`, but setters like `setBio()` have strict `string` type hints — fixed to pass empty strings for string fields instead of null.

#### Routes (auto-loaded via attribute annotations with en/ar locale prefixes)
| Route | Path (ar) | Path (en) |
|-------|-----------|-----------|
| `app_settings` | `/settings` | `/en/settings` |
| `app_settings_profile` | `/settings/profile` | `/en/settings/profile` |
| `app_settings_account` | `/settings/account` | `/en/settings/account` |
| `app_settings_subscription` | `/settings/subscription` | `/en/settings/subscription` |
| `app_settings_change_password` | `/settings/change-password` (POST) | `/en/settings/change-password` |
| `app_settings_update_study_field` | `/settings/update-study-field` (POST) | `/en/settings/update-study-field` |

#### 2.6 Settings — Profile Enhancements ✅ (Mar 5, 2026)

**Searchable Study Field Dropdown:**
- Replaced static `<select>` with custom searchable input + AJAX dropdown
- User types to filter — 200ms debounced search queries `/settings/search-fields`
- Results show both Arabic and English field names
- Clear button (×) resets selection
- Auto-saves on selection via existing update endpoint

**"Add New Field" Feature:**
- "Add new field" option always visible at bottom of search dropdown
- Opens modal overlay with Arabic name + English name inputs
- Submits to `POST /settings/create-field` — server checks for duplicates, creates `Field` entity
- New field auto-selected after creation, sets `createdBy` to current user

**LinkedIn-Style Work Experience:**
- Full CRUD work experience section in profile settings
- Timeline display with briefcase icons, title/company/dates
- Inline add/edit form: title, company, start month, end month, "I currently work here" checkbox, description textarea
- Edit/delete buttons per entry with confirmation dialog
- Empty state message encouraging users to add experience
- Old "Work" text field kept as "Current Position" quick summary with hint
- Entity: `UserWorkExperience` (id, user, title, company, startDate, endDate, isCurrent, description, sortOrder, createdAt, updatedAt)
- Migration: `Version20260305100000` — creates `user_work_experience` table with FK to `fos_user` (CASCADE delete)

**Files Created:**
- `src/Entity/UserWorkExperience.php` — new entity with PrePersist/PreUpdate lifecycle callbacks
- `migrations/Version20260305100000.php` — creates `user_work_experience` table

**Files Modified:**
- `src/Controller/SettingsController.php` — 5 new endpoints added (search-fields, create-field, work-experience add/update/delete), `profile()` now passes `workExperiences` to template
- `src/Entity/User.php` — added `$workExperiences` OneToMany collection with OrderBy, getter/adder/remover
- `templates/settings/profile.html.twig` — major rewrite: searchable field dropdown, add-field modal, full work experience CRUD section with timeline UI
- `translations/Settings.ar.yml` — ~30 new keys (field search, work experience labels)
- `translations/Settings.en.yml` — ~30 new keys

**New Routes (Phase 2.6):**
| Route | Path | Method |
|-------|------|--------|
| `app_settings_search_fields` | `/settings/search-fields` | GET |
| `app_settings_create_field` | `/settings/create-field` | POST |
| `app_settings_work_experience_add` | `/settings/work-experience/add` | POST |
| `app_settings_work_experience_update` | `/settings/work-experience/{id}/update` | POST |
| `app_settings_work_experience_delete` | `/settings/work-experience/{id}/delete` | POST |

**Data Fix:**
- Fixed Arabic typo in `field` table: ID 107 `الذكاء الاصناعي` → `الذكاء الاصطناعي` (missing ط)

**Commit:** `4c9cb35d` — "Searchable study field, add-new-field, LinkedIn-style work experience"

#### Additional Changes (Related)
- **Founder boost + improved suggestion algorithm**: See [06-social-platform.md — Researcher Suggestion Algorithm](06-social-platform.md) for full details. Key: multi-signal scoring (quality + recency + field match) with randomization, founder always first.
- **Profile view counter (Mar 24, 2026)**: Added eye icon + `visitors` count to the hero stats bar, visible to all profile visitors. Uses existing `visitors` field incremented on each unique visit.

---

### Phase 3 — Notification Preferences ✅ COMPLETED (Mar 9, 2026)

**Goal**: Give users granular control over what notifications they receive and how.

**Status**: Implemented and deployed to production.

#### 3.1 Notification Preference Entity

New entity: `UserNotificationPreference`

| Field | Type | Default |
|-------|------|---------|
| `id` | integer (PK) | auto |
| `user` | ManyToOne → User | unique |
| `new_follower_inapp` | boolean | true |
| `new_follower_email` | boolean | true |
| `post_liked_inapp` | boolean | true |
| `post_liked_email` | boolean | false |
| `post_commented_inapp` | boolean | true |
| `post_commented_email` | boolean | true |
| `comment_replied_inapp` | boolean | true |
| `comment_replied_email` | boolean | true |
| `paper_shared_inapp` | boolean | true |
| `paper_shared_email` | boolean | false |
| `wall_question_inapp` | boolean | true |
| `wall_question_email` | boolean | true |
| `weekly_digest_email` | boolean | true |
| `recommendation_email` | boolean | true |
| `marketing_email` | boolean | false |

#### 3.2 Settings — Notifications Section (`/settings/notifications`)
- Grouped by category (Social + Email newsletters)
- Event-level toggles for in-app/email where applicable
- Save via AJAX per toggle (instant save)
- Added backward-compatible redirect: `/settings/notification` → `/settings/notifications`

**Implemented note**:
- Push channel is not implemented yet
- "Mute all" master toggle is not implemented yet

#### 3.3 Integrate Preferences into NotificationService
- `UserNotification::notifyUser()` checks preferences before creating notification
- Follow/comment/reply notification flows check `UserNotificationPreference` before email dispatching

**Migration**: Create `user_notification_preference` table. Migrate existing booleans:
- `User::$emailRecivedType` → `marketing_email`
- `User::$recommendationNewsletterEnabled` → `recommendation_email`
- `User::$digestNewsletterEnabled` → `weekly_digest_email`

**Files created/updated (deployed):**
- `src/Entity/UserNotificationPreference.php`
- `src/Repository/UserNotificationPreferenceRepository.php`
- `src/Service/NotificationPreferenceService.php`
- `templates/settings/notifications.html.twig`
- `migrations/Version20260309130000.php`
- `src/Controller/SettingsController.php`
- `templates/settings/layout.html.twig`
- `translations/Settings.ar.yml`
- `translations/Settings.en.yml`
- `src/Service/UserNotification.php`
- `src/Controller/FollowController.php`
- `src/Controller/ProfilePostCommentController.php`

**Production notes:**
- Migration applied successfully on prod with full backfill (`user_notification_preference` row count matches `fos_user`)
- Route compatibility hotfix deployed for singular URL
- Template syntax hotfix deployed after initial production error

**Commits:**
- `07f0feb2` — Phase 3 implementation
- `d44ea048` — legacy redirect `/settings/notification`
- `f4fa76a3` — Twig syntax fix for notifications template

**Estimated effort**: 2-3 days

---

### Phase 4 — Privacy & Visibility Controls

**Goal**: Let users control what's visible to whom.

#### 4.1 Privacy Settings Entity / Fields

Add columns to `fos_user` (or create a separate `UserPrivacySettings` entity):

| Setting | Options | Default |
|---------|---------|---------|
| `profile_visibility` | `public` / `followers_only` / `private` | `public` |
| `email_visibility` | `nobody` / `followers` / `everyone` | `nobody` |
| `birthdate_visibility` | `nobody` / `followers` / `everyone` | `nobody` |
| `country_visibility` | `everyone` / `followers` / `nobody` | `everyone` |
| `phone_visibility` | `nobody` / `followers` / `everyone` | `nobody` |
| `posts_visibility_default` | `public` / `followers` / `private` | `public` |
| `allow_wall_posts` | `everyone` / `followers` / `nobody` | `followers` |

#### 4.2 Settings — Privacy Section (`/settings/privacy`)
- Per-field visibility dropdowns
- Wall posting permission
- Block list management (see Phase 6)
- Profile visibility (replaces current `publicProfile` toggle)

#### 4.3 Enforce Privacy in Controllers
- `ProfileController::profileShow()` checks `profile_visibility`
- Profile fields conditionally rendered based on visitor relationship + visibility setting
- Default post visibility applied when creating new posts

**Files to create:**
- `src/Entity/UserPrivacySettings.php`
- `templates/settings/privacy.html.twig`
- `migrations/VersionXXXX_privacy_settings.php`

**Estimated effort**: 2-3 days

---

### Phase 5 — Wall Posts ("Ask {Name}")

**Goal**: Let visitors post questions/messages on a researcher's profile wall, creating rich social interactions visible in the feed.

#### 5.1 Wall Post Entity

New entity: `WallPost` (or extend `ProfilePost` with a `targetUser` field)

| Field | Type | Notes |
|-------|------|-------|
| `id` | integer | PK |
| `author` | ManyToOne → User | Who posted the question |
| `targetUser` | ManyToOne → User | Whose wall it's on |
| `content` | text | The question/message |
| `slug` | string(20) | unique |
| `createdAt` | datetime | |
| `likesCount` | integer | 0 |
| `commentsCount` | integer | 0 |
| `visibility` | string(20) | public/followers — inherits from target user's `allow_wall_posts` |
| `isAnswered` | boolean | false, set to true when target user replies |

#### 5.2 UI on Profile Page
- Below the hero card and above the activity feed: "Ask {FirstName} a question" input box (visible if `allow_wall_posts` permits)
- Wall posts appear in the profile feed mixed with regular posts, tagged with "Question from @asker"
- Target user can reply → reply is highlighted as "Answer"
- "Unanswered" filter tab option

#### 5.3 Feed Integration
- Wall posts surface in `/feed` with special format:
  - `"{Author} asked {TargetUser} a question"` — shows question preview
  - Click → opens wall post page (like `/post/{slug}` but with conversation thread)
- Feed tab "all" includes wall posts from followed users (both as author and target)

#### 5.4 Notifications
- Target user notified: "{Author} asked you a question on your profile"
- Author notified when target user replies: "{TargetUser} answered your question"
- Both respect notification preferences

**Files to create:**
- `src/Entity/WallPost.php` (or extend ProfilePost)
- `src/Controller/WallPostController.php`
- `templates/social/wall_post.html.twig`
- Feed service updates

**Estimated effort**: 4-5 days

---

### Phase 6 — User Blocking

**Goal**: Allow users to block others, hiding all interactions.

#### 6.1 Block Entity

New entity: `UserBlock`

| Field | Type | Notes |
|-------|------|-------|
| `id` | integer | PK |
| `blocker` | ManyToOne → User | Who is blocking |
| `blocked` | ManyToOne → User | Who is blocked |
| `createdAt` | datetime | |
| Unique constraint on (`blocker`, `blocked`) | | |

#### 6.2 Block API
- `POST /api/block/{userId}` — block user
- `POST /api/unblock/{userId}` — unblock user
- `GET /api/blocked-users` — list blocked users

#### 6.3 Effects of Blocking
When User A blocks User B:
- B cannot see A's profile (shows "This profile is not available")
- B cannot see A's posts in feed, search results, or anywhere
- B cannot follow A (auto-unfollow on block)
- B cannot comment on A's posts or wall
- A cannot see B's posts, comments, or profile either (mutual hide)
- Existing comments from B on A's posts remain but are hidden from A's view
- No notification sent to B about being blocked

#### 6.4 Block Enforcement Points
- `FeedService` — filter out blocked users' posts
- `ProfileController::profileShow()` — check block status
- `FollowController` — prevent following blocked users
- `ProfilePostCommentController` — prevent comments from blocked users
- `WallPostController` — prevent wall posts from blocked users
- Search results — filter blocked users' content

#### 6.5 UI
- Block option in user profile dropdown menu ("More" → "Block {Name}")
- Block confirmation modal with explanation
- Blocked users list in `/settings/privacy` with unblock buttons

**Files to create:**
- `src/Entity/UserBlock.php`
- `src/Repository/UserBlockRepository.php`
- `src/Service/BlockService.php` (centralized check: `isBlocked(userA, userB)`)
- `src/Controller/BlockController.php`
- `migrations/VersionXXXX_user_block.php`

**Estimated effort**: 3-4 days

---

### Phase 7 — Enhanced Profile Fields (LinkedIn-style) — PARTIALLY STARTED

**Goal**: Rich academic profile with structured education history, work experience, and publications.

**Status**: Work Experience entity and CRUD implemented in Phase 2.6. Education and remaining fields still pending.

#### 7.1 Education History Entity

New entity: `UserEducation`

| Field | Type |
|-------|------|
| `id` | integer (PK) |
| `user` | ManyToOne → User |
| `institution` | string(255) — University name |
| `degree` | string(100) — PhD, Master, Bachelor, etc. |
| `fieldOfStudy` | string(255) |
| `startYear` | integer |
| `endYear` | integer (nullable — "Present") |
| `description` | text (nullable) |
| `sortOrder` | integer |

#### 7.2 Work Experience Entity ✅ (Implemented in Phase 2.6)

New entity: `UserWorkExperience`

| Field | Type |
|-------|------|
| `id` | integer (PK) |
| `user` | ManyToOne → User |
| `title` | string(255) — e.g. "Associate Professor" |
| `organization` | string(255) — e.g. "Damascus University" |
| `startYear` | integer |
| `endYear` | integer (nullable) |
| `isCurrent` | boolean |
| `description` | text (nullable) |
| `sortOrder` | integer |

#### 7.3 Profile "About" Section Redesign
- Education timeline (most recent first)
- Work experience timeline
- Skills / research methodologies (tag list)
- Languages spoken
- ORCID ID link (text field)

#### 7.4 Settings — Profile Section Updates
- Add "Education" sub-section with add/edit/delete/reorder
- Add "Experience" sub-section with add/edit/delete/reorder
- Add ORCID, languages, skills fields

**Files to create:**
- `src/Entity/UserEducation.php`
- `src/Entity/UserWorkExperience.php`
- `migrations/VersionXXXX_education_experience.php`
- Updated profile template sections

**Estimated effort**: 3-4 days

#### 7.5 Google Scholar Integration ✅ COMPLETED (Mar 13, 2026)

**Goal**: Allow researchers to link their Google Scholar profile and display citation metrics, h-index, and recent publications on their Shamra Academia profile.

**Status**: Backend API + Settings page UI + Public profile display fully implemented.

##### Backend Implementation (Completed)

**Entity**: `UserScholarProfile` — stores linked Scholar data

| Field | Type | Description |
|-------|------|-------------|
| `id` | int (PK) | Auto-increment |
| `user` | OneToOne → User | Unique, CASCADE delete |
| `scholarId` | string(32) | Google Scholar author ID (e.g., "qMzDFQYAAAAJ") |
| `authorName` | string(255) | Name from Scholar |
| `affiliation` | string(500) | Institution/affiliation text |
| `interests` | JSON | Research interest labels/tags |
| `thumbnailUrl` | string(500) | Scholar avatar URL |
| `citationsAll` | int | Total citations (all time) |
| `citationsSince2021` | int | Citations since 2021 |
| `hIndexAll` | int | h-index (all time) |
| `hIndexSince2021` | int | h-index since 2021 |
| `i10IndexAll` | int | i10-index (all time) |
| `i10IndexSince2021` | int | i10-index since 2021 |
| `citationGraph` | JSON | Year-by-year citation counts |
| `publications` | JSON | Top 200 publications with citation counts |
| `publicationCount` | int | Total publication count |
| `coAuthors` | JSON | Frequent co-authors list |
| `syncStatus` | string(20) | `pending`, `syncing`, `completed`, `failed` |
| `syncError` | text | Last sync error message |
| `lastSyncedAt` | datetime | Last successful sync time |

**API Endpoints** (all require authentication):

| Method | Route | Purpose |
|--------|-------|---------|
| GET | `/api/scholar` | Get current user's Scholar profile |
| GET | `/api/scholar/publications` | Get publications with pagination |
| POST | `/api/scholar/validate` | Validate Scholar ID before linking (accepts URL or ID) |
| POST | `/api/scholar/link` | Link Scholar profile and start async sync |
| POST/DELETE | `/api/scholar/unlink` | Remove Scholar profile link |
| POST | `/api/scholar/sync` | Trigger manual re-sync (24h rate limit) |
| GET | `/api/scholar/co-authors` | Get co-authors list |

**Service**: `GoogleScholarService` — fetches data via SerpAPI
- Extracts Scholar ID from URLs (`scholar.google.com/citations?user=XXX`)
- Paginates through all publications (up to 200)
- Parses citation metrics, interests, co-authors

**Async Processing**: `SyncScholarProfile` message + handler
- Runs in background via Messenger worker
- Updates profile entity with fetched data
- Sets `syncStatus` to track progress

**Files Created:**
- `src/Entity/UserScholarProfile.php`
- `src/Repository/UserScholarProfileRepository.php`
- `src/Service/GoogleScholarService.php`
- `src/Controller/ScholarProfileController.php`
- `src/Message/SyncScholarProfile.php`
- `src/MessageHandler/SyncScholarProfileHandler.php`
- `migrations/Version20260312100000.php`

##### ⚠️ SerpAPI Rate Limiting & Cost Considerations

**Current Plan**: Free tier — **250 searches/month**

| Metric | Value |
|--------|-------|
| Monthly quota | 250 calls |
| Used (as of Mar 12) | 20 calls |
| Remaining | 230 calls |
| Cost per call | ~10 API calls per full profile sync (pagination) |

**Cost Breakdown per User Action:**
- **Validate Scholar ID**: 1 API call
- **Initial sync (full profile)**: ~10 API calls (1 for profile + up to 9 for publication pagination at 20/page)
- **Re-sync**: ~10 API calls

**Current Protections:**
- 24-hour minimum between manual syncs (`MIN_SYNC_INTERVAL_HOURS = 24`)
- Publications capped at 200 (10 pages max)

**Recommendations for Scale:**

1. **Limit initial rollout** — Soft-launch to ~20 users first to validate usage patterns
2. **Consider paid tier** — $50/month for 5,000 searches if adoption grows
3. **Add server-side rate limiting** — Track API calls in `app_setting` table, block syncs when quota low
4. **Batch refresh strategy** — Instead of on-demand sync, run nightly cron for stale profiles (>7 days old)
5. **Cache validation calls** — Store validated Scholar IDs temporarily to avoid repeat validation API calls

**Future Monitoring:**
- Add `serpapi_calls_this_month` to admin dashboard
- Alert when quota hits 80% (200 calls)
- Block new syncs when quota exhausted (show "Try again next month" message)

##### Frontend UX Design (Pending Implementation)

###### A. Settings → Profile: "Link Google Scholar" Section

**Location**: Settings → Profile page, new card below "Social Links"

**Empty State** (no Scholar linked):
```
┌─────────────────────────────────────────────────────────────┐
│  🎓 Google Scholar                                          │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  Link your Google Scholar profile to display your           │
│  citation metrics and publications on your profile.         │
│                                                             │
│  ┌─────────────────────────────────────────────────────┐   │
│  │ 🔗 Paste Scholar URL or Author ID                    │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
│  Examples:                                                  │
│  • https://scholar.google.com/citations?user=qMzDFQYAAAAJ   │
│  • qMzDFQYAAAAJ                                             │
│                                                             │
│                            [ Link Profile ]                 │
└─────────────────────────────────────────────────────────────┘
```

**Input Behavior**:
- Accepts full Scholar URL OR just the author ID
- On blur/submit: calls `/api/scholar/validate` to verify
- Shows author name preview: "Found: **Shadi Saleh, PhD** — Is this you?"
- Confirm button triggers `/api/scholar/link`

**Syncing State** (after linking):
```
┌─────────────────────────────────────────────────────────────┐
│  🎓 Google Scholar                            [ Unlink ]    │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  ┌─────────────────────────────────────────────────────┐   │
│  │   ⏳ Syncing your Google Scholar data...             │   │
│  │   This usually takes 10-30 seconds.                  │   │
│  │   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━░░░░░░░░░░░░░░░░░░░░░  │   │
│  └─────────────────────────────────────────────────────┘   │
│                                                             │
└─────────────────────────────────────────────────────────────┘
```
- Poll `/api/scholar` every 3 seconds until `syncStatus === 'completed'`
- Show indeterminate progress bar with pulsing animation
- Auto-transition to "Linked State" when sync completes

**Linked State** (sync completed):
```
┌─────────────────────────────────────────────────────────────┐
│  🎓 Google Scholar                            [ Unlink ]    │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  ✓ Linked to: Shadi Saleh, PhD                              │
│    Damascus University                                      │
│                                                             │
│    ┌──────────┐  ┌──────────┐  ┌──────────┐                │
│    │   1,234  │  │    18    │  │    25    │                │
│    │Citations │  │ h-index  │  │i10-index │                │
│    └──────────┘  └──────────┘  └──────────┘                │
│                                                             │
│    📚 142 publications synced                               │
│    🕐 Last synced: Today at 2:30 PM                         │
│                                                             │
│                    [ ↻ Sync Now ]  [ View on Scholar → ]    │
└─────────────────────────────────────────────────────────────┘
```

**Error State** (sync failed):
```
┌─────────────────────────────────────────────────────────────┐
│  🎓 Google Scholar                            [ Unlink ]    │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  ⚠️ Sync failed: Could not fetch Scholar data               │
│     This may be a temporary issue. Please try again.        │
│                                                             │
│                              [ ↻ Retry Sync ]               │
└─────────────────────────────────────────────────────────────┘
```

###### B. Public Profile: Scholar Metrics Card

**Location**: Profile sidebar, prominent position (above "About" or as hero stat)

**Design Option 1 — Metrics Badge Row** (recommended):
Integrate directly into the hero card stats bar:
```
┌─────────────────────────────────────────────────────────────┐
│  [Avatar]  Shadi Saleh, PhD                                 │
│            @shadi · Damascus University                     │
│            AI, NLP, Machine Learning                        │
│                                                             │
│  ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐           │
│  │ 142 │ │  89 │ │1.2K │ │  18 │ │  25 │ │ 12  │           │
│  │Posts│ │Paprs│ │Cites│ │h-idx│ │i10  │ │Flwrs│           │
│  └─────┘ └─────┘ └─────┘ └─────┘ └─────┘ └─────┘           │
│                          ↑ Scholar metrics (green accent)   │
│                                                             │
│  [ Follow ]  [ Message ]                                    │
└─────────────────────────────────────────────────────────────┘
```
- Scholar metrics shown with subtle 🎓 icon or green color accent
- Clicking citations/h-index opens Scholar profile in new tab
- Tooltip on hover: "Google Scholar metrics — View full profile"

**Design Option 2 — Sidebar Card**:
Separate card in sidebar for users with Scholar linked:
```
┌─────────────────────────────────────────────────────────────┐
│  🎓 Google Scholar                          [ → ]           │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│    1,234          18           25                           │
│   Citations     h-index     i10-index                       │
│                                                             │
│   ────────────────────────────────────────                  │
│   📈 Citation trend:  +156 this year                        │
│                                                             │
│   Top publications:                                         │
│   • Deep Learning for Arabic NLP (324 cites)                │
│   • Neural Machine Translation... (198 cites)               │
│   • Sentiment Analysis in... (156 cites)                    │
│                                                             │
└─────────────────────────────────────────────────────────────┘
```

**Design Option 3 — Compact Badge** (minimal):
Small badge near the name, similar to verified badges:
```
│  Shadi Saleh, PhD  🎓 h-index: 18                          │
```
- Hovering shows tooltip with full metrics
- Clicking opens modal or sidebar expansion

###### C. Profile "Papers" Tab Enhancement

For users with Scholar linked, enhance the Papers tab:

**Shamra + Scholar Combined View**:
```
┌─────────────────────────────────────────────────────────────┐
│  Papers                                                     │
│  ┌─────────────────────┐ ┌─────────────────────┐            │
│  │ Shamra (23)         │ │ Google Scholar (142)│            │
│  └─────────────────────┘ └─────────────────────┘            │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  [Combined list or tab-switched view]                       │
│                                                             │
│  📄 Deep Learning for Arabic NLP                            │
│     🎓 324 citations · Published 2019                       │
│     [Shamra badge if also on Shamra]                        │
│                                                             │
│  📄 Neural Machine Translation for Arabic                   │
│     🎓 198 citations · Published 2020                       │
│                                                             │
└─────────────────────────────────────────────────────────────┘
```

**Matching Publications**:
- If a Scholar publication matches a Shamra paper (by title similarity), show combined entry
- Display both Shamra download count AND Scholar citations
- Badge: "📚 On Shamra + 🎓 324 citations"

###### D. Translation Keys Needed

```yaml
# Settings.ar.yml
scholar:
  section_title: "Google Scholar"
  link_description: "اربط ملفك الشخصي في Google Scholar لعرض مقاييس الاستشهاد ومنشوراتك."
  input_placeholder: "الصق رابط Scholar أو معرّف المؤلف"
  input_hint: "مثال: https://scholar.google.com/citations?user=XXX أو فقط XXX"
  link_btn: "ربط الملف الشخصي"
  unlink_btn: "إلغاء الربط"
  sync_btn: "مزامنة الآن"
  view_on_scholar: "عرض في Scholar"
  syncing_title: "جارٍ مزامنة بيانات Google Scholar..."
  syncing_hint: "يستغرق هذا عادةً 10-30 ثانية."
  linked_to: "مرتبط بـ:"
  last_synced: "آخر مزامنة:"
  publications_synced: "منشورات تمت مزامنتها"
  sync_failed: "فشلت المزامنة"
  retry_sync: "إعادة المحاولة"
  confirm_found: "تم العثور على: %name% — هل هذا أنت؟"
  confirm_btn: "نعم، هذا أنا"
  citations: "الاستشهادات"
  h_index: "مؤشر h"
  i10_index: "مؤشر i10"
  
# Settings.en.yml  
scholar:
  section_title: "Google Scholar"
  link_description: "Link your Google Scholar profile to display your citation metrics and publications."
  input_placeholder: "Paste Scholar URL or Author ID"
  input_hint: "Example: https://scholar.google.com/citations?user=XXX or just XXX"
  link_btn: "Link Profile"
  unlink_btn: "Unlink"
  sync_btn: "Sync Now"
  view_on_scholar: "View on Scholar"
  syncing_title: "Syncing your Google Scholar data..."
  syncing_hint: "This usually takes 10-30 seconds."
  linked_to: "Linked to:"
  last_synced: "Last synced:"
  publications_synced: "publications synced"
  sync_failed: "Sync failed"
  retry_sync: "Retry Sync"
  confirm_found: "Found: %name% — Is this you?"
  confirm_btn: "Yes, that's me"
  citations: "Citations"
  h_index: "h-index"
  i10_index: "i10-index"
```

###### E. Implementation Checklist

**Settings Page:** ✅ COMPLETED (Mar 13, 2026)
- [x] Add Scholar section to `templates/settings/profile.html.twig`
- [x] URL/ID input with validation
- [x] Preview confirmation step before linking
- [x] Syncing state with progress indicator + polling
- [x] Linked state with metrics display
- [x] Error state with retry button
- [x] Unlink confirmation dialog
- [x] Manual sync button

**Public Profile:** ✅ COMPLETED (Mar 13, 2026)
- [x] Add Scholar metrics to hero card stats row (Design Option 1)
- [x] Tooltip on hover showing "Google Scholar metrics"
- [x] External link to Scholar profile on click
- [x] Hide section entirely if user has no Scholar linked

**Papers Tab (future enhancement):**
- [ ] Tab toggle: Shamra / Google Scholar / All
- [ ] Citation count display for Scholar publications
- [ ] Match Shamra papers with Scholar publications by title

**Estimated effort**: 
- Settings page: 1 day
- Public profile display: 0.5 day
- Papers tab integration: 1 day (optional, can defer)

---

### Phase 8 — Mobile-First Responsive Polish

**Goal**: Ensure every profile and settings surface works beautifully on phones.

#### 8.1 Responsive Profile
- Hero card stacks vertically on mobile (photo → name → stats → actions)
- Feed cards full-width with proper padding
- Sidebar sections accordion-collapse on mobile
- Touch-friendly buttons (min 44px tap targets)
- Swipe gestures for feed navigation (future)

#### 8.2 Responsive Settings
- Settings sidebar converts to horizontal tab bar on mobile
- Forms stack vertically, inputs full-width
- Toggle switches instead of checkboxes
- Bottom sheet modals for selections instead of dropdowns

#### 8.3 Performance
- Lazy-load profile feed (already infinite scroll)
- Image optimization (srcset for profile photos)
- Skeleton loaders for feed cards while loading
- Minimize CSS (remove Bootstrap 3 overrides, use modern CSS)

**Estimated effort**: 2-3 days

---

## Phase Summary & Priority

| Phase | Name | Effort | Priority | Status |
|-------|------|--------|----------|--------|
| **1** | Public Profile Redesign | 3-4 days | **P0 — Critical** | ✅ COMPLETED |
| **2** | Unified Settings Page | 3-4 days | **P0 — Critical** | ✅ COMPLETED |
| **3** | Notification Preferences | 2-3 days | **P1 — High** | ✅ COMPLETED (push + mute-all pending) |
| **4** | Privacy & Visibility Controls | 2-3 days | **P1 — High** | Not started |
| **5** | Wall Posts ("Ask {Name}") | 4-5 days | **P2 — Medium** | Not started |
| **6** | User Blocking | 3-4 days | **P2 — Medium** | Not started |
| **7** | Enhanced Profile Fields | 3-4 days | **P3 — Nice to have** | 🔄 Partial (Work Experience done) |
| **7.5** | Google Scholar Integration | 1.5 days | **P2 — Medium** | ✅ COMPLETED |
| **8** | Mobile Polish | 2-3 days | **P1 — High** | Not started |
| **9** | Profile Gamification | 6 days | **P0 — Critical** | Not started |

**Total estimated effort**: ~30-36 days

**Recommended execution order** (updated Mar 13, 2026):
1. ✅ Phase 1 + 2 + 3 + 7.5 (done)
2. **Phase 9 (Gamification)** — Profile Completeness + Badge + Achievements — foundation for engagement
3. **Phase 6 (Blocking)** — trust & safety prerequisite for wall posts
4. **Phase 5 (Wall Posts)** — with blocking in place, safe to add
5. **Phase 4 (Privacy)** + **Phase 8 (Mobile)** — can run in parallel

---

## Database Changes Summary

### New Tables

| Table | Phase | Entity |
|-------|-------|--------|
| `user_notification_preference` | 3 | `UserNotificationPreference` |
| `user_privacy_settings` | 4 | `UserPrivacySettings` |
| `wall_post` | 5 | `WallPost` |
| `wall_post_comment` | 5 | Reuse `ProfilePostComment` or new entity |
| `user_block` | 6 | `UserBlock` |
| `user_education` | 7 | `UserEducation` |
| `user_work_experience` | 2.6 | `UserWorkExperience` ✅ |
| `user_scholar_profile` | 7.5 | `UserScholarProfile` ✅ |
| `user_scholar_publication` | 7.5 | `UserScholarPublication` ✅ |

### Modified Tables

| Table | Change | Phase |
|-------|--------|-------|
| `fos_user` | Add `cover_image` column (nullable string) | 1 |
| `fos_user` | Legacy notification columns kept for backward compatibility (not removed yet) | 3 |
| `fos_user` | Add `orcid_id`, `languages_spoken` (json) | 7 |

### Routes to Deprecate / Redirect

| Old Route | Action | Phase |
|-----------|--------|-------|
| `/users/credit/{username}` | 301 redirect → `/settings/subscription` | 2 |
| `/users/subscribtion/{username}` | 301 redirect → `/settings/subscription` | 2 |
| `/users/playground/{username}` | 301 redirect → `/settings/subscription` | 2 |
| `/profile/image` | Move functionality into `/settings/profile` | 2 |
| `/profile/image/echosan` | Deprecate | 2 |

---

## Template Architecture

```
templates/
├── profile/                          # Phase 1 — Public profile
│   ├── index.html.twig               # Main profile page (hero + feed + sidebar)
│   ├── _hero_card.html.twig          # Profile hero partial
│   ├── _feed.html.twig               # Inline feed partial
│   ├── _sidebar.html.twig            # Academic info sidebar
│   ├── _wall_post_form.html.twig     # "Ask" form partial (Phase 5)
│   └── not_available.html.twig       # Blocked / private profile
│
├── settings/                         # Phase 2 — Settings
│   ├── layout.html.twig              # Settings shell with sidebar nav
│   ├── profile.html.twig             # Edit profile form
│   ├── account.html.twig             # Email, password, 2FA, delete
│   ├── privacy.html.twig             # Visibility controls + block list
│   ├── notifications.html.twig       # Per-event toggles
│   └── subscription.html.twig        # AI credits + legacy subscriptions
│
├── social/                           # Existing (reuse components)
│   ├── feed.html.twig                # Global feed (already done)
│   ├── post_show.html.twig           # Single post view (already done)
│   ├── followers.html.twig           # Followers list (already done)
│   └── following.html.twig           # Following list (already done)
```

---

## Design Principles

1. **Mobile-first**: Design for 375px width first, then scale up
2. **Arabic-first**: RTL layout is the default, LTR is the adaptation
3. **Progressive disclosure**: Show essential info first, expand on demand
4. **Social-first profile**: The profile IS the feed. Research papers are secondary metadata.
5. **Separation of concerns**: Public profile ≠ Settings. Visitors never see settings UI.
6. **Consistent card design**: Profile feed cards match `/feed` cards exactly — one design language
7. **Instant feedback**: Toggles save immediately, forms show loading states, toasts confirm actions
8. **Accessibility**: Semantic HTML, ARIA labels, keyboard navigation, sufficient contrast

---

## Execution Notes & Recommendations (Added Mar 9, 2026)

> Goal: keep shipping fast without breaking production. Build in small slices, measure impact, and keep rollback easy.

### 1) Release Gates Per Phase (Definition of Done)

Each phase should ship only when all three gates pass:

1. **Functional gate**
  - Core user journey works end-to-end
  - No blocking 500 errors on primary routes
2. **Quality gate**
  - Syntax/lint checks pass
  - Critical smoke tests pass (owner view + visitor view + API call)
3. **Impact gate**
  - At least one measurable KPI is tracked before/after rollout

Recommended per-phase KPI examples:
- Phase 3 (Notifications): toggle save success rate, opt-out rate per event, follow/comment notification delivery rate
- Phase 4 (Privacy): profile view success vs denied views, privacy setting adoption rate
- Phase 5 (Wall posts): wall-post creation rate, reply rate, unanswered ratio
- Phase 6 (Blocking): block/unblock completion rate, blocked-interaction prevention count

### 2) Feature Flags for Risky Surfaces

Ship behind flags, then enable gradually by cohort (% users or staff-only first):
- `feature.notifications.preferences`
- `feature.privacy.v2`
- `feature.wall_posts`
- `feature.user_blocking`
- `feature.recommendation.profile_boost`

Rollout sequence:
1. internal/staff users
2. 5% users
3. 25% users
4. 100% users

If error rate or latency spikes, disable flag immediately (no redeploy required).

### 3) Ranking Safety for "Visibility Incentives"

Use bounded boosts to avoid quality collapse or overexposure:
- Cap profile-completeness boost in recommendations/search to a small weight
- Keep relevance/freshness as dominant ranking signals
- Add fairness guardrail: max repeated exposure per author in a session window

Suggested safety checks:
- CTR and follow-conversion should improve without reducing content diversity
- No single account should dominate recommendation slots excessively

### 4) Notification Fatigue Controls

Before push notifications, add guardrails:
- Per-event cooldown windows (avoid repeated burst emails)
- Daily cap for low-priority notifications
- Automatic digest fallback for repetitive events
- Quiet-hours option for email/push (future)

### 5) Production Stability Checklist (Pre/Post Deploy)

Before deploy:
- Confirm migration is safe and reversible
- Confirm cache rebuild method is `rm -rf var/cache/prod` + `cache:warmup`
- Confirm worker/services healthy

After deploy:
- Check key routes (`/users/{username}`, `/settings/profile`, `/settings/notifications`)
- Check last 5–10 minutes of prod errors for `CRITICAL` spikes
- Verify one write path (save settings toggle) and one read path (page load)

### 6) Suggested Near-Term Order (Updated Mar 13, 2026)

Given current progress (Phases 1, 2, 3, 7.5 done):
1. **Profile Gamification** — Completeness Score + Badge + Achievements (foundation for engagement)
2. **Phase 6 (Blocking)** — trust & safety prerequisite
3. **Phase 5 (Wall posts)** — with blocking in place, safe to add
4. **Phase 4 (Privacy)** + **Phase 8 (Mobile polish)** — can run in parallel
5. Continue remaining Phase 7 enhancements (Education, ORCID)

This order:
- Builds engagement foundation first (gamification drives profile completion)
- Adds safety controls before social features (blocking before wall posts)
- Reduces moderation risk

---

### 7) Quick-Win Features to Add

These were identified during Mar 13 review as missing from original plan:

| Feature | Effort | Where to Add |
|---------|--------|--------------|
| WhatsApp/Twitter share buttons | 0.5 day | Profile hero, paper cards |
| ~~Profile view counter~~ | ~~1 day~~ | ✅ DONE — displayed in hero stats bar (Mar 24) |
| ~~"Active Researcher" badge (green dot)~~ | ~~0.5 day~~ | ✅ DONE — `isOnlineNow()` on User entity, green dot on feed sidebar (Mar 24) |

Total: ~2 days. Could ship alongside Profile Completeness in Week 1.

---

## Profile Engagement & Growth Strategy

> **Why this matters**: A profile that feels empty has no gravity — users visit once and forget. A profile that shows progress, rewards completion, and surfaces value becomes a reason to return, share, and invest. Every field a researcher fills makes the platform more useful for everyone.

### 1. Profile Completeness Score ✅ COMPLETED

**Status**: Fully implemented and deployed.

**Implementation:**
- **Service**: `src/Service/ProfileCompletionService.php` — calculates score, tier, next action
- **Twig Extension**: `src/Service/ProfileCompletionExtension.php` — `profile_completion()` and `profile_public_tier()` functions
- **Template**: `templates/Profile/show/_completion_banner.html.twig` — LinkedIn-style banner
- **Integration**: Included in `base.html.twig` — shows site-wide for logged-in users

**Scoring Weights (implemented):**
| Field | Weight |
|-------|--------|
| Joined | 5% (always complete) |
| Profile photo | 15% |
| Gender | 5% |
| Academic interests (3+) | 15% |
| Field of study | 10% |
| Study degree | 10% |
| Work / Position | 10% |
| Bio (20+ chars) | 10% |
| Following 3+ researchers | 10% |
| Work experience | 10% |

**Tiers (implemented):**
| Level | Score | Color |
|-------|-------|-------|
| مبتدئ / Beginner | 0-25% | Gray |
| نسبة الإكمال / Developing | 26-50% | Amber |
| متقدم / Established | 51-75% | Blue |
| قوي / Strong | 76-99% | Green |
| نجم / All-Star | 100% | Purple |

**Features:**
- Progress bar with tier color
- Next action suggestion with "+X%" bonus indicator
- Dismissable for 7 days (localStorage)
- 5-minute cache per user

**Concept**: A visible percentage score shown in the settings page and on the profile (to the owner only) that breaks down what's complete and what's missing.
  - "Complete your profile" CTA that links to `/settings/profile`
  - Disappears at 100% — replaced with a "✓ Profile complete" badge

**Implementation:**
- Service: `ProfileCompletenessService` with `calculateScore(User $user): array` returning `['score' => 65, 'missing' => ['work_experience', 'bio'], 'tips' => [...]]`
- No DB storage needed — compute on the fly (cheap, <10ms)
- Expose via Twig global or controller variable

### 2. "Profile Strength" Indicator on Public Profile ✅ COMPLETED (Mar 13, 2026)

**Status**: Implemented and deployed.

**Concept**: A subtle badge on the public profile that shows profile strength to visitors — incentivizing completion through social pressure.

**Tiers (Academic Progression theme):**
| Level | Score | Icon | Arabic | English | Color |
|-------|-------|------|--------|---------|-------|
| Beginner | 0-25% | — | مبتدئ | Beginner | Gray (no badge shown) |
| Developing | 26-50% | — | متطور | Developing | Amber (no badge shown) |
| Researcher | 51-75% | 📖 | باحث | Researcher | Blue |
| Scholar | 76-99% | 📚 | أكاديمي | Scholar | Green |
| Scientist | 100% | 🎓 | عالم | Scientist | Purple |

**Implementation:**
- Badge added to profile hero card (next to name)
- Only shown for profiles ≥51% complete (via existing `profile_public_tier()` function)
- Tooltip shows exact completion percentage
- Color-coded background with transparency

**Files modified:**
- `src/Service/ProfileCompletionService.php` — Updated TIERS constant with academic names + icons
- `templates/Profile/show/personal_info.html.twig` — Added badge HTML + CSS
- `translations/Social.ar.yml` — Added `tier_tooltip` key
- `translations/Social.en.yml` — Added `tier_tooltip` key

- Badge appears next to the name on profile hero card
- Tooltip on hover: "Distinguished Researcher — Profile 95% complete"
- **Strategic value**: visitors to a "Distinguished" profile trust the researcher more → more follows → more engagement

### 3. Smart Nudges & Contextual Prompts

**Concept**: Instead of nagging emails, show contextual prompts when the user is already engaged on the platform.

**Nudge Triggers:**
| Trigger | Nudge | Where |
|---------|-------|-------|
| User visits own profile, bio is empty | "Add a bio to tell other researchers who you are →" | Below hero card |
| User has 0 work experience | "Where do you work? Adding your position helps others find you →" | Profile sidebar |
| User has 0 posts, account >3 days old | "Share your first thought with the community →" | Feed page top |
| User searches for research but has no study field set | "Set your study field to get personalized recommendations →" | Search results page |
| User has no interests, visits feed | "Add your research interests to see a personalized feed →" | Feed empty state |
| User follows 5+ people but profile <50% | "You're active! Complete your profile so followers can learn about you →" | Settings page |

**Rules:**
- Each nudge shown max 3 times total, then dismissed permanently (track via cookie or DB flag)
- User can dismiss any nudge (× button) — never shows again
- Never show more than 1 nudge at a time
- Nudges have a friendly, encouraging tone — never guilt-tripping

### 4. Visibility Incentives (Algorithmic Rewards)

**Concept**: Users with richer profiles naturally surface more across the platform. Make this explicit.

**Benefits of a Complete Profile:**
- **Search ranking boost**: Researchers with profiles ≥80% appear higher in "Suggested Researchers" and search results
- **Feed priority**: Posts from users with complete profiles get slightly higher ranking in followers' feeds (small weight, not dominant)
- **Recommendation eligibility**: Only users with ≥60% profile + study field set appear in "Researchers you might want to follow" suggestions
- **Featured researcher**: Monthly "Featured Researcher" spotlight on homepage — only complete profiles eligible

**Messaging:**
- Settings page: "Complete profiles appear in more search results and recommendations"
- Profile strength tooltip: "Distinguished researchers are 3× more likely to be followed"

### 5. Milestone Celebrations & Achievements

**Concept**: Celebrate meaningful moments to create positive reinforcement loops.

**Milestones:**
| Achievement | Trigger | Reward |
|-------------|---------|--------|
| 🎉 Profile Complete | Reach 100% profile score | Confetti animation + "Profile Complete" badge |
| 📝 First Post | Publish first post | Toast: "Welcome to the community! Your voice matters." |
| 👥 First Follower | Get first follower | Notification: "Someone wants to hear from you!" |
| 🔥 5-Day Streak | Visit 5 consecutive days | Subtle flame icon on profile |
| 📚 Knowledge Sharer | Share 10+ research papers | "Knowledge Sharer" badge |
| 💬 Conversation Starter | Get 10+ comments on posts | "Conversation Starter" badge |
| 🌍 Global Researcher | Get followers from 3+ countries | "Global Researcher" badge |

**Display:**
- Badges shown on profile page in a small "Achievements" row below the bio
- Total count shown: "5 achievements earned"
- Clickable → expands to show all earned + locked (grayed) achievements
- **Not gamification for its own sake** — only reward behaviors that add genuine value to the platform

### 6. Weekly Progress Email

**Concept**: A short, motivating weekly email that shows researchers their impact and suggests next steps.

**Email Content:**
```
Subject: Your week on Shamra Academia

Hi {firstName},

This week:
- 📊 Your profile was viewed {viewCount} times
- 👥 You gained {newFollowers} new followers
- ❤️ Your posts received {totalLikes} likes

{if profile < 100%}
💡 Quick win: Add your {missingField} to reach {nextScore}% profile strength.
[Complete your profile →]
{/if}

{if hasNoRecentPost}
📝 It's been a while since your last post. Share what you're working on:
[Write a post →]
{/if}

Keep building your academic presence!
```

**Rules:**
- Only send if user had ≥1 profile view OR ≥1 interaction that week (don't email inactive users about nothing)
- Respects notification preferences (can opt out)
- Max 1 email per week, sent on Sunday morning (researcher-friendly timing)

### 7. Onboarding Checklist for New Users

**Concept**: First-time visitors to `/settings/profile` see a clean onboarding checklist instead of a wall of empty forms.

**Checklist Steps:**
1. ✅ Upload a profile photo
2. ✅ Write a short bio
3. ✅ Set your study degree and field
4. ✅ Add your current position
5. ✅ Add 3+ research interests
6. ✅ Follow 5 researchers
7. ✅ Share your first post

**UX:**
- Each completed step shows a green checkmark + celebration micro-animation
- Progress bar at top: "4 of 7 complete — Almost there!"
- After all 7 complete, checklist auto-dismisses with confetti and a "You're all set!" message
- Can be dismissed early with "Skip for now" — but gently resurfaces later
- Checklist state stored in a simple JSON column on User or in localStorage

### 8. Social Proof & Peer Comparison

**Concept**: People are motivated by what others around them are doing.

**Implementations:**
- **Profile page**: "Joined alongside 2,400 other researchers" (for new users)
- **Settings page**: "89% of researchers in your field have added a profile photo"
- **Work experience section**: "Most researchers add 2-3 positions. You have 0."
- **Feed empty state**: "Researchers who post weekly get 4× more followers"

**Rules:**
- Numbers must be real (queried from DB, cached hourly)
- Never fabricate or exaggerate
- Tone is informational, not pressuring

### Implementation Priority

| Feature | Effort | Impact | Priority | Status |
|---------|--------|--------|----------|--------|
| Profile Completeness Score | 1 day | **Very High** — foundation for everything else | **P0** | ✅ DONE |
| Onboarding Checklist | 1 day | **High** — reduces new-user drop-off | **P0** | Not started |
| Smart Nudges | 2 days | **High** — contextual, non-intrusive | **P1** | Not started |
| Visibility Incentives | 1 day | **High** — algorithmic motivation | **P1** | Not started |
| Profile Strength Badge | 0.5 day | **Medium** — social pressure | **P2** | ✅ DONE |
| Milestone Celebrations | 2 days | **Medium** — positive reinforcement | **P2** | Not started |
| Weekly Progress Email | 2 days | **Medium** — retention tool | **P2** | Not started |
| Social Proof Stats | 1 day | **Medium** — peer motivation | **P3** | Not started |

**Total estimated effort**: ~9 days remaining (Profile Completeness done)

**Key principle**: **Show value, don't demand effort.** Every prompt should answer "what's in it for me?" — more visibility, more followers, better recommendations, recognition.

---

## Prioritized Action Plan (Updated Mar 13, 2026)

> Review of all gamification/engagement features to identify highest-impact, lowest-effort wins.

### Current Progress

| Phase | Status |
|-------|--------|
| Phase 1-3 | ✅ Completed |
| Phase 7.5 (Google Scholar) | ✅ Completed |
| Profile Completeness Score | ✅ Completed |
| Profile Strength Badge | ✅ Completed |
| Phase 4 (Privacy) | ❌ Not started |
| Phase 5 (Wall Posts) | ❌ Not started |
| Phase 6 (Blocking) | ❌ Not started |
| Phase 7 (Education, ORCID) | 🔄 Partial (Work Experience done) |
| Phase 8 (Mobile Polish) | ❌ Not started |

### Recommended 2-Week Sprint (Updated)

| Week | Tasks | Effort | Impact |
|------|-------|--------|--------|
| **Week 1** | Onboarding Checklist + Share Buttons | 1.5 days | UX polish, viral mechanics (Profile Strength Badge done) |
| **Week 2** | Achievements System + Visibility Incentives | 3 days | Badges, algorithmic rewards |

**Total:** ~5 days of focused work (Profile Completeness already done).

### Missing Quick-Win Features

These are **not in the current plan** but have high ROI:

| Feature | Effort | Impact | Notes |
|---------|--------|--------|-------|
| **Share to WhatsApp/Twitter** | 0.5 day | **High** | Arabs use WhatsApp heavily — viral loop |
| ~~**Profile View Counter**~~ | ~~1 day~~ | ~~**High**~~ | ✅ **DONE** (Mar 24, 2026) — Views displayed in hero stats bar with eye icon. Uses existing `visitors` field on User entity. |
| ~~**Active Researcher Badge**~~ | ~~0.5 day~~ | ~~**Medium**~~ | ✅ **DONE** (Mar 24, 2026) — `User::isOnlineNow()` + green dot on feed sidebar. Uses `lastActiveAt` field + `UserActivitySubscriber`. |
| **Research Match Suggestions** | 3 days | **Very High** | "Researchers working on similar topics" — discovery |
| **Citation Alerts** (Scholar-powered) | 2 days | **Medium** | Notify when cited — requires Scholar expansion |

**Recommendation**: Add Share buttons to Week 2 sprint. ~~Profile View Counter~~ ✅ shipped Mar 24, 2026.

### Critical Dependency Warning ⚠️

**Phase 5 (Wall Posts) requires Phase 6 (Blocking) first.**

Without blocking:
- Harassment risk from unwanted questions
- No way to remove abusive wall posts
- Moderation nightmare

**Corrected execution order:**
1. ✅ Done: Phases 1, 2, 3, 7.5
2. **Next**: Profile Completeness + Badge + Achievements (gamification foundation)
3. **Then**: Phase 6 (Blocking) — trust & safety prerequisite
4. **Then**: Phase 5 (Wall Posts) — social interaction with safety controls
5. **Parallel**: Phase 4 (Privacy) + Phase 8 (Mobile Polish)

### Arabic-Specific Engagement Opportunities

| Feature | Notes |
|---------|-------|
| **WhatsApp Share** | Primary sharing channel for Arab users — button on profile + papers |
| **Arabic badges/achievements** | Use culturally relevant metaphors (🏅 وسام, 🌟 نجم) |
| **Ramadan activity boost** | Seasonal gamification during Islamic calendar events |
| **University affiliation badges** | Partner with Arab universities for verified badges |

---

## Out of Scope (Future Consideration)

- Cover photo upload (use gradient initially)
- Profile verification badge (✓) for institutional accounts
- Profile analytics (who viewed your profile)
- Direct messaging between users
- Portfolio / project showcases
- Research collaboration matching
- Two-factor authentication (Phase 2 shows placeholder)
- Profile export (download your data — GDPR)

---

## Decisions Log

| # | Decision | Rationale | Date |
|---|----------|-----------|------|
| 1 | Separate public profile from settings into distinct pages | Visitors should never see settings UI; owner needs clean editing experience | 2026-03-05 |
| 2 | Remove Credit tab entirely, merge Playground + Subscription | Credits are legacy, nobody uses them. One "Subscription" section is clearer. | 2026-03-05 |
| 3 | Wall posts as new entity (not extending ProfilePost) | Different semantics: wall posts have `targetUser`, different feed display, answered/unanswered state | 2026-03-05 |
| 4 | Notification preferences as separate entity (not columns on User) | Cleaner separation, easier to add new event types, avoids bloating 30+ columns onto fos_user | 2026-03-05 |
| 5 | Privacy settings as separate entity | Same rationale as notification preferences — clean separation | 2026-03-05 |
| 6 | Mutual hide on block (both users hidden from each other) | Prevents awkward "I can see them but they can't see me" asymmetry | 2026-03-05 |
| 7 | Phase 1+2 can be built in parallel | Public profile has no dependency on settings — they share API endpoints but different templates | 2026-03-05 |
| 8 | Pull work experience into Phase 2 (from Phase 7) | Users need structured experience now, not later. Quick win that makes profiles feel professional. | 2026-03-05 |
| 9 | Make study field searchable + allow user-created fields | 400+ fields in DB is too many for a dropdown. User-created fields ensure no one is left out. | 2026-03-05 |
| 10 | Profile engagement via value, not nagging | Show users what they gain (visibility, followers, recommendations) rather than guilting them into filling fields. | 2026-03-05 |
| 11 | Completeness score computed on-the-fly, not stored | Cheap to calculate (<10ms), avoids stale data, no migration needed. | 2026-03-05 |
| 12 | Blocking must ship before Wall Posts | Wall posts without blocking = moderation nightmare + harassment risk. Safety controls first. | 2026-03-13 |
| 13 | Add WhatsApp share button | Arabs primarily share via WhatsApp — critical for viral growth. Quick win (0.5 day). | 2026-03-13 |
| 14 | Profile Completeness is foundation for all gamification | Badge, nudges, visibility incentives all depend on score. Build first. | 2026-03-13 |
| 15 | Profile view counter adds motivation | "12 people viewed your profile" creates return visits without being invasive. | 2026-03-13 |
