Skip to content

Slice 3 (Module 02): Per-doctor sharing management (grant / revoke / state) #11

Description

@mGasiorek998

What to build

Give patients fine-grained control over which doctors can access each document. This slice adds three endpoints — sharing state, grant, revoke — and wires them into a sharing panel on the /patient/documents page.

  • getSharingState use case: returns all doctors in the system, each with a hasAccess boolean for the given document.
  • grantAccess use case: upserts into document_shares (ON CONFLICT DO NOTHING — idempotent).
  • revokeAccess use case: deletes from document_shares where matching pair exists (no error if absent — idempotent).
  • GET /documents/:id/shares → 200 + Array<{ doctorId, displayName, hasAccess }> behind requireAuth() + requireRole(['patient']).
  • PUT /documents/:id/shares/:doctorId → 200 (grant) behind requireAuth() + requireRole(['patient']).
  • DELETE /documents/:id/shares/:doctorId → 200 (revoke) behind requireAuth() + requireRole(['patient']).
  • Fill in these three endpoints in packages/contracts/src/documents.ts.
  • Sharing panel on /patient/documents: per-document expandable list of all doctors with a toggle (grant/revoke). Ownership boundary enforced (patient can only manage their own documents).

Acceptance criteria

  • GET /documents/:id/shares returns all doctors with correct hasAccess flags; returns 404 for unknown document; returns 403 for documents not owned by the calling patient.
  • PUT /documents/:id/shares/:doctorId creates a document_shares row and returns 200; calling it again for the same pair returns 200 with exactly one row (no duplicate).
  • DELETE /documents/:id/shares/:doctorId removes the document_shares row and returns 200; calling it when no share exists also returns 200 (idempotent).
  • Both grant and revoke return 404 { error: "DOCTOR_NOT_FOUND", ... } when doctorId does not correspond to a user with the doctor role.
  • Both grant and revoke return 403 when the calling patient does not own the document.
  • All three endpoints return 401 without a valid JWT and 403 with a doctor JWT.
  • The sharing panel in the UI reflects live state and updates immediately after toggling a doctor.
  • pnpm verify exits 0.

User stories covered

Blocked by

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    afkEligible for the main agent looppriority:2Priority 2qa-readyPR opened, awaiting human QAsliceVertical tracer-bullet slice

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions