Skip to content

moooon

Motir

Vibe your whole project. Bring an idea — Motir's three AI layers plan it, track it, and ship it, end to end. You're looking at Motir, built in Motir.

  • Vibe Project
  • Open Source
  • AI Agent
  • AI Loop
1
requests
0
upvotes
145
planned
1,361
shipped

Motir · Work items

MOTIR-353Done

6.4.4 Project members + access API — manage memberships, roles, access level (project-admin-gated)

Estimate: 24m · Depends on: 6.4.2

The write path for project membership + access, 4-layer (Route → Service → Repository → Prisma) with the explicit workspace gate (finding #26) + a project-admin check. projectMembersService: addMember(projectId, userId, role) (the user must be a workspace member), removeMember, setRole, and setAccessLevel(projectId, level). Setting a project private seeds its currently-eligible viewers as member rows (so the owner + current users aren’t locked out — the Jira "go private → keep current people" shape). All gated to project admin (or workspace owner/admin). Routes: …/projects/[key]/members (GET/POST/PATCH/DELETE) + PATCH …/projects/[key]/access; HTTP-only, typed-error→status.

Acceptance criteria

  • projectMembersService add/remove/setRole + setAccessLevel exist, own their transaction, validate (add target must be a workspace member; last-admin guard on remove/role-change), return DTOs; setting private seeds current viewers as members.
  • Routes are HTTP-only (one service call, typed-error→status: 400 invalid, 403 not project admin, 404 missing); project-admin (or workspace owner/admin) gated.
  • Vitest (real Postgres) covers add/remove/setRole, the go-private seeding, the last-admin guard, and a non-admin denial.

Context refs

  • lib/services/workspacesService.ts addMember/removeMember/listMembers (Story 1.2) — the membership service precedent to mirror at project scope; the last-member guard pattern
  • Story 6.4.2 (ProjectMembership + accessLevel); motir-core/CLAUDE.md (4-layer)