Specifikation: Jönköping Kommun - Ledighetsansökan (AI-native)

Variant

Vklass V2 (vklassv2). Strategi: replicate-then-extend mot design-reference-screenshots i epic-files/.

Roller

  • Lärare/mentor (teacher.html, teacher-detail.html, teacher-create.html) — ser, följer upp och hanterar ansökningar för elever med aktiv klasskoppling; beslutar eller delegerar/yttrar sig enligt AllowDecision.
  • Rektor/biträdande rektor (rektor.html, rektor-detail.html) — filtrerbar enhetsvy med summering; beslutar med mall och redigerbar beslutstext. Biträdande rektor med Principal-/adminåtkomst har samma åtgärder.
  • Myndig elev (student.html) — ansöker om ledighet och ser egna ansökningar med slutlig beslutstext.
  • Vårdnadshavare (custodian.html) — policy-gate, ansöker för barn med aktiv relation, ser barnets ansökningar med slutlig beslutstext.
  • Kommunadministratör (admin.html) — förvaltar beslutsmallar på organisationsnivå.

Användningsfall (UC)

UC-01: Ansöka om ledighet med policy-gate (vårdnadshavare)

  • Aktör: Vårdnadshavare (Linda Nilsson)
  • Förutsättning: Barnets skola har UseLeaveApplications aktiverat och policytext i leaveDescription.
  • Flöde:
    1. Linda öppnar Frånvaro och ledighet > Ledighetsansökan.
    2. Skolans policytext visas direkt i en tydlig ruta ovanför formuläret (inte hopfälld bakom plustecken).
    3. Ansökningsformuläret är otillgängligt tills Linda aktivt bekräftat "Jag har läst och förstått skolans policy för ledighetsansökan".
    4. Efter bekräftelse väljer Linda barn (Theo), anger period och anledning och skickar.
    5. Bekräftelsen sparas som metadata kopplad till ansökan (tidpunkt + policyversion, ingen fritext).
  • Resultat: Ansökan visas i "Tidigare ledighet" med status Ej besvarad och policybekräftelse-metadata.
  • Acceptanskriterier:
    • Policytexten visas direkt utan klick.
    • Formuläret kan inte skickas innan bekräftelsen är gjord (knappen inaktiverad + kontrollerat valideringsfel).
    • Alice (Trollmånes Förskola, funktion ej aktiverad) erbjuds inte ansökan — kontrollerad förklaringstext, ingen teknisk tomvy.
    • Ansökans metadata visar "Policy bekräftad (version )" utan att policy-/motiveringstext loggas.

UC-02: Se egna ansökningar med slutlig beslutstext (myndig elev)

  • Aktör: Myndig elev (Emma Karlsson)
  • Förutsättning: Emma är 18 år och använder MainWeb-flödet; skolan har funktionen aktiv.
  • Flöde:
    1. Emma öppnar Frånvaroanmälan/Närvarorapport/Ledighetsansökan-fliken Ledighetsansökan.
    2. Befintligt formulär (hopfälld policypanel, datumfält, anledning, Skicka) visas.
    3. Under "Tidigare ledighet" fäller Emma ut en beslutad rad.
  • Resultat: Expanderad rad visar anledning, slutlig beslutstext, beslutsfattare (faktisk användare) och beslutstid.
  • Acceptanskriterier:
    • Eleven ser inte rektorsfilter, summeringar för andra elever eller malladministration.
    • Slutlig beslutstext visas exakt som den sparades vid beslutstillfället.
    • Policy-panelen är hopfälld som idag (ingen elev-gate — öppen fråga Q-01).

