Here's a complete, production-ready refactoring following your target structure. Each module has a clear responsibility, imports are properly scoped, and the public API is cleanly exposed.

### 📁 `queue/__init__.py`
```python
"""Job Queue Package - Clean public API"""

from .core import Job, JobQueue
from .priority import PriorityQueue
from .retry import process_with_retry

__all__ = ["Job", "JobQueue", "PriorityQueue", "process_with_retry"]
```

### 📁 `queue/core.py`
```python
"""Core job data structures and FIFO queue operations."""

from collections import deque
from dataclasses import dataclass, field
from datetime import datetime, timezone
from threading import Lock
from typing import Any, Optional


@dataclass
class Job:
    """Represents a unit of work in the queue."""
    id: str
    payload: Any
    status: str = "pending"
    retries: int = 0
    created_at: datetime = field(default_factory=lambda: datetime.now(timezone.utc))
    error: Optional[str] = None


class JobQueue:
    """Thread-safe FIFO job queue."""

    def __init__(self):
        self._queue: deque[Job] = deque()
        self._lock = Lock()

    def enqueue(self, job: Job) -> None:
        """Add a job to the end of the queue."""
        with self._lock:
            self._queue.append(job)

    def dequeue(self) -> Optional[Job]:
        """Remove and return the next job, or None if empty."""
        with self._lock:
            return self._queue.popleft() if self._queue else None

    def mark_complete(self, job_id: str) -> bool:
        """Mark a job as completed by ID."""
        with self._lock:
            for job in self._queue:
                if job.id == job_id:
                    job.status = "completed"
                    return True
            return False

    def mark_failed(self, job_id: str, error: str) -> bool:
        """Mark a job as failed by ID."""
        with self._lock:
            for job in self._queue:
                if job.id == job_id:
                    job.status = "failed"
                    job.error = error
                    return True
            return False

    @property
    def size(self) -> int:
        """Return the number of jobs in the queue."""
        with self._lock:
            return len(self._queue)
```

### 📁 `queue/priority.py`
```python
"""Priority queue implementation using a min-heap."""

import heapq
from threading import Lock
from typing import Optional

from .core import Job


class PriorityQueue:
    """Thread-safe priority queue where lower numbers = higher priority."""

    def __init__(self):
        self._heap: list[tuple[int, int, Job]] = []
        self._counter: int = 0  # Tie-breaker to preserve insertion order
        self._lock = Lock()

    def enqueue(self, job: Job, priority: int = 0) -> None:
        """Add a job with the given priority."""
        with self._lock:
            entry = (priority, self._counter, job)
            self._counter += 1
            heapq.heappush(self._heap, entry)

    def dequeue(self) -> Optional[Job]:
        """Remove and return the highest priority job, or None if empty."""
        with self._lock:
            if self._heap:
                _, _, job = heapq.heappop(self._heap)
                return job
            return None

    @property
    def size(self) -> int:
        """Return the number of jobs in the priority queue."""
        with self._lock:
            return len(self._heap)
```

### 📁 `queue/retry.py`
```python
"""Retry logic with exponential backoff and jitter."""

import random
import time
from typing import Any, Callable, Optional, Type, Tuple

from .core import Job


def process_with_retry(
    job: Job,
    func: Callable[..., Any],
    max_retries: int = 3,
    base_delay: float = 1.0,
    backoff_factor: float = 2.0,
    jitter: bool = True,
    retryable_exceptions: Tuple[Type[Exception], ...] = (Exception,),
) -> Optional[Any]:
    """
    Execute a function with retry logic and exponential backoff.

    Args:
        job: The job context to update on failure.
        func: Callable to execute.
        max_retries: Maximum number of retry attempts.
        base_delay: Initial delay in seconds before first retry.
        backoff_factor: Multiplier applied to delay after each retry.
        jitter: Whether to add randomization to prevent thundering herd.
        retryable_exceptions: Tuple of exception types that trigger a retry.

    Returns:
        The function's return value on success, or None on final failure.
    """
    last_exception: Optional[Exception] = None

    for attempt in range(max_retries + 1):
        try:
            result = func(job.payload)
            job.status = "completed"
            return result
        except retryable_exceptions as e:
            last_exception = e
            job.retries += 1
            job.error = str(e)

            if attempt < max_retries:
                delay = base_delay * (backoff_factor ** attempt)
                if jitter:
                    delay *= (0.5 + random.random())
                time.sleep(delay)
            else:
                job.status = "failed"
                return None

    return None
```

### 🔑 Key Design Decisions:
1. **Single Responsibility**: 
   - `core.py`: Data model + FIFO queue mechanics
   - `priority.py`: Heap-based ordering logic
   - `retry.py`: Resilience & backoff strategy
2. **Thread Safety**: All queue operations use `threading.Lock` to prevent race conditions in concurrent environments.
3. **Relative Imports**: Uses `.core`, `.priority`, `.retry` so the package works correctly when installed or imported as `import queue`.
4. **Clean Public API**: `__init__.py` explicitly exports only what consumers need, hiding internal implementation details.
5. **Type Hints & Docstrings**: Added for IDE support, static analysis, and maintainability.

> ⚠️ **Naming Note**: `queue` is already a Python standard library module. In production, consider renaming the package to `job_queue` or `task_queue` to avoid shadowing conflicts. You can achieve this by simply renaming the folder and updating `__init__.py` imports accordingly.