<reasoning_content>
Thinking Process:

1.  **Analyze the Request:**
    *   Goal: Implement a basic job queue in Python.
    *   Class Name: `JobQueue`
    *   Methods:
        *   `add_job(job_id: str, data: dict) -> str`: Add job, return job_id.
        *   `get_result(job_id: str) -> dict | None`: Get result of completed job.
    *   Behavior:
        *   FIFO order.
        *   Store jobs internally until processed.
        *   Unique job_id.
    *   Output: Only Python code, no explanations.

2.  **Determine Implementation Details:**
    *   Needs a data structure to store jobs. A dictionary mapping `job_id` to job details seems appropriate for `get_result`.
    *   Needs a data structure to manage the order. A `collections.deque` or a `list` (as a queue) is suitable for FIFO.
    *   Needs a way to simulate processing. Since the prompt doesn't specify *how* it's processed (async, synchronous, background thread), I need to define a mechanism.
        *   *Option 1: Synchronous simulation.* The user calls `add_job`, then calls a `process` method or assumes the queue processes immediately. However, `get_result` implies the job might be pending.
        *   *Option 2: Background processing.* Use `threading` or `concurrent.futures`.
        *   *Option 3: Simple simulation.* Just store state. The prompt says "The queue should store jobs internally until they are processed". It doesn't explicitly require a worker thread, but `get_result` implies checking status.
        *   *Interpretation:* To make it functional based on the example, I should probably include a mechanism to "process" the jobs so they move from "pending" to "completed". Without a `process` method explicitly required, I can either:
            1.  Auto-process on `get_result` (lazy).
            2.  Add a `process_all` or `process_next` method.
            3.  Simulate the processing logic within the class (e.g., a `process` method to trigger execution).
            4.  Since the prompt asks for `add_job` and `get_result`, I need to make sure `get_result` returns `None` if not done, and the data if done.
        *   To keep it "basic" but functional as a queue, I will add a `process` method or simulate execution logic so the example makes sense. However, strict adherence to the requirements says only `add_job` and `get_result` are required methods in the class definition signature.
        *   Wait, the requirement says "Create a `JobQueue` class with the following methods". It doesn't forbid *other* methods, but I should focus on the required ones.
        *   How to handle the "processing" state?
            *   `pending_jobs`: Queue of job_ids.
            *   `completed_jobs`: Dict mapping job_id to result.
            *   `job_data`: Dict mapping job_id to original data.
        *   I need a way to mark jobs as completed. Since there's no specific `process_job` method in the requirements, I will assume the user might process them or I can provide a `process_all` helper for the implementation to be realistic, OR I can just implement the state management.
        *   Actually, looking at the example:
            ```python
            job_id = queue.add_job("job1", {"task": "process_data"})
            # After processing...
            result = queue.get_result("job1")
            ```
            This implies an external process or an internal mechanism that updates the result. To make the code runnable and demonstrable, I should probably include a `process` method that simulates the work, or simply manage the state so `get_result` works.
            Let's keep it simple: Store the job. To make `get_result` return something, I need a way to mark it completed. I will add a private helper or a `process` method to simulate the lifecycle.
            Actually, a common pattern for these interview-style tasks is to just manage the state. I will assume a `process_all` method exists to move jobs from queue to completed. Or, I can simulate processing inside `add_job` if I want, but that defeats the queue purpose.
            Best approach:
            1.  `self.queue`: Deque for FIFO order.
            2.  `self.results`: Dict for completed jobs.
            3.  `self.jobs`: Dict for original data (optional, but good for state).
            4.  I will add a `process_jobs` method to simulate the worker so the example logic holds up. Or, I can just make the class responsible for processing if I define a `process` method.
            Let's stick strictly to the requested methods for the *interface*, but implement internal logic.
            Wait, if I don't provide a way to mark a job as processed, `get_result` will always be `None`.
            I'll add a `process` method (even if not explicitly listed in the "methods" list, it's necessary for the queue to function as described "until they are processed") OR I can assume the user will manually update status? No, that's too complex.
            Let's add a `process` method to trigger execution.
            Actually, reading the prompt again: "Implement a basic job queue... Create a JobQueue class with the following methods...". It implies those are the main interface methods.
            To make the example work ("After processing..."), I should probably include a `process` method or similar to simulate the work.
            Let's add a `process` method that processes the next job in the queue.
            Wait, requirements say "with the following methods". It doesn't say "only".
            Okay, I will implement `add_job`, `get_result`, and a helper `process` method to simulate execution so the state changes.
            Actually, to be safe and strictly follow "Write only the Python code", I will implement the logic such that `get_result` checks the state. I'll add a `process` method to simulate the work.

            Refined Plan:
            1.  Import `deque` from `collections`.
            2.  Class `JobQueue`.
            3.  Init: `self._queue` (deque), `self._results` (dict), `self._job_ids` (set or just check results).
            4.  `add_job`: Validate ID, store data, add to queue, return ID.
            5.  `get_result`: Check if ID in results, return result, else None.
            6.  To make it work as a queue, I need a way to move items from `_queue` to `_results`. I'll add a `_process_next` or `process` method.
            7.  Wait, if I strictly follow "with the following methods", adding `process` might be seen as violating "only" if interpreted strictly, but usually it means "these methods must exist".
            8.  Better: I can simulate processing inside the class if I want, but usually a queue needs a consumer.
            9.  Let's create a `process` method to complete the lifecycle.

            Wait, looking at the example:
            `job_id = queue.add_job(...)`
            `# After processing...`
            `result = queue.get_result(...)`
            This implies the processing happens *after* add.
            I will add a `process_all` method to simulate the worker consuming the queue.

            Wait, I should check if I need to return the job_id in `add_job`. Yes.
            I should check if I need to ensure uniqueness. The input `job_id` is passed in. The prompt says "Each job has a unique job_id that is returned when added". It implies the input is the ID. I should probably check if it exists, or just trust the caller. I'll assume the caller provides unique IDs based on the signature `job_id: str`.

            Let's write the code.

            Structure:
            ```python
            from collections import deque

            class JobQueue:
                def __init__(self):
                    self._queue = deque()
                    self._results = {}

                def add_job(self, job_id: str, data: dict) -> str:
                    # Store job data and queue ID
                    # Actually, just queue ID and store data in a separate dict for retrieval if needed
                    # But get_result needs to return the result, not the input data.
                    # The prompt says "Get the result of a completed job".
                    # So I need to store the result.
                    self._queue.append(job_id)
                    self._results[job_id] = None # Pending state
                    return job_id

                def get_result(self, job_id: str) -> dict | None:
                    # Check if job_id is in results
                    # If processed, return result. If not, return None.
                    # How to know if processed?
                    # I need a mechanism to mark it processed.
                    pass

                # I need a way to process.
                # I'll add a private method or a public process method.
                # To keep it simple and compliant, I'll add a `process` method.
            ```

            Wait, if I add `process`, is it allowed? "Create a JobQueue class with the following methods". Usually implies these are the required public API. Adding others is fine.
            I'll add `process` to simulate the work.

            Wait, I need to make sure I don't overcomplicate.
            Let's stick to the requested methods and maybe assume the user handles the processing logic or I provide a `process` method.
            Actually, to make the code useful, I will add a `process` method.

            Wait, one detail: `get_result` returns `dict | None`.
            So the result must be a dict.
            When adding a job, `data` is a dict.
            Maybe the result is the same as data, or processed data.
            I'll simulate processing by just returning the data as the result for simplicity, or mark it as done.

            Implementation:
            1. `self._queue`: deque of job_ids.
            2. `self._completed`: dict of job_id -> result.
            3. `self._pending`: dict of job_id -> data (optional, maybe not needed for get_result).
            4. `add_job`: add to `_queue`, store ID. Return ID.
            5. `get_result`: check `_completed`.
            6. `process`: iterate `_queue`, pop, simulate work, store in `_completed`.

            Wait, if I add `process`, the example usage implies:
            1. Add job.
            2. Do something (process).
            3. Get result.
            So I will add a `process` method.

            Wait, strict reading: "Create a JobQueue class with the following methods: ...".
            It does not say "only".
            Okay.

            Let's refine the `add_job`. It should return the `job_id`.
            If the `job_id` is passed in, I just return it.
            If I need to generate one, I'd need to check uniqueness. The prompt says "return job_id", and the signature takes `job_id: str`. So the caller provides it.
            I will store the job state.

            Code structure:
            ```python
            from collections import deque
            import threading
            import time

            class JobQueue:
                def __init__(self):
                    self._queue = deque()
                    self._results = {}

                def add_job(self, job_id: str, data: dict) -> str:
                    if job_id in self._results and self._results[job_id] is not None:
                         # Check if exists?
                         pass
                    self._queue.append(job_id)
                    # Store data if needed, or just result placeholder
                    self._results[job_id] = None
                    return job_id

                def get_result(self, job_id: str) -> dict | None:
                    if job_id in self._results:
                        return self._results[job_id]
                    return None

                def process_all(self):
                    while self._queue:
                        job_id = self._queue.popleft()
                        # Simulate processing
                        self._results[job_id] = {"status": "completed", "data": self._results[job_id]}
            ```
            Wait, `self._results[job_id]` in `add_job` stores `None`. In `process_all`, I need the original data.
            So I need `self._job_data`.

            Revised:
            ```python
            from collections import deque

            class JobQueue:
                def __init__(self):
                    self._queue = deque()
                    self._results = {}
                    self._job_data = {}

                def add_job(self, job_id: str, data: dict) -> str:
                    self._queue.append(job_id)
                    self._job_data[job_id] = data
                    self._results[job_id] = None
                    return job_id

                def get_result(self, job_id: str) -> dict | None:
                    return self._results.get(job_id)

                def process(self):
                    if self._queue:
                        job_id = self._queue.popleft()
                        data = self._job_data.get(job_id)
                        self._results[job_id] = {"status": "processed", "input": data}
            ```
            Wait, the requirement says "Jobs should be processed in FIFO".
            And "The queue should store jobs internally until they are processed".
            The example shows `add_job` then `get_result`.
            I will add a `process` method to simulate the execution so the example makes sense.

            Wait, I should check if I can do it without `process`.
            If I don't have `process`, `get_result` will always be `None` unless I process it.
            I'll add a `process` method to be safe.

            One more thing: `get_result` return type `dict | None`.
            So I must return a dict.

            Final check on constraints:
            - Python code only.
            - No explanations.
            - `JobQueue` class.
            - `add_job` and `get_result`.
            - FIFO.
            - Unique ID.

            I will write the code now.

            Wait, I should ensure I don't use external libraries if not needed. `collections.deque` is standard.
            I'll add a `process` method to make it functional.

            Wait, looking at the example usage again:
            ```python
            queue = JobQueue()
            job_id = queue.add_job("job1", {"task": "process_data"})
            # After processing...
            result = queue.get_result("job1")
            ```
            The comment `# After processing...` implies the processing happens between add and get.
            So I must provide a way to process.
            I'll add a `process` method.

            Wait, I'll make sure the code is clean.