UC-03: Följa upp och hantera ansökningar (lärare/mentor)

  • Aktör: Lärare/mentor (Kerstin Berg)
  • Förutsättning: Kerstin har aktiv klasskoppling (7A m.fl.); listan avgränsas till hennes elever.
  • Flöde:
    1. Kerstin öppnar Uppföljning > Ledighetsansökningar (stripe-tabell NAMN/STARTDATUM/SKOLDAGAR + status + beslutsmetadata).
    2. Hon fäller ut en rad (anledning, inskickad av, beslutstext) eller klickar på perioden för detaljsidan.
    3. Detaljsidan visar elevinfo, period, ansökan inskickad, anledning, skoldagar, HÄNDELSER-panel och Hantera ansökan.
    4. I dialogen ser hon BESLUT (Neka/Bevilja) när ansökan får beslutas av mentor, annars DELEGERA TILL REKTOR (Tillstyrker/Avstyrker).
    5. Via gröna plusknappen når hon Skapa ledighetsansökan (befintligt flöde).
  • Resultat: Beslut/yttrande sparas med faktisk användare; listan uppdateras.
  • Acceptanskriterier:
    • Endast elever inom aktiv relation visas.
    • Ansökningar över leaveDaysTeacher skoldagar visar delegeringsläge i stället för beslutsläge.
    • Mallval fungerar som i UC-06 för lärarens beslutbara ansökningar (mallar för Lärare/Mentor eller Alla).

UC-04: Filtrera rektorsvyn (rektor/biträdande rektor)

  • Aktör: Rektor/biträdande rektor (Magnus Widén, adminåtkomst)
  • Förutsättning: Magnus har Principal-/adminåtkomst på Proximaskolan; standardurval är pågående läsår.
  • Flöde:
    1. Magnus öppnar rektorsvyn (skol-/klassväljarbarer + reglage "Visa även ansökningar som kan beslutas av klasslärare" per produktions-UI).
    2. Han öppnar filtret (filter_list-trigger) och filtrerar på status, datumintervall (eller snabbval Läsår/Termin/30 dagar), elev, klass/grupp och beslutsomfång ("Kräver rektorsbeslut" / "Alla ledighetsansökningar på enheten").
    3. Lista och summering uppdateras tillsammans; aktiva filter visas som pills.
    4. "Återställ" tar bort filter och återgår till pågående läsår.
  • Resultat: Lista och summering visar exakt samma serverside-urval.
  • Acceptanskriterier:
    • Datumfilter använder överlappningslogik: startDate <= filterTo AND endDate >= filterFrom.
    • Ogiltigt intervall (från > till) ger kontrollerat valideringsfel.
    • Filtervärden (elever/klasser) innehåller endast enhetens elever.
    • 0 träffar visar tomläge med "Återställ"-erbjudande; träffantal annonseras i live region.

UC-05: Summera beviljad ledighet (rektor/biträdande rektor)

  • Aktör: Rektor/biträdande rektor
  • Förutsättning: Samma urval som listan (UC-04).
  • Flöde:
    1. Summeringsbannern visar "Beviljad ledighet {läsår}: beviljade ansökningar · beviljade skoldagar" för aktuellt urval.
    2. Vid filterändring uppdateras summeringen tillsammans med listan.
  • Resultat: Ingen manuell räkning behövs.
  • Acceptanskriterier:
    • Endast beslutade beviljade ansökningar ingår.
    • Summeringen omfattar hela det filtrerade urvalet, inte aktuell sida.
    • Dagdefinition = skoldagar (samma som LeaveApplication.Length); hjälptext förklarar definitionen.
    • Överlappande beviljade perioder för samma elev dedupliceras per elev och dag (hjälptexten förklarar; demo-data innehåller överlapp).

UC-06: Besluta med mall och redigerbar beslutstext (beslutsfattare)

  • Aktör: Lärare/mentor eller rektor/biträdande rektor
  • Förutsättning: Hantera-dialogen är öppen; aktiva mallar finns för rollen och utfallet.
  • Flöde:
    1. Beslutsfattaren väljer utfall (Bevilja/Neka); mallväljaren visar endast aktiva mallar för aktuell roll (Lärare/Mentor, Rektor, Alla) och valt utfall.
    2. Vid mallval ersätts mallens variabler (, , , , , , , ) med ärendets aktuella värden.
    3. Den färdiga, variabelersatta texten placeras i den vanliga redigerbara beslutstextrutan.
    4. Om rutan redan innehåller osparad text visas en bekräftelse innan innehållet ersätts.
    5. Beslutsfattaren redigerar texten fritt och sparar; UI:t markerar att texten i rutan är den kompletta text som sparas och kommuniceras till den som ansökt.
    6. Om vald mall hunnit inaktiveras visas ett tydligt fel; beslutsfattaren kan välja annan mall eller fortsätta med redan infogad text.
  • Resultat: Slutlig beslutstext sparas på ansökan med mallreferens/-version som metadata; dubbelklick på Spara ger inte dubbla beslut (knappen låses med aria-busy).
  • Acceptanskriterier:
    • Ingen låst malltext och inget separat kompletteringsfält.
    • Malltexten är ett startvärde — hela texten är redigerbar efter mallval.
    • Den slutliga texten i rutan är den som sparas och visas för elev/vårdnadshavare.
    • Inaktiva mallar är inte valbara; race-fallet visar kontrollerat fel (demo-state).

