Skip to content

feat: replace scattered permission flags with document-level RBAC #61

Description

@Alimedhat000

Problem

Authorization today is ad-hoc booleans and stringly-typed flags duplicated across every layer:

  • Server: controllers re-implement isOwner / isCollaborator / 'view'|'edit' checks per endpoint (~6 sites in server/src/controllers/document.controller.ts alone), each with its own status-code choice (403 vs 401) and log action
  • Client: access.isOwner, access.isCollaborator, permission are threaded as parallel booleans through prop chains (document.tsxDocumentHeaderDocumentToolbar → dropdowns)
  • WS (CRITICAL: Realtime sync ignores permissions (WS has no onAuthenticate) #24): Hocuspocus onAuthenticate will need the same role resolution again for read-only enforcement

Every new endpoint re-invents the rules — drift risk is exactly how #43 happened.

Proposal

  • Single server guard, e.g. requireDocumentAccess('owner' | 'editor' | 'viewer'), mounted on document routes; one shared resolver for "effective role of user X on doc Y"
  • Decide schema direction: role enum on Collaborator rows vs keeping ownership implicit in Document.authorId
  • Client consumes a single derived role from the /document/:id access payload instead of parallel booleans; UI gates map from role
  • Reuse the same resolver/guard in onAuthenticate for CRITICAL: Realtime sync ignores permissions (WS has no onAuthenticate) #24 readOnly enforcement

Acceptance criteria

  • One source of truth module for document permission resolution
  • Every document route (+ WS auth path) goes through it
  • Role × action matrix tests (owner/editor/viewer/stranger × list/read/update/delete/manage/share)
  • Consistent status codes (403 for denied authorization)

Related

#43, #24, #45

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions