Skip to content

Datakontrakt

Datakontrakten definerer strukturen på payloaden som sendes fra Lumi Survey-widgeten til Lumi API.

Transport payload

Widgeten samler inn svar og sender en strukturert JSON-payload til backend. Payloaden har følgende hoveddeler:

FeltPåkrevdBeskrivelse
schemaVersionAlltid 2 (gjeldende versjon)
submittedAtISO 8601 tidsstempel for innsending
surveyIdUnik survey-identifikator — immutabel når først registrert
surveyTypeEn av: "rating", "topTasks", "discovery", "taskPriority", "custom"
answersStrukturert array med svar (se under)
definitionSurvey-strukturen (felter, etiketter, valg). Registreres ved første innsending og valideres mot ved senere innsendinger
contextAnbefaltNettleser-/brukerkontekst for segmentering

Survey-versjonering

surveyId + definition er en immutabel kobling. Strukturelle endringer (felt lagt til/fjernet/flyttet, fieldType endret, ratingVariant endret, option-id-er endret eller flyttet) krever en ny surveyId. Label-endringer (spørsmålstekst, beskrivelser og option-labels) oppdateres i-place og regnes som "safe changes". Ved strukturkonflikt returnerer API-et 409 definition_conflict med diff. Responsen beholder rå surveyId for bakoverkompatibilitet, men klienter skal bruke surveyIdRef i logger. Diffen kan redigere PII-formede felt- eller option-id-er; da settes diffRedacted: true, og diffen må behandles som diagnostikk, ikke som en rå ekko av alle identifikatorer.

Definition-blokken

typescript
interface SurveyDefinitionPayload {
  surveyType: SurveyType;
  fields: Array<{
    fieldId: string;       // Må matche fieldId i answers
    fieldType: "RATING" | "TEXT" | "SINGLE_CHOICE" | "MULTI_CHOICE" | "DATE";
    label: string;
    description?: string;
    ratingVariant?: "emoji" | "thumbs" | "stars" | "nps";  // Påkrevd for RATING
    ratingScale?: number;
    lowLabel?: string;     // Kun NPS
    highLabel?: string;    // Kun NPS
    options?: Array<{ id: string; label: string }>;  // Påkrevd for choice-typer
  }>;
}

Answers-arrayet

Hvert element i answers følger dette skjemaet:

typescript
interface TransportAnswer {
  fieldId: string;       // Unik spørsmåls-ID (f.eks. "task", "feedback")
  fieldType: string;     // En av: "RATING", "TEXT", "SINGLE_CHOICE", "MULTI_CHOICE", "DATE"
  value: AnswerValue;    // Selve svaret
  question: {
    label: string;       // Spørsmålsteksten vist til bruker
    description?: string;
    options?: Array<{ id: string; label: string }>;  // Påkrevd for valg-typer (for label-oppslag)
  };
}

Svartyper

AnswerValue er en union med fem varianter:

typescript
// Fritekst
{ type: "text", text: "Veldig bra!" }

// Rating — ratingVariant og ratingScale må samsvare med definition-feltet
{ type: "rating", rating: 5, ratingVariant: "emoji", ratingScale: 5 }

// Enkeltvalg — selectedOptionId må finnes i definition.fields[i].options
{ type: "singleChoice", selectedOptionId: "opt_1" }

// Flervalg
{ type: "multiChoice", selectedOptionIds: ["opt_1", "opt_2"] }

// Dato (YYYY-MM-DD)
{ type: "date", date: "2026-03-29" }

Context-objektet

Widgeten samler automatisk nettleserkontekst og slår sammen med bruker-definert segmenteringsdata:

typescript
interface LumiContext {
  // Auto-samlet av widgeten
  deviceType?: DeviceType;   // "mobile" | "tablet" | "desktop"
  viewport?: { width: number; height: number };
  userAgent?: string;

  // Opt-in (krever collectLocation: true)
  url?: string;              // Gjeldende side-URL
  pathname?: string;         // URL pathname

  // Segmentering (LAV KARDINALITET → dashboard-grafer)
  tags?: Record<string, string | number | boolean>;

  // Debugging (HØY KARDINALITET → kun i detaljvisning)
  debug?: Record<string, unknown>;
}

Tags vs. debug

FeltKardinalitetBruksområdeEksempel
tagsLav (< 10 verdier)Grafer, segmentering{ abTest: "A", rolle: "arbeidsgiver" }
debugHøy (OK)Inspeksjon av enkeltinnslag{ sessionId: "abc-123", behandlingId: "..." }

Ikke legg høy-kardinalitet i tags

Tags med mange unike verdier (f.eks. bruker-IDer) gir ubrukelige grafer i dashboardet. Bruk debug-feltet for slike verdier.

Survey-typer

Backend mapper surveyType-strenger til enums:

Widget-verdiBackend-enum
"rating"SurveyType.RATING
"topTasks"SurveyType.TOP_TASKS
"discovery"SurveyType.DISCOVERY
"taskPriority"SurveyType.TASK_PRIORITY
Alt annetSurveyType.CUSTOM

Komplett eksempel

json
{
  "schemaVersion": 2,
  "submittedAt": "2024-12-03T14:22:00.000Z",
  "surveyId": "sykepenger-rating",
  "surveyType": "rating",
  "context": {
    "url": "https://nav.no/sykepenger",
    "pathname": "/sykepenger",
    "deviceType": "mobile",
    "tags": {
      "abTest": "A",
      "rolle": "bruker"
    }
  },
  "answers": [
    {
      "fieldId": "rating",
      "fieldType": "RATING",
      "question": { "label": "Hvordan var opplevelsen din?" },
      "value": { "type": "rating", "rating": 4, "ratingVariant": "emoji", "ratingScale": 5 }
    },
    {
      "fieldId": "feedback",
      "fieldType": "TEXT",
      "question": { "label": "Har du andre tilbakemeldinger?" },
      "value": { "type": "text", "text": "Veldig bra!" }
    }
  ],
  "definition": {
    "surveyType": "rating",
    "fields": [
      { "fieldId": "rating", "fieldType": "RATING", "label": "Hvordan var opplevelsen din?", "ratingVariant": "emoji", "ratingScale": 5 },
      { "fieldId": "feedback", "fieldType": "TEXT", "label": "Har du andre tilbakemeldinger?" }
    ]
  }
}

Se også

Lumi Analytics — bygget på navikt/lumi (MIT-lisens)