Hoppa till innehållet

Devportalen /portal/dev

Startsideportalens ekosystem för människa och agent

Devportalen

Beslutsregistret

ADR:erna: vad som är bestämt, varför, och vad som ännu inte är avgjort.

Antagna beslut

Ett arkitekturbeslut skrivs som en kort ADR i docs/beslut/ i samma commit som ändringen. Ändras ett beslut ersätts ADR:en, den skrivs inte om.

Tabell: ADR, Beslut, Status, Innebörd
ADRBeslutStatusInnebörd
ADR-001App Router istället för Pages RouterAntagenKommunens starter kör Pages Router; ett nybygge väljer App Router. Server components passar modulkompositionen och det är Next:s huvudspår framåt.
ADR-002Egen designgrund istället för @sk-web-guiErsattFormspråket i V3 skulle inte tvingas in i ett bibliotek som bär sin egen design. Ersatt av ADR-008, som behåller slutsatsen men byter grund.
ADR-003"Sidor" är en egen sidtypAntagenRedaktionellt innehåll beskrivs av ett tunnare PageManifest vid sidan av ModuleManifest. Två varianter av samma sidtyp: sektionsingång och artikel.
ADR-004routes + fokusläge i ModuleManifestAntagenEn modul kan äga en helskärmsvy. mode: "focus" ger topprad med Avbryt och inget annat krom.
ADR-005Flödesmotorns kontraktSkrivsSkrivs i M4, när motorn lyfts ur felanmalan till packages/flow-engine.
ADR-006Rollen i cookie; moduler hämtar egen dataAntagenDemoanvändaren bor i en cookie och läses på servern. Modulerna är server components som hämtar sin egen data i stället för att få den i props.
ADR-007Aggregerande modulerAntagenModulen agera äger ingen egen data utan renderar andras actions. Registret läses via provideRegistry.
ADR-008shadcn/ui som komponentgrundAntagenKomponenterna kopieras in i repot och all färg går genom våra egna CSS-variabler. Radix bär tillgängligheten; primitivernas API är oförändrat.
ADR-009Designsystemet som dataAntagenSystemet skrivs som typad data och renderas som sida, JSON och plattext ur samma källa. Stabila id, uttömmande varianter, felindex i formen fel → rätt → varför.
ADR-010Devportalen som ingång för människa och agentAntagenAllt en byggare behöver samlas under /dev, i två vyer ur samma data. Designsystemet blir en del av portalen och nås på /dev/ui.
ADR-011Dokumentation som leveransvillkorAntagenVarje del har ett dok i portalen enligt ett dokumentationskontrakt. Klar betyder körbar, granskad och dokumenterad; täckningen räknas fram på /dev/docs.
ADR-012Åtkomstkod som demospärrAntagenACCESS_CODE låser demon i middleware. Projektsidan, prototypens ingång, visionssidan och devportalen är öppna, så att dokumentationen går att läsa och hämta av verktyg. Uttryckligen inte autentisering: koden delas av alla och säger ingenting om vem användaren är.
ADR-014Portalens påståenden verifierasAntagenDet portalen påstår om koden kontrolleras av yarn test och yarn lint: drifttester, uppräkningsbara fält där det stod prosa, lintregel för R4 och namngivna antimönster. Går ett påstående inte att kontrollera ska räckvidden stå utskriven.
ADR-013Signerad fältförankring mellan turerAntagenFältens tidigare värden skickas tillbaka så att assistenten inte formulerar om dem, men bara med serverns egen HMAC. Utan signaturen vore de en inmatningsväg förbi samtalet.
ADR-015Dokumentflöden definieras som data i modulenAntagenEtt dokument med typade avsnitt passar inte i FlowDefinition, som beskriver platta fält. Definitionen bor i modulen med samma bärande idéer, och ADR-005 skrivs i M4 mot två former i stället för en. Utan fältförankring: varje avsnitt går att skriva i direkt, så klientens värden är inte en väg förbi samtalet utan själva inmatningen. ADR-013 gäller flöden där modellens extraktion är enda källan.
ADR-016PageManifest med källoberoende innehållAntagenPageManifest skrivs i module-sdk med parent (hierarkin) och content (statiskt eller en källa). Innehållet är typade block, aldrig HTML. Första källan är Sitevisions headless-API på sundsvall.se, med timeout, cache och inspelad reserv; adaptern bor i modulen webbsidor tills en andra konsument finns.
ADR-017En Sitevision-webbplats inramad i skaletAntagenSimulerar en väg tillbaka till startsidan från Sitevision: webbplatsens meny som rad överst, sidorna i en sandlådad ram med skalet runt. PageLayout får "embed"; skalet äger listan webbplatser och läser källans ramskydd i förväg. En sida visas via REST som jämförelse. Tillägg: exemplen samlas i sektionen Sitevision, och menyraden visas bara inne på webbplatsen.
ADR-018Användaren ordnar korten på startsidanAntagenLäget "Anpassa startsidan" med dragning (@dnd-kit) och knappar som alternativ, tillgängligt enligt WCAG 2.2: fokus stannar, flyttar annonseras med plats, reducerad rörelse respekteras, Ångra finns. Ordningen sparas per roll i en kaka som servern läser. Inga kort låses till en spalt: varje kort ligger i en @container och anpassar sig efter sin bredd (R11). Widget får label.
ADR-019Modulvyer med skalets krom och vägparametrarAntagenmode "standard" från ADR-004 byggs: modulvyer under /verktyg/ med sidopanel och menyrad. path får parametrar (/verktyg/personal/:id) som vyn får som params. Fokusflöden ligger kvar under /flode/.
ADR-020Notiserna kommer från modulerna och leder till funktionerAntagenModuleManifest.notifications och notificationsFor, som actions i ADR-007. Varje notis har href till funktionen. Klockan är en panel i skalet; läst sparas per roll i en kaka. Notiser räknas fram ur datat, t.ex. ett utvecklingssamtal som väntar på chefens godkännande.
ADR-021Fokusytan under AI-fältet på startsidanAntagenslots.fokus lämnar en FokusItem som data; skalet visar den nyaste som inte stängts under AI-fältet, formad som en nyhet med bild, tills användaren stänger den. Stängt sparas per roll i en kaka. Demoknapp i användarmenyn.
ADR-022Ingångens egna kort och hopfällbara block – IT-support som första sidaAntagenIT-support byggs som första sida enligt ADR-003. Prövningen ger PageManifest.slots (modulens egna kort på en ingång), PageContent.cards (fler redaktionella kort), blocket details (hopfällbar fråga med valfritt chip) och QuickLink.cta. Felanmälans nav-post flyttar till sidans snabbväg.
ADR-023Min AI – en personlig assistent med Eneos sessionskontraktAntagenMin AI är en modul med modulvy, navpost och kort på startsidan. Kontraktet är Eneos ({ question, session_id }), så att motorn kan bytas mot Eneo i route handlern. Samtalen och historiken bor på servern och nås bara av ägaren. Svaret strömmas som text och renderas som typade block, aldrig HTML.
ADR-024Verktyg, skills och MCP-tjänster i Min AIAntagenMin AI får webbsök, skapa bild (SVG), skapa dokument (.docx) och skapa graf, plus MCP-tjänster via Anthropics connector. Användaren slår på och av var och en i skrivfältet; valen sparas på servern, som ensam avgör vilka verktyg modellen får. Egna verktyg har strict-schema mot modellen och zod-validering på servern. Nya diagramtokens --color-graf-1…4.
ADR-025Modulvyer över hela arbetsytan, och genvägar bredvid hälsningenAntagenmode: "full" ger en modulvy under /verktyg/ med sidopanelen kvar men hela arbetsytan i skärmens höjd – ingen marginal, sidfot eller AI-knapp. slots.genvag ger knappar bredvid hälsningen på startsidan, AI-tonade med ai: true. Min AI använder båda: knappen ersätter kortet, och samtalet tar ytan som i de stora chattjänsterna, med plats för ett dokument till höger.
ADR-026AI tonas i blått, inte grönt – grönt är bara statusAntagenGrönt är status – klart, godkänt, positivt – och betyder aldrig AI. AI-tokens behåller namnen men byter till blå toner, ljusare än identitetsblått (--color-ai #1f64b8). Signalen för AI är märkningen ✦/AiChip, inte färgen. Ersätter regeln att grönt är reserverat för AI.
ADR-027Målgruppsingång – Verktygslådan under Digitalisering, IT och AIAntagenEn målgruppsingång är en sektion med en ingång – inget nytt i kontraktet. Sektionen Digitalisering, IT och AI får ingången Verktygslådan, porterad från den fristående verktygslådan, med katalog, verksamheter, omvärld och kontakt som egna kort och en artikel per verktyg. Det databasburna (digitala arvet, PIOS, nyttoportföljen) stannar i verktygslådan.
ADR-028Workshoprösten – röstkoder utanför spärren, prickar i en filAntagenPrioriteringen efter workshopen görs med prickröstning på /rosta. En röstkod per deltagare, framräknad ur adminkoden med HMAC och aldrig sparad, ger tre prickar. Sidan och API:t ligger utanför demospärren: röstkoden är nyckeln, och lapparna visas i publik form. Prickarna sparas i en JSON-fil på en volym – ingen databas för en workshop. Röstkoden är en biljett, inte en identitet; ingenting byggs ovanpå åtkomstkakan.
ADR-029Projektets sida på roten, prototypen på /portalAntagenRoten blir projektets sida: vad projektet är, var det står, vad som kommer och allt material samlat, med "Testa prototypen" som huvudärende. Den tidigare introsidan med rollvalet flyttar till /portal, och Logga ut leder dit. Båda är öppna och skrivs publikt; projektboken, tidslinjen, samtalen och workshopen ligger kvar bakom spärren och får bara en rubrik på roten.
ADR-030Kompetens är ett register, inte ett LMSAntagenKommunen köper eller bygger inget nytt LMS. Lärplattformen (Moodle) förblir kursmotorn; det som saknas – vad en person har, vad rollen kräver och när det går ut – blir ett eget register bakom WSO2 med kontraktet kompetens@1, matat från Moodle, ID06, Skolverket och chefens intyg. Startsidan visar det som modulen kompetens, som ersätter utveckling. Planen föds ur utvecklingssamtalet; servern prövar varje aktivitet innan något sparas.
ADR-031Projektboken ordnas efter typ, inte efter tillfälleAntagenProjektbokens meny har fasta flikar – Läget, Tidslinjen, Spåren, Beslut och frågor, Material – som inte blir fler när projektet växer. Allt är typade poster med en fast adress. Varje möte och workshop får en sida under /projekt/handelser/<datum>-<namn>, och tidslinjen är ingången till dem, senast först med filter på slag och spår. Läget skrivs över; historiken läggs till. Toppraden bär kommunens logotyp enligt kommunikationsguidens mall.
ADR-032Projektet är roten, med statusrapporter och funktionernaAntagenProjektbokens innehåll flyttar från /projekt till roten och den gamla projektsidan slås ihop med Läget. Prototypen står överst men lågt. En topprad med fasta flikar gäller alla projektets sidor. Statusrapporter på /status skrivs i ett formulär eller via /api/status med skrivnyckeln STATUS_SKRIVNYCKEL, och servern prövar varje fält. Funktionerna samlas på /funktioner i tre lager. Allt är öppet utom mötenas anteckningar och ritningen; gamla adresser leds permanent vidare.
ADR-033Projektets meny är en klassisk huvudmeny enligt WCAG 2.2 AAAntagenFlikraden ersätts av en klassisk huvudmeny efter header A: Start, Status, Tidslinje, Beslut och Funktioner, och grupperna Dokument och Teknik som fälls ut, i en rad dockad mot toppradens underkant under avsändaren. Prototypen länkas inte från projektets yta tills vidare; den nås på /portal. Grå text, blått och ett streck för sidan man är på. Under md en Meny-knapp med samma lista, en post per rad; toppraden klistrar bara från lg. W3C:s disclosure-mönster med aria-expanded och aria-current, Escape stänger. Hopplänk till <main id="innehall"> på varje sida med toppraden. Menyn är data i projektyta/meny.ts.
ADR-034Projektstödet svarar bara utifrån projektets öppna sidorAntagenFråga om projektet är ett stöd för att förstå projektet, inte en chattassistent: en frågeruta på startsidan och en knapp på varje öppen undersida. Underlaget är de öppna sidorna som en besökare ser dem – servern läser sina egna sidor utan kaka – och ett test fäller bygget om en sida i underlaget är låst. Varje sida är ett dokument med källhänvisningar, så att svaret visar var det står. Servern äger samtalet; /api/fraga är öppen med egna takgränser. Claude Opus 5.5 som standard, utbytbar med PROJEKTSTOD_MODELL.
ADR-035Notiser till teamschatten via ett flöde i Power Automate, avstängda tills de slås påAntagenNya händelser i tidslinjen blir kort i teamets gruppchatt. Ett flöde i Power Automate tar emot kortet och publicerar det som Flödesrobot; Teams gamla Incoming Webhooks är avvecklade. Servern skickar när en ny version startar, så att sidan finns, och minns vad som skickats i datavolymen. TEAMS_NOTISER är av som standard; första gången och i läget logg markeras allt utan att skickas. Varje inlägg i tidslinjen godkänns av Jari Koponen innan det läggs till, och varje godkänt inlägg skickas oavsett slag, högst fem kort per start.
ADR-036Att göra-listan redigeras på sidan och bor i en SQLite-filAntagenUppgifterna på /att-gora läggs till, ändras och byter läge på sidan av den som loggat in med samma skrivnyckel som statusrapporterna; åtkomstkoden räcker inte. De bor i en SQLite-fil med Nodes inbyggda node:sqlite i datavolymen, ATT_GORA_FIL. uppgifter.ts är startdata: det som saknas läggs in vid start, det som finns rörs inte. Servern prövar varje skrivning – ett möte med egen sida eller löpande, länkar från roten – och en uppgift tas aldrig bort.
ADR-037En ändringslogg i startsidans databasAntagenAtt göra-listans SQLite-fil blir startsidans databas, DATABAS_FIL, med ett schema som växer i numrerade steg; den gamla filen kopieras in en gång. En tabell andringar får en rad för varje ändring – statusrapporter, uppgifter och nya byggen – skriven av den som ändrar. Uppgifternas rader är inte publika: till chatten går bara statusrapporterna. Den tekniska tidslinjen är /andringar bakom åtkomstkoden, och varje uppgift visar sina rader. Notiserna till teamschatten ska läsa loggen i ett senare steg, och då bara statusrapporterna.
ADR-038Funktionerna läggs till på sidan och via API, och bor i databasenAntagenFunktionerna på /funktioner bor i startsidans databas; funktioner.ts är startdata. Ett nytt läge, Önskemål, för det som kommit in men inte prövats. Den som har skrivnyckeln lägger till och ändrar på sidan, och API:t /api/funktioner tar emot POST, PUT och PATCH med skrivnyckeln som Bearer-token – vägen för en agent att lägga upp något i produktion. GET är öppet. Servern prövar varje skrivning, ger id:t ur namnet och tar aldrig bort en funktion; varje ändring loggas.
ADR-039Konton för projektgruppen – användarnamn och lösenord, först för att göra-listanAntagenProjektgruppen får egna konton med användarnamn och lösenord, som en mellanlösning tills SAML-sessionen i fas 4; åtkomstkoden är fortfarande ingen identitet. Två roller, medlem och admin. Admin skapar konton på /konton med ett engångslösenord som byts vid första inloggningen; det första kontot skapas med skrivnyckeln. Engångslösenordet gäller i sju dagar. Lösenorden sparas som scrypt med OWASP:s parametrar och prövas mot vanliga lösenord; tio fel i rad spärrar kontot i en kvart. Sessionen gäller i 90 dagar och förnyas när den används (ändrat 20 oktober 2026), med bara kakans fingeravtryck i databasen. Ett konto stängs men tas aldrig bort. Ändringsloggen får kolumnen av, som visas bara för inloggade. Först för att göra-listan; statusrapporterna, funktionerna och API:erna behåller skrivnyckeln.
ADR-040Projektportalen och startsideportalen är två applikationer på en domänAntagenstart.sundsvall.dev rymmer två applikationer med olika syften: projektportalen, projektet om startsidan, och startsideportalen, prototypen av själva produkten. De delar domän för användarnas skull, inte för att de hör ihop. Allt som hör till prototypen ska ligga under /portal, också devportalen som blir /portal/dev; allt annat är projektportalen. CLAUDE.md delas i gemensamt, projektportalen och startsideportalen, och ingen identitet korsar gränsen. Koden delas i steg enligt docs/plan-uppdelning.md – fas 6 i planen – när projektet är redo.

Öppna frågor

  • Flödesmotorns kontrakt (ADR-005) skrivs i M4. Acceptanskriteriet är att ett andra flöde kan definieras på under en timme utan ny UI-kod.
  • Största risken är fortfarande att modulkontraktet blir fel dimensionerat – för tunt och skalet måste ändras för varje modul, för tjockt och det blir byråkrati.
  • Nya fält i ModuleManifest ska bäras av minst två moduler innan de blir permanenta.
  • Intranätets Sitevision som källa för Sidor: samma headless-API som sundsvall.se, men bakom inloggning. Kräver servicekonto via BFF eller WSO2 i fas 4 (ADR-016).
  • Vilket innehåll hör hemma på intranätet? Spiken visar skolavtalet från sundsvall.se för att pröva kontraktet, inte för att det är rätt innehåll.