Hoppa till innehållet

Devportalen /portal/dev

Startsideportalens ekosystem för människa och agent

Devportalen

Arkitekturen

Skal och moduler, de tre ytformerna, dataflödet och rollfiltreringen.

Bärande idé

Skalet äger kromet och kompositionen. Modulen äger innehållet och sin data. Kontraktet däremellan är ModuleManifest – och det är avsiktligt tunt.

Kompositionen

        ┌──────────────────────────────────────────────┐
        │  Skalet (apps/projekt/src/shell)                 │
        │  sidopanel · AI-fält · rollväxling · rutnät  │
        └───────────────┬──────────────────────────────┘
                        │  läser registry, filtrerar på roll
        ┌───────────────▼──────────────────────────────┐
        │  ModuleManifest  (packages/module-sdk)       │
        │  nav · routes · slots · ai                   │
        └───────────────┬──────────────────────────────┘
                        │  ett paket per modul
   ┌────────┬───────────┼───────────┬──────────┬───────────┐
oversikt  agera     arenden     kalender   ledighet   utveckling …
   │         │          │           │          │
   └─────────┴──────────┴───────────┴──────────┘
           hämtar sin egen data på servern (ADR-006)
Tabell: Ansvar, Skalet, Modulen
AnsvarSkaletModulen
Layout och kromJa – sidopanel, rutnät, sidfot, fokuslägeNej
Vad som visasNej – vet bara vilken slot en widget hör tillJa
DataNejJa – hämtar själv på servern
Roll och identitetJa – cookie, demoanvändare, UserContextNej – tar emot ctx
Designtokens och primitiverJa – tillhandahållerNej – konsumerar
Beslut om att skapa någotJa – route handlern validerarNej – föreslår

Tre ytformer, ett skal

Alla tre delar sidopanel, tokens och AI-märkning. De skiljer sig i vad skalet renderar runt innehållet.

Tabell: Ytform, Facit i docs/, Kännetecken, Deklareras med
YtformFacit i docs/KänneteckenDeklareras med
Verktygsytastartsidan-prototyp-v3.htmlRollfiltrerad, datadriven, komponerad av modulernas slotsslots.kpi / main / side / actions
Sidait-support-prototyp.html, innehallssida-prototyp.htmlRedaktionellt innehåll, brödsmulor, sidkontext i AI-fältetpages: PageManifest[] (ADR-016) – layout "hub", "article" eller "embed" (ram, ADR-017), innehåll som ContentBlock
Fokusflödefelanmalan-poc.htmlHelskärm utan sidopanel, smal topprad med Avbrytroutes med mode: "focus" (ADR-004)
Modulvy– (kort och artikel ur /dev/ui)Modulens egen vy med sidopanel och menyrad, t.ex. personalaktenroutes med mode: "standard" under /verktyg/, path med :parametrar (ADR-019)
Modulvy över hela ytan– (Min AI)Sidopanelen kvar, vyn tar hela arbetsytan i skärmens höjd – som en chattjänstroutes med mode: "full" under /verktyg/ (ADR-025)

En modul kan bidra med alla tre. felanmalan äger ett fokusflöde och snabbvägskortet som leder dit från IT-supportsidan.

Dataflödet

  • Rollen bor i en cookie och läses på servern med getCurrentUser() (ADR-006).
  • Skalet gör om användaren till UserContext och skickar den till varje widget.
  • Widgeten är en async server component som anropar modulens egen datafunktion i data/ – inget nätverksanrop, ingen fetch. I fas 4 byts funktionens insida mot BFF:en.
  • /api/mock/<modul> är inte modulens datakälla utan en tunn spegel: route handlern anropar samma funktion och visar vilken form ett riktigt mikrotjänst-API skulle ge.
  • Ingenting om användaren skickas upp från klienten. En profil som klienten skickar vore en injektionsväg rakt in i ärendet.

Så ser en widget ut

export async function Idag({ ctx }: { ctx: UserContext }) {
  const { poster } = await hamtaDagen(ctx);   // modulens egen data
  return <Card headingId="idag-h" title="Idag">…</Card>;
}

Rollfiltrering

Allt filtreras mot två roller: medarbetare och chef. Filtret finns på tre nivåer och den snävaste vinner – modulen, widgeten, nav-posten.

export const manifest = defineModule({
  id: "kalender",
  roles: ["medarbetare", "chef"],          // modulens roller
  slots: {
    side: [
      { id: "kalender-idag", order: 10, Component: Idag },
      { id: "kalender-aterkommande", order: 40,
        roles: ["chef"],                    // snävare än modulen
        Component: AterkommandeHandelser },
    ],
  },
});

Rollskillnader i text väljs i komponenten, inte genom två manifestposter: title={ctx.role === "chef" ? … : …}.