openapi: 3.0.3 info: title: Guidad Felsökning – plattforms-API version: 1.0.0 description: | API-first-ytan för Guidad Felsökning: autentisering, organisationens användare, ärenden med append-only händelselogg, arbetsledaröversikt, publik Live Share-delning samt AI-orkestern. **Händelseloggen är append-only.** Det finns inga update- eller delete-operationer — historik kan aldrig ändras eller raderas, vilket även garanteras av databastriggers. En händelse med redan känt `id` ignoreras tyst (idempotent synk). **Multi-tenant.** All ärendedata är organisationsknuten. Ett ärende i en annan organisation ger `404`, som om det inte fanns. Specen serveras live av tjänsten på `GET /api/openapi.yaml`. servers: - url: https://app.exempel.se description: Klustrets ingress (ersätt med er domän) tags: - name: Auth - name: Användare - name: Ärenden - name: Översikt - name: Delning - name: AI - name: Integrationer - name: Drift paths: /halsa: get: tags: [Drift] summary: Hälsokontroll security: [] responses: "200": description: Tjänsten svarar. content: application/json: schema: type: object properties: status: { type: string, example: ok } /api/openapi.yaml: get: tags: [Drift] summary: Denna specifikation security: [] responses: "200": description: OpenAPI-specen i YAML. content: application/yaml: schema: { type: string } /api/auth/registrera: post: tags: [Auth] summary: Skapa organisation + systemadministratör description: > Registrerar en ny organisation (tenant) och dess första användare, som blir systemadministratör. Kan stängas av driften (REGISTRERING_OPPEN=false → 403). security: [] requestBody: required: true content: application/json: schema: type: object required: [epost, losenord, namn, organisation] properties: epost: { type: string, format: email } losenord: { type: string, minLength: 8 } namn: { type: string } organisation: { type: string } responses: "200": { $ref: "#/components/responses/Inloggad" } "400": { $ref: "#/components/responses/Fel" } "403": { $ref: "#/components/responses/Fel" } "409": { $ref: "#/components/responses/Fel" } /api/auth/logga-in: post: tags: [Auth] summary: Logga in description: > Takt-begränsad i databasen, så spärren håller bakom flera repliker: 10 misslyckade försök per konto och 30 per källadress inom 15 minuter ger 429. Spärren gäller kontot även vid rätt lösenord — annars vore den meningslös. Ett avstängt konto svarar 403. security: [] requestBody: required: true content: application/json: schema: type: object required: [epost, losenord] properties: epost: { type: string, format: email } losenord: { type: string } responses: "200": { $ref: "#/components/responses/Inloggad" } "401": { $ref: "#/components/responses/Fel" } "403": description: Kontot är avstängt. content: application/json: schema: { $ref: "#/components/schemas/Fel" } "429": description: För många misslyckade försök. content: application/json: schema: { $ref: "#/components/schemas/Fel" } /api/anvandare: get: tags: [Användare] summary: Lista organisationens användare description: Kräver rollen `admin` eller `arbetsledare`. responses: "200": description: Användare i den egna organisationen. content: application/json: schema: type: object properties: anvandare: type: array items: { $ref: "#/components/schemas/Anvandare" } "401": { $ref: "#/components/responses/Fel" } "403": { $ref: "#/components/responses/Fel" } post: tags: [Användare] summary: Skapa användare i den egna organisationen description: Kräver rollen `admin`. requestBody: required: true content: application/json: schema: type: object required: [epost, losenord, namn, roll] properties: epost: { type: string, format: email } losenord: { type: string, minLength: 8 } namn: { type: string } roll: { $ref: "#/components/schemas/Roll" } responses: "200": description: Den skapade användaren. content: application/json: schema: { $ref: "#/components/schemas/Anvandare" } "400": { $ref: "#/components/responses/Fel" } "401": { $ref: "#/components/responses/Fel" } "403": { $ref: "#/components/responses/Fel" } "409": { $ref: "#/components/responses/Fel" } /api/ecm/regler: get: tags: [Drift] summary: ECM Knowledge Library — aktuellt regelpaket description: > Serverdistribuerat, versionerat regelpaket (compliance-regler per ärendetyp, orsakskategorier, evidenskällor, undantagsorsaker). Uppdateras i driften utan appändring; klienten cachar och faller tillbaka till sitt inbyggda standardpaket offline. responses: "200": description: Regelpaketet. content: application/json: schema: type: object properties: version: { type: string } arendetypRegler: { type: object, additionalProperties: true } undantagsorsaker: { type: array, items: { type: string } } orsakskategorier: { type: array, items: { type: string } } underlagskallor: { type: array, items: { type: string } } /api/fordon/{identifierare}/historik: get: tags: [Ärenden] summary: Fordonshistorik — tidigare ärenden på samma objekt description: > Organisationens tidigare ärenden där objektet (regnr/VIN) matchar, med dokumenterade felorsaker. Underlag för pre-diagnostikens historiksteg och orsakskedjan. parameters: - name: identifierare in: path required: true schema: { type: string } responses: "200": description: Tidigare ärenden (senaste 20). content: application/json: schema: type: object properties: arenden: type: array items: type: object properties: id: { type: string } nummer: { type: integer } skapad: { type: string, format: date-time } avslutat: { type: boolean } felbeskrivning: { type: string, nullable: true } felorsaker: { type: array, items: { type: object, additionalProperties: true } } "401": { $ref: "#/components/responses/Fel" } /api/statistik/felorsaker: get: tags: [Översikt] summary: Felorsaksstatistik per orsakskategori description: > Flottdata ur dokumenterade felorsaksanalyser i organisationen. Kräver rollen `arbetsledare` eller `admin`. responses: "200": description: Antal per orsakskategori, fallande. content: application/json: schema: type: object properties: orsaker: type: array items: type: object properties: orsak: { type: string } antal: { type: integer } "401": { $ref: "#/components/responses/Fel" } "403": { $ref: "#/components/responses/Fel" } /api/anvandare/{anvandarId}/avaktivera: post: tags: [Användare] summary: Stäng av ett konto description: > Kräver rollen `admin` och att användaren tillhör samma organisation. Avstängningen höjer kontots token-version, så **pågående sessioner upphör omedelbart** — annars vore den verkningslös tills utfärdade tokens gick ut. Ett konto kan inte stänga av sig självt. parameters: - name: anvandarId in: path required: true schema: { type: string, format: uuid } responses: "200": description: Kontot är avstängt. content: application/json: schema: type: object properties: id: { type: string, format: uuid } namn: { type: string } aktiv: { type: boolean } "400": description: Försök att stänga av sitt eget konto. content: application/json: schema: { $ref: "#/components/schemas/Fel" } "401": { $ref: "#/components/responses/Fel" } "403": { $ref: "#/components/responses/Fel" } "404": { $ref: "#/components/responses/Fel" } /api/anvandare/{anvandarId}/aktivera: post: tags: [Användare] summary: Öppna ett avstängt konto description: > Kräver rollen `admin`. Kontot kan logga in igen, men tokens som återkallades vid avstängningen förblir ogiltiga. parameters: - name: anvandarId in: path required: true schema: { type: string, format: uuid } responses: "200": { description: Kontot är öppnat. } "401": { $ref: "#/components/responses/Fel" } "403": { $ref: "#/components/responses/Fel" } "404": { $ref: "#/components/responses/Fel" } /api/auth/logga-ut-alla: post: tags: [Auth] summary: Logga ut på alla enheter description: > Höjer den egna token-versionen, vilket gör samtliga utfärdade tokens för kontot ogiltiga direkt — vägen ut när en enhet tappats bort. responses: "200": { description: Alla sessioner är avslutade. } "401": { $ref: "#/components/responses/Fel" } /api/arenden/{arendeId}/bilagor: post: tags: [Ärenden] summary: Ladda upp en bilaga description: > Foton, videoklipp och instrumentbilder. Kroppen är råa bytes och `Content-Type` anger mediatypen — endast bild och video tas emot. Servern beräknar innehållets SHA-256 och returnerar en referens som ska läggas i händelsen; **hashen hamnar därmed i den append-only-skyddade loggen**, så en utbytt bild går att upptäcka. Innehållsadresserat: samma innehåll lagras en gång. parameters: - name: arendeId in: path required: true schema: { type: string } requestBody: required: true content: image/jpeg: { schema: { type: string, format: binary } } image/png: { schema: { type: string, format: binary } } image/webp: { schema: { type: string, format: binary } } video/mp4: { schema: { type: string, format: binary } } video/webm: { schema: { type: string, format: binary } } responses: "200": description: Referensen att spara i händelsen. content: application/json: schema: type: object properties: id: { type: string } hash: { type: string, description: "SHA-256 av innehållet, hex." } mediatyp: { type: string } storlek: { type: integer } "400": { $ref: "#/components/responses/Fel" } "401": { $ref: "#/components/responses/Fel" } "404": { $ref: "#/components/responses/Fel" } "413": description: Bilagan är större än 32 MB. content: application/json: schema: { $ref: "#/components/schemas/Fel" } "415": description: Endast bilder och videoklipp tas emot. content: application/json: schema: { $ref: "#/components/schemas/Fel" } /api/bilagor/{bilagaId}: get: tags: [Ärenden] summary: Hämta en bilaga description: > Organisationsknuten. Innehållet kontrolleras mot hashen innan det lämnas ut — stämmer det inte svarar tjänsten 409 i stället för att visa en bild som kan ha bytts ut. parameters: - name: bilagaId in: path required: true schema: { type: string } responses: "200": description: Innehållet. content: application/octet-stream: schema: { type: string, format: binary } "401": { $ref: "#/components/responses/Fel" } "404": { $ref: "#/components/responses/Fel" } "409": description: Innehållet stämmer inte med hashen i loggen. content: application/json: schema: { $ref: "#/components/schemas/Fel" } /api/delad/{delningskod}/bilagor/{bilagaId}: get: tags: [Delning] summary: Hämta en bilaga via delningslänk description: > Samma filtrering som händelserna: bilagan lämnas bara ut om händelsen den hör till är synlig på delningens nivå. En bild som hör till en intern händelsetyp — t.ex. den skannade arbetsordern — nås alltså aldrig via kundlänken. security: [] parameters: - name: delningskod in: path required: true schema: { type: string } - name: bilagaId in: path required: true schema: { type: string } responses: "200": description: Innehållet. content: application/octet-stream: schema: { type: string, format: binary } "404": { $ref: "#/components/responses/Fel" } "409": { $ref: "#/components/responses/Fel" } /api/integrationer/leverantorer: get: tags: [Integrationer] summary: Registret över märkesspecifika kopplingar description: > Leverantörer är data, inte kod: registret läses ur `integrationer.json` (eller filen i `INTEGRATIONER_FIL`) och kan bytas via ConfigMap utan att applikationen byggs om. Innehåller endast fältdefinitioner — aldrig någon organisations uppgifter. responses: "200": description: Leverantörsdefinitioner. content: application/json: schema: type: object properties: version: { type: string } leverantorer: type: array items: type: object properties: id: { type: string } namn: { type: string } beskrivning: { type: string } nyckeltyp: type: string enum: [vin, regnr] description: Vad uppslaget sker på. Utelämnat betyder VIN. falt: type: array items: type: object properties: nyckel: { type: string } etikett: { type: string } hemlig: type: boolean description: > Hemliga fält maskeras alltid i svar och visas aldrig igen efter sparande. "401": { $ref: "#/components/responses/Fel" } /api/integrationer: get: tags: [Integrationer] summary: Organisationens konfigurerade kopplingar description: > Kräver rollen `admin`. Uppgifterna lagras krypterade (AES-256-GCM) och returneras alltid maskerade — hemliga värden lämnar aldrig servern i klartext. responses: "200": description: Konfigurerade kopplingar med maskerade uppgifter. content: application/json: schema: type: object properties: krypteringKonfigurerad: type: boolean description: Falskt om `INTEGRATION_NYCKEL` saknas — då kan inget sparas. integrationer: type: array items: type: object properties: leverantor: { type: string } namn: { type: string } aktiv: { type: boolean } uppdaterad: { type: string, format: date-time } senast_testad: { type: string, format: date-time, nullable: true } senaste_status: { type: string, nullable: true } uppgifter: type: object additionalProperties: { type: string } "401": { $ref: "#/components/responses/Fel" } "403": { $ref: "#/components/responses/Fel" } post: tags: [Integrationer] summary: Spara eller uppdatera en kopplings uppgifter description: > Kräver rollen `admin`. Endast leverantörens definierade fält sparas och samtliga måste fyllas i. Uppgifterna krypteras innan de skrivs. Ett sparande nollställer tidigare testresultat. requestBody: required: true content: application/json: schema: type: object required: [leverantor, uppgifter] properties: leverantor: { type: string } aktiv: { type: boolean, default: true } uppgifter: type: object additionalProperties: { type: string } responses: "200": { description: Sparad. } "400": { $ref: "#/components/responses/Fel" } "401": { $ref: "#/components/responses/Fel" } "403": { $ref: "#/components/responses/Fel" } "503": description: Kryptering är inte konfigurerad (`INTEGRATION_NYCKEL` saknas). content: application/json: schema: { $ref: "#/components/schemas/Fel" } /api/integrationer/{leverantor}: delete: tags: [Integrationer] summary: Ta bort en kopplings uppgifter description: Kräver rollen `admin`. parameters: - name: leverantor in: path required: true schema: { type: string } responses: "200": { description: Borttagen. } "401": { $ref: "#/components/responses/Fel" } "403": { $ref: "#/components/responses/Fel" } /api/integrationer/{leverantor}/uppslag: post: tags: [Integrationer] summary: Slå upp ett fordon hos leverantören description: > Anropet görs alltid av servern — kundens leverantörsnycklar når aldrig webbläsaren. Svaret mappas till våra fält enligt registrets `svarsfalt`. Resultatet skrivs som kopplingens senaste teststatus. parameters: - name: leverantor in: path required: true schema: { type: string } requestBody: required: true content: application/json: schema: type: object required: [identifierare] properties: identifierare: type: string description: VIN eller registreringsnummer beroende på leverantörens `nyckeltyp`. responses: "200": description: Fordonsuppgifter från leverantören. content: application/json: schema: type: object properties: fordon: type: object additionalProperties: { type: string } "400": { $ref: "#/components/responses/Fel" } "401": { $ref: "#/components/responses/Fel" } "404": description: Kopplingen är inte konfigurerad för organisationen. content: application/json: schema: { $ref: "#/components/schemas/Fel" } "502": description: Leverantören svarade med fel eller inga kända fält. content: application/json: schema: { $ref: "#/components/schemas/Fel" } "503": description: Kryptering är inte konfigurerad. content: application/json: schema: { $ref: "#/components/schemas/Fel" } /api/delad/{delningskod}/beslut: post: tags: [Delning] summary: Kundens besked på ett åtgärdsförslag description: > Den enda skrivande publika vägen. Endast delningar på **kundnivå** som inte återkallats får svara, det måste finnas ett åtgärdsförslag, och **ett besked per ärende** — svaret kan inte ändras i efterhand. Takt-begränsad per delningskod. Beskedet loggas som `kundbeslut` med kanal `Delningslänk`. security: [] parameters: - name: delningskod in: path required: true schema: { type: string } requestBody: required: true content: application/json: schema: type: object required: [beslut] properties: beslut: { type: string, enum: [godkant, avbojt, delvis] } kommentar: { type: string, maxLength: 500 } responses: "200": description: Beskedet registrerat. content: application/json: schema: type: object properties: ok: { type: boolean } "400": { $ref: "#/components/responses/Fel" } "404": { $ref: "#/components/responses/Fel" } "409": { $ref: "#/components/responses/Fel" } "429": { $ref: "#/components/responses/Fel" } /api/organisation: get: tags: [Organisation] summary: Hämta organisationens namn och inställningar description: > Inställningarna styr vad som visas när ett ärende startas (objekttyper och identifieringsmetoder). Alla inloggade läser. responses: "200": description: Organisationen. content: application/json: schema: type: object properties: namn: { type: string } installningar: { $ref: "#/components/schemas/OrganisationsInstallningar" } "401": { $ref: "#/components/responses/Fel" } /api/organisation/installningar: post: tags: [Organisation] summary: Uppdatera organisationens inställningar description: Kräver rollen `admin`. Minst ett alternativ per lista. requestBody: required: true content: application/json: schema: { $ref: "#/components/schemas/OrganisationsInstallningar" } responses: "200": description: Sparat. content: application/json: schema: type: object properties: ok: { type: boolean } "400": { $ref: "#/components/responses/Fel" } "401": { $ref: "#/components/responses/Fel" } "403": { $ref: "#/components/responses/Fel" } /api/arenden: get: tags: [Ärenden] summary: Lista organisationens ärenden responses: "200": description: Ärenden (senaste 200). content: application/json: schema: type: object properties: arenden: type: array items: { $ref: "#/components/schemas/Arende" } "401": { $ref: "#/components/responses/Fel" } post: tags: [Ärenden] summary: Registrera ett ärende (idempotent) description: > Skapar ärendet i användarens organisation. Ett redan känt `id` ignoreras tyst — ärenderaden ändras aldrig. requestBody: required: true content: application/json: schema: type: object required: [id, nummer, skapad] properties: id: { type: string } nummer: { type: integer } skapad: { type: string, format: date-time } delningskod: { type: string, nullable: true } metodikId: { type: string, nullable: true } responses: "200": description: Mottaget. content: application/json: schema: type: object properties: ok: { type: boolean } "400": { $ref: "#/components/responses/Fel" } "401": { $ref: "#/components/responses/Fel" } /api/arenden/{arendeId}/handelser: parameters: - name: arendeId in: path required: true schema: { type: string } get: tags: [Ärenden] summary: Hämta ärendets händelselogg responses: "200": description: Händelser i tidsordning. content: application/json: schema: type: object properties: handelser: type: array items: { $ref: "#/components/schemas/LoggPost" } "401": { $ref: "#/components/responses/Fel" } "404": { $ref: "#/components/responses/Fel" } post: tags: [Ärenden] summary: Lägg till händelser (append-only, idempotent) description: > Lägger till händelser i loggen. Max 500 per anrop. En händelse med redan känt `id` ignoreras tyst — befintliga händelser skrivs aldrig över, och databastriggern stoppar alla ändringsförsök. requestBody: required: true content: application/json: schema: type: object required: [handelser] properties: handelser: type: array maxItems: 500 items: { $ref: "#/components/schemas/LoggPost" } responses: "200": description: Mottaget. content: application/json: schema: type: object properties: ok: { type: boolean } "400": { $ref: "#/components/responses/Fel" } "401": { $ref: "#/components/responses/Fel" } "404": { $ref: "#/components/responses/Fel" } /api/oversikt: get: tags: [Översikt] summary: Organisationsöversikt med status och statistikunderlag description: > Kräver rollen `arbetsledare` eller `admin`. Status, deltagande tekniker och sammanfattning härleds ur händelseloggen. responses: "200": description: Alla ärenden i organisationen med härledd status. content: application/json: schema: type: object properties: arenden: type: array items: { $ref: "#/components/schemas/OversiktsRad" } "401": { $ref: "#/components/responses/Fel" } "403": { $ref: "#/components/responses/Fel" } /api/arenden/{arendeId}/delningar: parameters: - name: arendeId in: path required: true schema: { type: string } get: tags: [Delning] summary: Lista ärendets delningslänkar responses: "200": description: Delningar (inklusive återkallade). content: application/json: schema: type: object properties: delningar: type: array items: { $ref: "#/components/schemas/Delning" } "401": { $ref: "#/components/responses/Fel" } "404": { $ref: "#/components/responses/Fel" } post: tags: [Delning] summary: Skapa delningslänk med behörighetsnivå description: > Verkstaden kontrollerar alltid delningen: kund (det kunddelbara), partner (även hypoteser, tydligt märkta ej verifierade) eller intern (full insyn). Nivåfiltreringen sker på serversidan. requestBody: required: true content: application/json: schema: type: object required: [niva] properties: niva: { $ref: "#/components/schemas/DelningsNiva" } responses: "200": description: Den skapade länkens kod. content: application/json: schema: type: object properties: kod: { type: string } niva: { $ref: "#/components/schemas/DelningsNiva" } "400": { $ref: "#/components/responses/Fel" } "401": { $ref: "#/components/responses/Fel" } "404": { $ref: "#/components/responses/Fel" } /api/delningar/{kod}/aterkalla: post: tags: [Delning] summary: Återkalla en delningslänk description: Efter återkallelse ger länken 404. Kan inte ångras. parameters: - name: kod in: path required: true schema: { type: string } responses: "200": description: Återkallad. content: application/json: schema: type: object properties: ok: { type: boolean } "401": { $ref: "#/components/responses/Fel" } "404": { $ref: "#/components/responses/Fel" } /api/delad/{delningskod}: get: tags: [Delning] summary: Publik Live Share-vy via delningskod description: > Kräver ingen inloggning — delningskoden är nyckeln. Filtreringen styrs av länkens behörighetsnivå: kund utesluter kategoribyten, hypoteser och AI-dialog; partner utesluter kategoribyten och AI-dialog; intern visar allt. Ärendets ursprungliga delningskod fungerar bakåtkompatibelt som kundnivå. security: [] parameters: - name: delningskod in: path required: true schema: { type: string, pattern: "^[A-Za-z0-9_-]+$" } responses: "200": description: Ärendet med nivåfiltrerad händelselogg. content: application/json: schema: type: object properties: arende: type: object properties: id: { type: string } nummer: { type: integer } skapad: { type: string, format: date-time } handelser: type: array items: { $ref: "#/components/schemas/LoggPost" } niva: { $ref: "#/components/schemas/DelningsNiva" } "404": { $ref: "#/components/responses/Fel" } /api/ai: post: tags: [AI] summary: AI-orkestern (separat tjänst bakom samma ingress) description: > Routas av ingressen till ai-orkester-tjänsten. Servern äger modellval, effort, systemprompt och svarsschema per uppgift: handledning (Claude Sonnet 5), granskning (Claude Opus 5), sammanfattning (Claude Sonnet 5), metodikval (Claude Haiku 4.5). requestBody: required: true content: application/json: schema: type: object required: [uppgift, prompt] properties: uppgift: type: string enum: [handledning, granskning, sammanfattning, metodikval] prompt: { type: string, maxLength: 40000 } responses: "200": description: Klassificerat AI-svar med modellen som svarade. content: application/json: schema: type: object properties: modell: { type: string, example: claude-sonnet-5 } svar: oneOf: - $ref: "#/components/schemas/AiSvar" - type: object properties: metodikId: type: string enum: [vibration, elsystem, generisk] "400": { $ref: "#/components/responses/Fel" } "401": { $ref: "#/components/responses/Fel" } "502": { $ref: "#/components/responses/Fel" } "503": { $ref: "#/components/responses/Fel" } components: securitySchemes: bearerAuth: type: http scheme: bearer bearerFormat: JWT description: > HS256-JWT från /api/auth/logga-in eller /api/auth/registrera. Anspråk: sub (användar-id), namn, org (organisations-id), roll, iat, exp (12 timmar). responses: Inloggad: description: Inloggad — token + kontouppgifter. content: application/json: schema: type: object properties: token: { type: string } namn: { type: string } roll: { $ref: "#/components/schemas/Roll" } organisation: { type: string } Fel: description: Felsvar. content: application/json: schema: type: object properties: error: { type: string } schemas: Fel: type: object properties: error: { type: string } Roll: type: string enum: [tekniker, arbetsledare, admin] OrganisationsInstallningar: type: object required: [objekttyper, identifieringsmetoder] properties: objekttyper: type: array minItems: 1 items: { type: string } identifieringsmetoder: type: array minItems: 1 items: { type: string } DelningsNiva: type: string enum: [kund, partner, intern] Delning: type: object properties: kod: { type: string } niva: { $ref: "#/components/schemas/DelningsNiva" } skapad: { type: string, format: date-time } aterkallad: { type: string, format: date-time, nullable: true } Anvandare: type: object properties: id: { type: string, format: uuid } epost: { type: string, format: email } namn: { type: string } roll: { $ref: "#/components/schemas/Roll" } Arende: type: object properties: id: { type: string } nummer: { type: integer } skapad: { type: string, format: date-time } delningskod: { type: string, nullable: true } metodik_id: { type: string, nullable: true } LoggPost: type: object required: [id, tidpunkt, anvandare, handelse] properties: id: { type: string } tidpunkt: { type: string, format: date-time } anvandare: { type: string } handelse: { $ref: "#/components/schemas/Handelse" } Handelse: type: object description: > Diskriminerad på `typ`; fullständiga fältdefinitioner i klientens domänmodell (src/felsokning/domain.ts). required: [typ] additionalProperties: true properties: typ: type: string enum: - objekt_identifierat - felbeskrivning - fraga_besvarad - kontroll_utford - observation - matvarde - hypotes - foto - kommentar - kategori_byte - inaktivitet_forklarad - overlamning - ansvarig_satt - arbetsorder_skannad - arendetyp_satt - historik_kontrollerad - matarstallning - video - atgardsforslag - kundbeslut - atgard_utford - kvalitetskontroll - reproducering - felorsak - export_skapad - ai_svar - arende_avslutat OversiktsRad: type: object properties: id: { type: string } nummer: { type: integer } skapad: { type: string, format: date-time } delningskod: { type: string, nullable: true } metodik_id: { type: string, nullable: true } antal_handelser: { type: integer } forsta: { type: string, format: date-time, nullable: true } senaste: { type: string, format: date-time, nullable: true } avslutat: { type: boolean } objekt: { type: string, nullable: true } felbeskrivning: { type: string, nullable: true } tekniker: type: array items: { type: string } nullable: true AiSvar: type: object required: [rader, nastaSteg] properties: rader: type: array items: type: object required: [typ, text] properties: typ: type: string enum: [observation, verifierat, hypotes, rekommendation] text: { type: string } nastaSteg: { type: string } security: - bearerAuth: []