Uebergabe der Dev-Interim-Screens aus HiveGrid-Cloud an den Wireframes-Vault. INDEX + 7 Domaenen-Seiten (CRM, Leads, HR, Files/Tasks, Audit/Notifications, Integrations, Auth/RBAC) mit je Screen: D-*-Ziel, Archetyp, Route, VM, benoetigte ~/ui-Elemente, Actions, States. Layout bleibt Davids freie Hand. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
54 lines
6.3 KiB
Markdown
54 lines
6.3 KiB
Markdown
# P02 · Auth & RBAC (R-P2a/b → D-P2)
|
||
|
||
> ℹ️ David-Delta liegt vor (`Tickets/Fertige Tickets/D-P2 Auth Wireframes.md`) — diese Seite dient dem
|
||
> Konsistenz-Abgleich, **kein neuer Design-Request**. Interim-UI-Referenz (AD-28), `~/ui`-komponiert, VM als Prop.
|
||
|
||
## Auth
|
||
|
||
### CreateWorkspacePage · D-P2 „Create-workspace (ohne Tenant)" · A3 Formular/Auth-Shell (kein A-Code im Header, inferiert)
|
||
- **Interim-Screen:** `apps/web/app/components/screens/auth/CreateWorkspacePage.tsx`
|
||
- **Route(n):** `/new-account` (`routes/new-account.tsx`) — nicht unter `app.$tenant/` (Pre-Tenant-Screen)
|
||
- **Daten (VM):** keine VM — reine Props `{ csrf, error?, backHref }` (route-injiziert; server-driven `/new-account`-Action erstellt den Tenant)
|
||
- **Benötigte UI-Elemente (KEIN Layout):** `~/ui`: Alert, Button, LinkButton, TextInput · Shell: `~/components/auth/AuthShell` (nicht `~/ui`) · Icons: FeatherArrowLeft
|
||
- **Interaktionen (Actions):** keine `…Actions` — natives `<form method="post">` postet `name` + `csrf` (+ vestigiales `action=create`); Back-Link → `backHref`
|
||
- **States:** Error-Alert (nur idle-gated, `error`-Prop) · kein Empty/Loading · Permission-Denied n/a (Login-gated im Loader)
|
||
- **Davids Delta:** ✅ vorhanden (D-P2) — nur Abgleich
|
||
|
||
## Users / RBAC
|
||
|
||
### MembersPage · D-P2 „WF-P2 Admin RBAC" S01 Mitarbeiterliste (+ D01/M03/V01) · A1 Liste/Tabelle (kein A-Code im Header, inferiert)
|
||
- **Interim-Screen:** `apps/web/app/components/screens/users/MembersPage.tsx`
|
||
- **Route(n):** `/app/:tenant/settings/members` (`routes/app.$tenant/settings/members.tsx`)
|
||
- **Daten (VM):** `MembersListVM` — `packages/view-models/src/users/members-list.vm.ts` (+ Helfer `filterMembersRows`, `EMPTY_MEMBERS_FILTER`, Typen `MembersListRow`/`MembersListFilterState`/`MemberStatus`)
|
||
- **Benötigte UI-Elemente (KEIN Layout):** `~/ui`: Avatar, BadgeFeedback, Button, Checkbox, Dialog, DropdownMenu, EmptyState, IconButton, SearchInput, Select, Table, Tabs · Icons: FeatherChevronDown, FeatherMoreHorizontal, FeatherPlus, FeatherTrash, FeatherUserCheck, FeatherUserX (+ `SubframeCore.DropdownMenu`)
|
||
- **Interaktionen (Actions):** `MembersActions` — onToggleRole({userId, roleId, add}), onDeactivate({userId}), onReactivate({userId}), onDeleteInvitation({invitationId}), onInvite()
|
||
- **States:** Empty (`EmptyState`, `emptyHeadlineKey`/`emptyBodyKey` wenn keine Rows/Invites) · No-matches (`EmptyState`, `noMatchesKey`) · Loading (`vm.status !== "ready"` → leeres Gerüst) · M03 Deaktivieren-Confirm-Dialog · V01 Last-Admin-Blocker-Dialog · Permission-Denied → 404 im Loader (`verifyUserHasPermission`)
|
||
- **Davids Delta:** ✅ vorhanden (D-P2) — nur Abgleich
|
||
|
||
### RolesPage · D-P2 „WF-P2 Admin RBAC" S02 Rollen & Berechtigungen (+ M04A/M04B/M02/D03) · A1 Liste/Tabelle + Editor-Dialog (kein A-Code im Header, inferiert)
|
||
- **Interim-Screen:** `apps/web/app/components/screens/users/RolesPage.tsx`
|
||
- **Route(n):** `/app/:tenant/settings/roles-and-permissions/roles` (`routes/app.$tenant/settings/roles-and-permissions/roles.tsx`)
|
||
- **Daten (VM):** `RolesListVM` — `packages/view-models/src/users/roles-list.vm.ts` (+ Editor-VM `buildRoleEditorVM`/`filterRoleEditorSections`/`togglePermission` + Typ `RoleEditorInputPermission` aus `packages/view-models/src/users/role-editor.vm.ts`; Helfer `filterRolesRows`, `EMPTY_ROLES_FILTER`, Typen `RolesListRow`/`RolesListFilterState`/`RoleTypeKey`)
|
||
- **Benötigte UI-Elemente (KEIN Layout):** `~/ui`: Alert, Button, Dialog, DropdownMenu, EmptyState, IconButton, SearchInput, Select, Switch, Table, Tabs, TextArea, TextInput · Icons: FeatherCopy, FeatherEdit2, FeatherMoreHorizontal, FeatherPlus, FeatherTrash (+ `SubframeCore.DropdownMenu`)
|
||
- **Interaktionen (Actions):** `RolesActions` — onCreate({name, description, permissionNames}), onUpdate(roleId, {name, description, permissionNames}), onDelete(roleId)
|
||
- **States:** Empty (`EmptyState`, `emptyHeadlineKey`/`emptyBodyKey` wenn keine Rollen) · No-matches (`EmptyState variant="no-results"`, `noMatchesKey`) · Loading (`vm.status !== "ready"` → leeres Gerüst) · M02-Editor No-matches (`EmptyState`) · D03 Delete-Blocker (`deleteBlockedInUse`) · Permission-Denied → 404 im Loader (`requireWorkspaceRolesBuilderAccess`)
|
||
- **Davids Delta:** ✅ vorhanden (D-P2) — nur Abgleich
|
||
|
||
### InviteMemberForm · D-P2 „WF-P2 Admin RBAC" M01 „Mitarbeiter einladen" · A4 Dialog-Formular (kein A-Code im Header, inferiert)
|
||
- **Interim-Screen:** `apps/web/app/components/screens/users/InviteMemberForm.tsx`
|
||
- **Route(n):** n/a — Sub-Komponente von `MembersSettingsRoute` (rendert im Outlet-Dialog; postet an `routes/app.$tenant/settings/members/new.tsx`)
|
||
- **Daten (VM):** keine VM — nutzt `NewMemberActionData` aus `~/routes/app.$tenant/settings/members/new` (via `useActionData`) + `useRootData` (csrf)
|
||
- **Benötigte UI-Elemente (KEIN Layout):** `~/ui`: Button, Checkbox, TextInput · Icons: keine
|
||
- **Interaktionen (Actions):** keine `…Actions` — `<Form method="post">` an `members/new` (Felder `email`, `first-name`, `last-name`, `send-invitation-email`, `csrf`); Prop-Callback `onClose()`
|
||
- **States:** Error-Toast (`actionData.error`) · Loading (`navigation.state === "submitting"` → Submit-Button loading) · kein Empty · Permission-Denied via Parent-Route
|
||
- **Davids Delta:** ✅ vorhanden (D-P2) — nur Abgleich
|
||
|
||
### GroupMembersDialog · D-P2 „WF-P2 Admin RBAC" Gruppen-Bulk (RBAC V2, offener design-nachzug) · A4 Dialog (kein A-Code im Header, inferiert)
|
||
- **Interim-Screen:** `apps/web/app/components/screens/users/GroupMembersDialog.tsx`
|
||
- **Route(n):** n/a — Sub-Komponente von `GroupsRoute` (`routes/app.$tenant/settings/groups.tsx`, URL `/app/:tenant/settings/groups`; postet Bulk an `settings/groups/:id`)
|
||
- **Daten (VM):** `GroupsDetailVM` — `packages/view-models/src/users/groups-detail.vm.ts` (+ Helfer `filterGroupMemberRows`, Typ `GroupMemberRow`)
|
||
- **Benötigte UI-Elemente (KEIN Layout):** `~/ui`: Avatar, Button, Checkbox, Dialog, EmptyState, SearchInput · Icons: keine
|
||
- **Interaktionen (Actions):** `GroupMembersActions` — onAdd(userIds: string[]), onRemove(userIds: string[]); Prop-Callback `onClose()`
|
||
- **States:** Loading (`vm.status !== "ready"` → `null`) · Empty pro Pick-Liste (`EmptyState variant="no-results"`, `emptyMembersKey`/`emptyCandidatesKey`) · Permission-Gate: Add/Remove-Buttons nur bei `data.canManage`
|
||
- **Davids Delta:** ✅ vorhanden (D-P2) — nur Abgleich
|