---
id: w4/m12/t005
title: Acceptance — role matrix enforced end-to-end for an invited member
worker: worker4
status: done
estimate: 25m
depends_on: [w4/m12/t002, w4/m12/t004]
---

## Objective

Prove the loop on the mock cluster with enforced OpenFGA: admin invites `viewer@example.com` → mail in Mailpit → signup → the viewer lists services but gets 403 on suspend; admin upgrades the role to developer → suspend succeeds without re-login (within the documented authz-cache TTL); admin removes the member → next request 403s.

## Context

- Needs the full stack: w1/m9 enforcement on, m7 Mailpit, the m12 surfaces. Script what's scriptable (curl + Mailpit API + GraphQL), browser-check the Team page states.
- The role matrix cases to spot-check are the matrix rows docs/ADR012-auth.md declares for viewer vs developer vs admin.

## Steps

1. Scripted path: invite → Mailpit fetch → signup → role-gated verb matrix assertions (viewer/developer).
2. Role change + removal propagation checks with cache TTL accounted for.
3. Browser pass over the Team page for the same lifecycle.

## Files

- `scripts/` (extension of the auth e2e family)

## Acceptance criteria

- [ ] Script exits 0 covering invite→enforce→upgrade→remove; browser states match.

## Out of scope

- Load testing; multi-workspace membership (one workspace per tenant until further w1 work).