```python
from collections import deque
from typing import Dict, Optional

class JobQueue:
    def __init__(self):
        self._queue = deque()
        self._results: Dict[str, Optional[dict]] = {}

    def add_job(self, job_id: str, data: dict) -> str:
        self._queue.append(job_id)
        self._results[job_id] = None  # Mark as pending
        return job_id

    def get_result(self, job_id: str) -> Optional[dict]:
        return self._results.get(job_id)

    def process(self):
        if self._queue:
            job_id = self._queue.popleft()
            self._results[job_id] = {"status": "completed", "data": "processed"}
```
Wait, `get_result` signature in requirement: `get_result(job_id: str) -> dict | None`.
Python 3.10+ union syntax `dict | None` or `Optional[dict]`. I'll use `dict | None` to match the prompt text exactly if possible, or `Optional`. The prompt uses `dict | None` in the description text. I will use `dict | None` in type hints.

Also, I need to make sure `add_job` returns the `job_id`.
The prompt says "return job_id".

One detail: "Each job has a unique job_id that is returned when added".
Since `job_id` is an input parameter in `add_job`, I just return it.
If I need to ensure uniqueness, I might need to check. But the prompt implies the caller provides it or I manage it. Given the signature `job_id: str`, the caller provides it. I will assume uniqueness is handled by caller or just store it. I'll assume the provided ID is the one returned.

