Receipt Photo Upload
Feature Detail
Description
Enables peer mentors to attach receipt photos to expense items exceeding the organization-configured reimbursement threshold. The camera integration uses the device camera or photo library, compresses images before upload, and stores each receipt as a one-to-one record linked to its expense_items row. The upload is non-blocking and queued in the mutation outbox, preserving the offline-first workflow so registration is never blocked by connectivity. The backend issues presigned upload URLs so the mobile client writes directly to object storage without holding long-lived credentials. Coordinators and admins view attached receipts during expense approval in the admin portal.
Sources & reasoning
Line 69 explicitly specifies receipt photo capture for expenses over 100 kr for HLF. The parent area is Fase 2 in the priority matrix at line 148, mapping to v1.0 by ordinal phase position.
-
docs/source/likeperson.md · line 69Kvitteringsbilde for utlegg over 100 kr (HLF).
-
docs/source/likeperson.md · line 148Reiserefusjon / utleggsregistrering | - | - | ✓ | ✓ | ✓ | SHOULD HAVE | 2
Analysis
Receipt documentation is a compliance requirement for expense reimbursement above defined thresholds; HLF sets this at 100 kr. Without digital capture, peer mentors retain paper receipts and submit them separately, creating friction, loss risk, and processing delays for coordinators who must reconcile paper with digital records. Integrating receipt capture into the same registration flow removes the paper step entirely and creates an immutable audit trail directly linked to the specific expense item. For Bufdir grant compliance and internal accounting audits, receipts digitally attached to expense records eliminate a manual reconciliation step. The result is faster approval cycles, fewer missing-receipt follow-ups from coordinators, and lower administrative cost per claim. Offline queuing ensures peer mentors in low-connectivity areas are not disadvantaged by the requirement.
Uses Flutter's image_picker package for camera and gallery access, with platform-level permission handling following the pattern established by CalendarPermissionHandler and SpeechPermissionHandler. Images are compressed to a configurable maximum resolution before upload to limit storage cost and transmission time. ReceiptStorageClient requests a presigned upload URL from the backend, writes the image directly to object storage, then stores the resulting object key in the expense_receipts table. In offline mode the compressed image is stored as a local file path reference in Drift and queued in the mutation outbox alongside the parent expense record. On reconnect the outbox processor uploads the image first, receives the object key, then persists the expense_receipts row. The backend enforces the receipt requirement server-side by checking whether a receipt record exists for above-threshold items before allowing approval, providing defense in depth independent of client flow.
Quality Assurance
Peer Mentor (primary) · Coordinator (same flow)Peer Mentor
Quick UAT
- Logg inn i mobilappen som Likeperson. Naviger til en pågående aktivitet og åpne utgiftsregistreringen. Velg et utleggsbeløp over 100 kr (f.eks. 150 kr) og bekreft at feltet «Legg til kvittering» vises.
- Trykk «Legg til kvittering». Bekreft at du får valget mellom kamera og bildebibliotek.
- Velg kamera. Ta bilde av kvitteringen og trykk «Bruk bilde». Bekreft at et forhåndsvisningsbilde vises i skjemaet med en fremdriftsindikator for opplasting.
- La appen laste opp (eller fortsett offline). Bekreft at kvitteringen vises som «Vedlagt» eller «I kø» dersom du er uten nett.
- Fullfør utgiftsregistreringen og send inn. Bekreft at kvitteringen er tilknyttet utleggsposten og vises på sammendragsskjermen.
Quick UAT — Accessibility
-
Logg inn i mobilappen som Likeperson. Naviger til en pågående aktivitet og åpne utgiftsregistreringen. Velg et utleggsbeløp over 100 kr (f.eks. 150 kr) og bekreft at feltet «Legg til kvittering» vises.
- Screen reader Sidetittel annonseres ved navigasjon; beløpsfelt har label 'Beløp'; 'Legg til kvittering'-knapp annonseres med rolle 'knapp' når terskel overskrides.
- Keyboard / focus Tab-rekkefølge: beløpsfelt → utleggstype → kvitteringsknapp. Kvitteringsknapp nås med Tab og aktiveres med Enter/Space.
- Focus visibility Synlig fokusring på alle interaktive felt; kvitteringsknapp får fokus automatisk etter beløpet overskrider terskel.
- Contrast «Legg til kvittering»-etiketten oppfyller 4.5:1; obligatorisk-indikator ikke formidlet med farge alene.
-
Trykk «Legg til kvittering». Bekreft at du får valget mellom kamera og bildebibliotek.
- Screen reader Bunnark annonseres som 'dialogboks'; valgene 'Kamera' og 'Bildebibliotek' leses opp med rolle 'knapp'.
- Keyboard / focus Bunnark fanges i fokus (focus trap); Tab navigerer mellom valg; Escape lukker arket uten handling.
- Focus visibility Første knapp i arket mottar fokus automatisk ved åpning; lukkeknapp er tydelig merket.
- Touch target Knappene 'Kamera' og 'Bildebibliotek' er minimum 48×48 CSS px.
-
Velg kamera. Ta bilde av kvitteringen og trykk «Bruk bilde». Bekreft at et forhåndsvisningsbilde vises i skjemaet med en fremdriftsindikator for opplasting.
- Screen reader Forhåndsvisningsbilde har alt-tekst 'Kvitteringsbilde vedlagt'; fremdriftsindikator annonseres som 'laster opp, X prosent'.
- Focus visibility Fokus returnerer til skjemaet etter kameralukkingen; fremdriftsindikatoren er ikke fokuserbar men leses av skjermleser via live region.
- Live region 'Kvittering laster opp' annonseres via polite live region ved oppstart; 'Opplasting fullført' ved suksess.
- Zoom Forhåndsvisningsbilde og fremdriftsindikator forblir synlige og ikke avskåret ved 200% zoom.
-
La appen laste opp (eller fortsett offline). Bekreft at kvitteringen vises som «Vedlagt» eller «I kø» dersom du er uten nett.
- Screen reader Status 'Vedlagt' eller 'I kø' annonseres som tekstendring via polite live region; ikonet som viser status har tilhørende tekstetikett.
- Live region 'Kvittering lagret lokalt, synkroniseres når nett er tilgjengelig' ved offlinestatus.
- Contrast Statusikoner ('Vedlagt' grønn hake, 'I kø' gult ikon) er ikke formidlet med farge alene; ledsagende tekst er alltid til stede.
-
Fullfør utgiftsregistreringen og send inn. Bekreft at kvitteringen er tilknyttet utleggsposten og vises på sammendragsskjermen.
- Screen reader Sammendragsskjermen annonserer 'Utlegg sendt inn med kvittering vedlagt'; kvitteringsminiatyrbildet har beskrivende alt-tekst.
- Keyboard / focus «Send inn»-knapp nås med Tab og aktiveres med Enter; ingen innsendings-handling utløses utilsiktet ved Enter i tekstfelt.
- Focus visibility Etter innsending flyttes fokus til bekreftelsesmeldingen øverst på sammendragsskjermen.
- Live region 'Utlegg registrert. Kvittering vedlagt og sendt til godkjenning.' annonseres via polite live region.
Role Boundaries
3 role(s) must NOT access this feature-
Organization Administrator
Skjermen finnes ikke i admin-portalens navigasjon; organisasjonsadministrator logger ikke inn i mobilappen og kan ikke nå kvitteringsopplastingen.
-
Global Administrator
Global administrator har ikke tilgang til mobilappen; deep-link til kvitteringsskjermen returnerer 403.
-
Prospective Organization Representative
Rollen eksisterer kun på salgsnettsiden og har ingen konto i driftsplattformen; alle API-kall returnerer 401.
Expected End State
Kvitteringsbildet er komprimert, lastet opp til objektlagring via presignert URL, og lagret som en expense_receipts-rad koblet til den aktuelle expense_items-posten. Utlegget vises med status 'Til godkjenning' i koordinatorens godkjenningskø med kvitteringsvedlegget tilgjengelig.
Components (21)
Shared Components
These components are reused across multiple features
User Stories
No user stories have been generated for this feature yet.