Hoppa till innehållet

Devportalen /portal/dev

Startsideportalens ekosystem för människa och agent

Dokumentationen / Yta

Åtkomstspärren

YtaStartsideportalen

Låser startsideportalens demo bakom en delad kod så att den kan ligga på en publik adress utan att vara öppen. Ingången /portal och devportalen /portal/dev ligger utanför spärren; projektportalen på roten har ingen spärr alls (ADR-040).

källa: apps/portal/src/middleware.ts, apps/projekt/src/atkomst/uppdaterad: 2026-10-19

Ansvar

  • Spärra allt i startsideportalen utom en kort, stängd lista öppna vägar, före routningen, så att en ny yta inte kan glömma spärren.
  • Hålla ingången /portal och devportalen /portal/dev öppna, så att beskrivningen av systemet går att läsa och hämta – också av verktyg som inte kan mata in en kod.
  • Vara avstängd när ACCESS_CODE är osatt, så att lokal utveckling inte kräver en kod.
  • Hålla koden borta ur kakan – den bär ett SHA-256-avtryck, inte klartext.
  • Validera ?vidare= mot öppen vidarebefordran innan den följs.
  • Aldrig utge sig för att vara autentisering, och aldrig vara behörighet i projektportalen. Spärren säger ingenting om vem användaren är.

Filer

Tabell: Sökväg, Roll
SökvägRoll
apps/portal/src/middleware.tsSpärren för startsideportalen. Kör i edge-runtime, före all routning. Vägarna är appens egna – Next tar bort basvägen /portal före middleware och lägger på den i omdirigeringen.
apps/portal/src/atkomst/kod.tsarOppenVag, atkomstkod, fingeravtryck, likaSakert. Fri från Node-API:er så middleware kan använda den. sakerVidare kommer ur @startsidan/gemensamt.
apps/portal/src/atkomst/actions.tslasUpp: jämför koden, sätter kakan, skickar vidare.
apps/portal/src/atkomst/kod.test.tsTester på avtryck, jämförelse, vidarebefordran och de öppna vägarna.
apps/portal/src/app/las-upp/page.tsxUpplåsningssidan, /portal/las-upp. Satt till noindex.
packages/gemensamt/src/felforsok.tsSpärren mot gissningar: tio fel per adress och tio minuter, med den adress Traefik lägger sist i X-Forwarded-For. Delas med projektportalens konton och skrivnyckel, men räknas per app.

API

Tabell: Namn, Signatur, Beskrivning
NamnSignaturBeskrivning
arOppenVag(pathname: string) => booleanLigger vägen utanför spärren? Vägen är appens egen, utan /portal. Listan är stängd: / (ingången), /dev, /api/health och /las-upp – var och en med allt under sig, utom roten.
atkomstkod() => string | undefinedKoden ur miljön. Osatt eller tom betyder att spärren är avstängd.
fingeravtryck(kod: string) => Promise<string>SHA-256 i hex med prefix, så avtrycket bara betyder något här.
likaSakert(a: string, b: string) => booleanJämförelse som tar lika lång tid oavsett var strängarna skiljer sig.
sakerVidare(vidare: unknown) => stringUr @startsidan/gemensamt/vidare. Släpper bara igenom interna vägar. Faller tillbaka på /.
lasUpp(formData: FormData) => Promise<void>Server action bakom upplåsningsformuläret.

Kontrakt

Detta är inte autentisering. Alla som kommer in delar samma kod, och rollen väljs fortfarande fritt på /portal. En modul som behöver veta vem användaren är ska vänta på SAML-sessionen i fas 4 – läs aldrig åtkomstkakan som en identitet. Projektportalens konton (ADR-039) är aldrig identiteten här.

Tabell: Väg, Läge, Varför
VägLägeVarför
/portalÖppenPrototypens ingång berättar vad prototypen är. Den visar inte demon, bara vägen in i den.
/portal/dev och allt underÖppenPortalen, designsystemet, dokumentationen, llms.txt och spec.json ska gå att läsa av både människor och verktyg.
/portal/api/healthÖppenDokploys healthcheck för start-portal markerar annars containern som sjuk.
/portal/las-uppÖppenDet är sidan man låser upp på.
/portal/start och allt underLåstSjälva demon.
/portal/verktyg/*, /portal/sidor/*LåstModulvyerna och sidorna i skalet.
/portal/flode/<namn>LåstFokuslägena är demon i helskärm.
/portal/api/flows/*, /portal/api/min-aiLåstAI-anropen kostar pengar.
/portal/api/mock/*, /portal/api/kompetens/*LåstDemons data om påhittade personer.
Allt utanför /portalIngen spärrProjektportalen (ADR-040). Öppen med flit; ändringsloggen, ritningen, organisationen och pitchen kräver ett konto (ADR-039).
/start, /dev, /verktyg … (gamla)OmledningProjektportalens next.config leder varje gammal adress permanent (308) till sin nya under /portal; utskickade länkar ska alltid fungera.
  • ACCESS_CODE måste sättas i Dokploy innan domänen delas. Osatt = öppet, utan varning. Variabeln listas bara under start-portal i docker-compose.yml.
  • /portal och /portal/dev är publika. Skriv dem därefter: namn på kommunens medarbetare och projektets deltagare får stå där, känsliga personuppgifter aldrig.
  • Allt får hämtas men inget indexeras: robots.txt är öppen, så att AI-tjänster kan läsa en länk, och varje sida sätter noindex. noindex verkar bara på en sida som får hämtas (ADR-012, ändrat 20 oktober 2026).
  • Byts koden loggas alla ut – avtrycket i kakan matchar inte längre. Det är den enda vägen att återkalla åtkomst.
  • Middleware kör i edge-runtime: atkomst/kod.ts får bara använda Web Crypto, aldrig node:crypto.

Beroenden och beslut

Kvarstår

  • Ingen utloggning ur spärren – bara kakans 30 dagar eller ett kodbyte.
  • Kakan har sökvägen / och syns därför också för projektportalen, som inte läser den.
  • Formulärets POST är verifierad i webbläsare, inte i test. Middleware och den delade logiken är verifierade i container respektive vitest.