# Plan: Reading Lists — Shareable Academic Paper Collections (Goodreads-style)

## TL;DR
Add a Goodreads-style reading list feature: users create named collections of papers, track reading status (to-read → reading → read), rate papers, and share collections publicly or with collaborators. Public lists are discoverable via user profiles and topic pages. This builds on the existing `UsersFavouriteResearches` system and Reference Library infrastructure.

---

## Implementation Status

| Phase | Status | Notes |
|-------|--------|-------|
| Phase 1: Core Infrastructure | ✅ Complete | Entities, service, controller, migration |
| Phase 2: Frontend | ✅ Complete | Vue SPA, translations, header nav |
| Phase 3: Paper Page Integration | ✅ Complete | Quick action buttons on all paper pages |
| Phase 4: Sharing & Collaboration | 🔄 In progress | Visibility done, share links & invites next |
| Phase 5: Discovery | ✅ Complete | Discover page, user profile integration |
| Phase 6: Migration & Polish | ⏳ Not started | Migrate favorites, stats dashboard |

**Last Updated:** March 18, 2026

### Files Created

**Entities:**
- `src/Entity/ReadingList.php`
- `src/Entity/ReadingListItem.php`
- `src/Entity/ReadingListMember.php`
- `src/Entity/ReadingListFollow.php`

**Repositories:**
- `src/Repository/ReadingListRepository.php`
- `src/Repository/ReadingListItemRepository.php`
- `src/Repository/ReadingListMemberRepository.php`
- `src/Repository/ReadingListFollowRepository.php`

**Service & Controller:**
- `src/Service/ReadingListService.php`
- `src/Controller/ReadingListController.php`

**Templates:**
- `templates/reading_list/index.html.twig` (Vue SPA)
- `templates/reading_list/show.html.twig` (public list view)
- `templates/reading_list/discover.html.twig` (discover public lists)
- `src/syndex/AcademicBundle/Resources/views/Research/_reading_list_buttons.html.twig` (quick action partial)

**Translations:**
- `translations/ReadingList.en.yml`
- `translations/ReadingList.ar.yml`

**Migration:**
- `migrations/Version20260316100000.php`
- `migrations/Version20260316110000.php` (add cached_slug column)

**Modified:**
- `templates/header.html.twig` (added nav link)
- `translations/UserBundle.en.yml`, `UserBundle.ar.yml` (header labels)
- `src/syndex/AcademicBundle/Resources/views/Research/show.html.twig` (include buttons)
- `src/syndex/AcademicBundle/Resources/views/Research/show_elastic.html.twig` (include buttons)
- `src/Controller/ProfileController.php` (pass public reading lists to profile)
- `templates/Profile/show/personal_info.html.twig` (display public lists in sidebar)
- `translations/Social.en.yml`, `Social.ar.yml` (profile.reading_lists translation)

### Bug Fixes (March 16, 2026)

1. **Twig namespace typo** — Fixed `@Academic` → `@syndexAcademic` in show_elastic.html.twig (caused ES papers to redirect to homepage)
2. **Clickable paper titles** — Added `cachedSlug` field to store paper slugs; papers in reading lists are now clickable links using `shamra_academia_research_show` route
3. **Modal flash on load** — Added `v-cloak` directive to prevent create modal from flashing before Vue.js initializes

---

## Problem Statement

Currently, users can:
- **Favorite papers** on Shamra (flat list, no organization, no status tracking)
- **Upload PDFs** to Reference Library (personal storage, no sharing)

