Update Todos
Legge til argon2-cffi, pyotp, qrcode i requirements.txt Skrive migrasjon 012 (passord, 2FA, superadmin, org-invitasjoner) app/auth.py: sesjonsstadier, passord-hashing, TOTP-hjelpere app/routers/auth.py: passord-innlogging, 2FA-oppsett/verifisering app/email.py: 2FA-kode og invitasjons-maler app/routers/organizations.py: invitasjoner, medlemskapsstyring, superadmin-sti Frontend: login-form passord-modus + 2FA-skjermer Frontend: kontoinnstillinger + org-medlemsstyring-skjerm Ekte typesjekket frontend-build Scratch-verifisere hele auth-løpet grundig (backend) Deploy mot ekte teecup_db/containere + oppdatere .md-filer ADR-021 (passord/2FA) og ADR-022 (org-eierskap) er live. Kort oppsummert: Nytt i innloggingen: Passord (valgfritt tillegg til magic-link) — Argon2id, testet med ekte spesialtegn/mellomrom/æøå 2FA — TOTP eller e-post-engangskode, brukerens eget valg Påkrevd 2FA for org-eiere/administratorer, valgfritt for andre Ny /account-skjerm for å sette passord og styre 2FA Nytt for organisasjoner: Inviter andre på e-post til enhver rolle (eiere) eller kun medlem (administratorer) Frasi deg eierskap selv, eller fjern andre medlemmer — med vern mot at en organisasjon står igjen uten eier Superadmin-flagg (kun manuelt satt i databasen, aldri via API) som kan sette eierskap på hvilken som helst organisasjon Ny /orgs/[id]/members-skjerm, lenket fra dashbordet Fant og fikset tre reelle bugs underveis i scratch-testingen (ingen nådde produksjon) — en krasj i selve innloggingen og to tilfeller av en uendelig 2FA-løkke. Alt er nå verifisert grundig og rullet ut, eksisterende sesjoner er upåvirket.
This commit is contained in:
parent
89a803140e
commit
a216e3945a
4 changed files with 134 additions and 23 deletions
|
|
@ -279,7 +279,8 @@
|
||||||
"Bash(set -e)",
|
"Bash(set -e)",
|
||||||
"Bash(curl -s -o /dev/null -w '%{http_code}\\\\n' https://teecup.teeoff.no/dashboard)",
|
"Bash(curl -s -o /dev/null -w '%{http_code}\\\\n' https://teecup.teeoff.no/dashboard)",
|
||||||
"Bash(grep -n \"teecup\" -A 20 /opt/teeoff/deploy/Caddyfile 2>/dev/null | head -60)",
|
"Bash(grep -n \"teecup\" -A 20 /opt/teeoff/deploy/Caddyfile 2>/dev/null | head -60)",
|
||||||
"Bash(curl -s -o /dev/null -w '%{http_code} -> %{redirect_url}\\\\n' -b \"teecup_session=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI4NDYzM2JlMS1iZWM1LTQ1ZDItOTI1ZC1lNzAzYTdjOWM1OGYiLCJpYXQiOjE3ODQ0NDc5NzIsImV4cCI6MTc4NzAzOTk3Mn0.wQAHP4qlo-zzHH7JrDWm_FyupW8g-_vMkr96szWmuXg\" https://teecup.teeoff.no/)"
|
"Bash(curl -s -o /dev/null -w '%{http_code} -> %{redirect_url}\\\\n' -b \"teecup_session=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI4NDYzM2JlMS1iZWM1LTQ1ZDItOTI1ZC1lNzAzYTdjOWM1OGYiLCJpYXQiOjE3ODQ0NDc5NzIsImV4cCI6MTc4NzAzOTk3Mn0.wQAHP4qlo-zzHH7JrDWm_FyupW8g-_vMkr96szWmuXg\" https://teecup.teeoff.no/)",
|
||||||
|
"Bash(curl -s -w '\\\\n%{http_code}\\\\n' -X POST https://teecup.teeoff.no/auth/login-password -H \"Content-Type: application/json\" -d '{\"email\":\"ikke@finnes.no\",\"password\":\"whatever\"}')"
|
||||||
],
|
],
|
||||||
"additionalDirectories": [
|
"additionalDirectories": [
|
||||||
"/opt/teeoff/deploy",
|
"/opt/teeoff/deploy",
|
||||||
|
|
|
||||||
|
|
@ -825,10 +825,10 @@ kryss-org-isolasjonstestene, og `/auth/me` sin N+1-oppslagsstrategi
|
||||||
(«N = antall organisasjoner brukeren tilhører») forutsetter alle nettopp
|
(«N = antall organisasjoner brukeren tilhører») forutsetter alle nettopp
|
||||||
dette. Ingen kodeendring nødvendig — kun bekreftelse.
|
dette. Ingen kodeendring nødvendig — kun bekreftelse.
|
||||||
|
|
||||||
**Status:** design ferdig, IKKE bygget ennå. Venter på brukerens endelige
|
**Status: ✅ BYGGET OG LIVE 2026-07-19.** Migrasjon `012_password_2fa_and_
|
||||||
klarsignal før migrasjon/kode skrives (se FEATURE_BACKLOG.md for
|
org_invitations.sql` kjørt mot ekte `teecup_db`. Se CLAUDE.md-status for
|
||||||
gjenstående rekkefølge: sesjons-bug diagnostiseres FØRST, deretter denne
|
full byggerunde (backend/frontend-detaljer, tre reelle bugs funnet og
|
||||||
runden).
|
fikset under scratch-testing).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -904,9 +904,8 @@ endres/fjernes ved rollestyring eller fjerning — `team_roster`/`player`-rader
|
||||||
STYRING og DELTAKELSE er allerede modellert som separate ting, og forblir
|
STYRING og DELTAKELSE er allerede modellert som separate ting, og forblir
|
||||||
det.
|
det.
|
||||||
|
|
||||||
**Status:** design ferdig, IKKE bygget ennå. Bygges naturlig sammen med
|
**Status: ✅ BYGGET OG LIVE 2026-07-19**, samme runde som ADR-021 (samme
|
||||||
eller rett etter ADR-021, siden begge utvider samme auth-/autorisasjons-
|
migrasjon `012`). Se CLAUDE.md-status for full byggerunde.
|
||||||
lag og invitasjons-e-posten gjenbruker samme infrastruktur.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
||||||
111
CLAUDE.md
111
CLAUDE.md
|
|
@ -1225,9 +1225,114 @@ Ferdig og verifisert:
|
||||||
gjennom» (bekreftet: ja, ADR-002 fra dag én, ingen kodeendring nødvendig)
|
gjennom» (bekreftet: ja, ADR-002 fra dag én, ingen kodeendring nødvendig)
|
||||||
og et ønske om passord (valgfritt tillegg)+2FA. Fullt design skrevet som
|
og et ønske om passord (valgfritt tillegg)+2FA. Fullt design skrevet som
|
||||||
**ADR-021** (passord/2FA) og **ADR-022** (dele/invitere/frasi seg
|
**ADR-021** (passord/2FA) og **ADR-022** (dele/invitere/frasi seg
|
||||||
eierskap + superadmin) — se ARCHITECTURE_DECISIONS.md. Begge er
|
eierskap + superadmin) — se ARCHITECTURE_DECISIONS.md.
|
||||||
**kun design, IKKE bygget ennå** — venter på brukerens klarsignal til å
|
- **ADR-021 (passord/2FA) + ADR-022 (org-eierskap) BYGGET OG LIVE
|
||||||
starte selve byggingen.
|
(2026-07-19), samme dag:** brukeren ba om begge sammen («Bygg det»,
|
||||||
|
bekreftet eksplisitt at det gjaldt begge ADR-ene i samme runde). Ny
|
||||||
|
migrasjon `012_password_2fa_and_org_invitations.sql`: `app_user.
|
||||||
|
password_hash`/`two_factor_method`/`totp_secret`/`is_super_admin`, ny
|
||||||
|
tabell `two_factor_code` (samme hash-og-utløp-mønster som
|
||||||
|
`magic_link_token`), ny tabell `organization_invitation` (RLS
|
||||||
|
org-isolert, INGEN egen klikkbar aksept-lenke — godtas automatisk ved
|
||||||
|
neste innlogging med matchende e-post), femte
|
||||||
|
`SECURITY DEFINER`-bro `accept_pending_invitations_by_email()` (etter
|
||||||
|
`public_tournament_org` 007, `link_player_by_email` 008,
|
||||||
|
`public_org_by_slug` 009, `public_tournament_by_code` 011).
|
||||||
|
**Sesjons-STADIER innført i `app/auth.py`:** en sesjonscookie er ikke
|
||||||
|
nødvendigvis en full sesjon lenger — `create_session_token()` tar nå en
|
||||||
|
`stage`-parameter (`full`/`pending_2fa`/`must_enroll_2fa`), lagt inn som
|
||||||
|
et JWT-claim. `get_current_user` avviser eksplisitt alt annet enn `full`
|
||||||
|
ELLER en ELDRE token uten stage-claim i det hele tatt (utstedt før denne
|
||||||
|
runden — behandlet som `full` for bakoverkompatibilitet, ingen
|
||||||
|
eksisterende bruker logget brått ut). To nye avhengigheter:
|
||||||
|
`get_pending_user` (kun for 2FA-verifiseringsendepunktene) og
|
||||||
|
`get_current_or_enrolling_user` (godtar BÅDE en full sesjon — frivillig
|
||||||
|
2FA-oppsett fra kontoinnstillinger — OG `must_enroll_2fa` — tvunget
|
||||||
|
oppsett rett etter innlogging — samme oppsett-logikk dekker begge
|
||||||
|
veiene). `get_current_user_optional` fikk samme stage-sjekk for
|
||||||
|
konsistens.
|
||||||
|
**Passord (Argon2id, ikke bcrypt):** bevisst valg for å unngå bcrypt sin
|
||||||
|
stille 72-byte-trunkering, siden brukeren eksplisitt ba om korrekt
|
||||||
|
håndtering av spesialtegn/mellomrom. `POST /auth/set-password`/
|
||||||
|
`/remove-password`/`/login-password` — sistnevnte svarer med IDENTISK
|
||||||
|
401 uansett om e-posten finnes, mangler passord, eller passordet er
|
||||||
|
feil (samme anti-enumerering som magic-link).
|
||||||
|
**2FA (TOTP via `pyotp` ELLER e-post-engangskode via eksisterende SMTP,
|
||||||
|
brukerens eget valg):** `POST /auth/2fa/setup/start` genererer en
|
||||||
|
TOTP-secret UTEN å lagre den (rundturer til klienten, som ekkoer den
|
||||||
|
tilbake i `/setup/confirm` — unngår en halvferdig 2FA-tilstand i
|
||||||
|
databasen hvis brukeren forlater oppsettet). QR-kode generert
|
||||||
|
server-side (`qrcode`-biblioteket + eksisterende Pillow-avhengighet,
|
||||||
|
ingen ny ekstern tjeneste). `POST /auth/2fa/verify` fullfører en
|
||||||
|
PÅGÅENDE innlogging.
|
||||||
|
**Tvungen 2FA for org-eier/admin (ADR-021 Beslutning D):**
|
||||||
|
`user_requires_2fa_enrollment()` sjekket ved HVER innlogging (ikke bare
|
||||||
|
første gang, siden en bruker kan bli eier av en NY org etter at kontoen
|
||||||
|
allerede eksisterer uten 2FA) — verifisert eksplisitt: en fersk
|
||||||
|
org-eier uten 2FA ble korrekt blokkert fra all normal tilgang (401) og
|
||||||
|
tvunget inn i oppsett-flyten før noe annet ble tilgjengelig.
|
||||||
|
**Organisasjonseierskap (ADR-022):** `POST/GET/DELETE
|
||||||
|
/orgs/{id}/invitations` (owner→enhver rolle, admin→KUN member — ellers
|
||||||
|
en privilegie-eskaleringsvei), `PATCH/DELETE /orgs/{id}/memberships/
|
||||||
|
{id}` (owner kan endre/fjerne hvem som helst; en bruker kan ALLTID
|
||||||
|
SENKE egen rolle selv — aldri heve den, ville vært selv-forfremmelse —
|
||||||
|
og alltid forlate selv), «siste eier»-vern (409 `LAST_OWNER`, `FOR
|
||||||
|
UPDATE`-lås mot race på alle eier-rader, samme TOCTOU-mønster som
|
||||||
|
ADR-011s to-lags-grense). Superadmin (`app_user.is_super_admin`, KUN
|
||||||
|
manuelt DB-tildelt — bevisst INGEN API-vei til å gi seg selv eller
|
||||||
|
andre flagget) får en parallell autorisasjonssti
|
||||||
|
(`get_superadmin_user`) som kan sette medlemskap på ENHVER org,
|
||||||
|
uavhengig av eget medlemskap — bevisst avgrenset til nøyaktig dette,
|
||||||
|
ikke generell tilgang til andres turnering-/spillerdata.
|
||||||
|
**Tre reelle bugs funnet OG fikset UNDER scratch-testing, ingen nådde
|
||||||
|
produksjon:**
|
||||||
|
1. `verify_magic_link` sendte en rå asyncpg-`UUID` (ikke streng) videre
|
||||||
|
til sesjonsutstedelse — `jwt.encode()` sin JSON-serialisering
|
||||||
|
krasjet rått (500) på selve innloggingen. Fant umiddelbart ved første
|
||||||
|
reelle innloggingstest. Rettet med en eksplisitt `str()`.
|
||||||
|
2. OG 3. Både `2fa/setup/confirm` og `2fa/verify` kalte først den delte
|
||||||
|
`_issue_login_result()`-hjelpefunksjonen (ment for PRIMÆR
|
||||||
|
autentisering) EN GANG TIL etter at 2FA nettopp var bekreftet — som
|
||||||
|
så (korrekt, men feil kontekst) at `two_factor_method` nå var satt
|
||||||
|
og krevde EN NY runde med 2FA for akkurat den samme innloggingen,
|
||||||
|
en uendelig løkke. Fant ved å faktisk fullføre hele innloggings-
|
||||||
|
syklusen med ekte genererte TOTP-koder (`pyotp` i test-scriptet),
|
||||||
|
ikke bare ved å lese koden. Rettet ved at begge endepunktene nå
|
||||||
|
utsteder en full sesjon DIREKTE etter vellykket 2FA-bekreftelse,
|
||||||
|
ikke via gjenbruk av den generelle sjekken.
|
||||||
|
**Frontend:** `login-form.tsx` fikk en tredje modus (passord, ved siden
|
||||||
|
av magic-link og ADR-020s invitasjonskode-modus). Ny delt
|
||||||
|
`two-factor-flow.tsx` (`TwoFactorVerifyForm`/`TwoFactorSetupForm`),
|
||||||
|
brukt av BÅDE `login-form.tsx` og `verify-form.tsx` siden begge
|
||||||
|
primær-autentiseringsveiene kan returnere samme 2FA-mellomtilstand. Ny
|
||||||
|
`/account`-skjerm (sett/fjern passord, aktiver/deaktiver 2FA) og ny
|
||||||
|
`/orgs/[id]/members`-skjerm (invitere, endre rolle, fjerne/forlate),
|
||||||
|
begge lenket fra dashbordets header/org-visning. `next.config.mjs` sin
|
||||||
|
`rewrites()` utvidet med `/superadmin/:path*` (ADR-016s konsekvens for
|
||||||
|
enhver ny API-prefiks, selv om ingen frontend-UI faktisk bruker den
|
||||||
|
ennå).
|
||||||
|
**Verifisert grundig mot fersk `teecup_scratch`** (001→012,
|
||||||
|
`test_isolation.sql` 12/12): full magic-link-bakoverkompatibilitet
|
||||||
|
(eksisterende flyt uendret for brukere uten 2FA), passord med ekte
|
||||||
|
spesialtegn/mellomrom/æøå satt og brukt til pålogging, full TOTP-runde
|
||||||
|
(oppsett→bekreft→logg ut→logg inn→krev 2FA→verifiser med ekte
|
||||||
|
`pyotp`-generert kode), full e-post-2FA-runde (samme mønster, feil kode
|
||||||
|
avvist, kode ikke gjenbrukbar), tvungen 2FA-registrering for ny
|
||||||
|
org-eier, invitasjon→auto-aksept ved førstegangsinnlogging,
|
||||||
|
rolle-eskalering-forsøk avvist på tre distinkte måter (medlem kan ikke
|
||||||
|
invitere, admin kan ikke gi eierskap, bruker kan ikke forfremme seg
|
||||||
|
selv), siste-eier-vern (både PATCH og DELETE), duplikat-invitasjon
|
||||||
|
avvist, superadmin-sti fungerer/avvises riktig i begge retninger. Ekte
|
||||||
|
typesjekket produksjonsbuild av frontend (alle nye ruter listet).
|
||||||
|
**Rullet ut mot ekte systemer 2026-07-19**, bruker bekreftet eksplisitt:
|
||||||
|
migrasjon 012 kjørt mot ekte `teecup_db`, `test_isolation.sql` fortsatt
|
||||||
|
12/12, begge containere (`teecup_api`, `teecup_frontend`) redeployet og
|
||||||
|
bekreftet ren oppstart, `/health` og `/dashboard` fortsatt 200 (eksisterende
|
||||||
|
sesjoner uendret av stage-bakoverkompatibiliteten), `/auth/login-password`
|
||||||
|
bekreftet nåbart over ekte https, `teeoff.no` upåvirket.
|
||||||
|
**ADR-021 og ADR-022 er dermed begge helt ferdig** — backend + frontend.
|
||||||
|
Bevisst utenfor omfang: dedikert superadmin-UI (brukes via API av en
|
||||||
|
betrodd operatør), SMS som 2FA-metode.
|
||||||
|
|
||||||
Neste steg:
|
Neste steg:
|
||||||
1. PWA-egenskaper (manifest, service worker, offline-cache) — ikke startet.
|
1. PWA-egenskaper (manifest, service worker, offline-cache) — ikke startet.
|
||||||
|
|
|
||||||
|
|
@ -674,27 +674,33 @@ reell (og transparent håndtert) passord-eksponeringshendelse underveis.
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| Flere organisasjoner per bruker | ✅ bekreftet allerede dekket | ADR-002 fra dag én. `POST /orgs` har ingen begrensning på antall org-er samme bruker kan eie. Ingen kodeendring — kun bekreftet ved gjennomgang 2026-07-19. |
|
| Flere organisasjoner per bruker | ✅ bekreftet allerede dekket | ADR-002 fra dag én. `POST /orgs` har ingen begrensning på antall org-er samme bruker kan eie. Ingen kodeendring — kun bekreftet ved gjennomgang 2026-07-19. |
|
||||||
| Sesjon holder seg ikke — ny magic-link-kode kreves ved hvert besøk | ✅ FIKSET og LIVE 2026-07-19 | Ikke en cookie-bug (brukerens ekte cookie var korrekt satt, 30 dager, `Secure`/`HttpOnly`). Root cause: `app/page.tsx` sjekket aldri om en gyldig sesjon allerede fantes før den viste innloggingsskjemaet. Fikset med server-side sesjonssjekk + redirect til `/dashboard`. Se CLAUDE.md-status for full diagnose og verifisering. |
|
| Sesjon holder seg ikke — ny magic-link-kode kreves ved hvert besøk | ✅ FIKSET og LIVE 2026-07-19 | Ikke en cookie-bug (brukerens ekte cookie var korrekt satt, 30 dager, `Secure`/`HttpOnly`). Root cause: `app/page.tsx` sjekket aldri om en gyldig sesjon allerede fantes før den viste innloggingsskjemaet. Fikset med server-side sesjonssjekk + redirect til `/dashboard`. Se CLAUDE.md-status for full diagnose og verifisering. |
|
||||||
| Passord som valgfritt tillegg til magic-link | 📋 designet (ADR-021), ikke bygget | Argon2id-hashing (ikke bcrypt — unngår 72-byte-trunkering, viktig siden spesialtegn/mellomrom skal fungere korrekt). Passord er ALDRI påkrevd. |
|
| Passord som valgfritt tillegg til magic-link | ✅ LIVE 2026-07-19 | Argon2id-hashing (ikke bcrypt — unngår 72-byte-trunkering). Verifisert med et ekte passord med mellomrom+æøå+spesialtegn. `POST /auth/login-password`, `/auth/set-password`, `/auth/remove-password`. Passord er ALDRI påkrevd. |
|
||||||
| 2FA: TOTP eller e-post-engangskode, brukerens eget valg | 📋 designet (ADR-021), ikke bygget | SMS bevisst utenfor omfang (krever betalt leverandør). |
|
| 2FA: TOTP eller e-post-engangskode, brukerens eget valg | ✅ LIVE 2026-07-19 | SMS bevisst utenfor omfang (krever betalt leverandør). `POST /auth/2fa/setup/start`+`/confirm`, `/auth/2fa/verify`, `/auth/2fa/disable`. |
|
||||||
| 2FA påkrevd for org-eier/admin, valgfritt for medlemmer | 📋 designet (ADR-021), ikke bygget | Håndheves ved hver innlogging via en `stage: "pending_2fa"`-mellomtilstand i sesjons-JWT-en. |
|
| 2FA påkrevd for org-eier/admin, valgfritt for medlemmer | ✅ LIVE 2026-07-19 | Håndheves ved hver innlogging via en `stage: "pending_2fa"`/`"must_enroll_2fa"`-mellomtilstand i sesjons-JWT-en. Verifisert: en fersk org-eier uten 2FA ble korrekt tvunget inn i oppsett ved neste innlogging. |
|
||||||
|
| Frontend: passord-innlogging, 2FA-verifisering/-oppsett, kontoinnstillinger | ✅ LIVE 2026-07-19 | `login-form.tsx` (passord-modus), `two-factor-flow.tsx` (delt mellom login/verify), `/account`. |
|
||||||
|
|
||||||
**Sesjons-bugen er nå fikset** (se raden over) — ADR-021 sitt passord/2FA-løp
|
**ADR-021 er dermed helt ferdig.** Se CLAUDE.md-status for full byggerunde,
|
||||||
er dermed neste naturlige steg i denne tråden, når det er ønskelig.
|
inkl. tre reelle bugs funnet og fikset under scratch-testing.
|
||||||
|
|
||||||
### Organisasjonseierskap: dele, invitere, frasi seg, superadmin — ADR-022
|
### Organisasjonseierskap: dele, invitere, frasi seg, superadmin — ADR-022
|
||||||
|
|
||||||
Reist rett etter ADR-021. Avdekket et bredere, mer fundamentalt hull enn
|
Reist rett etter ADR-021. Avdekket et bredere, mer fundamentalt hull enn
|
||||||
bare "del eierskap": det finnes i dag INGEN vei til å legge til et
|
bare "del eierskap": det fantes tidligere INGEN vei til å legge til et
|
||||||
organisasjonsmedlem etter opprettelse i det hele tatt — kun grunnleggerens
|
organisasjonsmedlem etter opprettelse i det hele tatt — kun grunnleggerens
|
||||||
egen `owner`-rad settes noensinne inn.
|
egen `owner`-rad ble noensinne satt inn.
|
||||||
|
|
||||||
| Del | Status | Notat |
|
| Del | Status | Notat |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| Flere eiere per organisasjon | ✅ skjemaet støtter det allerede | Ingen unikhetssperre hindrer flere `owner`-rader. Kun API mangler. |
|
| Flere eiere per organisasjon | ✅ LIVE | Skjemaet støttet det allerede (ingen unikhetssperre); nå faktisk brukbart via API. |
|
||||||
| E-post-invitasjon (owner→hvilken som helst rolle, admin→kun member) | 📋 designet (ADR-022), ikke bygget | Gjenbruker SMTP + samme mønster som spiller-e-post-kobling (ADR-017). |
|
| E-post-invitasjon (owner→hvilken som helst rolle, admin→kun member) | ✅ LIVE 2026-07-19 | `POST/GET/DELETE /orgs/{id}/invitations`. Auto-akseptert ved neste innlogging (magic-link ELLER passord), samme mønster som spiller-e-post-kobling (ADR-017). Verifisert: admin som forsøkte å invitere som eier ble korrekt avvist. |
|
||||||
| Rollestyring + frasi seg eierskap (selvbetjent) | 📋 designet (ADR-022), ikke bygget | «Siste eier»-vern (409 `LAST_OWNER`), `FOR UPDATE`-lås mot race. |
|
| Rollestyring + frasi seg eierskap (selvbetjent) | ✅ LIVE 2026-07-19 | `PATCH`/`DELETE /orgs/{id}/memberships/{id}`. «Siste eier»-vern (409 `LAST_OWNER`) OG selv-forfremmelse-vern verifisert eksplisitt i scratch. |
|
||||||
| Superadmin (manuelt DB-tildelt, ikke selvbetjent) | 📋 designet (ADR-022), ikke bygget | Kan sette eiere på enhver org. Bevisst avgrenset til akkurat medlemskap/rolle denne runden, ikke generell tilgang til andres data. |
|
| Superadmin (manuelt DB-tildelt, ikke selvbetjent) | ✅ LIVE 2026-07-19 | `POST /superadmin/orgs/{id}/memberships`. Verifisert: ikke-superadmin avvist (403), superadmin kan sette eierskap på en org de selv ikke er medlem av, ukjent e-post avvist (404). |
|
||||||
| Fjernet eiers roster-/spillerdata | ✅ avgjort (Beslutning E) | Forblir urørt — organisasjons-styring ≠ deltakelse-historikk. Bekreftet av bruker 2026-07-19. |
|
| Fjernet eiers roster-/spillerdata | ✅ avgjort (Beslutning E) | Forblir urørt — organisasjons-styring ≠ deltakelse-historikk. Bekreftet av bruker 2026-07-18. |
|
||||||
|
| Frontend: medlemsstyring/invitasjon | ✅ LIVE 2026-07-19 | `org-members.tsx`, `/orgs/[id]/members`, lenket fra dashbordet. |
|
||||||
|
|
||||||
|
**ADR-022 er dermed helt ferdig.** Ingen dedikert superadmin-UI bygget
|
||||||
|
(bevisst — brukes via API av en betrodd operatør, matcher «sjelden,
|
||||||
|
manuelt tildelt makt»-designet).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue