# 2026-04-18 — Document delete permissions + three-dots menu fix **Timestamp:** 2026-04-18T00:00:00Z ## Summary Added a proper permission model for document deletion: owners and admins can always delete; group members can delete only when the share was explicitly granted `can_delete=true`. Fixed silent delete failures (watch docs returning 404 with no user feedback) and fixed the three-dots context menu being clipped by `overflow-hidden` on the table container. ## Files Added / Modified / Deleted ### Added - `features/doc-service/alembic/versions/0005_add_share_can_delete.py` — migration: adds `can_delete BOOLEAN NOT NULL DEFAULT false` to `document_shares` ### Modified - `features/doc-service/app/models/document_share.py` — added `can_delete: Mapped[bool]` column - `features/doc-service/app/schemas/share.py` — added `can_delete` to `DocumentShareOut` and `DocumentShareCreate`; added `viewer_can_delete` to `SharedDocumentOut` - `features/doc-service/app/schemas/document.py` — added `viewer_can_delete: bool = False` to `DocumentOut` - `features/doc-service/app/deps.py` — added `get_user_is_admin()` dep reading `x-user-is-admin` header - `features/doc-service/app/routers/documents.py` — added `_get_deletable_doc_ids()` helper; updated list/get/delete endpoints with permission logic; updated `add_share` to store `can_delete`; updated shared-with-me to include `viewer_can_delete` - `backend/app/routers/documents_proxy.py` — `_forward_headers()` now injects `x-user-is-admin` header - `frontend/src/api/client.ts` — `DocumentOut`: added `viewer_can_delete`; `DocumentShareOut`: added `can_delete`; `addDocumentShare`: accepts `canDelete` param - `frontend/src/pages/DocumentsPage.tsx` — `RowActionsMenu`: replaced absolute dropdown with `createPortal` to fix clipping; delete button now uses `doc.viewer_can_delete`; added `onError` handler for silent failures - `frontend/src/components/DocumentSlideOver.tsx` — sharing section: shows trash icon badge on shares with `can_delete=true`; added "Allow group members to delete" checkbox before group picker; delete button uses `doc.viewer_can_delete` - `features/doc-service/CLAUDE.md` — updated `document_shares` table docs + migration chain - `backend/CLAUDE.md` — noted `x-user-is-admin` header injection