Missing capabilities:
- No way to track reading progress (what I've read vs. plan to read)
- No way to organize papers into themed collections
- No way to share curated lists publicly or with collaborators
- No discovery of what other researchers are reading
- No social proof / reading goals / streaks

---

## Feature Overview

### Core Concepts

| Concept | Description |
|---------|-------------|
| **Reading List** | A named collection of papers (e.g., "NLP Fundamentals", "PhD Thesis Sources") |
| **Item** | A paper in a list, with status (to-read/reading/read), rating, notes, date added |
| **Visibility** | Private (only me), Team (invited collaborators), Public (anyone with link + discoverable) |
| **Default Lists** | Every user gets 3 auto-created lists: "Want to Read", "Currently Reading", "Read" |
| **Custom Lists** | Users can create unlimited themed lists |

### Reading Status Flow

```
┌──────────────┐    ┌──────────────────┐    ┌──────────┐
│  TO READ 📚  │ ─→ │  READING 📖      │ ─→ │  READ ✅ │
│  (Backlog)   │    │  (In Progress)   │    │  (Done)  │
└──────────────┘    └──────────────────┘    └──────────┘
                           │
                           ↓
                    Progress: 45/120 pages
                    Started: March 10, 2026
```

---

## Data Model

### New Entities

#### 1. `ReadingList` (table: `reading_list`)

```php
#[ORM\Entity(repositoryClass: ReadingListRepository::class)]
#[ORM\Index(columns: ['user_id', 'visibility'])]
#[ORM\Index(columns: ['slug'])]
class ReadingList
{
    #[ORM\Id]
    #[ORM\GeneratedValue]
    #[ORM\Column]
    private ?int $id = null;

    #[ORM\ManyToOne(targetEntity: User::class)]
    #[ORM\JoinColumn(nullable: false, onDelete: 'CASCADE')]
    private User $owner;

    #[ORM\Column(length: 255)]
    private string $name;  // "NLP Fundamentals"

    #[ORM\Column(length: 255, unique: true)]
    private string $slug;  // "nlp-fundamentals-abc123"

    #[ORM\Column(type: 'text', nullable: true)]
    private ?string $description = null;

    #[ORM\Column(length: 20)]
    private string $visibility = 'private';  // private, team, public

    #[ORM\Column(length: 20)]
    private string $listType = 'custom';  // custom, want_to_read, reading, read

    #[ORM\Column(type: 'string', length: 50, nullable: true)]
    private ?string $coverColor = null;  // Hex color for list card

    #[ORM\Column]
    private \DateTimeImmutable $createdAt;

    #[ORM\Column]
    private \DateTimeImmutable $updatedAt;

    #[ORM\Column(nullable: true)]
    private ?\DateTimeImmutable $deletedAt = null;

    #[ORM\OneToMany(mappedBy: 'list', targetEntity: ReadingListItem::class, orphanRemoval: true)]
    private Collection $items;

    #[ORM\OneToMany(mappedBy: 'list', targetEntity: ReadingListMember::class, orphanRemoval: true)]
    private Collection $members;

    // Cached counts (updated on item add/remove)
    #[ORM\Column(options: ['default' => 0])]
    private int $itemCount = 0;

    #[ORM\Column(options: ['default' => 0])]
    private int $followerCount = 0;
}
```

#### 2. `ReadingListItem` (table: `reading_list_item`)

```php
#[ORM\Entity(repositoryClass: ReadingListItemRepository::class)]
#[ORM\UniqueConstraint(columns: ['list_id', 'research_id', 'research_type'])]
#[ORM\Index(columns: ['reading_status'])]
class ReadingListItem
{
    #[ORM\Id]
    #[ORM\GeneratedValue]
    #[ORM\Column]
    private ?int $id = null;

    #[ORM\ManyToOne(targetEntity: ReadingList::class, inversedBy: 'items')]
    #[ORM\JoinColumn(nullable: false, onDelete: 'CASCADE')]
    private ReadingList $list;

    // Polymorphic reference to paper (Research, EnglishResearch, ES-only, or UserReference)
    #[ORM\Column(length: 20)]
    private string $researchType;  // 'arabic', 'english', 'elastic', 'reference'

    #[ORM\Column]
    private int $researchId;

    // For ES-only papers, cache essential metadata
    #[ORM\Column(length: 500, nullable: true)]
    private ?string $cachedTitle = null;

    #[ORM\Column(type: 'text', nullable: true)]
    private ?string $cachedAuthors = null;

    #[ORM\Column(nullable: true)]
    private ?int $cachedYear = null;

    // Reading tracking
    #[ORM\Column(length: 20)]
    private string $readingStatus = 'to_read';  // to_read, reading, read

    #[ORM\Column(nullable: true)]
    private ?int $progress = null;  // 0-100 percentage or page number

    #[ORM\Column(nullable: true)]
    private ?int $totalPages = null;

    #[ORM\Column(nullable: true)]
    private ?\DateTimeImmutable $startedAt = null;

    #[ORM\Column(nullable: true)]
    private ?\DateTimeImmutable $finishedAt = null;

    // User interaction
    #[ORM\Column(nullable: true)]
    private ?int $rating = null;  // 1-5 stars

    #[ORM\Column(type: 'text', nullable: true)]
    private ?string $notes = null;  // Personal notes (private even on public lists)

    #[ORM\Column(type: 'text', nullable: true)]
    private ?string $review = null;  // Public review (visible on public lists)

    // Metadata
    #[ORM\ManyToOne(targetEntity: User::class)]
    #[ORM\JoinColumn(nullable: false)]
    private User $addedBy;

    #[ORM\Column]
    private \DateTimeImmutable $addedAt;

    #[ORM\Column]
    private int $sortOrder = 0;  // Manual ordering within list
}
```

#### 3. `ReadingListMember` (table: `reading_list_member`)

```php
#[ORM\Entity(repositoryClass: ReadingListMemberRepository::class)]
#[ORM\UniqueConstraint(columns: ['list_id', 'user_id'])]
class ReadingListMember
{
    #[ORM\Id]
    #[ORM\GeneratedValue]
    #[ORM\Column]
    private ?int $id = null;

    #[ORM\ManyToOne(targetEntity: ReadingList::class, inversedBy: 'members')]
    #[ORM\JoinColumn(nullable: false, onDelete: 'CASCADE')]
    private ReadingList $list;

    #[ORM\ManyToOne(targetEntity: User::class)]
    #[ORM\JoinColumn(nullable: false, onDelete: 'CASCADE')]
    private User $user;

    #[ORM\Column(length: 20)]
    private string $role = 'viewer';  // owner, editor, viewer

    // For invitation flow
    #[ORM\Column(length: 255, nullable: true)]
    private ?string $inviteEmail = null;  // If invited by email before registration

    #[ORM\Column(length: 50, nullable: true)]
    private ?string $inviteToken = null;

    #[ORM\Column(length: 20)]
    private string $status = 'active';  // pending, active, declined

    #[ORM\Column]
    private \DateTimeImmutable $createdAt;

    #[ORM\Column(nullable: true)]
    private ?\DateTimeImmutable $acceptedAt = null;
}
```

#### 4. `ReadingListFollow` (table: `reading_list_follow`)

```php
#[ORM\Entity]
#[ORM\UniqueConstraint(columns: ['list_id', 'user_id'])]
class ReadingListFollow
{
    #[ORM\Id]
    #[ORM\GeneratedValue]
    #[ORM\Column]
    private ?int $id = null;

    #[ORM\ManyToOne(targetEntity: ReadingList::class)]
    #[ORM\JoinColumn(nullable: false, onDelete: 'CASCADE')]
    private ReadingList $list;

    #[ORM\ManyToOne(targetEntity: User::class)]
    #[ORM\JoinColumn(nullable: false, onDelete: 'CASCADE')]
    private User $user;

    #[ORM\Column]
    private \DateTimeImmutable $followedAt;

    #[ORM\Column]
    private bool $notifyOnUpdate = true;  // Get notified when new items added
}
```

### Migration

```php
// Version20260315120000.php
public function up(Schema $schema): void
{
    $this->addSql('
        CREATE TABLE reading_list (
            id INT AUTO_INCREMENT NOT NULL,
            owner_id INT NOT NULL,
            name VARCHAR(255) NOT NULL,
            slug VARCHAR(255) NOT NULL,
            description LONGTEXT DEFAULT NULL,
            visibility VARCHAR(20) NOT NULL DEFAULT "private",
            list_type VARCHAR(20) NOT NULL DEFAULT "custom",
            cover_color VARCHAR(50) DEFAULT NULL,
            item_count INT NOT NULL DEFAULT 0,
            follower_count INT NOT NULL DEFAULT 0,
            created_at DATETIME NOT NULL COMMENT "(DC2Type:datetime_immutable)",
            updated_at DATETIME NOT NULL COMMENT "(DC2Type:datetime_immutable)",
            deleted_at DATETIME DEFAULT NULL COMMENT "(DC2Type:datetime_immutable)",
            UNIQUE INDEX UNIQ_CC844E76989D9B62 (slug),
            INDEX IDX_CC844E767E3C61F9 (owner_id),
            INDEX idx_reading_list_visibility (owner_id, visibility),
            PRIMARY KEY(id),
            CONSTRAINT FK_reading_list_owner FOREIGN KEY (owner_id) REFERENCES fos_user (id) ON DELETE CASCADE
        ) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci ENGINE = InnoDB
    ');

    $this->addSql('
        CREATE TABLE reading_list_item (
            id INT AUTO_INCREMENT NOT NULL,
            list_id INT NOT NULL,
            research_type VARCHAR(20) NOT NULL,
            research_id INT NOT NULL,
            cached_title VARCHAR(500) DEFAULT NULL,
            cached_authors LONGTEXT DEFAULT NULL,
            cached_year INT DEFAULT NULL,
            reading_status VARCHAR(20) NOT NULL DEFAULT "to_read",
            progress INT DEFAULT NULL,
            total_pages INT DEFAULT NULL,
            started_at DATETIME DEFAULT NULL COMMENT "(DC2Type:datetime_immutable)",
            finished_at DATETIME DEFAULT NULL COMMENT "(DC2Type:datetime_immutable)",
            rating SMALLINT DEFAULT NULL,
            notes LONGTEXT DEFAULT NULL,
            review LONGTEXT DEFAULT NULL,
            added_by_id INT NOT NULL,
            added_at DATETIME NOT NULL COMMENT "(DC2Type:datetime_immutable)",
            sort_order INT NOT NULL DEFAULT 0,
            INDEX IDX_item_list (list_id),
            INDEX idx_reading_status (reading_status),
            UNIQUE INDEX uniq_list_research (list_id, research_id, research_type),
            PRIMARY KEY(id),
            CONSTRAINT FK_item_list FOREIGN KEY (list_id) REFERENCES reading_list (id) ON DELETE CASCADE,
            CONSTRAINT FK_item_added_by FOREIGN KEY (added_by_id) REFERENCES fos_user (id)
        ) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci ENGINE = InnoDB
    ');

    $this->addSql('
        CREATE TABLE reading_list_member (
            id INT AUTO_INCREMENT NOT NULL,
            list_id INT NOT NULL,
            user_id INT DEFAULT NULL,
            role VARCHAR(20) NOT NULL DEFAULT "viewer",
            invite_email VARCHAR(255) DEFAULT NULL,
            invite_token VARCHAR(50) DEFAULT NULL,
            status VARCHAR(20) NOT NULL DEFAULT "pending",
            created_at DATETIME NOT NULL COMMENT "(DC2Type:datetime_immutable)",
            accepted_at DATETIME DEFAULT NULL COMMENT "(DC2Type:datetime_immutable)",
            INDEX IDX_member_list (list_id),
            INDEX IDX_member_user (user_id),
            UNIQUE INDEX uniq_list_user (list_id, user_id),
            PRIMARY KEY(id),
            CONSTRAINT FK_member_list FOREIGN KEY (list_id) REFERENCES reading_list (id) ON DELETE CASCADE,
            CONSTRAINT FK_member_user FOREIGN KEY (user_id) REFERENCES fos_user (id) ON DELETE CASCADE
        ) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci ENGINE = InnoDB
    ');

    $this->addSql('
        CREATE TABLE reading_list_follow (
            id INT AUTO_INCREMENT NOT NULL,
            list_id INT NOT NULL,
            user_id INT NOT NULL,
            followed_at DATETIME NOT NULL COMMENT "(DC2Type:datetime_immutable)",
            notify_on_update TINYINT(1) NOT NULL DEFAULT 1,
            INDEX IDX_follow_list (list_id),
            INDEX IDX_follow_user (user_id),
            UNIQUE INDEX uniq_follow (list_id, user_id),
            PRIMARY KEY(id),
            CONSTRAINT FK_follow_list FOREIGN KEY (list_id) REFERENCES reading_list (id) ON DELETE CASCADE,
            CONSTRAINT FK_follow_user FOREIGN KEY (user_id) REFERENCES fos_user (id) ON DELETE CASCADE
        ) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci ENGINE = InnoDB
    ');
}
```

---

## User Experience

### 1. Default Lists (Auto-created on first use)

Every user gets 3 system lists that mirror Goodreads shelves:

| List | Icon | Purpose |
|------|------|---------|
| **Want to Read** | 📚 | Papers saved for later |
| **Currently Reading** | 📖 | Papers actively reading |
| **Read** | ✅ | Completed papers |

These are `listType: want_to_read|reading|read` and cannot be deleted (only hidden).

### 2. Quick Actions on Paper Pages

On every research page (`show.html.twig`, `show_elastic.html.twig`), add:

```
┌─────────────────────────────────────────────────────────┐
│  📚 Want to Read  │  📖 Reading  │  ✅ Read  │  + List  │
└─────────────────────────────────────────────────────────┘
```

- Click toggles status (like Goodreads "Want to Read" button)
- "+ List" opens modal to add to custom lists
- Already-added status shown with checkmark

### 3. Reading List Page (`/lists` or `/reading-lists`)

```
┌────────────────────────────────────────────────────────────────┐
│  My Reading Lists                              [+ Create List] │
├────────────────────────────────────────────────────────────────┤
│                                                                │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐         │
│  │ 📚 Want to   │  │ 📖 Currently │  │ ✅ Read      │         │
│  │    Read      │  │    Reading   │  │              │         │
│  │              │  │              │  │              │         │
│  │   47 papers  │  │   3 papers   │  │  156 papers  │         │
│  └──────────────┘  └──────────────┘  └──────────────┘         │
│                                                                │
│  Custom Lists                                                  │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐         │
│  │ 🔬 PhD       │  │ 🌐 NLP       │  │ 🤖 LLM       │         │
│  │    Sources   │  │    Papers    │  │    Safety    │         │
│  │   Public 🔗  │  │   Team 👥    │  │   Private 🔒 │         │
│  │   23 papers  │  │   12 papers  │  │   8 papers   │         │
│  │   45 follows │  │   3 members  │  │              │         │
│  └──────────────┘  └──────────────┘  └──────────────┘         │
│                                                                │
└────────────────────────────────────────────────────────────────┘
```

### 4. Single List View (`/lists/{slug}`)

```
┌────────────────────────────────────────────────────────────────┐
│  NLP Fundamentals                                    [Share 🔗]│
│  by @username · 23 papers · 45 followers                       │
│  "Essential NLP papers for getting started in the field"       │
├────────────────────────────────────────────────────────────────┤
│  Filter: [All] [To Read] [Reading] [Read]    Sort: [Date ▼]   │
├────────────────────────────────────────────────────────────────┤
│                                                                │
│  ┌─────────────────────────────────────────────────────────┐  │
│  │ ⭐⭐⭐⭐⭐  Attention Is All You Need                    │  │
│  │ Vaswani et al. · 2017 · ✅ Read                         │  │
│  │ "The transformer paper that changed everything..."       │  │
│  │ [View] [Remove] [Move to...]                             │  │
│  └─────────────────────────────────────────────────────────┘  │
│                                                                │
│  ┌─────────────────────────────────────────────────────────┐  │
│  │ ☆☆☆☆☆  BERT: Pre-training Deep Bidirectional...       │  │
│  │ Devlin et al. · 2018 · 📖 Reading (45%)                 │  │
│  │ Started Mar 10 · Progress: page 6/14                     │  │
│  │ [View] [Update Progress] [Mark Read]                     │  │
│  └─────────────────────────────────────────────────────────┘  │
│                                                                │
└────────────────────────────────────────────────────────────────┘
```

### 5. Public Profile Section (`/u/{username}`)

```
┌────────────────────────────────────────────────────────────────┐
│  @username's Reading Lists                                     │
├────────────────────────────────────────────────────────────────┤
│                                                                │
│  📊 Reading Stats                                              │
│  ┌─────────────────────────────────────────────────────────┐  │
│  │  156 papers read  ·  3 currently reading  ·  47 to read │  │
│  │  Average: 12 papers/month  ·  🔥 Reading streak: 5 days │  │
│  └─────────────────────────────────────────────────────────┘  │
│                                                                │
│  Public Lists                                                  │
│  • NLP Fundamentals (23 papers) — 45 followers                 │
│  • Machine Translation Classics (15 papers) — 12 followers    │
│  • Arabic NLP Resources (31 papers) — 89 followers            │
│                                                                │
└────────────────────────────────────────────────────────────────┘
```

### 6. Share Modal

```
┌────────────────────────────────────────────────────────────────┐
│  Share "NLP Fundamentals"                                   ✕  │
├────────────────────────────────────────────────────────────────┤
│                                                                │
│  Visibility                                                    │
│  ○ Private — Only you can see this list                       │
│  ○ Team — Only invited members can see                        │
│  ● Public — Anyone with link, discoverable on your profile    │
│                                                                │
│  ─────────────────────────────────────────────────────────    │
│                                                                │
│  Share Link                                                    │
│  ┌──────────────────────────────────────────────────┐ [Copy]  │
│  │ https://shamra-academia.com/lists/nlp-fund-abc12 │         │
│  └──────────────────────────────────────────────────┘         │
│                                                                │
│  ─────────────────────────────────────────────────────────    │
│                                                                │
│  Invite Collaborators (Team visibility)                        │
│  ┌──────────────────────────────────────────────────┐         │
│  │ Enter email addresses...                          │ [Invite]│
│  └──────────────────────────────────────────────────┘         │
│                                                                │
│  Current Members:                                              │
│  • @you (Owner)                                                │
│  • @colleague (Editor) [Remove]                               │
│  • invited@email.com (Pending) [Resend] [Cancel]              │
│                                                                │
└────────────────────────────────────────────────────────────────┘
```

---

## API Endpoints

### Reading Lists

| Method | Endpoint | Description |
|--------|----------|-------------|
| GET | `/api/reading-lists` | Get user's lists |
| POST | `/api/reading-lists` | Create new list |
| GET | `/api/reading-lists/{slug}` | Get list details + items |
| PATCH | `/api/reading-lists/{slug}` | Update list metadata |
| DELETE | `/api/reading-lists/{slug}` | Delete list (soft) |

### List Items

| Method | Endpoint | Description |
|--------|----------|-------------|
| POST | `/api/reading-lists/{slug}/items` | Add paper to list |
| PATCH | `/api/reading-lists/{slug}/items/{id}` | Update item (status, rating, notes) |
| DELETE | `/api/reading-lists/{slug}/items/{id}` | Remove paper from list |
| POST | `/api/reading-lists/{slug}/items/reorder` | Reorder items |

### Quick Actions (for paper pages)

| Method | Endpoint | Description |
|--------|----------|-------------|
| GET | `/api/paper-status/{type}/{id}` | Get paper's status across all lists |
| POST | `/api/paper-status/{type}/{id}` | Quick add to default list (to_read/reading/read) |

### Sharing & Collaboration

| Method | Endpoint | Description |
|--------|----------|-------------|
| POST | `/api/reading-lists/{slug}/invite` | Invite collaborator by email |
| POST | `/api/reading-lists/{slug}/invite/{token}/accept` | Accept invitation |
| DELETE | `/api/reading-lists/{slug}/members/{userId}` | Remove member |
| POST | `/api/reading-lists/{slug}/follow` | Follow public list |
| DELETE | `/api/reading-lists/{slug}/follow` | Unfollow list |

### Discovery

| Method | Endpoint | Description |
|--------|----------|-------------|
| GET | `/api/reading-lists/discover` | Popular/trending public lists |
| GET | `/api/reading-lists/user/{username}` | User's public lists |
| GET | `/api/reading-lists/following` | Lists the current user follows |

---

## Controller Structure

```php
// src/Controller/ReadingListController.php
#[Route('/lists', name: 'reading_list_')]
class ReadingListController extends AbstractController
{
    #[Route('', name: 'index')]
    public function index(): Response
    {
        // Vue.js SPA entry point (like /myreferences)
    }

    #[Route('/{slug}', name: 'show')]
    public function show(string $slug): Response
    {
        // Public list view (SSR for SEO on public lists)
    }
}

// src/Controller/Api/ReadingListApiController.php
#[Route('/api/reading-lists', name: 'api_reading_list_')]
class ReadingListApiController extends AbstractController
{
    // All API endpoints for Vue.js frontend
}
```

---

## Service Layer

```php
// src/Service/ReadingListService.php
class ReadingListService
{
    public function createDefaultLists(User $user): void;
    public function createList(User $user, string $name, string $visibility): ReadingList;
    public function addItem(ReadingList $list, string $type, int $id, User $addedBy): ReadingListItem;
    public function updateItemStatus(ReadingListItem $item, string $status, ?int $progress = null): void;
    public function generateSlug(string $name): string;
    public function canUserAccess(ReadingList $list, ?User $user): bool;
    public function canUserEdit(ReadingList $list, ?User $user): bool;
    public function getPopularLists(int $limit = 10): array;
    public function getUserStats(User $user): array;
}

// src/Service/ReadingListInvitationService.php
class ReadingListInvitationService
{
    public function invite(ReadingList $list, string $email, string $role): ReadingListMember;
    public function acceptInvitation(string $token, User $user): ReadingListMember;
    public function sendInvitationEmail(ReadingListMember $member): void;
}
```

---

## Integration Points

### 1. Paper Pages (Existing)

Add reading list buttons to:
- `templates/AcademicBundle/show.html.twig` (Arabic papers)
- `templates/AcademicBundle/show_elastic.html.twig` (English/ES papers)
- `templates/AcademicBundle/show_english.html.twig` (English MySQL papers)

### 2. Reference Library

Link to UserReference:
- "Add to Reading List" button on each reference
- Sync status: if reference is in a list, show its status

### 3. User Profile (Future)

Add "Reading Lists" tab to user profile page with:
- Public lists
- Reading stats
- Activity feed: "X finished reading Y"

### 4. Gamification (Future)

Award points for:
- Creating a public list: 10 pts
- Adding 10 papers to a list: 5 pts
- Marking a paper as read: 2 pts
- Getting 10 followers on a list: 20 pts

### 5. Notifications (Future)

Notify followers when:
- New paper added to followed list
- List owner shares a new list

---

## Migration from Existing Favorites

Migrate `UsersFavouriteResearches` → default "Want to Read" list:

```php
// One-time migration command
// bin/console app:migrate-favorites-to-reading-lists

foreach ($favoriteResearchesRepo->findAll() as $fav) {
    if ($fav->getCancelled()) continue;
    
    $list = $this->getOrCreateDefaultList($fav->getUser(), 'want_to_read');
    
    $item = new ReadingListItem();
    $item->setList($list);
    $item->setResearchType($fav->getEnglishResearch() ? 'english' : 'arabic');
    $item->setResearchId($fav->getResearch()?->getId() ?? $fav->getEnglishResearch()->getId());
    $item->setReadingStatus('to_read');
    $item->setAddedBy($fav->getUser());
    $item->setAddedAt($fav->getAddedAt());
    
    $em->persist($item);
}
```

---

## Implementation Phases

### Phase 1: Core Infrastructure (3 days) ✅ COMPLETED
- [x] Create entities + migration (`ReadingList`, `ReadingListItem`, `ReadingListMember`, `ReadingListFollow`)
- [x] Create `ReadingListService` with core CRUD
- [x] Create API endpoints for list management (15+ routes in `ReadingListController`)
- [x] Default list creation on user first access

### Phase 2: Frontend — List Management (3 days) ✅ COMPLETED
- [x] Vue.js SPA at `/reading-lists` (reuse myreferences patterns)
- [x] Create/edit list modal
- [x] List view with items
- [x] Item status updates
- [x] Translations (EN/AR) in `ReadingList.en.yml`, `ReadingList.ar.yml`
- [x] Header navigation integration

### Phase 3: Paper Page Integration (2 days) ✅ COMPLETED
- [x] Quick action buttons on paper pages (`_reading_list_buttons.html.twig` partial)
- [x] "Add to list" dropdown
- [x] Integrated into `show.html.twig` (Arabic/English MySQL papers)
- [x] Integrated into `show_elastic.html.twig` (ES-only papers)
- [ ] Status indicator on paper cards in search results (deferred)

### Phase 4: Sharing & Collaboration (3 days)
- [x] Visibility settings (create modal + edit modal with radio buttons)
- [ ] Share link generation
- [ ] Invitation flow + email
- [ ] Member management UI

### Phase 5: Discovery & Public Lists (2 days)
- [x] Public list SSR pages (SEO)
- [x] Discover page with popular lists (`/reading-lists/discover`)
- [x] User profile integration (public lists in sidebar)
- [ ] Follow functionality

### Phase 6: Migration & Polish (1 day)
- [ ] Migrate existing favorites
- [ ] Reading stats dashboard
- [ ] Mobile responsiveness

**Total Estimate: ~2 weeks**

---

## Success Metrics

| Metric | Target (3 months) |
|--------|-------------------|
| Users with 1+ list | 30% of active users |
| Papers added to lists | 10,000 |
| Public lists created | 500 |
| Average list size | 15 papers |
| List follows | 2,000 |
| Papers marked as "read" | 5,000 |

---

## Future Enhancements

1. **Reading challenges**: "Read 50 papers in 2026"
2. **List templates**: Pre-populated lists for common topics ("Getting Started with NLP")
3. **Import from Zotero/Mendeley**: Import existing libraries as reading lists
4. **Reading groups**: Multiple users reading same list together with discussions
5. **Recommendations**: "Based on your reading lists, you might like..."
6. **Export**: Export list as BibTeX, RIS, CSV
7. **Annotations sync**: Link highlights/notes from Reference Library to reading list items
