439 lines
12 KiB
Markdown
439 lines
12 KiB
Markdown
# Feature 3 – Uppgiftspoäng
|
||
|
||
## Status
|
||
|
||
Pågående.
|
||
|
||
## Bakgrund
|
||
|
||
HemHub ska på sikt kunna använda spelifiering för att uppmuntra
|
||
familjemedlemmar att utföra uppgifter. Exempel på framtida funktioner kan vara
|
||
mål, achievements och belöningar baserade på hur många poäng en användare
|
||
samlar under en viss period.
|
||
|
||
Feature 3 inför den grundläggande poänginformationen på uppgiften. Funktionen
|
||
registrerar endast uppgiftens poängvärde. Intjäning av poäng och övrig
|
||
spelifiering införs i senare features.
|
||
|
||
## Mål
|
||
|
||
Feature 3 ska:
|
||
|
||
- lägga till ett obligatoriskt poängvärde på varje uppgift;
|
||
- låta användaren ange poäng när en uppgift skapas;
|
||
- visa poängen på uppgiftskortet;
|
||
- validera poängen konsekvent i frontend och backend;
|
||
- dokumentera hur lokal utvecklingsdata hanteras.
|
||
|
||
## Betydelsen av poäng
|
||
|
||
Poängen uttrycker uppgiftens samlade värde utifrån hur:
|
||
|
||
- tidskrävande uppgiften är;
|
||
- besvärlig uppgiften är;
|
||
- viktig uppgiften är.
|
||
|
||
När poängintjäning införs i en senare feature ska samma värde motsvara hur många
|
||
poäng användaren får när uppgiften slutförs.
|
||
|
||
Poängen är inte en exakt tidsuppskattning. En snabb men viktig uppgift kan
|
||
därför ha ett högre poängvärde än en längre men mindre betydelsefull uppgift.
|
||
|
||
Feature 3 registrerar endast poängvärdet. Den ska inte registrera:
|
||
|
||
- vem som har tjänat poängen;
|
||
- om poängen har delats ut;
|
||
- när poängen har tjänats in;
|
||
- någon historik över poäng.
|
||
|
||
## Poängskala
|
||
|
||
Poäng ska vara ett heltal mellan 1 och 99, inklusive gränsvärdena.
|
||
|
||
Alla heltal i intervallet är tillåtna. Feature 3 inför inte någon fast skala med
|
||
fördefinierade steg.
|
||
|
||
Giltiga exempel:
|
||
|
||
- 1
|
||
- 7
|
||
- 25
|
||
- 99
|
||
|
||
Ogiltiga exempel:
|
||
|
||
- inget värde;
|
||
- `null`;
|
||
- 0;
|
||
- negativa tal;
|
||
- 100 eller högre;
|
||
- decimaltal;
|
||
- text som inte kan tolkas som ett heltal.
|
||
|
||
En fast poängskala kan införas senare om erfarenhet från användningen visar att
|
||
det är lämpligt.
|
||
|
||
## Avgränsning
|
||
|
||
Feature 3 omfattar endast:
|
||
|
||
- uppgiftens titel;
|
||
- uppgiftens valfria beskrivning;
|
||
- uppgiftens obligatoriska poängvärde;
|
||
- visning av poäng på uppgiftskortet.
|
||
|
||
Feature 3 ska inte införa:
|
||
|
||
- tilldelning av uppgifter;
|
||
- ändring av uppgiftsstatus;
|
||
- drag-and-drop;
|
||
- redigering av befintliga uppgifter;
|
||
- radering av uppgifter;
|
||
- deadlines;
|
||
- återkommande uppgifter;
|
||
- poänghistorik;
|
||
- användares poängsaldo;
|
||
- topplistor;
|
||
- statistik;
|
||
- mål;
|
||
- achievements;
|
||
- belöningar;
|
||
- automatisk utdelning av poäng när en uppgift slutförs.
|
||
|
||
Dessa funktioner hanteras i senare features enligt roadmapen.
|
||
|
||
## Användarflöde
|
||
|
||
När användaren öppnar dialogen för att skapa en uppgift ska formuläret
|
||
innehålla:
|
||
|
||
- titel;
|
||
- beskrivning;
|
||
- poäng.
|
||
|
||
Poängfältet ska initialt innehålla värdet `1`.
|
||
|
||
Användaren kan behålla standardvärdet eller ange ett annat heltal mellan 1 och
|
||
99.
|
||
|
||
När uppgiften skapas ska frontend alltid skicka poängvärdet uttryckligen till
|
||
backend. Backend ska inte själv fylla i ett saknat värde.
|
||
|
||
Efter att en uppgift har skapats framgångsrikt ska formuläret återställas.
|
||
Poängfältet ska då återgå till `1`.
|
||
|
||
Om dialogen stängs och senare öppnas igen ska poängfältet också börja på `1`.
|
||
|
||
## Skapandedialog
|
||
|
||
Poäng ska anges med ett vanligt numeriskt inmatningsfält.
|
||
|
||
Fältet ska ha:
|
||
|
||
- etiketten `Poäng`;
|
||
- initialt värde `1`;
|
||
- minsta värde `1`;
|
||
- högsta värde `99`;
|
||
- heltalssteg.
|
||
|
||
En kort hjälptext kan visas:
|
||
|
||
> 1–99 poäng beroende på hur tidskrävande, besvärlig eller viktig uppgiften är.
|
||
|
||
Fältet får tillfälligt vara tomt medan användaren redigerar värdet. Frontend ska
|
||
inte automatiskt återställa värdet till `1` medan användaren skriver.
|
||
|
||
Validering ska främst ske när användaren försöker skicka formuläret. Avancerad
|
||
validering vid varje tangenttryckning ingår inte i denna feature.
|
||
|
||
## Frontendvalidering
|
||
|
||
Frontend ska blockera skapandeanropet om poängen inte är ett heltal mellan 1 och
|
||
99.
|
||
|
||
Vid ett ogiltigt värde ska följande meddelande visas:
|
||
|
||
> Poäng måste vara ett heltal mellan 1 och 99.
|
||
|
||
Samma meddelande kan användas för:
|
||
|
||
- tomt värde;
|
||
- värde under 1;
|
||
- värde över 99;
|
||
- decimaltal;
|
||
- annat ogiltigt innehåll.
|
||
|
||
HTML-fältets attribut för minsta värde, högsta värde och heltalssteg får användas
|
||
som stöd, men formulärlogiken ska också kontrollera värdet explicit.
|
||
|
||
Backend är alltid den slutliga garanten för valideringsreglerna.
|
||
|
||
## Visning på uppgiftskortet
|
||
|
||
Uppgiftens poäng ska visas på uppgiftskortet som en kompakt och dynamisk badge.
|
||
|
||
Badgen ska:
|
||
|
||
- renderas som en vanlig React- och HTML-komponent;
|
||
- använda text och CSS;
|
||
- läsa värdet från uppgiftens `points`;
|
||
- visa värdet i formatet `{points} p`.
|
||
|
||
Exempel:
|
||
|
||
- `1 p`
|
||
- `7 p`
|
||
- `99 p`
|
||
|
||
Ingen genererad bild eller statisk grafik ska användas för själva poängvärdet.
|
||
|
||
Placering och visuell utformning ska följa projektets befintliga skärmbilder och
|
||
nuvarande kortdesign. Poängindikatorn ska ligga i kortets metadataområde på
|
||
motsvarande plats som poängindikatorn i designreferensen.
|
||
|
||
Mindre justeringar får göras för att passa den faktiska kortimplementationen.
|
||
Feature 3 ska däremot inte införa en ny övergripande design för uppgiftskortet.
|
||
|
||
## API
|
||
|
||
Fältnamnet ska vara `points` genomgående i API, backend och frontend.
|
||
|
||
### Skapa uppgift
|
||
|
||
Requesten för att skapa en uppgift ska innehålla:
|
||
|
||
```json
|
||
{
|
||
"title": "Töm diskmaskinen",
|
||
"description": "Ställ in allt i rätt skåp",
|
||
"points": 3
|
||
}
|
||
```
|
||
|
||
`points` är obligatoriskt.
|
||
|
||
Backend ska inte tolka ett saknat värde som `1`.
|
||
|
||
### Uppgiftssvar
|
||
|
||
API-svar som innehåller en uppgift ska också innehålla `points`.
|
||
|
||
Exempel:
|
||
|
||
```json
|
||
{
|
||
"id": "00000000-0000-0000-0000-000000000000",
|
||
"title": "Töm diskmaskinen",
|
||
"description": "Ställ in allt i rätt skåp",
|
||
"status": "WAITING",
|
||
"points": 3,
|
||
"createdAt": "2026-07-26T12:00:00Z"
|
||
}
|
||
```
|
||
|
||
Det gäller både:
|
||
|
||
- svaret efter att en uppgift skapats;
|
||
- listning av uppgifter.
|
||
|
||
Det exakta API-formatet ska i övrigt följa den befintliga implementationen.
|
||
|
||
## Backendregler
|
||
|
||
En uppgift får aldrig existera med ett poängvärde utanför intervallet 1–99.
|
||
|
||
Regeln ska skyddas genom hela backend, inte bara i HTTP-lagret.
|
||
|
||
Beroende på repositoryts befintliga struktur ska valideringen tillämpas på
|
||
relevanta nivåer, exempelvis:
|
||
|
||
- requestvalidering;
|
||
- applikations- eller domänlogik;
|
||
- entitetsmodell;
|
||
- databasens schema.
|
||
|
||
Implementation ska följa projektets etablerade kodstruktur och inte introducera
|
||
ett nytt arkitekturmönster enbart för denna feature.
|
||
|
||
## Felhantering
|
||
|
||
Ett ogiltigt eller saknat `points` ska ge:
|
||
|
||
```text
|
||
400 Bad Request
|
||
```
|
||
|
||
Backend ska använda projektets befintliga felformat och befintliga
|
||
felhantering.
|
||
|
||
Feature 3 ska inte introducera en separat felmodell endast för poäng.
|
||
|
||
Backend får ge mer precisa valideringsdetaljer för exempelvis:
|
||
|
||
- saknat värde;
|
||
- `null`;
|
||
- värde under 1;
|
||
- värde över 99.
|
||
|
||
Frontend behöver inte återge varje backenddetalj separat, utan kan visa det
|
||
gemensamma användarmeddelandet:
|
||
|
||
> Poäng måste vara ett heltal mellan 1 och 99.
|
||
|
||
Vid andra eller oväntade backendfel ska frontend fortsätta använda projektets
|
||
befintliga generella felhantering.
|
||
|
||
## Databas
|
||
|
||
Databasschemat ska innehålla ett obligatoriskt heltalsfält för uppgiftens poäng.
|
||
|
||
Det logiska slutläget är:
|
||
|
||
```text
|
||
points INTEGER NOT NULL
|
||
```
|
||
|
||
Databasen ska, om den befintliga schemahanteringen stödjer det, även skydda
|
||
intervallet 1–99 med en motsvarande constraint.
|
||
|
||
Databasen ska inte ha ett permanent defaultvärde för nya uppgifter. Nya
|
||
uppgifter ska alltid få ett uttryckligt poängvärde från applikationen.
|
||
|
||
Det förvalda värdet `1` är ett frontendbeteende och inte ett sätt för backend
|
||
eller databasen att tyst komplettera ofullständiga anrop.
|
||
|
||
## Lokal utvecklingsdatabas
|
||
|
||
Den lokala utvecklingsdatabasen ska vara en in-memory H2-databas.
|
||
|
||
Databasen och dess innehåll ska återställas när backend startas om.
|
||
|
||
Lokal utvecklingsdata betraktas därför som tillfällig. Användare och uppgifter
|
||
som skapats manuellt under utveckling behöver inte bevaras mellan starter.
|
||
|
||
Detta innebär att Feature 3 inte behöver migrera verkliga befintliga
|
||
utvecklingsposter. En ny databas skapas direkt med det obligatoriska
|
||
poängfältet.
|
||
|
||
Före Feature 3 var lokal H2 filbaserad. Feature 3 ändrar utvecklingsanslutningen
|
||
till in-memory och uppdaterar utvecklingsdokumentationen i samma ändring.
|
||
|
||
## Schemahantering och framtida migrering
|
||
|
||
Att lokal utvecklingsdata inte bevaras innebär inte att framtida
|
||
produktionsdata kan återställas vid varje release.
|
||
|
||
När HemHub börjar använda en beständig PostgreSQL-databas med data som ska
|
||
bevaras måste schemaändringar hanteras med kontrollerade migreringar.
|
||
|
||
Feature 3 behöver inte införa eller färdigställa hela den framtida
|
||
produktionsstrategin om den ännu inte finns i repositoryt.
|
||
|
||
Projektet använder redan Flyway och versionshanterade migreringar. Feature 3 ska
|
||
därför lägga till en ny Flyway-migrering för poängfältet och inte ändra tidigare
|
||
migreringar. Hibernate ska fortsatt validera schemat i stället för att skapa
|
||
det.
|
||
|
||
Bytet till in-memory H2 innebär att befintliga lokala utvecklingsposter inte
|
||
behöver bevaras eller fyllas på med poäng. Själva schemaändringen ska ändå
|
||
hanteras som en kontrollerad migrering så att migrationshistoriken förblir
|
||
sammanhängande inför framtida beständig data.
|
||
|
||
Repositoryts faktiska arkitektur och dokumentation har företräde.
|
||
|
||
## Backendtester
|
||
|
||
Feature 3 ska minst verifiera att:
|
||
|
||
- en uppgift kan skapas med ett giltigt `points`;
|
||
- det skapade API-svaret innehåller samma `points`;
|
||
- listning av uppgifter innehåller `points`;
|
||
- gränsvärdet `1` accepteras;
|
||
- gränsvärdet `99` accepteras;
|
||
- saknat `points` ger `400 Bad Request`;
|
||
- `points: null` ger `400 Bad Request`;
|
||
- `points: 0` ger `400 Bad Request`;
|
||
- negativa värden ger `400 Bad Request`;
|
||
- `points: 100` ger `400 Bad Request`.
|
||
|
||
Testerna ska följa befintlig teststil och utöka nuvarande tester där det är
|
||
lämpligt.
|
||
|
||
## Frontendtester
|
||
|
||
Feature 3 ska minst verifiera att:
|
||
|
||
- skapandedialogen öppnas med poängvärdet `1`;
|
||
- ett giltigt poängvärde skickas i create-anropet;
|
||
- tomt poängfält blockerar submit;
|
||
- ett värde under 1 blockerar submit;
|
||
- ett värde över 99 blockerar submit;
|
||
- ett ogiltigt värde visar felmeddelandet;
|
||
- formuläret återställs till poängvärdet `1` efter lyckad skapning;
|
||
- ett uppgiftskort visar uppgiftens dynamiska poängbadge;
|
||
- badgen visar värdet från uppgiftsdata, exempelvis `7 p`.
|
||
|
||
Testerna ska inte vara beroende av en viss pixelplacering eller detaljerad CSS.
|
||
|
||
## Manuell verifiering
|
||
|
||
Följande ska verifieras manuellt:
|
||
|
||
1. Starta frontend och backend enligt projektets utvecklingsinstruktioner.
|
||
2. Skapa en uppgift utan att ändra poängfältet.
|
||
3. Verifiera att uppgiften får `1 p`.
|
||
4. Skapa en uppgift med ett mellanvärde, exempelvis `7`.
|
||
5. Verifiera att uppgiften får `7 p`.
|
||
6. Skapa en uppgift med `99`.
|
||
7. Verifiera att uppgiften får `99 p`.
|
||
8. Försök skapa en uppgift med tomt poängfält.
|
||
9. Verifiera att anropet blockeras och att rätt felmeddelande visas.
|
||
10. Försök använda värdena `0` och `100`.
|
||
11. Verifiera att båda avvisas.
|
||
12. Kontrollera att poängbadgen följer projektets designreferens och fungerar
|
||
med ett- och tvåsiffriga värden.
|
||
13. Starta om backend.
|
||
14. Verifiera att den lokala utvecklingsdatan inte finns kvar.
|
||
|
||
## Acceptanskriterier
|
||
|
||
Feature 3 är klar när:
|
||
|
||
- varje ny uppgift har ett obligatoriskt `points`;
|
||
- `points` är ett heltal mellan 1 och 99;
|
||
- frontendens standardvärde är `1`;
|
||
- frontend alltid skickar `points` uttryckligen;
|
||
- backend avvisar saknat eller ogiltigt `points`;
|
||
- backend fyller inte automatiskt i ett saknat värde;
|
||
- uppgiftens poäng returneras av API:t;
|
||
- uppgiftens poäng visas dynamiskt på uppgiftskortet;
|
||
- frontend- och backendtester täcker centrala giltiga och ogiltiga fall;
|
||
- lokal H2 körs som in-memory och återställs vid omstart;
|
||
- relevant dokumentation är uppdaterad;
|
||
- Feature 3 inte inför funktionalitet som hör till senare features.
|
||
|
||
## Implementationsprinciper
|
||
|
||
När Feature 3 senare implementeras ska Codex först läsa:
|
||
|
||
```text
|
||
AGENTS.md
|
||
README.md
|
||
docs/architecture.md
|
||
docs/development.md
|
||
docs/roadmap.md
|
||
docs/decisions/
|
||
docs/features/
|
||
```
|
||
|
||
Codex ska även läsa relevant backendkod, frontendkod och befintliga tester innan
|
||
ändringar görs.
|
||
|
||
Repositoryts faktiska kod och dokumentation har företräde framför antaganden i
|
||
denna featurebeskrivning.
|
||
|
||
Dokumentation, implementation och tester ska uppdateras tillsammans.
|
||
|
||
Codex ska inte committa, pusha, skapa pull request eller merga utan uttrycklig
|
||
instruktion.
|