Files
kvitt/docs/ux/flows.md
T
jacobh2 b72ac5bb9e UX sprint U1: three directions, IA, screens, flows, components, tokens, strings
Three visual directions (Skärgård, Kvitto, Kalas) as self-contained HTML pages with
every SPEC §13.3 screen in light and dark, Swedish, plus PNG exports and the exporter
script. Direction-independent docs: ia.md, screens.md, flows.md, components.md,
tokens.md (values for all three directions), strings.csv (key,en,sv,notes), and the
comparison with a recommendation in directions/README.md.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-18 08:27:51 +02:00

11 KiB
Raw Blame History

Kvitt: flows

Status: U1 proposal (2026-10-17). Step-by-step flows with screen ids (ia.md, screens.md). Rules referenced by spec section; nothing here redefines them. Data from the shared mock household (Jacob = owner/admin, Anna = partner; today lördag 17 oktober 2026).

Notation: User does · System does · S-n screen · ⟶ navigation.


F-1 First run as admin (US-1, FR-1, FR-2, FR-5)

  1. Jacob runs kvitt-server bootstrap on the Pi (outside the app); it prints the code 7K3M-QX9D-2HPA and the link https://icehack.asuscomm.com:8443/i/7K3MQX9D2HPA (AC-1.1).
  2. Jacob opens the link on the phone. The landing page (AC-2.5) offers "Ladda ner Kvitt" (first time) and "Öppna i Kvitt".
  3. Jacob installs the APK (Android asks once to allow installs from the browser; outside the app), then taps "Öppna i Kvitt" ⟶ S-1 with server and code filled (AC-2.6). Without a link: S-1 empty, he types the code (server prefilled).
  4. Jacob types his name in "Ditt namn" and taps "Para ihop". Progress "Parar ihop…"; pairs with the phone model as device name ("Galaxy S26"). (S-1 always has "Ditt namn" on a first pairing because AC-2.4 sends the display name in the accept call and the app cannot know the invite kind beforehand; the server ignores it for device invites. The field is hidden in the "Para ihop telefonen igen" variant.)
  5. Full sync (AC-2.9) ⟶ S-4 loading state "Hämtar era utgifter…" ⟶ the system notification-permission prompt.
  6. Partner not yet joined ⟶ S-4 shows the S-3 content "Väntar på din partner" (AC-5.1).
  7. Jacob taps "Bjud in partner" ⟶ S-21, a partner invite is created and shown: code in groups of 4, link, "Gäller till tis 20 okt. 14:02".
  8. Jacob taps "Dela" ⟶ Android share sheet ⟶ sends the message to Anna (SMS, Signal, …). Back ⟶ S-3 now shows the expiry.
  9. When Anna has joined (F-2), the next sync replaces S-3 with S-4 empty state "Skapa ert första konto" ⟶ Jacob taps "Nytt konto" ⟶ S-6 "Vardag", 50/50 ⟶ Spara ⟶ S-4 with the account and the FAB.

Error branches: invite_invalid / network / rate_limited inline on S-1 (screens.md S-1). Lost every phone later: kvitt-server pair-device (AC-1.6) then F-1 steps 2–5.

