Files
Cibello-app/docs/19-beslutslogg.md
2026-08-05 19:21:11 +07:00

26 lines
12 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Beslutslogg låsta beslut med motivering
> Beslut refereras löpande i respektive dokument (arkitektur, subscriptions,
> säkerhet, i18n). Här samlas de centralt. Nummerserien är stabil återanvänd
> aldrig ett nummer.
| # | Beslut | Motivering | Var det syns |
| ----- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------- |
| D-011 | Zod-validering via central `parse()`-hjälpare i stället för Fastify type-provider | Full kontroll över felformatet (VALIDATION_ERROR + correlationId) och samma mönster i alla routes | `apps/api/src/lib/errors.ts` |
| D-014 | Ingen hälso-/kostdata till reklam; inga annons-SDK:er i appen | Policybeslut (spec §56): förtroende är produktens kärna | docs/12 |
| D-021 | Val av butiksbibliotek i mobilen (StoreKit2/expo-iap) skjuts till fas 7 | Backend-verifieringen är kontraktet; klientbiblioteket kan väljas när butikskonton finns | docs/13 |
| D-023 | Interims-t() byggdes namespace-format ("home._", "scan._") för mekanisk flytt till i18next | Undvika total omskrivning i M4 flytten blev ren datamigrering av nycklar | docs/20, M4 |
| D-024 | Adminpanelen förblir svensk tills internationell ops finns | Internverktyg; nyckel-migrering (M9) kostar mer än den ger före internationell drift | docs/20 |
| D-025 | i18next med inbyggd Intl.PluralRules-plural (`_one`/`_other`) i stället för ICU-tilläggspaket | Samma korrekthet för våra språk utan extra runtime-beroende; ICU-syntax kan läggas till per-nyckel senare om behov uppstår | `apps/mobile/src/lib/i18n.ts`, M4 |
| D-026 | Varumärket är ENDAST konfiguration: neutrala platshållare i `brand.config.json` tills namnet beslutas; git-historiken tillplattad så inget arbetsnamn förekommer någonstans | Namnet är inte beslutat; ett byte ska vara en enradsändring, inte en kodsanering. Extern historik-backup finns utanför repot | brand.config.json, docs/namnbyte.md |
| D-027 | Översättningar är RADER per språk (aldrig kolumner), svensk källtext är sanningen, endast `status=published` serveras användare; AI-utkast verifieras deterministiskt (stegantal, bevarade tal, konfidens) före mänsklig publicering | Skalar till godtyckligt många språk utan schemaändring; AI kan aldrig tyst ändra mängder/struktur (spec §61.1) | packages/database/schema/translations.ts, worker/translation.ts, M2M3 |
| D-028 | Katalogpriser (ingredienser, receptkostnad, inköpsuppskattningar) ligger i basvaluta SEK tills M8 inför per-marknadspriser; hushållets `currency_code` styr användarens egna belopp | Undviker låtsas-valutakonvertering utan riktiga växelkurser ärlighet före skenprecision | schema/ingredients.ts, routes/shopping.ts, M1 |
| D-029 | Måttvisning konverterar ALDRIG lagrade värden: kanoniskt värde är sanning, `displayQuantity` räknar fram visning per måttsystem och märker konverterade värden med ≈ | Förlustfrihet (i18n-spec §30) + ärlig osäkerhet (spec §61.4) | shared-types/measurement.ts, M5 |
| D-030 | Marknadsprofiler (nutrition/allergener) styr endast VISNING användarens personliga allergisäkerhet filtrerar alltid, oavsett marknad | En marknadsregel får aldrig försvaga en säkerhetsspärr (spec §61.2) | schema/markets.ts, M6 |
| D-031 | Språkpolicy: (1) första start → enhetens språk om stött, (2) ostött → engelska, (3) manuellt val i profilen vinner alltid och synkas till backend; registreringen bär enhetens locale så att välkomstmejl + preferenser är rätt från första sekunden | Spanjoren som laddar ner appen får spanska automatiskt; spanjoren i Sverige väljer själv. Nytt språk = en JSON-fil + SUPPORTED_LANGUAGES-rad + seed-rader (paritet testvaktad) | apps/mobile/src/lib/i18n.ts, routes/auth.ts, D-031-tester |
| D-032 | Första utgåvans språk: sv, en, es, it, de, fr, da, nb, fi, nl, pl, pt (Norden + de stora EU-marknaderna + engelska). Norska varianter (no/nn) mappas till nb. Fler EU-språk läggs till efter behov via språkmallen | Täcker spec-fasernas lanseringsmarknader (Norden→EU→UK/US/CA) med korrekt pluralhantering (polskans one/few/many). Seed-översättningar är AI-skrivna native-granskning före lansering står i runbooken | locales/, D-031/D-032-tester, seed |
| D-033 | UTC-kalenderpolicy: alla deterministiska motorer och API:ts server-side-datummatte räknar i UTC (`Date.UTC`/`getUTC*`, datumsträngar tolkas `T00:00:00Z`); tester skrivs med UTC-datum och verifieras under flera tidszoner | Fältfynd från första OpenClaw-deployen: två tester var tidszonkänsliga (lokal `new Date(y,m,d)` mot UTC-`toISOString`). Motorer ska ge identiskt resultat oavsett serverns TZ och UTC saknar sommartid | inventory-engine/expiry.ts, recommendation-engine/season.ts, budget.ts |
| D-034 | Docker är valfritt i first-deploy: Grind 0 noterar bara om docker finns; Grind 2 avgör på faktisk nåbarhet (Postgres via pg-klient, Redis via rå TCP-PING) och använder Docker enbart som reservstart i staging | Fältfynd: WSL-värd utan Docker tvingade agenten bygga ett docker-shim trots att native Postgres/Redis fungerade perfekt. Nåbarhet är sanningen, inte verktygslistan | infrastructure/deployment/first-deploy.sh, OPENCLAW-DEPLOY-PROMPT.md |
| D-035 | Mjölkprincipen: passerat "bäst före" är en KVALITETSsignal (status expiring + pastBestBefore, aldrig expired; FEFO räddar den FÖRST; täckning räknar den som tillgänglig; UI säger "lukta och smaka"), medan "sista förbrukningsdag" är en hård säkerhetsgräns. Användaren väljer datumtyp vid skanningsgranskning | "Bara för att mjölken gick ut igår är den inte automatiskt dålig" appen får varken döma ätbar mat (svinn) eller mjuka upp riktiga säkerhetsgränser (spec §13, §61.3). Ingen automatisk kassering finns någonstans | expiry.ts, fefo.ts, matching.ts, scan-review, home, mjölkprincip-tester |
| D-036 | Inga hårdkodade UI-strängar: samtliga användarsynliga texter i mobilappen går via i18n-katalogen (svep 2026-08-05: ~130 nycklar flyttade ur 15 skärmar till alla 12 språk) | Testprotokollets löfte "byt språk → HELA appen byter direkt" ska vara sant bokstavligen; hårdkodade etikettkartor (mål, allergener, butikssektioner, måltidstyper, dialoger) bröt det | apps/mobile/src/app/_, locales/_/common.json |