Commit Graph

5 Commits

Author SHA1 Message Date
Claude d3cae27fa4 Bilagor ut ur händelseloggen — referens och hash i stället för inbäddat
Foton, video och instrumentbilder låg som data-URL:er inne i händelserna.
Det drabbade allt som läser loggen: synken drog med hela bildmassan var
femtonde sekund, kundvyn likaså, och en säkerhetskopia av loggen var i
praktiken en kopia av alla foton.

Nu ligger innehållet utanför händelsen och loggen bär en referens med
innehållets SHA-256. Det försvagar inte bevisvärdet utan stärker det:
hashen står i den append-only-skyddade loggen, så en bild som bytts ut
går att upptäcka. Tidigare låg bilden i loggen och måste helt enkelt tros
på. Innehållet kontrolleras mot hashen varje gång det lämnas ut — stämmer
det inte svarar tjänsten 409 i stället för att visa bilden.
Innehållsadresserat, så samma foto som dokumenteras två gånger lagras en
gång.

Två lägen: databas (bytea, fungerar överallt utan konfiguration) och s3
(AWS, MinIO, Ceph). Signeringen är egen — SigV4 för PUT och GET — i
stället för molnleverantörens SDK, eftersom två operationer inte
motiverar tiotals megabyte beroenden i en bild som annars bara har
pg-drivrutinen. Den korsverifieras bit för bit mot botocore i testerna.
Det avslöjade en riktig bugg direkt: host-huvudet saknade portnummer,
vilket hade fungerat mot AWS men avvisats av all självhostad S3.

Kodningen av objektnycklar kanoniseras medvetet inte. S3 följer andra
URL-regler än övriga AWS-tjänster och en felgissad regel ger signaturer
som ser rimliga ut men avvisas. I stället begränsas hink och prefix till
tecken som aldrig behöver kodas — då finns ingen regel att gissa fel på.

Delningsgränsen gäller även bilagor: en bilaga lämnas bara ut via en
delningslänk om händelsen den hör till är synlig på den nivån, så den
skannade arbetsordern nås aldrig via kundlänken.

Uppladdningen sker på ett enda ställe — sidans egna skicka() flyttar
innehållet innan händelsen skrivs, så ingen panel behövde ändras.
Misslyckas det, eller saknas server som i lokalt läge, bäddas det in
precis som förut. Dokumentationen får aldrig gå förlorad för att nätet
ligger nere, och äldre händelser med inbäddad data-URL fortsätter fungera
för alltid eftersom loggen är append-only.

Verifierat: 96 vitest-tester (varav 9 nya för signering och
innehållsadressering), typkontroll, eslint, OpenAPI-validering, terraform
fmt och referenskontroll, samt integrationstest mot riktig Postgres med
13 nya kontroller — bland annat att ett manipulerat innehåll upptäcks och
inte lämnas ut, och att kundlänken når fotot men inte arbetsordern.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012EQg3rJsrQ1ZNTvkzmQAtt
2026-08-04 11:28:52 +00:00
Claude 3a0be7261e Märkesspecifika kopplingar — kunden lägger in sina egna credentials
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
2026-08-03 12:50:44 +00:00
Claude a37cc027ae Personbil-etikett i granskningen + ECM Knowledge Library
Arbetsordergranskningens fältgrupp heter nu Personbil (tidigare Fordon),
liksom raden i rapportens fordonsinformation.

ECM Knowledge Library: regelbiblioteket är nu serverdistribuerat —
regler uppdateras i driften utan appändring, precis som rekommenderat:

- Compliance-reglerna är deklarativ data (krav-typ i stället för kod):
  services/plattform/ecm-regler.json serveras på GET /api/ecm/regler,
  i klustret utbytbar via ConfigMap (ECM_REGLER_FIL)
- Klienten hämtar paketet vid sidladdning, cachar det och faller
  tillbaka till inbyggt standardpaket offline; trasiga paket och okända
  krav-typer filtreras (normaliseraRegelpaket)
- Kvalitetsgrinden, orsakskategorierna, evidenskällorna och
  undantagsorsakerna läses ur det aktiva paketet; spårbarhetspaketet
  bär regelpaketets version
- Testat: paritet server/standardpaket, fallback, att ett uppdaterat
  paket ändrar grinden utan appändring; integrationstestet verifierar
  serveringen (57 vitest-tester gröna)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012EQg3rJsrQ1ZNTvkzmQAtt
2026-08-03 09:38:44 +00:00
Claude 12c5f1c617 API-first: OpenAPI 3.0-spec för plattforms-API:t
- services/plattform/openapi.yaml dokumenterar hela ytan: auth
  (registrera organisation, logga in), användarhantering (admin),
  ärenden + append-only händelselogg (idempotent synk), arbetsledar-
  översikten, publik Live Share-delning och AI-orkestern — inklusive
  scheman för alla 15 händelsetyper, roller, JWT-anspråken och
  API:ts bärande principer (append-only, multi-tenant-404).
- Specen serveras live av plattformstjänsten på GET /api/openapi.yaml
  och följer med i containern.
- Verifierad i tre lager: maskinell validering (swagger-cli),
  paritetstest i vitest (varje dokumenterad väg finns i servern,
  händelsetyperna är kompletta) och integrationsteststeg som hämtar
  specen från den körande tjänsten.

Verifierat: integrationstestets 18 kontroller gröna mot Postgres 16,
29 vitest-tester gröna, produktionsbygge ok.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012EQg3rJsrQ1ZNTvkzmQAtt
2026-08-03 07:22:05 +00:00
Claude 7c24186cc5 Helt självhostat: plattformsbackend, Postgres i klustret, klientläge
Sista externa beroendet borta — hela stacken kör i eget kluster:

- Ny plattformstjänst (services/plattform): egen inloggning
  (registrering + inloggning, lösenord bcrypt-hashade med pgcrypto,
  HS256-JWT), append-only händelse-API för synken (endast insert,
  on conflict do nothing) och publik delningsendpoint för Live Share
  med samma filtrering som Supabase-funktionen. Fail closed utan
  hemligheter; inga update/delete-operationer exponeras.
- Postgres som StatefulSet med PVC och init-schema; append-only
  garanterat i databasen med triggers på både händelser och ärenden —
  historik kan inte ändras oavsett ansluten roll. CloudNativePG
  rekommenderas för produktion i docs.
- JWT-hemligheten delas mellan plattform och AI-orkester (orkestern
  läser JWT_SECRET med SUPABASE_JWT_SECRET som fallback) — flödet
  livetestat: plattformens token accepteras av orkestern, fel
  hemlighet och utgångna tokens avvisas.
- Klienten får självhostat läge via VITE_PLATTFORM_URL: inloggnings-
  panel på startsidan, synk mot plattformens API (samma konfliktfria
  flätning), Live Share via /api/delad och AI via klustrets orkester.
  Utan variabeln är Supabase-läget oförändrat.
- Ingress routar /api/ai → orkestern, /api + /halsa → plattformen,
  / → webben; kustomize inkluderar hela stacken; CI bygger alla tre
  bilderna; DRIFT.md omskriven för självhostad drift.

Verifierat: 28 vitest-tester gröna (inkl. append-only-triggers och
API-ytan), plattformstjänsten livetestad (hälsa, 401, fail closed),
JWT-paritet mellan tjänsterna testad, alla manifest YAML-validerade,
produktionsbygge ok, Playwright-röktest grönt.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012EQg3rJsrQ1ZNTvkzmQAtt
2026-08-03 01:41:58 +00:00