The signup/cancel endpoints were passing the Keycloak sub claim (external UUID) directly as MemberId, but ShiftSignup.MemberId references the internal Member.Id. Now ShiftService resolves ExternalUserId to the internal Member.Id before creating the signup record. Integration tests updated to seed proper Member entities.