# Architecture Documentation

## Document Purpose

This document describes the system architecture of the Aniworld anime download manager.

---

## 1. System Overview

Aniworld is a web-based anime download manager built with Python, FastAPI, and SQLite. It provides a REST API and WebSocket interface for managing anime libraries, downloading episodes, and tracking progress.

### High-Level Architecture

```
+------------------+     +------------------+     +------------------+
|   Web Browser    |     |   CLI Client     |     |   External       |
|   (Frontend)     |     |   (Main.py)      |     |   Providers      |
+--------+---------+     +--------+---------+     +--------+---------+
         |                        |                        |
         | HTTP/WebSocket         | Direct                 | HTTP
         |                        |                        |
+--------v---------+     +--------v---------+     +--------v---------+
|                  |     |                  |     |                  |
|   FastAPI        <----->   Core Layer    <----->   Provider       |
|   Server Layer   |     |   (SeriesApp)    |     |   Adapters       |
|                  |     |                  |     |                  |
+--------+---------+     +--------+---------+     +------------------+
         |                        |
         |                        |
+--------v---------+     +--------v---------+
|                  |     |                  |
|   SQLite DB      |     |   File System    |
|   (aniworld.db)  |     |   (anime/*/)     |
|  - Series data   |     |   - Video files  |
|  - Episodes      |     |   - NFO files    |
|  - Queue state   |     |   - Media files  |
+------------------+     +------------------+
```

