> ## Documentation Index
> Fetch the complete documentation index at: https://devperez08-platform-list-anime-54.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Library Management

> Manage your personal anime collection with EpiNeko's comprehensive library system

## Overview

EpiNeko's library management system allows users to organize their anime collection across different viewing statuses. The library is built on top of Supabase with row-level security, ensuring each user's data is private and secure.

<CardGroup cols={2}>
  <Card title="Add to Library" icon="plus">
    Save anime to your collection with a single click
  </Card>

  <Card title="Update Status" icon="arrows-rotate">
    Change viewing status as you progress through series
  </Card>

  <Card title="Track Progress" icon="chart-line">
    Monitor episodes watched and completion percentage
  </Card>

  <Card title="Remove Items" icon="trash">
    Clean up your library by removing unwanted entries
  </Card>
</CardGroup>

## Library Item Structure

Each item in your library contains comprehensive information about the anime and your viewing progress:

```typescript theme={null}
export interface LibraryItem {
  id?: string;                    // Unique identifier (UUID)
  user_id?: string;               // User who owns this item
  anime_id_jikan: number;         // MyAnimeList ID from Jikan API
  title: string;                  // Anime title
  image_url?: string;             // Poster image URL
  status: LibraryStatus;          // Current viewing status
  score?: number;                 // User rating (0-10)
  episodes_watched?: number;      // Progress tracking
}

export type LibraryStatus = 'watching' | 'completed' | 'dropped' | 'plan_to_watch';
```

## Core Functions

### Adding to Library

Add a new anime to your personal collection using the `addToLibrary` function:

```typescript theme={null}
import { addToLibrary, LibraryItem } from '@/services/library';

// Add an anime with initial status
const newItem: LibraryItem = {
  anime_id_jikan: 52991,
  title: "Sousou no Frieren",
  image_url: "https://cdn.myanimelist.net/images/anime/...",
  status: 'watching',
  episodes_watched: 5
};

const result = await addToLibrary(newItem);
```

<Note>
  The `user_id` is automatically populated from the authenticated user's session. Users must be logged in to add items to their library.
</Note>

**Implementation Details** (src/services/library.ts:16-30):

* Retrieves the current user from Supabase Auth
* Inserts the item into the `user_library` table
* Returns the created item with all fields populated
* Throws an error if the user is not authenticated

### Updating Library Items

Change the status or progress of an existing library item:

```typescript theme={null}
import { updateLibraryItem } from '@/services/library';

// Update viewing status
await updateLibraryItem(52991, { 
  status: 'completed',
  score: 9,
  episodes_watched: 28
});

// Update only specific fields
await updateLibraryItem(52991, { 
  episodes_watched: 15 
});
```

**Function Signature** (src/services/library.ts:46-61):

```typescript theme={null}
export const updateLibraryItem = async (
  animeIdJikan: number, 
  updates: Partial<LibraryItem>
) => Promise<LibraryItem>
```

### Removing from Library

Remove an anime from your library completely:

```typescript theme={null}
import { removeFromLibrary } from '@/services/library';

// Remove by Jikan anime ID
await removeFromLibrary(52991);
```

**Implementation** (src/services/library.ts:32-44):

* Deletes the item matching both `user_id` and `anime_id_jikan`
* Ensures users can only remove their own items
* No error thrown if item doesn't exist

### Retrieving Library Data

Fetch your entire library or a specific item:

<Tabs>
  <Tab title="Get All Items">
    ```typescript theme={null}
    import { getLibrary } from '@/services/library';

    // Get all library items for the current user
    const items = await getLibrary();

    // Items are sorted by most recently updated
    console.log(`You have ${items.length} anime in your library`);
    ```

    Returns all items ordered by `updated_at` descending (src/services/library.ts:63-72).
  </Tab>

  <Tab title="Get Single Item">
    ```typescript theme={null}
    import { getLibraryItem } from '@/services/library';

    // Check if a specific anime is in the library
    const item = await getLibraryItem(52991);

    if (item) {
      console.log(`Status: ${item.status}`);
      console.log(`Progress: ${item.episodes_watched} episodes`);
    } else {
      console.log('Not in library');
    }
    ```

    Returns `null` if the item doesn't exist (src/services/library.ts:74-88).
  </Tab>
</Tabs>

## UI Components

### LibraryButton Component

The `LibraryButton` component provides a complete interface for managing library items with status dropdown:

```tsx theme={null}
import LibraryButton from '@/components/anime/LibraryButton';

<LibraryButton 
  animeId={52991}
  title="Sousou no Frieren"
  imageUrl="https://cdn.myanimelist.net/images/anime/..."
/>
```

<Steps>
  <Step title="Initial State">
    When not in library, displays "+ AÑADIR A MI LISTA" button
  </Step>

  <Step title="Added State">
    After adding, shows "✓ EN MI LISTA" and a status dropdown appears
  </Step>

  <Step title="Status Selection">
    Users can change between watching, completed, plan to watch, and dropped
  </Step>

  <Step title="Removal">
    Clicking the main button when in library removes the item
  </Step>
</Steps>

**Status Labels** (src/components/anime/LibraryButton.tsx:73-78):

* 📺 VIENDO (watching)
* ✅ COMPLETADO (completed)
* ⏳ PENDIENTE (plan\_to\_watch)
* ❌ ABANDONADO (dropped)

### Library Page

The library page displays all items in a responsive grid layout:

<Tabs>
  <Tab title="Features">
    * Responsive grid (2-6 columns based on screen size)
    * Loading skeletons during data fetch
    * Empty state with call-to-action
    * Direct links to anime detail pages
    * Sorted by most recently updated
  </Tab>

  <Tab title="Usage">
    ```tsx theme={null}
    // Access at /library route
    // Automatically displays current user's library

    // Component: src/app/library/page.tsx
    // Fetches data using getLibrary()
    // Renders AnimeCard for each item
    ```
  </Tab>
</Tabs>

## Database Schema

The library is backed by a PostgreSQL table with row-level security:

```sql theme={null}
create table public.user_library (
  id uuid default gen_random_uuid() primary key,
  user_id uuid references public.profiles(id) on delete cascade not null,
  anime_id_jikan integer not null,
  title text not null,
  image_url text,
  status public.library_status default 'watching' not null,
  score integer check (score >= 0 and score <= 10),
  episodes_watched integer default 0,
  created_at timestamp with time zone default timezone('utc'::text, now()) not null,
  updated_at timestamp with time zone default timezone('utc'::text, now()) not null,
  
  unique(user_id, anime_id_jikan)
);
```

<Warning>
  The unique constraint on `(user_id, anime_id_jikan)` prevents duplicate entries. Attempting to add the same anime twice will result in a database error.
</Warning>

**Security Policies** (supabase/migrations/20260218\_initial\_schema.sql:65-75):

* Users can only view, insert, update, and delete their own library items
* All operations are protected by `auth.uid() = user_id` checks
* Row-level security is enabled on the table

## Error Handling

All library functions properly handle authentication and database errors:

<CodeGroup>
  ```typescript Authentication Error theme={null}
  try {
    await addToLibrary(item);
  } catch (error) {
    if (error.message.includes('logged in')) {
      // User is not authenticated
      alert('Please log in to add items to your library');
    }
  }
  ```

  ```typescript Database Error theme={null}
  try {
    await updateLibraryItem(animeId, updates);
  } catch (error) {
    // Handle database errors (network, constraints, etc.)
    console.error('Database error:', error);
    alert('Failed to update library item');
  }
  ```

  ```typescript Not Found theme={null}
  const item = await getLibraryItem(animeId);

  if (!item) {
    // Item not found in library
    console.log('This anime is not in your library');
  }
  ```
</CodeGroup>

## Best Practices

<CardGroup cols={2}>
  <Card title="Optimistic Updates" icon="bolt">
    Update the UI immediately before API calls complete for better UX

    ```typescript theme={null}
    setIsInLibrary(true); // Update UI
    await addToLibrary(item); // Then sync
    ```
  </Card>

  <Card title="Error Rollback" icon="rotate-left">
    Revert optimistic updates if operations fail

    ```typescript theme={null}
    try {
      // Update
    } catch (error) {
      setIsInLibrary(false); // Rollback
    }
    ```
  </Card>

  <Card title="Check Before Add" icon="circle-check">
    Use `getLibraryItem` to check if an anime is already in the library before attempting to add it
  </Card>

  <Card title="Partial Updates" icon="pen">
    Only include changed fields in `updateLibraryItem` calls to minimize data transfer
  </Card>
</CardGroup>

## Related Features

* [Progress Tracking](/features/progress-tracking) - Track episode completion
* [Scoring System](/features/scoring) - Rate your anime
* [Watch Status](/features/watch-status) - Understanding status types
* [User Profile](/features/profile-settings) - View library statistics
