Here's a clean, production-ready refactoring that follows your target structure and requirements. Each module has a single responsibility, uses modern typing, and maintains clear separation of concerns.

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

# Strictly exported names per requirements
__all__ = ["Job", "JobQueue"]
```

### `queue/core.py`
```python
"""Core job data model and standard FIFO queue operations."""
from __future__ import annotations

import time
from dataclasses import dataclass, field
from typing import Any, Optional
from collections import deque


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


class JobQueue:
    """A standard FIFO queue for processing jobs."""
    
    def __init__(self) -> None:
        self._queue: deque[Job] = deque()

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

    def dequeue(self) -> Optional[Job]:
        """Remove and return the first job in the queue."""
        return self._queue.popleft() if self._queue else None

    def peek(self) -> Optional[Job]:
        """Return the first job without removing it."""
        return self._queue[0] if self._queue else None

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

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

### `queue/priority.py`
```python
"""Priority-based queue implementation using a min-heap."""
from __future__ import annotations

import heapq
from typing import Any, Optional
from .core import Job


class PriorityQueue:
    """Manages jobs ordered by priority (lower value = higher priority)."""
    
    def __init__(self) -> None:
        self._heap: list[tuple[int, int, Job]] = []
        self._counter: int = 0  # Ensures stable sorting for equal priorities

    def enqueue(self, job: Job, priority: int = 0) -> None:
        """Insert a job with the given priority."""
        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."""
        if self._heap:
            _, _, job = heapq.heappop(self._heap)
            return job
        return None

    def peek(self) -> Optional[Job]:
        """Return the highest priority job without removing it."""
        return self._heap[0][2] if self._heap else None

    def is_empty(self) -> bool:
        """Check if the priority queue contains no jobs."""
        return len(self._heap) == 0

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

### `queue/retry.py`
```python
"""Retry logic with exponential backoff."""
from __future__ import annotations

import time
from typing import Any, Callable

def process_with_retry(
    func: Callable[..., Any],
    *args: Any,
    max_retries: int = 3,
    base_delay: float = 1.0,
    **kwargs: Any,
) -> Any:
    """Execute a function with exponential backoff retry logic.
    
    Args:
        func: Callable to execute.
        *args: Positional arguments for the callable.
        max_retries: Maximum number of retry attempts.
        base_delay: Base delay in seconds for backoff calculation.
        **kwargs: Keyword arguments for the callable.
        
    Returns:
        The return value of the successfully executed function.
        
    Raises:
        The last encountered exception if all retries fail.
    """
    last_exception = None
    
    for attempt in range(max_retries + 1):
        try:
            return func(*args, **kwargs)
        except Exception as e:
            last_exception = e
            if attempt == max_retries:
                break
            delay = base_delay * (2 ** attempt)
            time.sleep(delay)
            
    raise last_exception
```

### Key Design Choices:
1. **Single Responsibility**: 
   - `core.py` handles data modeling (`Job`) and basic FIFO operations (`JobQueue`)
   - `priority.py` isolates heap-based ordering logic
   - `retry.py` contains only backoff mechanics, making it easily testable and swappable
2. **Proper Import Structure**: Uses relative imports (`.core`, `.priority`) to avoid circular dependencies and keep the package self-contained.
3. **Type Safety**: Full type hints with `from __future__ import annotations` for forward references and modern syntax compatibility (Python 3.7+).
4. **Clean Public API**: `__init__.py` explicitly controls the public surface. Additional classes/functions can be added to `__all__` as the package grows.
5. **Stable Priority Queue**: Uses a monotonic counter in `PriorityQueue` to break ties deterministically, preventing `heapq` comparison errors between `Job` objects.

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

# Basic queue
q = JobQueue()
q.enqueue(Job(id="1", payload={"task": "email"}))
job = q.dequeue()

# Priority queue
pq = PriorityQueue()
pq.enqueue(Job(id="2", payload={"task": "report"}), priority=1)
pq.enqueue(Job(id="3", payload={"task": "alert"}), priority=0)

# Retry logic
def unstable_task(x):
    return x * 2

result = process_with_retry(unstable_task, 5, max_retries=3, base_delay=0.5)
```