Source: [src/server/fastapi_app.py](../src/server/fastapi_app.py#L1-L252)

---

## 2. Architectural Layers

### 2.1 CLI Layer (`src/cli/`)

Legacy command-line interface for direct interaction with the core layer.

| Component | File                          | Purpose         |
| --------- | ----------------------------- | --------------- |
| Main      | [Main.py](../src/cli/Main.py) | CLI entry point |

### 2.2 Server Layer (`src/server/`)

FastAPI-based REST API and WebSocket server.

```
src/server/
+-- fastapi_app.py          # Application entry point, lifespan management
+-- api/                    # API route handlers
|   +-- anime.py            # /api/anime/* endpoints
|   +-- auth.py             # /api/auth/* endpoints
|   +-- config.py           # /api/config/* endpoints
|   +-- download.py         # /api/queue/* endpoints
|   +-- scheduler.py        # /api/scheduler/* endpoints
|   +-- nfo.py              # /api/nfo/* endpoints
|   +-- websocket.py        # /ws/* WebSocket handlers
|   +-- health.py           # /health/* endpoints
+-- controllers/            # Page controllers for HTML rendering
|   +-- page_controller.py  # UI page routes
|   +-- health_controller.py# Health check route
|   +-- error_controller.py # Error pages (404, 500)
+-- services/               # Business logic
|   +-- anime_service.py    # Anime operations
|   +-- auth_service.py     # Authentication
|   +-- config_service.py   # Configuration management
|   +-- download_service.py # Download queue management
|   +-- progress_service.py # Progress tracking
|   +-- websocket_service.py# WebSocket broadcasting
|   +-- queue_repository.py # Database persistence
|   +-- nfo_service.py      # NFO metadata management
|   +-- folder_scan_service.py # Daily folder maintenance scan
+-- models/                 # Pydantic models
|   +-- auth.py             # Auth request/response models
|   +-- config.py           # Configuration models
|   +-- download.py         # Download queue models
|   +-- websocket.py        # WebSocket message models
+-- middleware/             # Request processing
|   +-- auth.py             # JWT validation, rate limiting
|   +-- error_handler.py    # Exception handlers
|   +-- setup_redirect.py   # Setup flow redirect
+-- database/               # SQLAlchemy ORM
|   +-- connection.py       # Database connection
|   +-- models.py           # ORM models
|   +-- service.py          # Database service
+-- utils/                  # Utility modules
|   +-- filesystem.py       # Folder sanitization, path safety
|   +-- validators.py       # Input validation utilities
|   +-- dependencies.py     # FastAPI dependency injection
+-- web/                    # Static files and templates
    +-- static/             # CSS, JS, images
    +-- templates/          # Jinja2 templates
```

Source: [src/server/](../src/server/)

### 2.2.1 Frontend Architecture (`src/server/web/static/`)

The frontend uses a modular architecture with no build step required. CSS and JavaScript files are organized by responsibility.

#### CSS Structure

```
src/server/web/static/css/
+-- styles.css              # Entry point with @import statements
+-- base/
|   +-- variables.css       # CSS custom properties (colors, fonts, spacing)
|   +-- reset.css           # CSS reset and normalize styles
|   +-- typography.css      # Font styles, headings, text utilities
+-- components/
|   +-- buttons.css         # All button styles
|   +-- cards.css           # Card and panel components
|   +-- forms.css           # Form inputs, labels, validation styles
|   +-- modals.css          # Modal and overlay styles
|   +-- navigation.css      # Header, nav, sidebar styles
|   +-- progress.css        # Progress bars, loading indicators
|   +-- notifications.css   # Toast, alerts, messages
|   +-- tables.css          # Table and list styles
|   +-- status.css          # Status badges and indicators
+-- pages/
|   +-- login.css           # Login page specific styles
|   +-- index.css           # Index/library page specific styles
|   +-- queue.css           # Queue page specific styles
+-- utilities/
    +-- animations.css      # Keyframes and animation classes
    +-- responsive.css      # Media queries and breakpoints
    +-- helpers.css         # Utility classes (hidden, flex, spacing)
```

#### JavaScript Structure

JavaScript uses the IIFE pattern with a shared `AniWorld` namespace for browser compatibility without build tools.

```
src/server/web/static/js/
+-- shared/                 # Shared utilities used by all pages
|   +-- constants.js        # API endpoints, localStorage keys, defaults
|   +-- auth.js             # Token management (getToken, setToken, checkAuth)
|   +-- api-client.js       # Fetch wrapper with auto-auth headers
|   +-- theme.js            # Dark/light theme toggle
|   +-- ui-utils.js         # Toast notifications, format helpers
|   +-- websocket-client.js # Socket.IO wrapper
+-- index/                  # Index page modules
|   +-- series-manager.js   # Series list rendering and filtering
|   +-- selection-manager.js# Multi-select and bulk download
|   +-- search.js           # Series search functionality
|   +-- scan-manager.js     # Library rescan operations
|   +-- scheduler-config.js # Scheduler configuration
|   +-- logging-config.js   # Logging configuration
|   +-- advanced-config.js  # Advanced settings
|   +-- main-config.js      # Main configuration and backup
|   +-- config-manager.js   # Config modal orchestrator
|   +-- socket-handler.js   # WebSocket event handlers
|   +-- app-init.js         # Application initialization
+-- queue/                  # Queue page modules
    +-- queue-api.js        # Queue API interactions
    +-- queue-renderer.js   # Queue list rendering
    +-- progress-handler.js # Download progress updates
    +-- queue-socket-handler.js # WebSocket events for queue
    +-- queue-init.js       # Queue page initialization
```

#### Module Pattern

All JavaScript modules follow the IIFE pattern with namespace:

```javascript
var AniWorld = window.AniWorld || {};

AniWorld.ModuleName = (function () {
    "use strict";

    // Private variables and functions

    // Public API
    return {
        init: init,
        publicMethod: publicMethod,
    };
})();
```

Source: [src/server/web/static/](../src/server/web/static/)

### 2.3 Core Layer (`src/core/`)

Domain logic for anime series management.

```
src/core/
+-- SeriesApp.py            # Main application facade
+-- SerieScanner.py         # Directory scanning, targeted single-series scan
+-- entities/               # Domain entities
|   +-- series.py           # Serie class with sanitized_folder property
|   +-- SerieList.py        # SerieList collection with sanitized folder support
|   +-- nfo_models.py       # Pydantic models for tvshow.nfo (TVShowNFO, ActorInfo…)
+-- services/               # Domain services
|   +-- nfo_service.py      # NFO lifecycle: create / update tvshow.nfo
|   +-- nfo_repair_service.py # Detect & repair incomplete tvshow.nfo files
|   |                       #   (parse_nfo_tags, find_missing_tags, NfoRepairService)
|   +-- tmdb_client.py      # Async TMDB API client
+-- utils/                  # Utility helpers (no side-effects)
|   +-- nfo_generator.py    # TVShowNFO → XML serialiser
|   +-- nfo_mapper.py       # TMDB API dict → TVShowNFO (tmdb_to_nfo_model,
|   |                       #   _extract_rating_by_country, _extract_fsk_rating)
|   +-- image_downloader.py # TMDB image downloader
+-- providers/              # External provider adapters
|   +-- base_provider.py    # Loader interface
|   +-- provider_factory.py # Provider registry
+-- interfaces/             # Abstract interfaces
|   +-- callbacks.py        # Progress callback system
+-- exceptions/             # Domain exceptions
    +-- Exceptions.py       # Custom exceptions
```

**Key Components:**

| Component      | Purpose                                                                    |
| -------------- | -------------------------------------------------------------------------- |
| `SeriesApp`    | Main application facade for anime operations                               |
| `SerieScanner` | Scans directories for anime; `scan_single_series()` for targeted scans     |
| `Serie`        | Domain entity with `sanitized_folder` property for filesystem-safe names   |
| `SerieList`    | Collection management with automatic folder creation using sanitized names |

**Initialization:**

`SeriesApp` is initialized with `skip_load=True` passed to `SerieList`, preventing automatic loading of series from data files on every instantiation. Series data is loaded once during application setup via `sync_series_from_data_files()` in the FastAPI lifespan, which reads data files and syncs them to the database. Subsequent operations load series from the database through the service layer.

Source: [src/core/](../src/core/)

### 2.4 Infrastructure Layer (`src/infrastructure/`)

Cross-cutting concerns.

```
src/infrastructure/
+-- logging/                # Structured logging setup
+-- security/               # Security utilities
```

### 2.5 Configuration Layer (`src/config/`)

Application settings management.

| Component | File                                     | Purpose                         |
| --------- | ---------------------------------------- | ------------------------------- |
| Settings  | [settings.py](../src/config/settings.py) | Environment-based configuration |

Source: [src/config/settings.py](../src/config/settings.py#L1-L96)

---

## 12. Startup Sequence

The FastAPI lifespan function (`src/server/fastapi_app.py`) runs the following steps on every server start.

### 12.1 Startup Order

```
1. Logging configured

2. Temp folder purged  ← cleans leftover partial download files
   +-- Iterate ./Temp/ and delete every file and sub-directory
   +-- Create ./Temp/ if it does not exist
   +-- Errors are logged as warnings; startup continues regardless

3. Database initialised (required – abort on failure)
   +-- SQLite file created / migrated via init_db()

4. Configuration loaded from data/config.json
   +-- Synced to settings (ENV vars take precedence)

5. Progress & WebSocket services wired up

6. Series loaded from database into memory

7. Download service initialised (queue restored from DB)

8. Background loader service started

9. Scheduler service started
   +-- Cron-based library rescans configured
   +-- Optional: auto-download missing episodes after rescan
   +-- Optional: folder maintenance (NFO repair, renaming, poster checks) during scheduled runs
```

### 12.2 Temp Folder Guarantee

Every server start begins with a clean `./Temp/` directory. This ensures that partial `.part` files or stale temp videos from a crashed or force-killed previous session are never left behind before new downloads start.

Source: [src/server/fastapi_app.py](../src/server/fastapi_app.py)

---

## 11. Graceful Shutdown

The application implements a comprehensive graceful shutdown mechanism that ensures data integrity and proper cleanup when the server is stopped via Ctrl+C (SIGINT) or SIGTERM.

### 11.1 Shutdown Sequence

```
1. SIGINT/SIGTERM received
   +-- Uvicorn catches signal
   +-- Stops accepting new requests

2. FastAPI lifespan shutdown triggered
   +-- 30 second total timeout

3. WebSocket shutdown (5s timeout)
   +-- Broadcast {"type": "server_shutdown"} to all clients
   +-- Close each connection with code 1001 (Going Away)
   +-- Clear connection tracking data

4. Download service stop (10s timeout)
   +-- Set shutdown flag
   +-- Persist active download as "pending" in database
   +-- Cancel active download task
   +-- Shutdown ThreadPoolExecutor with wait

5. Progress service cleanup
   +-- Clear event subscribers
   +-- Clear active progress tracking

6. Database cleanup (10s timeout)
   +-- SQLite: Run PRAGMA wal_checkpoint(TRUNCATE)
   +-- Dispose async engine
   +-- Dispose sync engine

7. Process exits cleanly
```

Source: [src/server/fastapi_app.py](../src/server/fastapi_app.py#L142-L210)

### 11.2 Key Components

| Component           | File                                                                | Shutdown Method                |
| ------------------- | ------------------------------------------------------------------- | ------------------------------ |
| WebSocket Service   | [websocket_service.py](../src/server/services/websocket_service.py) | `shutdown(timeout=5.0)`        |
| Download Service    | [download_service.py](../src/server/services/download_service.py)   | `stop(timeout=10.0)`           |
| Database Connection | [connection.py](../src/server/database/connection.py)               | `close_db()`                   |
| Uvicorn Config      | [run_server.py](../run_server.py)                                   | `timeout_graceful_shutdown=30` |
| Stop Script         | [stop_server.sh](../stop_server.sh)                                 | SIGTERM with fallback          |

### 11.3 Data Integrity Guarantees

1. **Active downloads preserved**: In-progress downloads are saved as "pending" and can resume on restart.

2. **Database WAL flushed**: SQLite WAL checkpoint ensures all writes are in the main database file.

3. **WebSocket clients notified**: Clients receive shutdown message before connection closes.

4. **Thread pool cleanup**: Background threads complete or are gracefully cancelled.

### 11.4 Manual Stop

```bash
# Graceful stop via script (sends SIGTERM, waits up to 30s)
./stop_server.sh

# Or press Ctrl+C in terminal running the server
```

Source: [stop_server.sh](../stop_server.sh#L1-L80)

---

## 3. Component Interactions

### 3.1 Request Flow (REST API)

```
1. Client sends HTTP request
2. AuthMiddleware validates JWT token (if required)
3. Rate limiter checks request frequency
4. FastAPI router dispatches to endpoint handler
5. Endpoint calls service layer
6. Service layer uses core layer or database
7. Response returned as JSON
```

Source: [src/server/middleware/auth.py](../src/server/middleware/auth.py#L1-L209)

### 3.2 Download Flow

```
1. POST /api/queue/add
   +-- DownloadService.add_to_queue()
       +-- QueueRepository.save_item() -> SQLite

2. POST /api/queue/start
   +-- DownloadService.start_queue_processing()
       +-- Process pending items sequentially
       +-- ProgressService emits events
       +-- WebSocketService broadcasts to clients

3. During download:
   +-- Provider writes to ./Temp/<filename>  (+ ./Temp/<filename>.part fragments)
   +-- ProgressService.emit("progress_updated")
   +-- WebSocketService.broadcast_to_room()
   +-- Client receives WebSocket message

4. After download attempt (success OR failure):
   +-- _cleanup_temp_file() removes ./Temp/<filename> and all .part fragments
   +-- On success: file was already moved to final destination before cleanup
   +-- On failure / exception: no partial files remain in ./Temp/
```

#### Temp Directory Contract

| Situation                        | Outcome                                                             |
| -------------------------------- | ------------------------------------------------------------------- |
| Server start                     | Entire `./Temp/` directory is purged before any service initialises |
| Successful download              | Temp file moved to destination, then removed from `./Temp/`         |
| Failed download (provider error) | Temp + `.part` fragments removed by `_cleanup_temp_file()`          |
| Exception / cancellation         | Temp + `.part` fragments removed in `except` block                  |

Source: [src/server/services/download_service.py](../src/server/services/download_service.py#L1-L150),
[src/core/providers/aniworld_provider.py](../src/core/providers/aniworld_provider.py),
[src/core/providers/enhanced_provider.py](../src/core/providers/enhanced_provider.py)

### 3.3 WebSocket Event Flow

```
1. Client connects to /ws/connect
2. Server sends "connected" message
3. Client joins room: {"action": "join", "data": {"room": "downloads"}}
4. ProgressService emits events
5. WebSocketService broadcasts to room subscribers
6. Client receives real-time updates
```

Source: [src/server/api/websocket.py](../src/server/api/websocket.py#L1-L260)

---

## 4. Design Patterns

### 4.1 Repository Pattern (Service Layer as Repository)

**Architecture Decision**: The Service Layer serves as the Repository layer for database access.

Database access is abstracted through service classes in `src/server/database/service.py` that provide CRUD operations and act as the repository layer. This eliminates the need for a separate repository layer while maintaining clean separation of concerns.

**Service Layer Classes** (acting as repositories):

- `AnimeSeriesService` - CRUD operations for anime series
- `EpisodeService` - CRUD operations for episodes
- `DownloadQueueService` - CRUD operations for download queue
- `UserSessionService` - CRUD operations for user sessions
- `SystemSettingsService` - CRUD operations for system settings

**Key Principles**:

1. **No Direct Database Queries**: Controllers and business logic services MUST use service layer methods
2. **Service Layer Encapsulation**: All SQLAlchemy queries are encapsulated in service methods
3. **Consistent Interface**: Services provide consistent async methods for all database operations
4. **Single Responsibility**: Each service manages one entity type

**Example Usage**:

```python
# CORRECT: Use service layer
from src.server.database.service import AnimeSeriesService

async with get_db_session() as db:
    series = await AnimeSeriesService.get_by_key(db, "attack-on-titan")
    await AnimeSeriesService.update(db, series.id, has_nfo=True)

# INCORRECT: Direct database query
result = await db.execute(select(AnimeSeries).filter(...))  # ❌ Never do this
```

**Special Case - Queue Repository Adapter**:

The `QueueRepository` in `src/server/services/queue_repository.py` is an adapter that wraps `DownloadQueueService` to provide domain model conversion between Pydantic models and SQLAlchemy models:

```python
# QueueRepository provides CRUD with model conversion
class QueueRepository:
    async def save_item(self, item: DownloadItem) -> None: ...  # Converts Pydantic → SQLAlchemy
    async def get_all_items(self) -> List[DownloadItem]: ...    # Converts SQLAlchemy → Pydantic
    async def delete_item(self, item_id: str) -> bool: ...
```

Source: [src/server/database/service.py](../src/server/database/service.py), [src/server/services/queue_repository.py](../src/server/services/queue_repository.py)

### 4.2 Dependency Injection

FastAPI's `Depends()` provides constructor injection.

```python
@router.get("/status")
async def get_status(
    download_service: DownloadService = Depends(get_download_service),
):
    ...
```

Source: [src/server/utils/dependencies.py](../src/server/utils/dependencies.py)

### 4.3 Event-Driven Architecture

Progress updates use an event subscription model.

```python
# ProgressService publishes events
progress_service.emit("progress_updated", event)

# WebSocketService subscribes
progress_service.subscribe("progress_updated", ws_handler)
```

Source: [src/server/fastapi_app.py](../src/server/fastapi_app.py#L98-L108)

### 4.4 Singleton Pattern

Services use module-level singletons for shared state.

```python
# In download_service.py
_download_service_instance: Optional[DownloadService] = None

def get_download_service() -> DownloadService:
    global _download_service_instance
    if _download_service_instance is None:
        _download_service_instance = DownloadService(...)
    return _download_service_instance
```

### 4.5 Error Handling Pattern

**Architecture Decision**: Dual error handling approach based on exception source.

The application uses two complementary error handling mechanisms:

1. **FastAPI HTTPException** - For simple validation and HTTP-level errors
2. **Custom Exception Hierarchy** - For business logic and service-level errors with rich context

#### Exception Hierarchy

```python
# Base exception with HTTP status mapping
AniWorldAPIException(message, status_code, error_code, details)
├── AuthenticationError (401)
├── AuthorizationError (403)
├── ValidationError (422)
├── NotFoundError (404)
├── ConflictError (409)
├── BadRequestError (400)
├── RateLimitError (429)
└── ServerError (500)
    ├── DownloadError
    ├── ConfigurationError
    ├── ProviderError
    └── DatabaseError
```

#### When to Use Each

**Use HTTPException for:**

- Simple parameter validation (missing fields, wrong type)
- Direct HTTP-level errors (401, 403, 404 without business context)
- Quick endpoint-specific failures

**Use Custom Exceptions for:**

- Service-layer business logic errors (AnimeServiceError, ConfigServiceError)
- Errors needing rich context (details dict, error codes)
- Errors that should be logged with specific categorization
- Cross-cutting concerns (authentication, authorization, rate limiting)

**Example:**

```python
# Simple validation - Use HTTPException
if not series_key:
    raise HTTPException(status_code=400, detail="series_key required")

# Business logic error - Use custom exception
try:
    await anime_service.add_series(series_key)
except AnimeServiceError as e:
    raise ServerError(
        message=f"Failed to add series: {e}",
        error_code="ANIME_ADD_FAILED",
        details={"series_key": series_key}
    )
```

#### Global Exception Handlers

All custom exceptions are automatically handled by global middleware that:

- Converts exceptions to structured JSON responses
- Logs errors with appropriate severity
- Includes request ID for tracking
- Provides consistent error format

**Source**: [src/server/exceptions/\_\_init\_\_.py](../src/server/exceptions/__init__.py), [src/server/middleware/error_handler.py](../src/server/middleware/error_handler.py)

Source: [src/server/services/download_service.py](../src/server/services/download_service.py)

---

## 5. Data Flow

### 5.1 Series Identifier Convention

The system uses two identifier fields:

| Field    | Type     | Purpose                                | Example                    |
| -------- | -------- | -------------------------------------- | -------------------------- |
| `key`    | Primary  | Provider-assigned, URL-safe identifier | `"attack-on-titan"`        |
| `folder` | Metadata | Filesystem folder name (display only)  | `"Attack on Titan (2013)"` |

All API operations use `key`. The `folder` is for filesystem operations only.

Source: [src/server/database/models.py](../src/server/database/models.py#L26-L50)

### 5.2 Database Schema

```
+----------------+       +----------------+       +--------------------+
|  anime_series  |       |    episodes    |       | download_queue_item|
+----------------+       +----------------+       +--------------------+
| id (PK)        |<--+   | id (PK)        |   +-->| id (PK)            |
| key (unique)   |   |   | series_id (FK) |---+   | series_id (FK)     |
| name           |   +---| season         |       | status             |
| site           |       | episode_number |       | priority           |
| folder         |       | title          |       | progress_percent   |
| created_at     |       | is_downloaded  |       | added_at           |
| updated_at     |       | file_path      |       | started_at         |
+----------------+       +----------------+       +--------------------+
```

Source: [src/server/database/models.py](../src/server/database/models.py#L1-L200)

### 5.3 Configuration Storage

Configuration is stored in `data/config.json`:

```json
{
    "name": "Aniworld",
    "data_dir": "data",
    "scheduler": {
        "enabled": true,
        "schedule_time": "03:00",
        "schedule_days": ["mon", "tue", "wed", "thu", "fri", "sat", "sun"],
        "auto_download_after_rescan": false
    },
    "logging": { "level": "INFO" },
    "backup": { "enabled": false, "path": "data/backups" },
    "other": {
        "master_password_hash": "$pbkdf2-sha256$...",
        "anime_directory": "/path/to/anime"
    }
}
```

Source: [data/config.json](../data/config.json)

---

## 6. Technology Stack

| Layer         | Technology          | Version | Purpose                |
| ------------- | ------------------- | ------- | ---------------------- |
| Web Framework | FastAPI             | 0.104.1 | REST API, WebSocket    |
| ASGI Server   | Uvicorn             | 0.24.0  | HTTP server            |
| Database      | SQLite + SQLAlchemy | 2.0.35  | Persistence            |
| Auth          | python-jose         | 3.3.0   | JWT tokens             |
| Password      | passlib             | 1.7.4   | bcrypt hashing         |
| Validation    | Pydantic            | 2.5.0   | Data models            |
| Templates     | Jinja2              | 3.1.2   | HTML rendering         |
| Logging       | structlog           | 24.1.0  | Structured logging     |
| Testing       | pytest              | 7.4.3   | Unit/integration tests |

Source: [requirements.txt](../requirements.txt)

---

## 7. Scalability Considerations

### Current Limitations

1. **Single-process deployment**: In-memory rate limiting and session state are not shared across processes.

2. **SQLite database**: Not suitable for high concurrency. Consider PostgreSQL for production.

3. **Sequential downloads**: Only one download processes at a time by design.

### Recommended Improvements for Scale

| Concern        | Current         | Recommended       |
| -------------- | --------------- | ----------------- |
| Rate limiting  | In-memory dict  | Redis             |
| Session store  | In-memory       | Redis or database |
| Database       | SQLite          | PostgreSQL        |
| Task queue     | In-memory deque | Celery + Redis    |
| Load balancing | None            | Nginx/HAProxy     |

---

## 8. Integration Points

### 8.1 External Providers

The system integrates with anime streaming providers via the Loader interface.

```python
class Loader(ABC):
    @abstractmethod
    def search(self, query: str) -> List[Serie]: ...

    @abstractmethod
    def get_episodes(self, serie: Serie) -> Dict[int, List[int]]: ...
```

Source: [src/core/providers/base_provider.py](../src/core/providers/base_provider.py)

### 8.2 Filesystem Integration

The scanner reads anime directories to detect downloaded episodes.

```python
SerieScanner(
    basePath="/path/to/anime",  # Anime library directory
    loader=provider,             # Provider for metadata
    db_session=session           # Optional database
)
```

Source: [src/core/SerieScanner.py](../src/core/SerieScanner.py#L59-L96)

---

## 9. Security Architecture

### 9.1 Authentication Flow

```
1. User sets master password via POST /api/auth/setup
2. Password hashed with pbkdf2_sha256 (via passlib)
3. Hash stored in config.json
4. Login validates password, returns JWT token
5. JWT contains: session_id, user, created_at, expires_at
6. Subsequent requests include: Authorization: Bearer <token>
```

Source: [src/server/services/auth_service.py](../src/server/services/auth_service.py#L1-L150)

### 9.2 Password Requirements

- Minimum 8 characters
- Mixed case (upper and lower)
- At least one number
- At least one special character

Source: [src/server/services/auth_service.py](../src/server/services/auth_service.py#L97-L125)

### 9.3 Rate Limiting

| Endpoint          | Limit       | Window     |
| ----------------- | ----------- | ---------- |
| `/api/auth/login` | 5 requests  | 60 seconds |
| `/api/auth/setup` | 5 requests  | 60 seconds |
| All origins       | 60 requests | 60 seconds |

Source: [src/server/middleware/auth.py](../src/server/middleware/auth.py#L54-L68)

---

## 10. Deployment Modes

### 10.1 Development

```bash
# Run with hot reload
python -m uvicorn src.server.fastapi_app:app --reload
```

### 10.2 Production

```bash
# Via conda environment
conda run -n AniWorld python -m uvicorn src.server.fastapi_app:app \
    --host 127.0.0.1 --port 8000
```

### 10.3 Configuration

Environment variables (via `.env` or shell):

| Variable          | Default                        | Description            |
| ----------------- | ------------------------------ | ---------------------- |
| `JWT_SECRET_KEY`  | Random                         | Secret for JWT signing |
| `DATABASE_URL`    | `sqlite:///./data/aniworld.db` | Database connection    |
| `ANIME_DIRECTORY` | (empty)                        | Path to anime library  |
| `LOG_LEVEL`       | `INFO`                         | Logging level          |
| `CORS_ORIGINS`    | `localhost:3000,8000`          | Allowed CORS origins   |

Source: [src/config/settings.py](../src/config/settings.py#L1-L96)