F-2 Join as spouse (US-2, AC-2.4, AC-2.10)

  1. Anna receives Jacob's message, taps the link ⟶ landing page ⟶ "Ladda ner Kvitt" ⟶ installs (Android "Install unknown apps" for her browser, once) ⟶ "Öppna i Kvitt" ⟶ S-1 filled.
  2. Anna types her name in "Ditt namn" ("Anna") and taps "Para ihop" ⟶ pairs, creates the member user.
  3. ⟶ S-2: "Du går med i Jacobs hushåll", her name prefilled, avatar with initials. Anna taps "Lägg till bild" ⟶ photo picker ⟶ picks a photo ⟶ upload with progress. Taps "Fortsätt".
  4. Full sync ⟶ S-4 loading ⟶ notification permission prompt ⟶ S-4 empty "Skapa ert första konto" (or Jacob's accounts, if he created any after she joined).
  5. On Jacob's phone the next sync (or push-triggered sync) removes S-3.

F-3 Add an expense online (US-3, AC-8.6) — the ten-second flow

  1. Jacob opens Kvitt ⟶ S-4.
  2. Taps FAB "Lägg till utgift" ⟶ S-7 with amount focused, keypad up; defaults: Konto Vardag (last used), Kategori (last used in Vardag, else Övrigt), Datum Idag, Betalt av Du, Delning Kontots standard 50/50.
  3. Types 412.
  4. Taps Beskrivning, types "Systembolaget".
  5. (optional, one tap each) taps the Kategori chip ⟶ grid ⟶ Nöje; taps Betalt av to switch to Anna; taps Delning to open the split section.
  6. Taps "Spara" ⟶ saved locally, pending ⟶ back to S-4, snackbar "Utgiften sparades"; Vardag's wording/amount and the global hero update immediately (AC-10.4).
  7. 2 s later, sync pushes (AC-15.3); the sync line returns to "Synkad nyss"; the server pushes expense_created to Anna's phone, which syncs and shows "Jacob lade till en utgift · Systembolaget · 412,00 kr · Vardag".

F-4 Add an expense offline, then sync (US-12, FR-15)

  1. Jacob is on a plane. S-4 sync line: "Offline · Synkad 14 okt. 08:12".
  2. F-3 steps 2–6 exactly. Snackbar "Sparad. Synkas när du är online." The row in S-5 shows the pending marker; S-4 sync line "Offline · 1 ändring väntar på synk".
  3. He adds more and edits one; the count increases ("3 ändringar väntar på synk"). Account, category and recurring actions show "Kräver anslutning".
  4. Landing: network returns ⟶ sync on foreground or WorkManager ⟶ sync line "Synkar…" ⟶ "Synkad nyss"; pending markers disappear.
  5. Conflict branch: Anna edited the same expense meanwhile with a later updated_at ⟶ push answers stale ⟶ the row shows Anna's version; sync line "Synkad nyss · 1 ändring synkades inte" (warning style) ⟶ tap ⟶ S-16 "Ändringar som inte synkades": "Babette · Din ändring ersattes av en nyare ändring från Anna" ⟶ tap opens the current expense (read-only S-8) ⟶ "Ta bort från listan".
  6. Delete branch: Anna deleted it ⟶ reason deleted "Den här togs bort innan din ändring kom fram".

F-5 Edit an expense the other person created (AC-8.2, AC-12.4)

  1. Jacob gets a notification "Anna lade till en utgift · ICA Maxi Lindhagen · 1 147,60 kr · Vardag" ⟶ taps ⟶ S-8 (after sync).
  2. Timeline: "Anna skapade den här · 16 okt. 14:02". He sees the receipt says 1 247,60.
  3. Taps "Ändra" ⟶ S-7 "Ändra utgift" with all fields loaded; amount focused.
  4. Changes 1 147,60 to 1 247,60 ⟶ "Spara" ⟶ back to S-8; timeline gains a last line "Din ändring väntar på synk".
  5. Sync ⟶ the pending line is replaced by "Du ändrade beloppet från 1 147,60 kr till 1 247,60 kr · 16 okt. 19:40".
  6. Anna's phone gets "Jacob ändrade en utgift · ICA Maxi Lindhagen · 1 247,60 kr"; her S-8 shows the same timeline (her view: "Jacob ändrade beloppet …").

F-6 Global settle-up with adjusted allocation (US-7, AC-11.3, AC-11.5, §9.4)

Start: global "Du är skyldig Anna 3 250,00 kr"; Vardag Anna owes Jacob 1 184,50; Huset Jacob owes 3 084,50; Japan 2027 Jacob owes 1 350,00.

  1. Jacob taps "Gör upp" on S-4 ⟶ S-9: "Du betalar Anna", amount 3 250,00 kr (default = global debt), proposal (oldest owing first): Huset 3 084,50, Japan 2027 165,50; "Kvar att fördela 0,00 kr"; info "Vardag påverkas inte: där är Anna skyldig dig 1 184,50 kr."
  2. They agreed to clear Japan first. Jacob edits Japan 2027 to 1 500,00 ⟶ row warning "Det här reglerar mer än som är skyldigt i Japan 2027" (1 500 > 1 350); remaining "−" ⟶ "1 334,50 kr för mycket"; Bekräfta disabled.
  3. Edits Huset to 1 750,00 ⟶ "Kvar att fördela 0,00 kr"; Bekräfta enabled; Japan warning remains.
  4. Sets Anteckning "Swish", Datum Idag. Taps "Bekräfta" ⟶ dialog repeating the warning ⟶ "Bekräfta ändå".
  5. Saved locally ⟶ back to S-4: global −3 250,00 + 3 250,00 = 0 ⟶ "Ni är kvitt"; per account Huset "Du är skyldig Anna 1 334,50 kr", Japan "Anna är skyldig dig 150,00 kr", Vardag unchanged. (This is §9.4's stated consequence; the per-account settle-ups in F-7 clear the rest.)
  6. Sync; Anna gets "Jacob registrerade en betalning · Jacob betalade dig 3 250,00 kr" (her view).

Variant: "Lägg till konto" ⟶ picker (all non-deleted accounts, archived included) ⟶ adds a row with 0,00 to fill in. Removing a row increases "Kvar att fördela".

F-7 Per-account settle-up (US-8, AC-11.4)

  1. Jacob on S-4 taps Huset ⟶ S-5 "Du är skyldig Anna 3 084,50 kr" ⟶ "Gör upp det här kontot".
  2. ⟶ S-9 per-account variant: "Du betalar Anna", 3 084,50 kr, one fixed row Huset 3 084,50. No "Lägg till konto".
  3. Optional: changes the amount to 2 000,00 ⟶ the single row follows the amount (it is the only allocation) ⟶ Bekräfta.
  4. ⟶ back to S-5: a settlement row "Du betalade Anna 3 084,50 kr" at the top of October; header "Kvitt".
  5. To settle an account where the other user owes (Vardag): S-5 Vardag ⟶ "Gör upp det här kontot" ⟶ direction defaults to "Anna betalar dig" (AC-11.4); Jacob records Anna's Swish.

F-8 Create a recurring expense (US-10, FR-9)

  1. Jacob ⟶ Inställningar S-13 ⟶ "Återkommande utgifter" S-19 ⟶ "Ny".
  2. Editor: amount 12 400,00; description "Hyra"; Konto Huset; Kategori Hem; Betalt av Anna (one tap); Delning Kontots standard 60/40; Dag i månaden 25; Första månad: defaults to oktober 2026 because the 25th is still ahead (AC-9.8); Sista månad empty.
  3. Spara (online) ⟶ list row "Hyra · 12 400,00 kr · Huset · Varje månad den 25:e · Nästa: 25 okt.".
  4. On 25 Oct at 06:00 the server creates the expense ⟶ both phones get "Återkommande utgift tillagd · Hyra · 12 400,00 kr · Huset" (AC-9.6) ⟶ S-8 shows "Återkommande: Hyra" and "Skapad automatiskt (återkommande) · 25 okt. 06:00".
  5. Offline at step 3 ⟶ Spara disabled with "Kräver anslutning".

Pause: list row ⟶ editor ⟶ "Pausad" on ⟶ Spara ⟶ row shows "Pausad". Resume does not backfill (§9.5); the editor shows the hint "Månader som passerat under pausen skapas inte i efterhand."

F-9 Archive an account (US-9, AC-6.4)

  1. Anna on S-4 ⟶ Japan 2027 ⟶ S-5 ⟶ overflow ⟶ "Arkivera" (online).
  2. Archived ⟶ back on S-4, snackbar "Japan 2027 arkiverades" with "Ångra". The account disappears from the active list and appears under "Arkiverade (2)" (collapsed) with its balance still shown; the global balance is unchanged (AC-10.5).
  3. In S-7 the account picker no longer lists it; S-9 "Lägg till konto" still does; S-11 still counts it.
  4. Unarchive: Home ⟶ "Arkiverade" ⟶ Japan 2027 ⟶ S-5 ("Arkiverat" badge) ⟶ "Återställ från arkiv".
  5. Delete branch: overflow "Ta bort konto" is disabled with "Kontot kan inte tas bort så länge det har utgifter, betalningar eller återkommande utgifter" unless the account is empty (AC-6.5).

F-10 In-app update (US-14, FR-16)

  1. Cold start of a release build ⟶ GET /apk/latest ⟶ version code higher ⟶ S-4 banner "Version 1.2 finns" [Uppdatera] [Senare].
  2. Jacob taps "Uppdatera". First time: dialog "Tillåt installation" explains that Android will ask once ⟶ "Fortsätt" ⟶ system settings "Installera okända appar" for Kvitt ⟶ he allows and taps back.
  3. Download ⟶ banner "Laddar ner… 64 %" with progress; the app stays usable.
  4. Size and SHA-256 verified ⟶ the system installer dialog ⟶ "Uppdatera" (system) ⟶ the app restarts on the new version.
  5. Failure ⟶ banner "Nedladdningen misslyckades. Försök igen." ⟶ "Försök igen" (AC-16.4).
  6. "Senare" hides the banner until the next cold start. The update is also reachable from S-22 "Sök efter uppdatering".

F-11 Remove a lost phone (US-17, FR-3) — supporting flow

  1. Jacob (admin) ⟶ S-13 ⟶ "Enheter" S-20 ⟶ the lost "Galaxy S26+" row ⟶ "Ta bort" ⟶ confirmation ⟶ revoked.
  2. The lost phone, if it ever connects, gets device_revoked ⟶ wipes local data ⟶ S-18 "Den här telefonen har tagits bort" ⟶ "Para ihop igen" ⟶ S-1.