Agentvy
Arkitekturen
Skal och moduler, de tre ytformerna, dataflödet och rollfiltreringen.
page manifest · /dev/arkitekturid: 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