Wait, I should probably store the original data so I can process it?
The `process` method in my draft just returns a dummy result.
To make it realistic, I should store the data passed to `add_job`.
I will add a `self._job_data` dict.

Revised code plan:
1. Import `deque`.
2. Class `JobQueue`.
3. `__init__`: `self._queue`, `self._results`, `self._data`.
4. `add_job`: Store in `self._queue`, `self._data`, `self._results` (init to None). Return `job_id`.
5. `get_result`: Return `self._results[job_id]`.
6. `process` (helper): Pop from `self._queue`, compute result, store in `self._results`.

Wait, if I add `process`, does it violate "with the following methods"? No, it's an implementation detail to make it work.
However, to be strictly compliant with "Implement a basic job queue... with the following methods", I should ensure those methods work correctly.
If I don't provide a `process` method, the queue never changes state.
I will include a `process` method to simulate the lifecycle.

Actually, to keep it minimal and focused on the requested methods, I can simulate processing inside `get_result`?
No, "until they are processed" implies an external trigger or method.
I will add `process`.

Let's refine the type hints to match the prompt exactly (`dict | None`).

One detail: `get_result` returns `dict | None`.
If the job is completed, return dict. If not, None.
So I need to distinguish between "pending" and "completed".
My `self._results` stores `None` for pending.
So `get_result` returns `None` if not completed.
This works.

Wait, what if the result is actually `None`?
The requirement says `-> dict | None`.
If the result is a dict, return it.
If the job is pending, return `None`.
This is ambiguous if a valid result can be `None` (but result type is `dict`).
So `None` means pending.

Okay, ready to write.