UC-07: Administrera beslutsmallar (kommunadministratör)

  • Aktör: Kommunadministratör (Anders Bergman)
  • Förutsättning: Anders har mallbehörighet på organisationsnivå (ger inte beslutsrätt i elevärenden).
  • Flöde:
    1. Anders öppnar malladministrationen (lista med namn, utfall, roll, status, ändrad).
    2. Han skapar/redigerar en mall: namn (unikt inom organisationen), utfall (Beviljad/Avslagen), roll (Lärare/Mentor, Rektor, Alla), malltext, aktiv-status.
    3. Tillåtna variabler visas med beskrivning och kan infogas med knapp för att minska skrivfel.
    4. Förhandsvisning renderar malltexten med exempeldata utan riktig elev.
    5. Mall med okänd variabel kan inte sparas — kontrollerad validering pekar ut variabeln.
    6. Inaktivering kräver bekräftelsedialog; inaktiva mallar är inte valbara i beslut.
  • Resultat: Mallar förvaltas på kommun-/organisationsnivå.
  • Acceptanskriterier:
    • Unikt namn valideras; obligatoriska fält och maxlängder valideras med summering + fältfel.
    • Okänd variabel (t.ex. {Elevnamn} med fel skiftläge eller {Ort}) ger valideringsfel som namnger variabeln.
    • Historiska beslut påverkas inte av malländringar (se UC-08).

UC-08: Historik och spårbarhet (alla roller)

  • Aktör: Alla
  • Förutsättning: Beslut finns sparade; en mall har ändrats efter beslutstillfället.
  • Flöde:
    1. Historisk detalj/expansion visar exakt den beslutstext som sparades vid beslutstillfället.
    2. Mallreferens och mallversion visas som metadata där mall användes.
    3. "Beslutad av" visar faktisk användare med tidpunkt.
  • Resultat: Spårbar, oföränderlig beslutshistorik.
  • Acceptanskriterier:
    • Demo-datan innehåller ett beslut fattat med mallversion 1 där mallen sedan ändrats — den historiska visningen visar version 1-texten oförändrad.
    • Äldre ärenden utan mallmetadata visar befintlig beslutstext (fallback ResponseDescription).

Datamodell

  • LeaveApplication (dbo.LeaveApplications): id, schoolID, studentID, classID, startDate, endDate, description (anledning), sentDate, senderID, senderType, status (ej_besvarad/beviljad/nekad), showToPrincipal, isDelegated, recommendation (tillstyrker/avstyrker), recommendedBy, answeredBy, answeredDate, schoolDays, decisionTemplateID, decisionTemplateVersion, finalDecisionText, policyAcknowledgedDate, policyVersion.
  • LeaveApplicationDecisionTemplate (föreslagen dbo.LeaveApplicationDecisionTemplate): id, customerOrganisationID, name (unik inom org), outcome (approved/declined), validForRole (teacher/principal/all), templateText (max 2000), isActive, version, createdBy/createdDate, modifiedBy/modifiedDate.
  • Variabel-whitelist: {ElevNamn}, {Skola}, {Period}, {FranDatum}, {TillDatum}, {Beslutsfattare}, {Beslutsdatum}, {AntalDagar} (skoldagar).
  • SchoolConfig (dbo.schoolConfig): useLeaveApplications, leaveDaysTeacher, leaveDescription (policytext), policyVersion.
  • Delade personer/klasser från Shared/demo-data/consolidated-demo-data.json.
  • Lärare: Uppföljning > Ledighetsansökningar → lista → period-länk → detalj → Hantera ansökan (dialog); FAB → Skapa ledighetsansökan.
  • Rektor/biträdande rektor: Uppföljning > Ledighetsansökningar (rektorsvy) → filter/summering → period-länk → detalj → Hantera ansökan (dialog).
  • Elev: Frånvaro och ledighet > Ledighetsansökan (flikrad Frånvaroanmälan/Närvarorapport/Ledighetsansökan).
  • Vårdnadshavare: Frånvaro och ledighet > Ledighetsansökan (flikrad Frånvaroanmälan/Frånvarorapport/Ledighetsansökan).
  • Admin: Mallar > Beslutsmallar ledighetsansökan.
  • index.html är rollväljare + demo-film.

