# Feature 7 – Radera uppgift ## Status Implementerad och verifierad på feature-branchen. Merge återstår. ## Bakgrund HemHub stödjer skapande, visning, tilldelning, statusändring och drag-and-drop av uppgifter. Det saknas möjlighet att ta bort uppgifter som inte längre är relevanta eller som skapats av misstag. Feature 7 inför permanent radering av en enskild uppgift. Radering hålls separat från generell redigering så att det destruktiva flödet, dess bekräftelse och felhantering kan implementeras och verifieras isolerat. ## Mål Feature 7 ska: - införa ett backend-API för permanent radering av en uppgift; - låta användaren initiera radering från uppgiftskortet; - kräva en tydlig bekräftelse före radering; - ta bort kortet från brädan först efter serverbekräftelse; - återanvända befintlig låsning och felhantering per task-id; - fungera tillsammans med statusändring, tilldelning och drag-and-drop utan parallella state- eller requestflöden. ## Omfattning Feature 7 omfattar endast permanent radering av en befintlig uppgift. En uppgift får raderas oavsett om dess status är `WAITING`, `IN_PROGRESS` eller `COMPLETED`. Uppgiftens ansvariga användare och aktiv browseranvändare påverkar inte möjligheten att radera. Det lokala användarvalet är inte autentisering eller behörighetskontroll. ## Avgränsningar Feature 7 ska inte införa: - mjuk radering, papperskorg, återställning eller undo; - arkivering, versions-, status- eller poänghistorik; - generell redigering; - batchradering eller markering av flera kort; - radering av användare; - behörigheter eller ägarskap; - realtidsuppdatering mellan browsers; - automatisk gallring; - persistent kortordning; - nya relationer till uppgifter; - generell cascade-logik för framtida modeller. ## Permanent radering Radering är permanent. När användaren har bekräftat raderingen tas uppgiften bort ur databasen. Ingen `deleted`-flagga, `deletedAt`, dold arkiveringsmodell eller annan form av mjuk radering införs. HemHub är en liten familjeapplikation utan revisionslogg, papperskorg eller återställningsflöde. En mjukraderingsmodell skulle därför öka komplexiteten utan ett tydligt nuvarande produktvärde. Om framtida features för återkommande uppgifter eller poänghistorik behöver bevara information efter radering ska deras datamodeller och raderingsregler beslutas i respektive feature. ## Tillåtna statusar Samtliga uppgifter får raderas oavsett status. Det krävs inte att en `IN_PROGRESS`-uppgift först flyttas till `WAITING`, och en `COMPLETED`-uppgift behandlas inte annorlunda än övriga uppgifter. Bekräftelseflödet är samma för alla statusar. Ingen extra varning eller ytterligare bekräftelse införs för pågående uppgifter. ## Raderingskontroll Raderingskontrollen ska visas som en diskret sopkorgsikon direkt på det befintliga uppgiftskortet, uppe till höger i ett eget åtgärdsområde. Feature 7 inför inget kompakt eller expanderat kortläge. Kontrollen ska: - visas på befintliga uppgiftskort; - ha en tillgänglig etikett som identifierar uppgiften, exempelvis `Radera Töm diskmaskinen`; - öppna bekräftelsedialogen; - inte starta drag-and-drop; - ha en rimlig klickyta för touch; - ha neutral stil i normalläge och tydlig hover- och fokusmarkering; - vara inaktiverad när samma uppgift har en pågående operation. Sopkorgen implementeras som inline-SVG enligt projektets befintliga ikonmönster. Feature 7 lägger inte till något ikonbibliotek. Den destruktiva visuella betoningen ska primärt ligga i bekräftelsedialogen. Kontrollen ska kunna flyttas till en framtida meny eller detaljdialog utan att backend-API eller delete-flödet behöver göras om. ## Bekräftelsedialog Radering bekräftas i en separat delete-modal. Den ska följa beteendemönstret i `CreateTaskModal`, men Feature 7 inför ingen gemensam modalkomponent och gör ingen bred modalrefaktorering. Dialogen ska visa: - rubriken `Radera uppgift?`; - uppgiftens titel; - tydlig information om att raderingen är permanent; - knappen `Avbryt`; - den destruktivt utformade knappen `Radera`. Exempel: > Är du säker på att du vill radera **Töm diskmaskinen**? Uppgiften raderas > permanent och kan inte återställas. Delete-modalen har inget stängningskryss. Innan delete-anropet har startat ska den kunna stängas med `Avbryt`, Escape eller klick på bakgrunden. Under pågående delete-anrop blockeras samtliga stängningsvägar. Dialogen ska följa projektets befintliga modalstruktur och fokusprinciper. `Avbryt` får initialt fokus när dialogen öppnas; den destruktiva knappen `Radera` får inte initialt fokus. Båda knapparna ska vara tangentbordsåtkomliga. ## Backend-API Radering sker genom: ```http DELETE /api/tasks/{taskId} ``` ### Lyckad radering När uppgiften finns och raderas svarar backend med `204 No Content` utan body. ### Okänd uppgift Om uppgiften inte finns svarar backend med `404 Not Found` och projektets befintliga felformat: ```text TASK_NOT_FOUND ``` Det gäller även om samma task-id tidigare har raderats. Ett andra delete-anrop mot samma id ger därför `404 TASK_NOT_FOUND`. ### Ogiltigt task-id Ett task-id som inte kan tolkas som UUID ger `400 Bad Request` med repositoryts nuvarande requestfel och felformat. Den befintliga felkoden `INVALID_TASK_ASSIGNMENT` ändras inte inom Feature 7. Feature 7 inför ingen separat felmodell för UUID-fel. ### Konflikter och transaktion Radering är tillåten för samtliga statusar och oavsett ansvarig. Feature 7 har därför inget domänfall som ger `409 Conflict`. Raderingen ska ske inom backendens normala transaktionsgräns och endast ta bort den identifierade uppgiften. Den får inte ändra eller radera ansvarig användare, andra användare eller andra uppgifter. ## Databas Feature 7 raderar raden permanent ur tabellen `task`. Nuvarande datamodell har inga dokumenterade beroendeentiteter som kräver en ny migrering eller särskild cascade-policy. Den befintliga relationen från `task.assignee_id` till `app_user.id` ska verifieras så att den inte hindrar radering av uppgiften. Den ansvariga användaren ska finnas kvar. Ingen databasmigrering ska skapas om det faktiska schemat redan stödjer radering. Framtida relationer till uppgifter får definiera sin delete-policy när de införs. ## Frontendens uppdateringsstrategi Frontend använder serverbekräftad radering. När användaren bekräftar ska frontend: 1. markera uppgiften som upptagen; 2. behålla kortet i dess nuvarande kolumn; 3. behålla bekräftelsedialogen öppen; 4. skicka delete-anropet; 5. vänta på serverns svar; 6. vid `204 No Content` ta bort uppgiften ur den lokala task-listan; 7. stänga dialogen; 8. frigöra låsningen för task-id. Kortet ska inte tas bort optimistiskt. Ingen rollback-modell behövs eftersom kortet ligger kvar under anropet. ## Vänteläge När delete-anropet pågår ska: - bekräftelsedialogen ligga kvar öppen; - `Radera` och `Avbryt` vara inaktiverade; - Escape och bakgrundsklick inte kunna stänga dialogen; - kortet ligga kvar i sin kolumn och tonas ned lätt; - alla interaktiva kontroller på samma kort vara inaktiverade. Ingen spinner eller text som `Raderar…` krävs. ## Låsning och samspel med andra operationer Delete ska återanvända den befintliga låsningen per task-id. När uppgiften har en pågående status-, tilldelnings- eller dragoperation ska radering inte kunna initieras. När delete-anropet pågår ska samma uppgift inte kunna dras, ändra status, ändra ansvarig, öppna en ny raderingsdialog eller skicka ytterligare delete-anrop. Andra kort ska förbli interaktiva och kunna ha egna samtidiga operationer. Feature 7 inför inget globalt vänteläge, separat delete-lås eller parallell requestmodell. ## Felhantering ### Vanliga delete-fel Vid nätverksfel, serverfel eller annat vanligt delete-fel ska: - kortet ligga kvar oförändrat; - dialogen ligga kvar öppen; - vänteläget avslutas; - kontrollerna aktiveras igen; - felmeddelandet `Det gick inte att radera uppgiften. Försök igen.` visas i dialogen; - användaren kunna försöka igen eller avbryta. Delete-felet ska inte blandas med status- eller tilldelningsfel på kortet. ### `404 TASK_NOT_FOUND` Om backend svarar med `404 TASK_NOT_FOUND` betraktas kortet som inaktuellt. Frontend ska då ta bort uppgiften ur den lokala task-listan, stänga dialogen och frigöra låsningen utan att visa det generella delete-felet. Frontendens generella `ApiError`-typ utökas med ett valfritt `code`. Delete- flödet ska använda `code === "TASK_NOT_FOUND"` och status `404` för detta fall och får inte tolka meddelandetexten. Andra typer av `404` ska inte behandlas som en redan borttagen uppgift. ## Frontendtester Frontendtesterna ska minst verifiera: - att sopkorgsknappen visas direkt på det befintliga uppgiftskortet; - att ikonen är inline-SVG och inte kräver ett ikonbibliotek; - tillgänglig etikett och rätt uppgift i bekräftelsedialogen; - information om permanent radering; - initialt fokus på `Avbryt`, aldrig på `Radera`; - att modalen saknar stängningskryss; - stängning med `Avbryt`, Escape och bakgrundsklick före anrop; - `DELETE /api/tasks/{taskId}` först efter bekräftelse; - att kort och dialog ligger kvar under anropet; - att dialogen inte kan stängas medan anropet pågår; - gemensam låsning för status, tilldelning, drag och radering; - att andra kort förblir interaktiva; - blockering av dubbla delete-anrop; - att `204 No Content` tar bort rätt kort och stänger dialogen; - att vanliga fel behåller kort och dialog samt kan återförsökas; - att `404 TASK_NOT_FOUND` tar bort det inaktuella kortet; - att ett annat `404`-fel inte feltolkas som `TASK_NOT_FOUND`; - att raderingskontrollen inte bryter drag-and-drop; - grundläggande tangentbordsfokus och knappaktivering. Testerna ska verifiera beteende och state, inte exakt ikonplacering, färg eller pixelmått. ## Backendtester Backendtesterna ska minst verifiera: - radering i `WAITING`, `IN_PROGRESS` och `COMPLETED`; - `204 No Content` utan body; - att den raderade uppgiften inte längre finns i `GET /api/tasks`; - att andra uppgifter och den ansvariga användaren finns kvar oförändrade; - `404 TASK_NOT_FOUND` för okänt id och ett andra delete-anrop; - projektets befintliga `400`-fel för ogiltigt UUID-format. Testerna ska följa repositoryts befintliga integrationsteststil. ## Manuell verifiering Följande ska verifieras manuellt: 1. Sopkorgsknappens placering uppe till höger i ett eget åtgärdsområde, neutrala normalläge, touchyta, hover, fokus och tillgängliga etikett. 2. Radering av uppgifter i samtliga tre statusar. 3. Initialt fokus på `Avbryt`, inget stängningskryss samt avbrytande med knapp, Escape och bakgrundsklick före anrop. 4. Rätt titel och information om permanent radering. 5. Titel nära maximal längd. 6. Blockering av dubbla delete-anrop. 7. Vänteläge för kort och dialog under fördröjt svar. 8. Låsning av drag, status, tilldelning och ny radering för samma kort. 9. Fortsatt interaktion med andra kort. 10. Vanligt serverfel, visat felmeddelande och nytt försök. 11. `404 TASK_NOT_FOUND` och lokal borttagning av inaktuellt kort. 12. Desktop- och mobilbredd samt tangentbordsaktivering. 13. Omladdning efter lyckad radering så att uppgiften inte återkommer. ## Dokumentation Feature 7 dokumenteras i: ```text docs/features/007-task-deletion.md ``` Vid implementation ska `README.md`, `docs/architecture.md` och `docs/roadmap.md` uppdateras när det är relevant. Roadmapen ska markera Feature 7 som `Klar` först efter implementation, automatiska tester, manuell verifiering och merge. Ett nytt ADR behövs inte för permanent radering. Beslutet gäller den nuvarande task-livscykeln och etablerar inte en generell raderingspolicy för framtida entiteter. ## Acceptanskriterier Feature 7 är klar när: - en uppgift kan raderas permanent med `DELETE /api/tasks/{taskId}`; - lyckad radering ger `204 No Content`; - okänd eller redan raderad uppgift ger `404 TASK_NOT_FOUND`; - ogiltigt UUID-format följer befintlig felhantering; - alla tre statusar kan raderas oavsett ansvarig eller aktiv användare; - radering kräver en egen bekräftelsedialog; - dialogen visar rätt titel och anger att raderingen inte kan återställas; - `Avbryt` får initialt fokus och `Radera` får inte initialt fokus; - modalen saknar stängningskryss och blockerar alla stängningsvägar under anropet; - en diskret inline-SVG-sopkorg visas direkt på befintliga uppgiftskort; - raderingskontrollen startar inte drag; - kortet tas bort först efter serverbekräftelse; - samma task-id låses för status, tilldelning, drag och ny radering; - andra kort förblir interaktiva; - vanliga fel behåller kort och dialog och kan återförsökas; - `404 TASK_NOT_FOUND` tar bort det inaktuella lokala kortet; - ingen mjukradering, återställningsmodell eller onödig migrering införs; - backend- och frontendtester täcker centrala flöden; - manuell verifiering genomförs; - relevant dokumentation uppdateras. ## Implementerad lösning Backendens task-controller och task-service har utökats med fysisk radering via `DELETE /api/tasks/{taskId}`. Servicen hämtar först uppgiften för att återanvända `TaskNotFoundException` och raderar därefter entiteten inom en transaktion. Ingen entitet, exception handler eller Flyway-migrering behövde ändras. Frontendens `TaskBoard` använder samma per-task-lås som status- och tilldelningsoperationerna. Radering är serverbekräftad: kortet och dialogen ligger kvar medan anropet pågår, och kortet tas bort först efter `204 No Content`. Endast ett svar med både status `404` och felkoden `TASK_NOT_FOUND` tar bort ett känt inaktuellt kort. Övriga fel behåller kortet och dialogen så att användaren kan försöka igen. `TaskCard` har inget kompakt eller expanderat läge. En neutral inline-SVG-knapp ligger direkt i kortets övre högra åtgärdsområde och stoppar pointer-händelsen innan den når dragytan. Den separata delete-modalen följer `CreateTaskModal`-mönstret utan en gemensam modalabstraktion. `Avbryt` får initialt fokus, modalen saknar stängningskryss och samtliga stängningsvägar blockeras under delete-anropet. Frontendens generella `ApiError` innehåller nu ett valfritt `code`. Den befintliga backendhanteringen av felaktigt UUID är oförändrad och returnerar fortsatt `400 INVALID_TASK_ASSIGNMENT`. ## Tester och verifiering Automatiskt verifierat på feature-branchen: - backendens fullständiga testsvit: 47 tester passerade; - frontendens fullständiga testsvit: 49 tester passerade; - frontendens produktionsbygge och TypeScript-kompilering passerade; - `git diff --check` passerade. Backendtesterna ligger i den separata integrationstestklassen `TaskDeletionApiTest`. Frontendens delete-flöden testas tillsammans med övriga brädbeteenden i `App.test.tsx`. Manuell browserverifiering genomfördes mot lokalt körande frontend och backend i Chrome. Följande verifierades: - permanent radering och kvarstående borttagning efter omladdning för `WAITING`, `IN_PROGRESS` och `COMPLETED`; - lång titel, radbrytning och korrekt uppgiftstitel i dialogen; - initialt fokus på `Avbryt`, tabb-ordning till `Radera`, Escape och bakgrundsklick före anrop samt avsaknad av stängningskryss; - fördröjd delete-respons med kvarvarande och nedtonat kort, öppen låst modal och inaktiverade stängningsvägar; - gemensam låsning av drag, status, ansvarig och ny radering för samma kort, samtidigt som andra kort förblev interaktiva; - snabbt dubbelklick på `Radera` utan dubbla delete-anrop; - vanligt serverfel där kort och modal låg kvar, felet visades och ett nytt försök lyckades; - `404 TASK_NOT_FOUND`, där det inaktuella kortet togs bort lokalt; - neutral sopkorgsknapp med 40 × 40 pixlars klickyta, inline-SVG och pointer-hantering som inte startade drag; - desktopbredd 1440 × 1000 och mobilbredd 390 × 844 utan horisontell scrollning. Inga problem upptäcktes i Feature 7-flödena. Featuren ska ändå inte markeras som mergad eller `Klar` i roadmapen förrän merge är genomförd. ## Relaterade commits Fylls i efter commit och merge. ## Implementationsprinciper Före implementation ska Codex läsa: ```text AGENTS.md README.md docs/architecture.md docs/development.md docs/roadmap.md docs/decisions/ docs/features/005-task-status.md docs/features/006-task-drag-and-drop.md ``` Codex ska även läsa relevant backendkod, frontendkod och befintliga tester. Repositoryts faktiska kod, tester och dokumentation har företräde framför antaganden i detta dokument. Implementation, tester och relevant dokumentation ska uppdateras tillsammans. Codex ska inte committa, pusha, skapa pull request eller merga utan uttrycklig instruktion.