```python
from collections import deque
from typing import Dict, Optional

class JobQueue:
    def __init__(self):
        self._queue = deque()
        self._results: Dict[str, Optional[dict]] = {}
        self._job_data: Dict[str, dict] = {}

    def add_job(self, job_id: str, data: dict) -> str:
        self._queue.append(job_id)
        self._job_data[job_id] = data
        self._results[job_id] = None
        return job_id

    def get_result(self, job_id: str) -> dict | None:
        return self._results.get(job_id)

    def process(self):
        if self._queue:
            job_id = self._queue.popleft()
            # Simulate processing
            self._results[job_id] = {"status": "completed", "data": self._job_data.get(job_id)}
```
Wait, I should check if I need to import `Dict` and `Optional` if I use `dict | None`.
`dict | None` is valid in Python 3.10+.
To be safe and compatible, I can use `Optional[dict]` or just `dict | None`.
The prompt uses `dict | None` in the text. I will use that in the code signature.
I'll avoid imports if possible to keep it simple, but `deque` needs import.
I'll stick to standard imports.

One more check: `add_job` signature `job_id: str, data: dict) -> str`.
`get_result` signature `job_id: str) -> dict | None`.
I will ensure the code matches this.

Wait, I should check if `process` is required.
If I don't include `process`, the example usage `# After processing...` implies the user does something.
If I don't provide `process`, the user can't trigger it.
So `process` is necessary for the implementation to be functional.
I'll include it.

Wait, I'll remove `process` if I want to strictly follow "with the following methods". But a queue without a way to consume it is useless.
I'll add a `process` method. It's a standard part of a queue implementation (consumer).
Actually, I can make `get_result` check if the job is done, but how does it get done?
I'll add `process`.

Wait, I can just implement the logic to simulate processing inside `add_job`?
No, that's not a queue.
I'll add `process`.

Wait, I should make sure the code is complete.
I'll write the code now.

Wait, I'll remove the `process` method if I want to be strictly minimal, but then the example doesn't work well.
I'll keep `process` because it's standard for a "Job Queue" to have a worker/process method.
Actually, I'll add a `process_all` method to be explicit.
Okay, I'll just add `process`.

Wait, I should check the imports.
`from collections import deque`
I will use `dict | None` for type hinting.

One detail: "Each job has a unique job_id that is returned when added".
If I pass `job_id` in `add_job`, I return it.
If I need to generate it, I'd need logic.
The signature `add_job(job_id: str, ...)` implies the caller provides it.
So I just return the input `job_id`.

Okay, final check on code.
```python
from collections import deque

class JobQueue:
    def __init__(self):
        self._queue = deque()
        self._results = {}
        self._data = {}

    def add_job(self, job_id: str, data: dict) -> str:
        self._queue.append(job_id)
        self._data[job_id] = data
        self._results[job_id] = None
        return job_id

    def get_result(self, job_id: str) -> dict | None:
        return self._results.get(job_id)

    def process(self):
        if self._queue:
            job_id = self._queue.popleft()
            self._results[job_id] = {"status": "completed", "data": self._data.get(job_id)}
```
This looks correct. I will remove comments and extra fluff.

Wait, I should check if I need to handle the case where `job_id` is already in queue?
The prompt doesn't specify. I'll assume valid unique IDs.

One detail: `get_result` return type `dict | None`.
If I use `self._results.get(job_id)`, it returns the value stored.
If stored `None`, returns `None`.
If stored dict, returns dict.
This matches the requirement.

I'll finalize the code.
I will add `process` method to make it functional.
I will ensure imports are correct.
I will ensure type hints match the prompt.

Wait, I should check if `dict | None` requires Python 3.10.
Yes. But it's standard now.
I will use it.

One more thing: The prompt asks for "Write only the Python code, no explanations."
So I will output the code block.

One detail: `job_id` uniqueness.
If the same `job_id` is added twice, what happens?
I'll just append to queue. It might process twice.
The prompt says "Each job has a unique job_id". This is a constraint on the data, not necessarily enforced by the class, but good to know.
I won't enforce it strictly to keep it simple, just store it.

Wait, I'll make sure `process` is a method of the class.
Yes.

Okay, generating code.

</reasoning_content>

<content>
```python
from collections import deque
from typing import Dict, Optional

class JobQueue:
    def __init__(self):
        self._queue = deque()
        self._results: Dict[str, Optional[dict]] = {}
        self._job_data: Dict[str, dict] = {}

    def add_job(self, job_id: str, data: dict) -> str:
        self._queue.append(job_id)
        self._job_data[job_id] = data
        self._results[job_id] = None
        return job_id

    def get_result(self, job_id: str) -> dict | None:
        return self._results.get(job_id)

    def process(self):
        if self._queue:
            job_id = self._queue.popleft()
            self._results[job_id] = {"status": "completed", "input_data": self._job_data.get(job_id)}
```
</content>