Tillgänglighetskontrakt (a11y baseline)

  • Dialogmodaler: decision-dialog (hantera ansökan, teacher-detail + rektor-detail), overwrite-confirm-dialog (ersätt befintlig beslutstext), template-dialog (skapa/redigera mall), confirm-deactivate-dialog (inaktivera mall). Alla öppnas via shared window.vklassDialogManager.openDialog(id, opener) — ingen lokal DialogManager. role="dialog" + aria-modal="true" + aria-labelledby, Escape stänger, fokus återställs till opener, .vk-layout får inert (sköts av shared manager). @ai:focus-lifecycle-annotering vid varje dialog.
  • Tabs/flikrad: Elev-/VH-flikarna (Frånvaroanmälan m.fl.) är sidnavigation → länkar med aria-current="page", INTE role="tab". Admin-mallistans statusflikar (Aktiva/Inaktiva/Alla) är äkta tabs → role="tablist"/tab + roving tabindex + piltangenter.
  • Filter/sök: Rektorsfiltret är disclosure (vk-page-filter-trigger med aria-expanded + aria-controls, panel hidden); träffantal annonseras i role="status" live region; aktiva filter som pills.
  • Expanderbara rader: disclosure-knappar med aria-expanded, aria-controls, hidden-panelrad.
  • Toolbar flyouts: aria-expanded synkas med --open-klass via _syncFlyoutAria-helpern.
  • Form validation: VH-policy-gate (skicka utan bekräftelse → fel + aria-describedby); malldialogen har valideringssummering (role="alert", länkar till fält) + fältfel med aria-describedby/aria-invalid; rektorsfiltrets datumfel role="alert".
  • Skip-link: <a class="skip-link" href="#main-menu"> + <a class="skip-link" href="#main-content"> + <main id="main-content" tabindex="-1"> (canonical pattern).
  • Dark mode: endast body.dark-mode — ingen prefers-color-scheme i feature-CSS.
  • Keyboard test scope: UC-01 (gate-bekräftelse + skicka), UC-03/UC-06 (öppna/stänga decision-dialog, mallval, overwrite-confirm), UC-04 (filter-disclosure + validering), UC-07 (template-dialog + valideringssummering + confirm-deactivate).

Bilder/sketcher

  • V2 design-references att följa: samtliga 12 PNG — se 1/epic-files/CLASSIFICATION.md och 1/design-reference-log.md.
  • Kravkontext (ej bild): epic-files/goteborg-inspel-policy-vid-ledighetsansokan.md (policy-gate).
  • Inga V1-bilder och inga design-sketcher.

Funktionalitet i scope

Se intake.md § Kravklassificering (R-01–R-18). Inga STORY-MENTIONED-funktioner implementeras.

Öppna frågor

  • Q-01: Ska myndig elev ha samma policy-gate som vårdnadshavare? (Ej byggd — eleven behåller dagens hopfällda policypanel.)
  • Q-02: Behövs status "förfallen/arkiverad" för gamla obesvarade ansökningar i första leverans? (Ej byggd.)
  • B1–B7 i intake.md är mockup-val som teknisk spec ska bekräfta före produktion.