b15a43f3d3
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
4.8 KiB
4.8 KiB
quick_id, type, wave, autonomous
| quick_id | type | wave | autonomous |
|---|---|---|---|
| 260929-dzu | quick | 1 | true |
Quick 260929-dzu: Eigene Module für jeden Benutzer (persönlich)
User request (29.09.2026)
"Jeder User soll eigene Module anlegen können. nicht nur admins." Decision (AskUserQuestion, locked): "Nur er selbst" — a normal user's entries are visible ONLY to that user. Admins keep creating shared entries (visible to everyone) on /admin/custom-modules as today. No user can put anything into another user's sidebar.
Existing state (quick 260929-9wc, commits b9d87be, e7fc4de)
- Prisma
CustomModule { id, tenantId, name, url, category, createdAt, updatedAt }, migration20260929120000_custom_modulewith RLS (tenant only, pattern ProxmoxServer). - API
apps/api/src/custom-modules/*: GET list/one for any authenticated user; POST/PATCH/DELETE admin only; https-only, no credentials in URL. - Web: sidebar loads
listCustomModules(), frame page/modules/custom/[id], admin page/admin/custom-moduleswithCustomModuleFormModal+DeleteCustomModuleDialog,bumpSidebarRefreshafter changes.
Task 1: Model + API (tests first)
- Add nullable
ownerUserId String?(+ relation to User with onDelete: Cascade, index[tenantId, ownerUserId]) via NEW migration (e.g.20260929130000_custom_module_owner).null= shared (admin-made), set = personal. - RLS: extend the existing policy the way user-scoped tables already do it (find the pattern used by e.g.
DashboardImage / Favorite / other tables with a user dimension). Personal rows must only be readable/writable by
their owner; shared rows readable by the whole tenant. If the project's RLS pattern handles the user dimension
in the service layer instead, follow that pattern and document it. Update the RLS inventory test and
docs/mandantentrennung-zugriffsklassifikation.md(re-measure totals as last time). - Service/controller:
GET /custom-modules→ shared rows + rows owned by the caller. Response carriespersonal: boolean(orownerUserId === me).GET /custom-modules/:id→ 404 unless shared or owned by caller.POST /custom-modules→ any authenticated user; body flagshared?: boolean.shared: trueonly allowed for admins (403 otherwise); default personal (ownerUserId = caller). The admin page sendsshared: true.PATCH/DELETE→ personal rows: only the owner (404 for others, do not leak existence); shared rows: admin only (403 for non-admin). Ownership/shared-ness cannot be changed via PATCH.- Keep URL validation. Keep static routes before
:id. - Admin page list:
GET /custom-modules?scope=shared(admin) or filter client-side — pick the simplest; the admin page shows only shared entries; the settings page only the caller's personal ones.
- Tests: service + controller specs for all permission cases (user A cannot see/edit/delete user B's entry; non-admin cannot create/edit/delete shared; admin personal vs shared).
- verify:
pnpm --filter @tessera/api exec vitest run src/custom-modules+ RLS inventory test green; migrate local DB (db container IP 172.19.x, tessera/tessera_dev), rebuild api, curl check.
Task 2: Web — settings section
- Settings: new section/page "Eigene Module" in the user settings (
apps/web/src/app/(portal)/settings/, follow howgeneral/dashboardsub-pages and their nav are built). ReuseCustomModuleFormModalandDeleteCustomModuleDialog(move to a shared location if needed, e.g.components/custom-modules/) — one form, two callers. Intro text (Sie-Form): e.g. "Nehmen Sie Webseiten, die Sie oft brauchen, als eigene Einträge in Ihre Seitenleiste auf. Diese Einträge sehen nur Sie." - Admin page: shows only shared entries; intro text states they are visible for all users.
- Sidebar: unchanged behavior, shows shared + own personal entries (API already filters).
bumpSidebarRefreshafter changes on the settings page too. - de + en texts; umlaut dictionary if needed.
- Tests: component tests for the settings page (create/edit/delete, list only personal), admin page still passes
shared: true. - verify:
pnpm --filter @tessera/web exec vitest rungreen;pnpm turbo run type-check lintgreen; biome web ≤ 55, api ≤ 82.
Task 3: CHANGELOG + rebuild
- CHANGELOG
## Unveröffentlicht→ adjust the existing "Eigene Module" bullet under "Neu" (not released yet, so rewrite it): every user can add own entries under "Einstellungen → Eigene Module", visible only to them; administrators can additionally add entries for everyone under "Verwaltung → Eigene Module". Plain German, Sie-Form. - Update
docs/anleitung-anwender.md(and admin guide if it mentions custom modules) accordingly. docker compose up -d --build web api.- Commits per task, end with
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>. NEVER git push. - Browser check is done by the orchestrator (normal user + admin, dark mode).