Hoppa till innehållet

Devportalen /portal/dev

Startsideportalens ekosystem för människa och agent

Agentvy

Arkitekturen

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

page manifest · /dev/arkitektur
id: arkitektur
path: /dev/arkitektur
titel: Arkitekturen
summering: Skal och moduler, de tre ytformerna, dataflödet och rollfiltreringen.
nyckelord: arkitektur, skal, moduler, slots, ytformer, roller, dataflöde

## 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)
```

Ansvar | Skalet | Modulen
Layout och krom | Ja – sidopanel, rutnät, sidfot, fokusläge | Nej
Vad som visas | Nej – vet bara vilken slot en widget hör till | Ja
Data | Nej | Ja – hämtar själv på servern
Roll och identitet | Ja – cookie, demoanvändare, UserContext | Nej – tar emot ctx
Designtokens och primitiver | Ja – tillhandahåller | Nej – konsumerar
Beslut om att skapa något | Ja – route handlern validerar | Nej – 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.

Ytform | Facit i docs/ | Kännetecken | Deklareras med
Verktygsyta | startsidan-prototyp-v3.html | Rollfiltrerad, datadriven, komponerad av modulernas slots | slots.kpi / main / side / actions
Sida | it-support-prototyp.html, innehallssida-prototyp.html | Redaktionellt innehåll, brödsmulor, sidkontext i AI-fältet | pages: PageManifest[] (ADR-016) – layout "hub", "article" eller "embed" (ram, ADR-017), innehåll som ContentBlock
Fokusflöde | felanmalan-poc.html | Helskärm utan sidopanel, smal topprad med Avbryt | routes med mode: "focus" (ADR-004)
Modulvy | – (kort och artikel ur /dev/ui) | Modulens egen vy med sidopanel och menyrad, t.ex. personalakten | routes 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änst | routes 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" ? … : …}.

Hela portalen i samma form: /dev/llms.txt · /dev/spec.json