Here's the refactored package structure with clean separation of concerns, proper relative imports, and a production-ready design.

### 📁 `queue/__init__.py`
```python
"""Public API for the job queue package."""
from .core import Job, JobQueue
from .priority import PriorityQueue

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

### 📁 `queue/core.py`
```python
"""Core job definition and basic FIFO queue implementation."""
import time
from dataclasses import dataclass, field
from typing import Any, Optional


@dataclass
class Job:
    """Represents a unit of work to be processed."""
    id: str
    payload: Any
    status: str = "pending"
    priority: int = 0
    retries: int = 0
    created_at: float = field(default_factory=time.time)
    completed_at: Optional[float] = None


class JobQueue:
    """Basic FIFO job queue implementation."""
    
    def __init__(self) -> None:
        self._queue: list[Job] = []

    def add(self, job: Job) -> None:
        """Append a job to the queue."""
        self._queue.append(job)

    def get_next(self) -> Optional[Job]:
        """Remove and return the next job in FIFO order."""
        if not self._queue:
            return None
        return self._queue.pop(0)

    def complete(self, job_id: str) -> None:
        """Mark a job as completed by its ID."""
        for job in self._queue:
            if job.id == job_id:
                job.status = "completed"
                job.completed_at = time.time()
                return
        raise ValueError(f"Job with id '{job_id}' not found in queue.")

    def is_empty(self) -> bool:
        """Check if the queue is empty."""
        return len(self._queue) == 0

    def size(self) -> int:
        """Return the number of pending jobs."""
        return len(self._queue)
```

### 📁 `queue/priority.py`
```python
"""Priority-aware queue implementation using a min-heap."""
import heapq
from typing import Optional
from .core import Job, JobQueue


class PriorityQueue(JobQueue):
    """Job queue that processes higher-priority jobs first."""
    
    def __init__(self) -> None:
        super().__init__()
        # Min-heap stores tuples: (-priority, tie_breaker, job)
        self._heap: list[tuple[int, int, Job]] = []
        self._counter: int = 0  # Ensures stable ordering for equal priorities

    def add(self, job: Job) -> None:
        """Add a job with priority ordering."""
        # Negate priority so min-heap behaves as max-priority
        heapq.heappush(self._heap, (-job.priority, self._counter, job))
        self._counter += 1

    def get_next(self) -> Optional[Job]:
        """Return the highest priority job."""
        if not self._heap:
            return None
        _, _, job = heapq.heappop(self._heap)
        return job

    def complete(self, job_id: str) -> None:
        """Mark a job as completed by searching the heap."""
        for _, _, job in self._heap:
            if job.id == job_id:
                job.status = "completed"
                job.completed_at = time.time()
                return
        raise ValueError(f"Job with id '{job_id}' not found in priority queue.")

    def is_empty(self) -> bool:
        return len(self._heap) == 0

    def size(self) -> int:
        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, TypeVar

from .core import Job

T = TypeVar("T")


def process_with_retry(
    job: Job,
    func: Callable[..., T],
    max_retries: int = 3,
    base_delay: float = 1.0,
    jitter: bool = True,
) -> T:
    """
    Execute a function with exponential backoff retry logic.
    
    Args:
        job: The job instance to update status/retries on.
        func: Callable that accepts `job.payload` and returns a result.
        max_retries: Maximum number of retry attempts.
        base_delay: Base delay in seconds for backoff calculation.
        jitter: Whether to add randomization to prevent thundering herd.
        
    Returns:
        The result of the successful function call.
        
    Raises:
        Exception: The last exception if all retries are exhausted.
    """
    last_exception: Optional[Exception] = None

    for attempt in range(max_retries + 1):
        try:
            result = func(job.payload)
            job.status = "completed"
            job.retries = attempt
            return result
        except Exception as e:
            last_exception = e
            job.retries = attempt + 1
            job.status = "failed"
            
            if attempt < max_retries:
                delay = base_delay * (2 ** attempt)
                if jitter:
                    delay *= (0.5 + random.random())  # ±50% jitter
                time.sleep(delay)
                
    job.status = "failed"
    raise last_exception
```

### 🔑 Key Design Decisions
1. **Single Responsibility**: 
   - `core.py` handles data modeling & basic FIFO behavior
   - `priority.py` handles ordering strategy via inheritance + heap
   - `retry.py` handles failure recovery & timing logic
2. **Clean Imports**: All cross-module imports use relative syntax (`.core`, `.priority`) which is best practice for packages.
3. **Public API**: `__init__.py` exposes only what consumers need. Internal classes/functions remain module-private.
4. **Type Safety**: Full type hints with `typing` module for better IDE support and static analysis.
5. **Extensibility**: `PriorityQueue` inherits from `JobQueue` but overrides storage/ordering methods. The retry function is stateless and works with any `Job` instance.

### 📦 Usage Example
```python
from queue import Job, JobQueue, PriorityQueue
from queue.retry import process_with_retry

# Basic queue
q = JobQueue()
q.add(Job(id="1", payload={"task": "email"}, priority=1))
next_job = q.get_next()

# Priority queue
pq = PriorityQueue()
pq.add(Job(id="2", payload={"task": "urgent"}, priority=10))
pq.add(Job(id="3", payload={"task": "normal"}, priority=5))
pq.get_next().id  # Returns "2"

# Retry logic
def my_processor(payload):
    # ... business logic
    return payload

result = process_with_retry(job, my_processor, max_retries=3, base_delay=0.5)
```

This structure scales well for larger codebases, enables independent testing per module, and follows Python packaging best practices.