Gate access at the project level, not just the workspace — the mirror-faithful model the PM core has been deferring (// TODO(6.4): gate by project role). A project gets an access level (Jira team-managed: open / limited / private) and an explicit project membership with a per-project role (admin / member / viewer); Story 1.2's flat workspace-membership role string is formalized into the same role set. Browse access is then computed: open → any workspace member (view + edit); limited → any workspace member (view + comment, no edit); private → only project members (workspace owner/admin always). This is enforced at the service layer and gated in the UI.
Verified mirror (rung 1, mistake #33 — checked, not asserted). Jira gates by project: a team-managed project’s Access level (open/limited/private) decides whether site members see it, and a private project requires explicit per-project role assignment; company-managed restrict the "Browse Projects" permission to project roles. So project access = per-project membership/role. We mirror the team-managed three-level model.
Migration-aware (no lockout). Existing WorkspaceMembership.role values map to the new role set (owner→owner/admin, the rest→member); existing projects default to open so every current workspace member keeps access on deploy (a private default would lock everyone out). Project membership is created lazily / on access-level change — making a project private seeds its current viewers as members (the Jira "set private → add the people who had access" shape), never an empty private project the owner is locked out of.
Scope: the role + project-membership + access-level model; the service-layer browse/edit gate threaded into the existing project / board / issue reads (the retrofit of the deferred seams); the project Members + Access admin UI; UI gating (inaccessible projects hidden from the switcher + a no-access state on direct nav; assignable users scoped to project members, the Jira behaviour); the seed update; tests.
Out of scope (Epic-6 siblings / later): field-level / workflow-level permission schemes (Jira’s full permission-scheme matrix — we ship the browse/edit gate + project roles, not the dozen-permission grid); global/site admin roles beyond workspace owner/admin; per-issue security levels; the unified project-admin area (Story 6.5 folds Members/Access in alongside workflow 2.2.5 + board-column 3.6).
pnpm install, pnpm prisma migrate dev, pnpm db:seed, pnpm dev.pnpm test — vitest covers: the browse gate per access level (open/limited/private), project-role assignment, the workspace-role migration mapping + the open project default, and assignable-users scoping to project members.zhuyue@motir.co) set the motir project to Private; sign in as a workspace member who is NOT a project member → the project is absent from the switcher and a direct /boards / /issues link shows the no-access state; add them as a project member → it appears and opens.pnpm test:e2e --grep project-access drives the real stack: a non-member is denied a private project; a member/viewer/admin get the right capabilities.