> ## Documentation Index
> Fetch the complete documentation index at: https://docs.a7manager.se/llms.txt
> Use this file to discover all available pages before exploring further.

# Maintainer integration

> How submitted defect reports are delivered to the maintainer's system, and what an integration needs.

Defects reported in the [reporter app](https://docs.a7manager.se/pages/reporter-app.md) belong in the maintainer's own
system, where the work is planned and closed. The platform delivers each submitted report
there and links its own `defect` row to the record the maintainer creates. One maintainer
system is configured per project.

## Delivery model

```mermaid theme={null}
flowchart LR
    A[Reporter app] -->|submit| B[Backend]
    B -->|one transaction| C[(defect row<br/>APP- identifier)]
    B -->|one transaction| D[(Outbox row<br/>PENDING)]
    E[drain-outbox job<br/>every 5 minutes] --> D
    E --> F[Adapter]
    F --> G[Maintainer's system]
    G -->|external identifier| E
    E -->|rewrite identifier| C
    H[Daily defect file] -->|upsert by identifier| C
```

**1. Submit writes locally**

Submitting creates the `defect` row and an **outbox** row in the same database
transaction. The reporter never waits for the maintainer's system, and a report is
never lost because that system was unavailable. The report is read-only from then on.

**2. The job delivers**

The `drain-outbox` job runs every five minutes. It picks up due outbox rows and hands
each one to the project's **adapter**, the connector that knows the maintainer
system's API.

**3. The identifier is linked**

When the maintainer's system accepts the report and returns its own identifier, the
`defect` row's `external_system_id` is changed from `APP-…` to that identifier, and the
report becomes `SYNCED`.

**4. The import takes over**

The maintainer's daily [defect file](https://docs.a7manager.se/data/files/defects.md) includes the new record. The
import matches it by `external_system_id` and updates the existing row instead of
creating a second one. From then on the defect is maintained by the import like any
other.

## Adapters

An adapter translates the platform's neutral defect record into one call to the
maintainer's system, and reports back success with an identifier, or failure with a reason
and whether retrying can help.

| Adapter | Behaviour |
| - | - |
| `log` | Records the report in the platform's log and sends nothing. Returns no identifier |

`log` is the only adapter available today. It is also the adapter used whenever a project
has no enabled integration, so reporting works before an integration exists. Adapters for
specific maintainer systems are added per customer.

Disabling the integration pauses delivery: rows for that adapter stay pending, Retry answers
`INTEGRATION_DISABLED`, and delivery resumes on the next run after the integration is
enabled again. Only reports submitted while no integration is enabled go to `log`.

## What is sent

Every adapter receives the same record, so the content of a delivery does not depend on the
target system.

| Group | Fields |
| - | - |
| Identity | Report id, defect id, the defect's `APP-` identifier, project id |
| Vehicle | Vehicle number, the vehicle's external identifier, vehicle type code |
| Component | Serial number and external identifier, when the report names a slot or a serial |
| Product group | Code, name, and the path of codes from the root of the tree |
| Position | Slot position and label; location code and label |
| Classification | Code and label for severity, category, consequence and fault indication |
| Description | Title (at most 40 characters), description, defect time, delay in minutes |
| Reporter | Name, email, submission time, report language |

When the report has a slot but no serial, the component mounted in that slot at the moment
of submission is used.

## Delivery states

```mermaid theme={null}
stateDiagram-v2
    [*] --> PENDING: submit
    PENDING --> IN_PROGRESS: picked up
    IN_PROGRESS --> SENT: accepted
    IN_PROGRESS --> PENDING: retryable failure
    IN_PROGRESS --> FAILED: final failure
    FAILED --> PENDING: retry
    SENT --> [*]
```

### Retry rules

| Situation | Outcome |
| - | - |
| Connection failure, timeout, or an error the adapter marks retryable | Back to `PENDING`. The next attempt is due 1, 5, 15 and 60 minutes after the first four failures, picked up by the next job run |
| Fifth failed attempt | `FAILED` |
| Authentication failure, missing credential, invalid configuration | `FAILED` at once; retrying cannot help until the cause is fixed |
| Attempt interrupted, for example by a restart | Returned to `PENDING` after 10 minutes, counted as an attempt |
| Returned identifier already used by another defect in the project | `FAILED`; the maintainer already holds that record |

A Project Admin can **retry** a pending or failed delivery from
[Reported Defects](https://docs.a7manager.se/pages/reported-defects.md). Retry resets the attempt count and delivers once,
immediately. It is refused once the maintainer has returned an identifier, because sending
again would create a duplicate there.

Every attempt carries a **correlation id**, the same across all attempts for one report, so
an attempt can be traced in both systems' logs.

## Credentials

Credentials are never stored in the database or shown in the application. The settings
page lists only the **names** of the secrets an adapter needs.

In the shared environments they live in **Azure Key Vault**, one secret per project,
adapter and credential, named `project-<project id>-<adapter>-<name>` in lower case with
hyphens for underscores. The backend reads
them with its managed identity and caches each value for five minutes, so a rotated secret
takes effect within that time. Local development reads them from environment variables
instead.

The non-secret settings of an adapter, such as an endpoint address, are saved on the
project's integration and validated against the adapter's own schema.

## What the customer provides

**1. The system**

Which maintenance system the maintainer uses, and the API through which it accepts new
defects or notifications.

**2. The endpoint**

The address of that API for each environment, and network access from the platform to
it.

**3. Credentials**

An account or client for the platform, with permission to create records and nothing
more. The values are placed in Key Vault by the operator.

**4. Aligned code lists**

Severity, category, consequence, fault indication and location values taken from the
maintainer system's own catalogs. The platform sends the **code**; see
[Code lists](https://docs.a7manager.se/pages/reporting-config.md#code-lists).

**5. The identifier in the daily file**

The maintainer's daily defect file must carry the identifier their system returned, so
the import can take over the row.

Once configured, **Test connection** on Project Config ▸ Reporting checks the settings and
credentials against the maintainer's system before the integration is enabled.

## Scheduled jobs

| Job | Schedule (UTC) | Does |
| - | - | - |
| `drain-outbox` | Every 5 minutes | Delivers due outbox rows |
| `archive-reports` | Daily at 02:15 | Archives drafts with no activity for 30 days |

## Tables

> **[Field reference](https://docs.a7manager.se/data/tables/reporting.md)**
>
> `integrations_maintainer_integration` and `integrations_outbound_sync`.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.