e90cbf99e9
Ett självständigt referensdokument som beskriver hela systemet utan att repot behöver vara tillgängligt: principer, domänmodell, metodikmotor, ECM, tjänster, säkerhet, infrastruktur, testning och repostruktur. Innehållet är hämtat ur koden, inte ur planer. Där något inte finns står det uttryckligen — inklusive ett avsnitt om kända begränsningar och öppna punkter, eftersom ett dokument som bara beskriver det som fungerar är svårare att resonera kring än ett som säger var kanterna går. Ett eget avsnitt samlar designbesluten med sina motiv. Motivet är oftare det som behövs vid en diskussion än beslutet i sig. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012EQg3rJsrQ1ZNTvkzmQAtt
884 lines
39 KiB
Markdown
884 lines
39 KiB
Markdown
# Guidad Felsökning — fullständig systembeskrivning
|
||
|
||
> Ett självständigt referensdokument. Allt nedan är hämtat ur koden i
|
||
> `felsokning/` (branch `claude/guidad-felsokning-vision-1mnx7f`), inte ur
|
||
> planer eller avsikter. Där något **inte** finns står det uttryckligen.
|
||
>
|
||
> Syftet är att kunna resonera om systemet utan tillgång till repot.
|
||
>
|
||
> Senast synkat mot kod: commit `1bb4031`, 2026-08-04.
|
||
|
||
---
|
||
|
||
## 0. Sammanfattning på trettio sekunder
|
||
|
||
Guidad Felsökning är en SaaS-plattform för **fordonsverkstäder**. Den leder en
|
||
tekniker genom en strukturerad felsökning, kräver bevis för varje påstående, och
|
||
producerar ett spårbart underlag som kan delas med kund, försäkringsbolag eller
|
||
nästa tekniker.
|
||
|
||
Den bärande idén är negativ snarare än positiv: **systemet presenterar aldrig en
|
||
hypotes som ett konstaterat fel.** Det är inte en policy i en dokumentfil — det
|
||
är kodat, testat och blockerar flöden. När evidens saknas står det "Evidens
|
||
saknas", inte en kvalificerad gissning.
|
||
|
||
Tekniskt: en **append-only händelselogg** är enda sanningskällan. Allt annat —
|
||
ärendevyn, briefen, kundrapporten, kvalitetsgrinden, statistiken — är rena
|
||
projektioner av loggen och kan alltid regenereras.
|
||
|
||
| | |
|
||
|---|---|
|
||
| Klient | React 18 + TypeScript + Vite + Tailwind + zustand + react-router |
|
||
| Backend | Två Node-tjänster (`plattform`, `ai-orkester`), rena `node:http`, minimala beroenden |
|
||
| Databas | PostgreSQL (Aurora Serverless v2), append-only via databastriggrar |
|
||
| Modell | Claude, serverägd routing per uppgift |
|
||
| Infra | AWS + EKS, 126 Terraform-resurser i två lager |
|
||
| Git & CI | **Självhostad Gitea + Actions-runners på egen EKS** — inget GitHub i driftvägen |
|
||
| Tester | 120 vitest-tester + integrationstest mot riktig Postgres |
|
||
| Språk i kod | Svenska (identifierare, kommentarer, commit-meddelanden) |
|
||
|
||
---
|
||
|
||
## 1. Produktprinciper
|
||
|
||
Dessa fem är inte riktlinjer utan invarianter. Var och en har en motsvarighet i
|
||
kod och i test.
|
||
|
||
### 1.1 Ingen hypotes presenteras som ett konstaterat fel
|
||
|
||
Hypoteser är en egen händelsetyp (`hypotes`) med obligatorisk
|
||
tillförlitlighetsnivå, och kan **aldrig** anta nivån `hog`
|
||
(`niva: Exclude<Tillforlitlighet, "hog">` — typsystemet förbjuder det).
|
||
I kundrapporten märks de uttryckligen som ej verifierade. Kvalitetsgrinden har
|
||
en egen rad för detta.
|
||
|
||
Formuleringen vid misslyckad reproduktion är
|
||
*"kunde inte reproduceras under de förhållanden som rådde"* — aldrig
|
||
*"felet konstaterat"* eller *"inget fel hittat"*. Detta är kodat i både
|
||
projektionerna och orkesterns grundprompt.
|
||
|
||
### 1.2 En kryssruta är inte evidens
|
||
|
||
Varje kontrollpunkt i varje metodik har ett **minimikrav**:
|
||
`matvarde | kommentar | foto`. En mätning kan inte markeras utförd utan värde;
|
||
en fotokontroll kan inte markeras utförd utan bild. Vill teknikern hoppa över
|
||
något krävs ett **dokumenterat undantag** med orsak ur en fast lista.
|
||
|
||
Låst av test: *"varje kontroll kräver bevis — en kryssruta är inte evidens"*.
|
||
|
||
### 1.3 Loggen är append-only, hela vägen ner
|
||
|
||
Inga update- eller delete-operationer finns i API:t, och databasen har triggrar
|
||
som avvisar dem även om någon kringgår applikationen. Ett test söker aktivt
|
||
efter `update`/`delete` mot händelsetabellen i serverkoden och faller om de dyker
|
||
upp.
|
||
|
||
Konsekvens: en felaktig uppgift *rättas genom en ny händelse*, aldrig genom att
|
||
den gamla försvinner. Historiken är det som ger underlaget värde i en tvist.
|
||
|
||
### 1.4 Terminologi
|
||
|
||
I UI och kundkommunikation används **systemet, analysen, bedömningen,
|
||
beslutsstödet** — inte "AI", om det inte är tekniskt nödvändigt. Produkten
|
||
beskrivs som *evidensbaserat diagnossystem* / *intelligent beslutsstöd*.
|
||
|
||
Skälet är kommersiellt och epistemiskt: en verkstadskund som hör "AI" hör
|
||
"gissning". En försäkringshandläggare som läser "AI-bedömning" i ett underlag
|
||
väger det lägre.
|
||
|
||
### 1.5 Delningsgränsen är en tillåtelselista
|
||
|
||
Vad som får lämna organisationen räknas upp **positivt**, per nivå. En ny
|
||
händelsetyp är därmed intern tills någon aktivt släpper fram den. Ett test
|
||
kräver att varje typ i domänmodellen är klassificerad — glöms en bort faller
|
||
bygget, i stället för att den läcker.
|
||
|
||
---
|
||
|
||
## 2. Domänmodellen — händelseloggen
|
||
|
||
`app/src/felsokning/domain.ts` (281 rader).
|
||
|
||
Ett ärende är: identitet + metadata + en **ordnad lista av loggposter**. Varje
|
||
loggpost bär `id`, `tidpunkt`, `tekniker` och en `handelse`.
|
||
|
||
### 2.1 Samtliga händelsetyper
|
||
|
||
| Typ | Innehåll | Roll |
|
||
|---|---|---|
|
||
| `objekt_identifierat` | `objekt` (regnr/VIN, märke, modell, motor …) | Vad ärendet gäller |
|
||
| `arbetsorder_skannad` | `falt[]` + bilaga | Tolkad arbetsorder (**intern**) |
|
||
| `felbeskrivning` | `text` | Kundens ord, ordagrant |
|
||
| `arendetyp_satt` | `arendetyp` | Garanti / försäkring / kund … styr regelpaket |
|
||
| `fraga_besvarad` | `stegId`, `frageId`, `fraga`, `svar` | Metodikens symptomfrågor |
|
||
| `kontroll_utford` | `stegId`, `kontrollId`, `text`, `resultat?`, `undantag?` | Verifierad checklistpunkt |
|
||
| `observation` | `text` | Vad teknikern såg — inte vad hen tror |
|
||
| `matvarde` | `beskrivning`, `varde`, `enhet?` | Mätning (E4) |
|
||
| `hypotes` | `text`, `niva` (aldrig `hog`) | Arbetshypotes (**intern**) |
|
||
| `foto` | `beskrivning` + bilaga | Bildbevis (E2) |
|
||
| `video` | `beskrivning` + bilaga | Rörligt bevis (E3) |
|
||
| `matarstallning` | `lage` (ingående/utgående), `varde` + bilaga | Miltal in/ut |
|
||
| `historik_kontrollerad` | `kontrollerad`, `kommentar?` | Servicehistorik |
|
||
| `reproducering` | `status` (ja/delvis/nej), `beskrivning` | **Symptomverifiering** |
|
||
| `felorsak` | strukturerad felorsaksanalys | Orsak, kategori, underlag |
|
||
| `atgardsforslag` | förslag med motivering | Vad som bör göras |
|
||
| `kundbeslut` | godkänt/avböjt, kanal | Kundens besked |
|
||
| `atgard_utford` | utfört arbete | Vad som faktiskt gjordes |
|
||
| `kvalitetskontroll` | verifiering efter åtgärd | Är symptomet borta? |
|
||
| `kommentar` | `text` | Fri anteckning |
|
||
| `kategori_byte` | `kategori` | Tidredovisning (**intern**) |
|
||
| `inaktivitet_forklarad` | `text`, `minuter` | Varför det stod stilla |
|
||
| `overlamning` | `fran`, `till?` | Skiftbyte |
|
||
| `ansvarig_satt` | `ansvarig` | Arbetsledarens omfördelning (**intern**) |
|
||
| `ai_svar` | `rader[]` klassificerade, modellnamn | Beslutsstödets svar (**intern**) |
|
||
| `export_skapad` | `format`, `version` | Exporten loggar sig själv |
|
||
| `arende_avslutat` | `signatur?` | Teknikerns signering |
|
||
|
||
### 2.2 Bilagor är innehållsadresserade
|
||
|
||
`foto`, `video`, `matarstallning` och `arbetsorder_skannad` är
|
||
*intersektionstyper* med `Bilaga`:
|
||
|
||
```ts
|
||
export interface Bilaga {
|
||
bilagaId?: string;
|
||
bilagaHash?: string; // SHA-256
|
||
dataUrl?: string; // finns kvar för alltid — loggen är append-only
|
||
}
|
||
```
|
||
|
||
Innehållet ligger utanför loggen (S3 eller databas), men **hashen ligger i
|
||
loggen**. Vid läsning verifieras hashen; stämmer den inte returneras `409`.
|
||
Innebörden: byter någon ut en bild i lagret upptäcks det, och loggen kan bevisa
|
||
att den ursprungliga bilden var en annan.
|
||
|
||
`dataUrl` behålls i typen därför att gamla poster har den inbäddad — och loggen
|
||
kan inte skrivas om.
|
||
|
||
---
|
||
|
||
## 3. Metodikmotorn
|
||
|
||
Sedan senaste ändringen är **motor och innehåll åtskilda**:
|
||
|
||
- `metodik.ts` (171 rader) — typer, val av metodik, härledning av nästa steg.
|
||
- `metodiker.ts` (899 rader) — de sexton metodikerna.
|
||
|
||
Biblioteket kan växa utan att motorn ändras.
|
||
|
||
### 3.1 Metodikbiblioteket
|
||
|
||
| id | Namn | Område | Steg | Kontroller |
|
||
|---|---|---|---|---|
|
||
| `vibration` | Vibration under körning | Hjul och balans | symptom → visuell → kontroller → provkorning | 19 |
|
||
| `bromsar` | Bromssystem | Chassi | symptom → visuell → matningar → system | 14 |
|
||
| `styrning_fjadring` | Styrning och fjädring | Chassi | symptom → visuell → glapp → installning | 11 |
|
||
| `elsystem` | Elsystem och strömförsörjning | El | symptom → visuell → matningar → rela → funktionstest | 12 |
|
||
| `start_laddning` | Start- och laddningssystem | El | symptom → batteri → start → laddning → krypstrom | 15 |
|
||
| `motor_drift` | Motorgång och effekt | Motor | symptom → felkoder → mekanik → tandning_bransle → provkorning | 16 |
|
||
| `kylsystem` | Kylsystem och överhettning | Motor | symptom → visuell → matningar → packning | 12 |
|
||
| `drivlina` | Växellåda och drivlina | Drivlina | symptom → visuell → matningar → provkorning | 10 |
|
||
| `avgas_emission` | Avgassystem och emissioner | Motor | symptom → avlasning → matningar → orsak | 12 |
|
||
| `klimat` | Klimatanläggning | Komfort | symptom → visuell → matningar → styrning | 11 |
|
||
| `hogvolt` | Högvoltsystem — elbil och hybrid | Högvolt | **sakerhet** → symptom → avlasning → laddning | 16 |
|
||
| `diagnos_natverk` | Felkoder och kommunikation | Diagnos | symptom → grund → buss → koder | 10 |
|
||
| `lackage` | Läckage | Övrigt | symptom → visuell → metod | 8 |
|
||
| `missljud` | Missljud | Övrigt | symptom → inspelning → lokalisering | 7 |
|
||
| `adas` | Förarassistans och kalibrering | Diagnos | symptom → forutsattningar → kalibrering | 9 |
|
||
| `generisk` | Generell strukturerad felsökning | Övrigt | symptom → visuell → grundkontroller → funktionstest | 9 |
|
||
|
||
### 3.2 Tre regler, låsta av test
|
||
|
||
1. **Varje kontroll har ett minimikrav.** Mätvärde, foto eller observation.
|
||
2. **Varje metodik börjar med att verifiera symptomet**, aldrig med att åtgärda.
|
||
Kundens ord blir ett verifierat symptom först när det reproducerats.
|
||
3. **Där arbetet kan skada någon ligger säkerhetssteget först.** Endast
|
||
`sakerhet` får föregå `symptom` — testet tillåter exakt det undantaget och
|
||
inget annat.
|
||
|
||
`hogvolt` är den enda metodiken med säkerhetssteg. Det kräver behörighet,
|
||
dokumenterad urtagen servicebrytare (foto), väntetid enligt tillverkaren, **mätt
|
||
spänningsfrihet** (mätvärde — inte ett ja på en fråga) och skyddsutrustning.
|
||
Testet kontrollerar att steget ligger först, att `spanningsfrihet` kräver
|
||
mätvärde, och att beskrivningen innehåller ordet "livsfarlig".
|
||
|
||
Skälet är enkelt: det arbetet kan döda någon. Där duger ingen kryssruta.
|
||
|
||
### 3.3 Val av metodik
|
||
|
||
Tidigare en regexkedja med tre utfall. Nu **poängsatt nyckelordsmatchning**:
|
||
|
||
```ts
|
||
export function metodikPoang(metodik: Metodik, text: string): number
|
||
export function valjMetodik(felbeskrivning: string): Metodik
|
||
```
|
||
|
||
- Poäng = summan av längden på de nyckelord som träffar. Ett längre — mer
|
||
specifikt — ord väger tyngre. `traktionsbatteri` (16) slår `batteri`.
|
||
- **Korta ord (≤3 tecken) matchas som helt ord, längre som ordstam.** Annars
|
||
hade `"ac"` träffat *acceleration* och en vibration hamnat i
|
||
klimatanläggningen.
|
||
- Vid lika poäng vinner den som står först i biblioteket → valet är **stabilt**
|
||
mellan körningar.
|
||
- Ingen träff → `generisk`.
|
||
|
||
**Fallgrop som faktiskt bet under utvecklingen:** nyckelorden måste vara
|
||
*stammar*, inte färdigböjda ord. Svensk böjning kapar ofta ett `e`:
|
||
*filter → filtret*, så `"partikelfilter"` matchar aldrig texten teknikern
|
||
skriver. Samma gäller *regenerering → regenererar*, *misständning → misständer*,
|
||
*skrammel → skramlar*. Biblioteket använder därför `partikelfilt`, `regenerer`,
|
||
`misständ`, `skram`.
|
||
|
||
**Valet är en frågeordning, inte en diagnos.** Det avgör var teknikern börjar
|
||
leta, inte vad som är fel. Träffar inget är `generisk` det ärliga svaret —
|
||
strukturellt komplett, och bättre än en gissning.
|
||
|
||
### 3.4 Nästa steg
|
||
|
||
```ts
|
||
export function nastaSteg(arende: Arende, metodik: Metodik): NastaSteg
|
||
```
|
||
|
||
Rent härlett ur loggen: första obesvarade frågan, därefter första ej utförda
|
||
kontrollen, i metodikens ordning. Ingen dold tillståndsmaskin — samma logg ger
|
||
alltid samma nästa steg.
|
||
|
||
### 3.5 Om "täcka allt"
|
||
|
||
Det går inte att lova ärligt, och dokumentationen påstår det inte. Det som går
|
||
är att täcka fordonets system systematiskt och låta `generisk` vara ett
|
||
strukturellt komplett skyddsnät för det ingen förutsett.
|
||
|
||
---
|
||
|
||
## 4. ECM v2.0 — evidens- och regelmotorn
|
||
|
||
`app/src/felsokning/ecm.ts` (749 rader). Sex motorer:
|
||
|
||
### 4.1 Evidence Engine
|
||
|
||
Evidensnivåer, härledda ur loggen:
|
||
|
||
| Nivå | Betydelse |
|
||
|---|---|
|
||
| E0 | Inget underlag |
|
||
| E1 | Teknikerns observation |
|
||
| E2 | Foto |
|
||
| E3 | Video |
|
||
| E4 | Mätvärde |
|
||
| E5 | Diagnosdata / dokument |
|
||
| E6 | Flera oberoende källor |
|
||
|
||
Ett ärendes evidensnivå är den högsta som underlaget bär. Den visas i UI och
|
||
följer med i exporten.
|
||
|
||
**Innehållshash:** `innehallsHash()` är en deterministisk FNV-1a över
|
||
evidensinnehållet. Samma underlag ⇒ samma hash, oavsett maskin eller tidpunkt.
|
||
Det gör exporten verifierbar i efterhand.
|
||
|
||
### 4.2 Rule Engine
|
||
|
||
- `ORSAKSKATEGORIER` — fast lista för felorsaksanalys (ger jämförbar statistik
|
||
över flottan).
|
||
- `UNDANTAGSORSAKER` — fast lista för "varför gjordes inte detta".
|
||
- `UNDERLAGSKALLOR` — vad en slutsats vilar på.
|
||
- `INGEN_ATGARD_ORSAKER`, `KUNDKANALER`.
|
||
- `granskaAvvikelse()` — flaggar text som formulerats som konstaterande utan
|
||
täckning.
|
||
|
||
Fasta listor i stället för fritext är ett medvetet val: fritext går inte att
|
||
aggregera, och statistiken över flottan är en av produktens verkliga tillgångar.
|
||
|
||
### 4.3 Compliance Engine
|
||
|
||
`ARENDETYPER` styr vilket **regelpaket** som gäller. Garantiärende kräver
|
||
claim-nummer och servicehistorik; försäkringsärende kräver skadenummer och
|
||
bildbevis; kundärende kräver mindre. Paketen är data (`ecm-regler.json`,
|
||
serverbart via `/api/ecm/regler`) — nya krav kräver ingen ny release.
|
||
|
||
### 4.4 Validation Engine — pre-diagnostik
|
||
|
||
Innan felsökningen får börja: objektidentifiering verifierad, arbetsorder
|
||
inläst, fordonshistorik kontrollerad **eller motiverad**, ingående mätarställning
|
||
dokumenterad, kundens felbeskrivning verifierad, tidiga observationer hanterade.
|
||
|
||
### 4.5 Completion Engine — kvalitetsgrinden
|
||
|
||
Den största enskilda funktionen (`kvalitetsgrind`, ~240 rader). Ärendet kan inte
|
||
avslutas förrän varje rad är grön eller motiverad:
|
||
|
||
- Fordonshistorik kontrollerad eller motiverad
|
||
- Ingående/utgående mätarställning dokumenterad
|
||
- Kundens felbeskrivning verifierad
|
||
- **Symptomverifiering:** reproducerat, eller dokumenterat ej reproducerbart
|
||
- Felorsaksanalys dokumenterad
|
||
- Åtgärd dokumenterad eller motiverad
|
||
- Kundens besked på åtgärdsförslaget registrerat
|
||
- Utfört arbete trots avböjt åtgärdsförslag (om tillämpligt)
|
||
- Kvalitetskontroll genomförd — symptomet verifierat
|
||
- Metodikens kontroller: evidens eller dokumenterat undantag
|
||
- Foton finns för fotokrävande kontroller
|
||
- Teknikerns slutsats signerad
|
||
- Hypoteser redovisas som ej verifierade
|
||
- Ärendetypens regelpaket uppfyllt (claim / skadenummer / miltal / historik)
|
||
|
||
### 4.6 Traceability Engine
|
||
|
||
`sparbarhetspaket()` — hela beviskedjan i ett strukturerat objekt: vad som
|
||
påstås, vad det vilar på, vem som dokumenterade det och när.
|
||
|
||
---
|
||
|
||
## 5. Symptomverifiering (SVP)
|
||
|
||
Egen princip därför att den är produktens skarpaste kant mot verkligheten.
|
||
|
||
**Kundens beskrivning ≠ konstaterat fel.**
|
||
|
||
1. Beskrivningen dokumenteras **ordagrant** (`felbeskrivning`).
|
||
2. Den förtydligas via metodikens symptomfrågor — *när, var, hur*, aldrig
|
||
"vad är fel".
|
||
3. Den **reproduceras**, med tre möjliga utfall:
|
||
- **Ja** — med dokumenterade förhållanden.
|
||
- **Delvis** — vad som kunde och inte kunde återskapas.
|
||
- **Nej** — obligatorisk motivering.
|
||
|
||
Rapportens beviskedja skiljer fyra saker som annars blandas ihop: *kundens
|
||
beskrivning*, *verifierad observation*, *felorsaksanalys* och *rekommenderad
|
||
åtgärd*.
|
||
|
||
---
|
||
|
||
## 6. Klienten
|
||
|
||
`app/src/felsokning/` + `app/src/pages/felsokning/`.
|
||
|
||
| Modul | Rader | Ansvar |
|
||
|---|---|---|
|
||
| `ArendeSida.tsx` | 2433 | Ärendevyn. Trekolumnslayout på skrivbord |
|
||
| `metodiker.ts` | 899 | Metodikbiblioteket |
|
||
| `ecm.ts` | 749 | Regel- och evidensmotorn |
|
||
| `NyttArende.tsx` | 497 | Ärendestart, arbetsorderskanning |
|
||
| `Arendelista.tsx` | 399 | Dashboard: räknare, filter |
|
||
| `projektioner.ts` | 356 | Alla vyer som rena funktioner av loggen |
|
||
| `ai.ts` | 305 | Klientsidan av orkestern, promptbygge, svarstolkning |
|
||
| `plattform.ts` | 296 | API-klient mot självhostad plattform |
|
||
| `DelatArendeVy.tsx` | 283 | Delad vy (kund/partner/intern) |
|
||
| `domain.ts` | 281 | Händelsetyper |
|
||
| `Installningar.tsx` | 281 | Organisation, användare, integrationer |
|
||
| `Oversikt.tsx` | 238 | Arbetsledarvy |
|
||
| `demo.ts` | 200 | Demoärende med 1 tim 35 min historik |
|
||
| `ui.tsx` | 174 | Industriellt verkstads-UI |
|
||
| `metodik.ts` | 171 | Metodikmotorn |
|
||
| `synk.ts` | 141 | Konfliktfri ihopflätning av händelser |
|
||
| `ikoner.tsx` | 132 | Egna SVG-linjeikoner (inga emojis) |
|
||
| `streckkod.ts` | 131 | Streckkods-/VIN-avläsning |
|
||
| `store.ts` | 106 | zustand-store |
|
||
| `bilagor.ts` | 96 | Uppladdning + blob-URL-cache |
|
||
| `installningar.ts` | 86 | Organisationsinställningar |
|
||
| `Bilagevisning.tsx` | 69 | `<Bild>` / `<Klipp>` |
|
||
| `Mikrofon.tsx` / `rost.ts` | 66 / 65 | Taligenkänning |
|
||
| `format.ts` | 48 | Fotoskalning m.m. |
|
||
|
||
### 6.1 Projektionerna
|
||
|
||
```
|
||
objekt · felbeskrivning · ansvarig · arendeidentitet · arAvslutat
|
||
lokalFordonshistorik · utfordaKontroller · ejKontrollerat
|
||
observationer · hypoteser · foton · videor
|
||
tidsfordelning · formateraTid · tillforlitlighet
|
||
brief · overlamningstext · tidsfordelningsRader · sistaAktivitet
|
||
```
|
||
|
||
Alla rena funktioner av `Arende`. `ejKontrollerat` är den som sparar mest tid i
|
||
verkligheten: *det som orsakar dubbelarbete vid skiftbyte är det ingen skrivit
|
||
ner att ingen gjort.*
|
||
|
||
### 6.2 UI-språk
|
||
|
||
ETKA-inspirerat verkstads-UI: plana ljusgrå ytor (#ECECEC/#F7F7F7), skarpa
|
||
kanter, djup marinblå primärfärg, tät typografi (11–15 px), rektangulära knappar
|
||
(max 4 px radie), verktygsrad ~44 px. Egna linjeikoner i stället för emojis;
|
||
status som färgpunkter.
|
||
|
||
Motivet: teknikern har handskar på sig, står i ett bullrigt utrymme och har inte
|
||
tid med ett luftigt konsument-UI.
|
||
|
||
### 6.3 Lokalt läge
|
||
|
||
Utan inloggning fungerar appen mot `localStorage`. Metodiken guidar ensam,
|
||
orkestern är avstängd. Status visas i ärendehuvudet. Vid inloggning flätas
|
||
lokala händelser ihop med serverns — konfliktfritt per händelse-id, testat.
|
||
|
||
---
|
||
|
||
## 7. Backend
|
||
|
||
### 7.1 `services/plattform` (1210 rader)
|
||
|
||
Ren `node:http`. Enda beroendet är `pg`.
|
||
|
||
**API-vägar:**
|
||
|
||
```
|
||
GET /halsa
|
||
GET /api/openapi.yaml
|
||
POST /api/auth/registrera skapar organisation + systemadministratör
|
||
POST /api/auth/logga-in
|
||
POST /api/auth/logga-ut-alla höjer token_version → alla sessioner dör
|
||
GET /api/anvandare admin
|
||
POST /api/anvandare
|
||
POST /api/anvandare/{id}/avaktivera | /aktivera
|
||
GET /api/organisation
|
||
GET/PUT /api/organisation/installningar
|
||
GET /api/ecm/regler regelpaket som data
|
||
GET/POST /api/arenden
|
||
POST /api/arenden/{id}/handelser append-only
|
||
POST /api/arenden/{id}/bilagor
|
||
GET /api/bilagor/{id} hash verifieras vid läsning
|
||
GET /api/fordon/{identifierare}/historik
|
||
GET /api/statistik/felorsaker
|
||
GET /api/oversikt arbetsledarvy
|
||
GET /api/delad/{kod} filtrerad enligt nivå
|
||
POST /api/delad/{kod}/beslut kundens besked utan inloggning
|
||
GET /api/delad/{kod}/bilagor/{id} nivåfiltrerad
|
||
GET /api/integrationer/leverantorer
|
||
GET/PUT/DELETE /api/integrationer/{leverantor}
|
||
POST /api/integrationer/{leverantor}/uppslag
|
||
```
|
||
|
||
Inga update- eller delete-vägar mot ärendedata. Med avsikt.
|
||
|
||
**Säkerhetsfunktioner i tjänsten:**
|
||
|
||
```
|
||
ursprungFor · forTataForsok · kallaFor · inloggningSparrad · loggaForsok
|
||
skapaJwt · verifieraJwt · kontoGiltigt · kravAuth · arendeIOrg
|
||
integrationsNyckel · kryptera · dekryptera · maskera
|
||
arPrivatAdress · pekarInat · gorUppslag · skickaBilaga · synligaTyper
|
||
```
|
||
|
||
### 7.2 `services/ai-orkester` (400 rader)
|
||
|
||
Äger Claude-nyckeln. Klienten har den **aldrig**. Routing per uppgift:
|
||
|
||
| Uppgift | Modell | Effort | Vision |
|
||
|---|---|---|---|
|
||
| `handledning` | `claude-sonnet-5` | medium | — |
|
||
| `granskning` | `claude-opus-5` | **high** | — |
|
||
| `sammanfattning` | `claude-sonnet-5` | low | — |
|
||
| `metodikval` | `claude-haiku-4-5` | *(ingen — modellen tar inte parametern)* | — |
|
||
| `instrumentavlasning` | `claude-sonnet-5` | low | ✔ |
|
||
| `dokumenttolkning` | `claude-sonnet-5` | low | ✔ |
|
||
|
||
Samtliga svar är **schema-bundna** (`json_schema`). Grundprompten kodar
|
||
AI-reglerna: *"Hitta aldrig på fakta"*, *"aldrig en hypotes som ett konstaterat
|
||
fel"*, *"KRÄVER verifiering"*. Vid avböjd förfrågan sker automatisk fallback
|
||
till reservmodell. **Modellen som svarade loggas i varje `ai_svar`-händelse** —
|
||
underlaget ska gå att granska i efterhand.
|
||
|
||
Metodikkatalogen byggs ur en enda lista (`METODIK_KATALOG`), som genererar både
|
||
schemats `enum` och promptens punktlista. Ett test jämför den mot klientens
|
||
bibliotek: glider listorna isär returnerar klassificeraren ett id klienten inte
|
||
känner igen, och valet skulle falla *tyst* tillbaka på generisk. Nu faller
|
||
testet i stället.
|
||
|
||
### 7.3 `services/gemensam/observation.mjs` (166 rader)
|
||
|
||
Spårning och mätvärden **utan nya beroenden**. Tjänsterna har medvetet nästan
|
||
inga beroenden; att dra in ett OpenTelemetry-SDK med trettio paket för att mäta
|
||
fyra saker vore fel avvägning. I stället två standarder som båda bara är text på
|
||
stdout:
|
||
|
||
- **W3C Trace Context** — `traceparent` följer med genom hela kedjan
|
||
(klient → plattform → orkester).
|
||
- **CloudWatch EMF** — strukturerad JSON som CloudWatch själv extraherar
|
||
mätvärden ur. Ingen agent, ingen SDK, inget som kan sluta fungera tyst.
|
||
|
||
```
|
||
spårFrån(huvud) · traceparent(spår) · starta(namn, spår)
|
||
→ .mät(delnamn, arbete) · .ms() · .delar()
|
||
logga(nivå, meddelande, fält) · mätvärde(namn, värde, enhet, dim, extra)
|
||
avsluta(spann, { status, väg, extra })
|
||
```
|
||
|
||
Det som mäts valdes utifrån en fråga: *vad vill man veta klockan tre på natten
|
||
när något är långsamt?* Svaret är **var tiden gick** — inte hur många anrop som
|
||
skett. Därför `delar()`: databasen, modellanropet, objektlagringen, kundens
|
||
leverantör, med antal och summa per del i samma loggrad.
|
||
|
||
`mät()` mäter även när arbetet kastar — annars ser fel ut som noll tid.
|
||
|
||
**Dimensioner hålls medvetet få.** Varje unik kombination är en egen tidsserie
|
||
som kostar pengar, så organisation, ärende och spår-id får aldrig bli
|
||
dimensioner — de ligger som vanliga fält. Låst av test som explicit förbjuder
|
||
`org`, `organisation`, `arende`, `spårId`, `anvandare` bland dimensionerna.
|
||
|
||
---
|
||
|
||
## 8. Säkerhet
|
||
|
||
| Skydd | Implementation |
|
||
|---|---|
|
||
| **Multi-tenant-isolering** | Alla ärendefrågor är organisationsknutna (`arendeIOrg`); integrationstestat mot riktig Postgres |
|
||
| **Roller** | `tekniker` / `arbetsledare` / `admin`, i JWT och databas-check |
|
||
| **JWT-anspråk** | `{ sub, namn, org, roll, tv }` — `tv` = token_version |
|
||
| **Omedelbar återkallelse** | `kontoGiltigt()` kontrollerar `aktiv` + `token_version` vid *varje* autentiserat anrop. En giltig signatur räcker inte |
|
||
| **Global utloggning** | `/api/auth/logga-ut-alla` höjer `token_version` → alla utfärdade tokens dör direkt |
|
||
| **Lösenord** | bcrypt via `gen_salt('bf')` i databasen |
|
||
| **Inloggningsspärr** | 15 min-fönster; max 10 försök per konto, 30 per källa. Städas probabilistiskt (2 % chans per skrivning) för att slippa ett cron-jobb |
|
||
| **Kryptering i vila** | AES-256-GCM för kundernas integrationsuppgifter; hemliga fält maskeras alltid i API-svar |
|
||
| **SSRF-försvar** | `arPrivatAdress()` + `pekarInat()`: 10/8, 127/8, 169.254/16, 172.16–31, 192.168/16, 100.64/10, ::1, fc/fd, fe80, ::ffff:. **DNS slås upp** innan anrop; `.local`/`.internal` blockeras. Escape-hatch `TILLAT_INTERNA_UPPSLAG` för testmiljö |
|
||
| **CORS** | `TILLATNA_URSPRUNG`-allowlist, ursprung sätts en gång per anrop |
|
||
| **Bilageintegritet** | SHA-256 i loggen, verifieras vid läsning → `409` vid avvikelse |
|
||
| **Append-only i databasen** | Triggrar `before update or delete` på både `felsokning_handelser` och `felsokning_arenden` |
|
||
| **Podd-härdning** | IMDSv2 obligatoriskt, hoppgräns 1 → podar kan inte låna nodens IAM-roll |
|
||
| **IRSA** | Varje tjänstekonto har egen roll; noderna delar inga rättigheter |
|
||
| **Delade IAM-roller** | `bygg` får publicera till ECR men inte röra klustret; `drift` får röra klustret men inte publicera bilder |
|
||
| **Nätverkspolicy** | Default deny in; explicita `_ut`-regler per tjänst |
|
||
| **Databasåtkomst** | Endast från klustrets noder, i ett subnätlager **utan routing ut** |
|
||
|
||
### 8.1 Databasschema
|
||
|
||
```
|
||
organisationer · anvandare · inloggningsforsok
|
||
felsokning_arenden · felsokning_handelser
|
||
bilagor · bilage_innehall
|
||
delningar · integrationer
|
||
```
|
||
|
||
---
|
||
|
||
## 9. Live Share — delningsnivåer
|
||
|
||
Tre nivåer, serverstyrd filtrering:
|
||
|
||
| Nivå | Ser |
|
||
|---|---|
|
||
| **kund** | 22 händelsetyper: objekt, felbeskrivning, frågor, kontroller, observationer, mätvärden, foton, videor, kommentarer, överlämningar, åtgärder, kvalitetskontroll … |
|
||
| **partner** | Allt kunden ser **+ `hypotes`** (märkta ej verifierade) |
|
||
| **intern** | Full insyn — ingen filtrering |
|
||
|
||
**Aldrig utanför organisationen:**
|
||
`kategori_byte`, `hypotes`, `ai_svar`, `ansvarig_satt`, `arbetsorder_skannad`.
|
||
|
||
```js
|
||
export function synligaTyper(niva) {
|
||
if (niva === "intern") return null; // full insyn
|
||
return niva === "partner" ? DELBART_PARTNER : DELBART_KUND;
|
||
}
|
||
```
|
||
|
||
Länkar är återkallbara. Publik delningssida (`/felsokning/delad/:kod`) kräver
|
||
ingen inloggning och pollar för liveuppdatering. Kunden kan lämna besked direkt
|
||
i vyn (`POST /api/delad/{kod}/beslut`).
|
||
|
||
**Varför tillåtelselista:** en neka-lista måste uppdateras när en ny
|
||
händelsetyp läggs till — och det är precis det man glömmer. En tillåtelselista
|
||
gör "glömt" till "intern", vilket är det säkra utfallet.
|
||
|
||
---
|
||
|
||
## 10. Märkesspecifika kopplingar
|
||
|
||
Leverantörer är **data, inte kod** (`integrationer.json`, monterbar som
|
||
ConfigMap via `INTEGRATIONER_FIL`). Nya märken kräver ingen ombyggnad.
|
||
|
||
| id | Leverantör |
|
||
|---|---|
|
||
| `generisk_vin` | Valfri VIN-tjänst över HTTP |
|
||
| `vag_erwin` | Volkswagen Group erWin (VW, Audi, Škoda, SEAT) |
|
||
| `volvo_vida` | Volvo VIDA |
|
||
| `fordonsregister` | Regnr → fordon |
|
||
|
||
Varje leverantör deklarerar sina fält, vilka som är hemliga (krypteras + maskeras),
|
||
och hur svaret mappas till domänens fält (`marke`, `modell`, `arsmodell`,
|
||
`motor`, `vaxellada`).
|
||
|
||
Uppslag går genom SSRF-skyddet — en kund kan alltså inte peka en "leverantör"
|
||
mot klustrets interna adresser.
|
||
|
||
---
|
||
|
||
## 11. Visual-first
|
||
|
||
Kameran **är** integrationslagret. Det som syns på en skärm eller ett instrument
|
||
fotograferas och tolkas, i stället för att integreras.
|
||
|
||
- **Arbetsorderskanning** är primärvägen vid ärendestart. Sonnet 5 (vision)
|
||
läser kund-, fordons- och verkstadsuppgifter oavsett layout, med konfidens per
|
||
fält:
|
||
- 🟢 ≥95 % godkänns automatiskt
|
||
- 🟡 80–95 % markeras för genomläsning
|
||
- 🔴 <80 % kräver aktiv bekräftelse
|
||
|
||
Teknikern granskar alltså bara osäkra fält. Visuell granskning med dokumentet
|
||
bredvid fälten; klick markerar ungefärlig position.
|
||
|
||
- **Instrumentavläsning** — foto av diagnosskärm eller instrument → strukturerade
|
||
värden.
|
||
|
||
Motivet är kommersiellt: en integration per verkstadssystem är en säljcykel per
|
||
kund. En kamera fungerar mot allt, direkt.
|
||
|
||
---
|
||
|
||
## 12. Infrastruktur
|
||
|
||
Två Terraform-lager. Basen körs sällan, arbetslastlagret ofta.
|
||
|
||
### 12.1 `infra/aws` — basen (91 resurser)
|
||
|
||
| Område | Innehåll |
|
||
|---|---|
|
||
| **Nät** | 1 VPC, 3 subnätlager × 3 zoner: publikt (bara ALB + NAT), privat (noder, inga publika adresser), data (Aurora, **ingen väg ut alls**). VPC-endpoints: S3 (gateway); ECR, loggar, Secrets Manager, STS, ELB (gränssnitt) → trafiken lämnar aldrig nätet |
|
||
| **Kluster** | EKS, arm64-noder, IRSA via OIDC-provider, IMDSv2 hoppgräns 1, alla fem kontrollplansloggar på |
|
||
| **Data** | Aurora PostgreSQL Serverless v2, PITR ned till sekunden, KMS med egen nyckel, `sslmode=require` |
|
||
| **Objektlagring** | S3 för bilagor: SSE-KMS, publik åtkomst blockerad, TLS obligatoriskt, versionshantering på. Plattformens roll får läsa och skriva — **men aldrig radera** |
|
||
| **Register** | ECR med **oföränderliga taggar** + sårbarhetsskanning |
|
||
| **Hemligheter** | Secrets Manager; läses endast av plattformsrollen via IRSA |
|
||
| **Roller** | 9 IAM-roller, bl.a. delade `bygg` / `drift` |
|
||
| **Domän** | Route 53 + ACM med DNS-validering |
|
||
| **Observation** | 7 larm, 1 instrumentpanel, 3 loggrupper, SNS-topic |
|
||
|
||
**Larmen** — få, men de som finns betyder något. *Ett larm som ingen agerar på
|
||
lär folk att ignorera larm.*
|
||
|
||
- Aurora CPU > 85 % i tre perioder (skalningstaket kan vara nått)
|
||
- Aurora fri lokal lagring < 5 GiB
|
||
- **Backup-ålder** — `treat_missing_data = "breaching"`. Saknas mätvärdet finns
|
||
ingen säkerhetskopiering. *En backup man tror finns är värre än ingen.*
|
||
- Färre noder än minsta önskade
|
||
- Svarstid **p95** > 3 s i tre perioder — inte medelvärde, som döljer att var
|
||
tjugonde tekniker väntar orimligt länge
|
||
- Serverfel (summa > 5)
|
||
- Modellen avböjer (tyder på oväntat underlag, inte driftfel)
|
||
|
||
### 12.2 `infra/terraform` — arbetslasten (35 resurser)
|
||
|
||
Läser basen via `terraform_remote_state`, upprepar ingenting.
|
||
|
||
```
|
||
kubernetes_namespace_v1 denna, gitea
|
||
kubernetes_service_account_v1 plattform (IRSA), drift, runner
|
||
kubernetes_deployment_v1 plattform, orkester, web
|
||
kubernetes_service_v1 plattform, orkester, web
|
||
kubernetes_horizontal_pod_autoscaler_v2 × 3
|
||
kubernetes_pod_disruption_budget_v1 × 3
|
||
kubernetes_ingress_v1 denna, gitea
|
||
kubernetes_network_policy_v1 neka_allt_in, tjanster_in, dns_ut,
|
||
plattform_ut, orkester_ut, web_ut
|
||
kubernetes_manifest hemlighetskalla, hemligheter (External Secrets)
|
||
helm_release lastbalanserare (ALB), external_secrets,
|
||
cloudwatch, metrics, gitea
|
||
aws_route53_record denna
|
||
```
|
||
|
||
`karta.tf` (117 rader) producerar en läsbar karta över hela driftbilden:
|
||
`terraform output karta`.
|
||
|
||
### 12.3 Git och CI — helt egenhostat
|
||
|
||
Uttrycklig produktbeslut: **inget GitHub i driftvägen.** Gitea + Actions-runners
|
||
kör på egen EKS. `.gitea/workflows/felsokning.yml`:
|
||
|
||
| Jobb | Innehåll |
|
||
|---|---|
|
||
| `test-och-bygg` | `vitest run`, `typkontroll`, eslint, `vite build` |
|
||
| `tjanster` | eslint på tjänsterna, **integrationstest mot riktig Postgres**, `swagger-cli validate` |
|
||
| `terraform` | `fmt -check -recursive`, `init -backend=false`, `validate` |
|
||
| `publicera` | Endast på `main`, endast om ovanstående gått igenom. Bygger tre bilder, taggar med commit-SHA, pushar till eget ECR. **OIDC, ingen statisk nyckel** |
|
||
| `driftsatt` | **Manuellt** (`workflow_dispatch`) med explicit bildtagg |
|
||
|
||
Driftsättning är ett eget steg med avsikt: *en bild i registret är inte samma
|
||
sak som en bild som kör.* Rollback = kör igen med tidigare tagg.
|
||
|
||
Klientens API-adress bakas in vid bygget (Vite), så bilden är miljöbunden.
|
||
Byggkontexten för tjänsterna är `felsokning/services` så att båda når den delade
|
||
observationsmodulen utan att den dupliceras.
|
||
|
||
---
|
||
|
||
## 13. Testning
|
||
|
||
**120 vitest-tester** i 13 filer:
|
||
|
||
| Fil | Antal | Låser |
|
||
|---|---|---|
|
||
| `ecm.test.ts` | 32 | Evidensnivåer, regelpaket, kvalitetsgrind, pre-diagnostik |
|
||
| `metodiker.test.ts` | 14 | Bibliotekets struktur, metodikval, katalogparitet mot orkestern |
|
||
| `projektioner.test.ts` | 13 | Vyer som rena funktioner, nästa steg |
|
||
| `ai.test.ts` | 11 | Orkesterparitet, OpenAPI ↔ server, append-only, promptregler |
|
||
| `observation.test.ts` | 10 | Spårning, EMF-format, **förbjudna dimensioner** |
|
||
| `bilagor.test.ts` | 9 | Innehållshash, SigV4, lagerval |
|
||
| `delning.test.ts` | 7 | Tillåtelselistan täcker varje händelsetyp |
|
||
| `integrationer.test.ts` | 7 | Leverantörsuppslag, SSRF-guard |
|
||
| `demo.test.ts` | 4 | Demoärendet är rikt nog att visa |
|
||
| `installningar.test.ts` | 4 | Organisationsinställningar |
|
||
| `streckkod.test.ts` | 4 | VIN/streckkod |
|
||
| `synk.test.ts` | 4 | Konfliktfri ihopflätning |
|
||
| `example.test.ts` | 1 | — |
|
||
|
||
**Utöver enhetstesterna:**
|
||
|
||
- `integrationstest.sh` — hela flödet mot **riktig Postgres**: organisationer,
|
||
roller, append-only-triggern, isolering, delning, bilagor.
|
||
- SigV4 **korsverifierad bit-för-bit mot botocore** (`sigv4-referens.json`).
|
||
- `swagger-cli validate` på OpenAPI-specen.
|
||
- Paritetstester som jämför spec ↔ server, klient ↔ orkester (× 2 kopior),
|
||
domänmodell ↔ delningslista.
|
||
|
||
### 13.1 Verifieringsloopen före varje commit
|
||
|
||
```
|
||
npx vitest run # 120 tester
|
||
npm run typkontroll # tsc --noEmit (vite build typkontrollerar INTE)
|
||
npx eslint src/felsokning src/pages/felsokning
|
||
cd ../services && npx eslint .
|
||
npm run build
|
||
terraform fmt -check -recursive
|
||
# rotens CI: lint · format:check · typecheck · test
|
||
```
|
||
|
||
`typkontroll` lades till efter att två latenta krascher (`TextFalt` och
|
||
`UNDANTAGSORSAKER` använda utan import) tagit sig förbi `vite build` — som
|
||
transpilerar men inte typkontrollerar.
|
||
|
||
---
|
||
|
||
## 14. Repostruktur
|
||
|
||
`main` är en npm-workspaces-monorepo som heter **Semantika** och äger roten. När
|
||
de två produkterna slogs ihop behölls båda, med verktygskedjorna **skilda åt per
|
||
träd** — inte genom att försvaga någons regler.
|
||
|
||
```
|
||
/ Semantika (workspaces-rot)
|
||
├── apps/mobile/ Semantika
|
||
├── services/api/ Semantika
|
||
├── infra/ Semantika
|
||
├── .github/workflows/ci.yml Semantika — rörs inte
|
||
│
|
||
├── .gitea/workflows/felsokning.yml Guidad Felsökning (självhostad CI)
|
||
└── felsokning/
|
||
├── app/ klient (egen package.json, eslint, vitest, tsconfig)
|
||
├── services/
|
||
│ ├── plattform/
|
||
│ ├── ai-orkester/
|
||
│ └── gemensam/ observation.mjs (delad)
|
||
├── infra/
|
||
│ ├── aws/ basen, 91 resurser
|
||
│ ├── terraform/ arbetslasten, 35 resurser
|
||
│ └── postgres-init.sql
|
||
├── docs/
|
||
└── supabase/ migrationer + edge-funktion (äldre driftväg)
|
||
```
|
||
|
||
**Två driftvägar finns parallellt:** den självhostade AWS-stacken (den som
|
||
gäller) och en äldre Supabase-baserad (edge-funktionen `felsokning-ai`,
|
||
migrationer). Orkestern finns därför i **två kopior** som hålls i synk av test.
|
||
|
||
---
|
||
|
||
## 15. Dokumentation i repot
|
||
|
||
```
|
||
docs/VISION.md produktvisionen
|
||
docs/MASTER-PROMPT.md grundinstruktionen
|
||
docs/MVP.md vad som är byggt, funktion för funktion
|
||
docs/DEMO.md demomanus för visning
|
||
docs/DRIFT.md drift
|
||
docs/SYSTEMBESKRIVNING.md detta dokument
|
||
docs/exempel/vibration-vid-88-km-h.md genomgående exempelflöde
|
||
docs/moduler/
|
||
arbetslogg-och-tidredovisning.md
|
||
arendebrief.md
|
||
evidensmotor.md
|
||
kommunikationsmodell.md
|
||
kundrapport.md
|
||
live-share.md
|
||
markesspecifika-kopplingar.md
|
||
verifierade-checklistor.md
|
||
```
|
||
|
||
---
|
||
|
||
## 16. Designbeslut och deras motiv
|
||
|
||
Sammanställda därför att motivet ofta är viktigare än beslutet.
|
||
|
||
| Beslut | Motiv |
|
||
|---|---|
|
||
| Event sourcing | Underlaget måste hålla i en tvist. Historiken *är* värdet |
|
||
| Append-only även i databasen | Applikationslagret kan kringgås; triggern kan det inte |
|
||
| Tillåtelselista för delning | Glömd händelsetyp blir intern, inte läckt |
|
||
| Fasta orsakskategorier | Fritext går inte att aggregera; flottstatistiken är en tillgång |
|
||
| Serverägd modellrouting | Klienten ska aldrig ha nyckeln, och routing ska kunna ändras utan release |
|
||
| Loggad modell per svar | Underlaget ska gå att granska i efterhand |
|
||
| Undvik ordet "AI" | Kunden hör "gissning"; handläggaren väger det lägre |
|
||
| Visual-first | En integration per verkstadssystem = en säljcykel per kund. Kameran fungerar direkt |
|
||
| Leverantörer som data | Nytt märke ska inte kräva release |
|
||
| Egen observation, noll beroenden | 30 paket för att mäta 4 saker är fel avvägning |
|
||
| Få dimensioner i EMF | Varje kombination är en betald tidsserie |
|
||
| p95 i larmet, inte medel | Medelvärdet döljer att var tjugonde tekniker väntar |
|
||
| Larm på *saknad* backupdata | En backup man tror finns är värre än ingen |
|
||
| Delade bygg-/driftroller | Ett komprometterat bygge ska inte kunna röra klustret |
|
||
| Manuell driftsättning | En bild i registret ≠ en bild som kör |
|
||
| Oföränderliga ECR-taggar | En tagg ska betyda samma sak imorgon |
|
||
| Innehållsadresserade bilagor | Utbytt bild ska upptäckas, inte antas |
|
||
| Hash-verifiering vid läsning | Det räcker inte att hasha vid skrivning |
|
||
| S3-rollen får inte radera | Append-only måste gälla även lagret |
|
||
| Motor skild från innehåll | Biblioteket växer; motorn ska inte behöva ändras |
|
||
| Poängsatt metodikval | Regexkedjor blir ogenomskådliga vid 16 alternativ |
|
||
| Nyckelord som stammar | Svensk böjning kapar ett `e` — annars matchar inget |
|
||
| `generisk` som fallback | Ett ärligt "vi vet inte" slår en gissning |
|
||
| Säkerhetssteg först i högvolt | Det arbetet kan döda |
|
||
| Svenska i koden | Domänen är svensk; översättning fram och tillbaka tappar precision |
|
||
|
||
---
|
||
|
||
## 17. Kända begränsningar och öppna punkter
|
||
|
||
Uttryckligen inte färdigt:
|
||
|
||
- **Två orkesterkopior** (Supabase edge-funktion + K8s-tjänst) hålls i synk av
|
||
test, inte av delad kod. Supabase-vägen är den äldre och bör avvecklas.
|
||
- **`ArendeSida.tsx` är 2433 rader.** Fungerar, men är den fil som kostar mest
|
||
att ändra i.
|
||
- **`terraform validate` kan inte köras lokalt** i utvecklingsmiljön
|
||
(utgående nätverkspolicy blockerar providernedladdning). Ersatt av
|
||
`terraform fmt` + en egen statisk referenskontroll; den riktiga valideringen
|
||
sker i CI.
|
||
- **Claude-nyckeln fylls i för hand** efter första `apply` — den ligger inte i
|
||
Terraform-state, med avsikt.
|
||
- **`postgres-init.sql` körs manuellt** mot databasen efter basens `apply`.
|
||
- **Ingen automatisk återställningstest av backup.** Larmet säger att backup
|
||
*sker*, inte att den *går att återställa*.
|
||
- **Metodikbiblioteket täcker inte allt** — och påstår det inte. `generisk` är
|
||
skyddsnätet.
|
||
- Rotens eslint har 20 förbefintliga fel i Semantikas egna sidor (`no-explicit-any`)
|
||
som inte hör till Guidad Felsökning.
|
||
|
||
---
|
||
|
||
## 18. Ordlista
|
||
|
||
| Svenska | Betydelse |
|
||
|---|---|
|
||
| Ärende | Ett felsökningsuppdrag |
|
||
| Händelse / loggpost | Odelbar post i append-only-loggen |
|
||
| Metodik | Strukturerat felsökningsflöde |
|
||
| Steg | Fas i en metodik (symptom, visuell, mätningar …) |
|
||
| Kontroll | Enskild checklistpunkt med minimikrav |
|
||
| Krav | `matvarde` / `kommentar` / `foto` |
|
||
| Undantag | Dokumenterad orsak till att en kontroll hoppades över |
|
||
| Brief | Sammanställd ärendebild — projektion |
|
||
| Kvalitetsgrind | Regeluppsättning som måste passeras före avslut |
|
||
| Evidensnivå | E0–E6, bevisvärdet i underlaget |
|
||
| Reproducering | Symptomverifiering: ja / delvis / nej |
|
||
| Felorsak | Strukturerad orsaksanalys med kategori och underlag |
|
||
| Delning | Extern länk med behörighetsnivå |
|
||
| Orkester | Tjänsten som äger modellroutingen |
|
||
| Spann / spår | Tidsmätning respektive W3C-spårning |
|
||
| Bilaga | Innehållsadresserat foto/video/dokument |
|