3a0be7261e
Verkstaden har redan sina avtal: Volvo-verkstaden har VIDA, VAG-verkstaden har erWin, den fria verkstaden har en fordonsdataleverantör. Kopplingarna konfigureras därför av kunden själv under Inställningar, med sina egna uppgifter — vi tillhandahåller ramen, inte kontot. Uppgifterna når aldrig webbläsaren. De krypteras med AES-256-GCM (INTEGRATION_NYCKEL) innan de skrivs till tabellen integrationer, och API:t returnerar hemliga fält maskerade. Alla uppslag görs av servern. Saknas krypteringsnyckeln sparas ingenting alls — 503 och en förklaring i gränssnittet i stället för klartext i databasen. Endast systemadministratören hanterar uppgifterna; kopplingarna är organisationsknutna som all annan ärendedata. Leverantörer är data, inte kod: URL-mall, autentiseringstyp (bearer/header/basic/query) och svarsmappning beskrivs i services/plattform/integrationer.json, utbytbar via ConfigMap (INTEGRATIONER_FIL). Nya märken läggs till utan att appen byggs om. Varje uppslag skriver senast_testad och senaste_status på kopplingen, så ett utgånget abonnemang syns i inställningarna i stället för att ge tysta tomma svar. Två latenta krascher hittade av klicktestet och åtgärdade: TextFalt och UNDANTAGSORSAKER användes utan import. vite build typkontrollerar inte, så de passerade bygget — därav nya npm-skriptet typkontroll, nu del av verifieringen. Verifierat: 80 vitest-tester, typkontroll, eslint, OpenAPI-validering, integrationstest mot riktig Postgres (rollstyrning, kryptering i vila, maskering, organisationsisolering, fail closed, borttagning) och klickgenomgång mot en körande plattform. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012EQg3rJsrQ1ZNTvkzmQAtt
102 lines
4.2 KiB
Markdown
102 lines
4.2 KiB
Markdown
# Märkesspecifika kopplingar
|
|
|
|
Verkstaden har redan sina avtal. Volvo-verkstaden har VIDA, VAG-verkstaden
|
|
har erWin, den fria verkstaden har en fordonsdataleverantör. Ingen av dem
|
|
vill att vi ska vara mellanhand för deras abonnemang — och ingen av dem
|
|
har samma uppsättning som grannen.
|
|
|
|
Därför konfigurerar **kunden själv** sina kopplingar under
|
|
**Inställningar → Märkesspecifika kopplingar**, med sina egna credentials.
|
|
Vi tillhandahåller ramen, inte kontot.
|
|
|
|
## Principer
|
|
|
|
**Uppgifterna når aldrig webbläsaren.** Samma regel som för
|
|
plattformens egna API-nycklar: hemligheter bor på servern. Credentials
|
|
krypteras med AES-256-GCM innan de skrivs till databasen, och API:t
|
|
returnerar hemliga fält maskerade (`••••3456`). Klienten kan se *att* en
|
|
koppling finns och när den senast fungerade — aldrig vad nyckeln är.
|
|
|
|
**Alla uppslag görs av servern.** Klienten skickar en identifierare
|
|
(VIN eller regnr); servern hämtar uppgifterna, dekrypterar dem i minnet,
|
|
anropar leverantören och returnerar bara de mappade fordonsfälten.
|
|
|
|
**Fail closed.** Saknas krypteringsnyckeln (`INTEGRATION_NYCKEL`) sparas
|
|
ingenting — API:t svarar 503 och inställningssidan förklarar varför.
|
|
Alternativet, att lagra i klartext "så länge", finns inte.
|
|
|
|
**Endast systemadministratören.** Att lägga till, ändra och ta bort
|
|
kopplingar kräver rollen `admin`. Teknikern kan läsa registret över
|
|
tillgängliga leverantörer (annars kan inställningssidan inte visa dem)
|
|
men aldrig någon organisations uppgifter.
|
|
|
|
**Organisationsknutet.** Kopplingarna hör till organisationen, precis
|
|
som ärendedata. Ingen tenant ser en annans.
|
|
|
|
## Leverantörer är data, inte kod
|
|
|
|
Registret ligger i `services/plattform/integrationer.json` och kan bytas
|
|
mot en ConfigMap-mount via `INTEGRATIONER_FIL`. En leverantör beskrivs
|
|
helt deklarativt:
|
|
|
|
```json
|
|
{
|
|
"id": "volvo_vida",
|
|
"namn": "Volvo VIDA",
|
|
"falt": [
|
|
{ "nyckel": "bas_url", "etikett": "Bas-URL (använd {vin} som platshållare)", "hemlig": false },
|
|
{ "nyckel": "api_nyckel", "etikett": "API-nyckel", "hemlig": true }
|
|
],
|
|
"uppslag": {
|
|
"urlFalt": "bas_url",
|
|
"auth": "header",
|
|
"authHeader": "X-Api-Key",
|
|
"authFalt": "api_nyckel",
|
|
"svarsfalt": { "marke": "make", "modell": "model", "arsmodell": "year" }
|
|
}
|
|
}
|
|
```
|
|
|
|
* `falt` — vad administratören ska fylla i. `hemlig: true` styr både
|
|
kryptering och maskering.
|
|
* `uppslag.auth` — `bearer`, `header`, `basic` eller `query`. Inga
|
|
leverantörsspecifika kodgrenar; all variation ligger i registret.
|
|
* `svarsfalt` — mappning från leverantörens JSON (punktnotation stöds)
|
|
till våra fordonsfält.
|
|
* `nyckeltyp: "regnr"` — uppslaget sker på registreringsnummer i stället
|
|
för VIN. `{vin}`/`{regnr}` i URL-mallen ersätts URL-kodat.
|
|
|
|
Ett nytt märke läggs alltså till genom att beskriva det — inte genom att
|
|
bygga om applikationen.
|
|
|
|
## Vad ett uppslag gör och inte gör
|
|
|
|
Uppslaget fyller i **fordonsbeskrivningen** (märke, modell, årsmodell,
|
|
motor, växellåda). Det är kontextdata, inte evidens: ett svar från en
|
|
leverantör är aldrig en utförd kontroll och räknas inte i
|
|
[evidensmotorn](evidensmotor.md). Returnerar leverantören inga kända fält
|
|
säger systemet det rakt ut i stället för att visa tomma rader.
|
|
|
|
Varje uppslag skriver `senast_testad` och `senaste_status` på
|
|
kopplingen. Ett utgånget abonnemang syns därför i inställningarna som ett
|
|
felmeddelande från leverantören, inte som tysta tomma svar.
|
|
|
|
## API
|
|
|
|
| Väg | Metod | Roll | Vad |
|
|
| --- | --- | --- | --- |
|
|
| `/api/integrationer/leverantorer` | GET | inloggad | Registret (fältdefinitioner, inga uppgifter) |
|
|
| `/api/integrationer` | GET | admin | Organisationens kopplingar, hemligheter maskerade |
|
|
| `/api/integrationer` | POST | admin | Spara/uppdatera credentials (krypteras) |
|
|
| `/api/integrationer/{leverantor}` | DELETE | admin | Ta bort |
|
|
| `/api/integrationer/{leverantor}/uppslag` | POST | inloggad | Slå upp VIN/regnr via servern |
|
|
|
|
Fullständigt dokumenterat i `services/plattform/openapi.yaml`.
|
|
|
|
## Drift
|
|
|
|
`INTEGRATION_NYCKEL` är 32 byte hex eller base64 (`openssl rand -hex 32`),
|
|
levererad via secret:en `felsokning-hemligheter` — se
|
|
[DRIFT.md](../DRIFT.md). Byts nyckeln måste kopplingarna sparas om;
|
|
tjänsten visar då inga värden i stället för att gissa.
|