b72ac5bb9e
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>
111 lines
11 KiB
Markdown
111 lines
11 KiB
Markdown
# 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`.
|