> ## Documentation Index
> Fetch the complete documentation index at: https://docs.mirurobotics.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Overview

export const Framed = ({image, background, link, alt = "Framed content", borderWidth = "24px", outerRadius = "10px", innerRadius = "6px"}) => {
  const parseShorthand = value => {
    const values = String(value).trim().split(/\s+/);
    switch (values.length) {
      case 1:
        return [values[0], values[0], values[0], values[0]];
      case 2:
        return [values[0], values[1], values[0], values[1]];
      case 3:
        return [values[0], values[1], values[2], values[1]];
      default:
        return values.slice(0, 4);
    }
  };
  const isZero = v => parseFloat(v) === 0;
  const padding = parseShorthand(borderWidth);
  const outer = parseShorthand(outerRadius);
  const cornerMasks = [];
  if (isZero(padding[0]) && isZero(padding[3])) {
    cornerMasks.push(`radial-gradient(circle at 0% 0%, transparent ${outer[0]}, black ${outer[0]})`);
  }
  if (isZero(padding[0]) && isZero(padding[1])) {
    cornerMasks.push(`radial-gradient(circle at 100% 0%, transparent ${outer[1]}, black ${outer[1]})`);
  }
  if (isZero(padding[2]) && isZero(padding[1])) {
    cornerMasks.push(`radial-gradient(circle at 100% 100%, transparent ${outer[2]}, black ${outer[2]})`);
  }
  if (isZero(padding[2]) && isZero(padding[3])) {
    cornerMasks.push(`radial-gradient(circle at 0% 100%, transparent ${outer[3]}, black ${outer[3]})`);
  }
  const backgroundMask = cornerMasks.length > 0 ? cornerMasks.join(", ") : undefined;
  const innerImage = <img src={image} alt={alt} noZoom={link ? true : false} style={{
    display: "block",
    width: "100%",
    margin: 0,
    borderRadius: 0
  }} />;
  return <div style={{
    display: "inline-block",
    position: "relative",
    borderRadius: outerRadius,
    overflow: "hidden"
  }}>
            {}
            {background && <div style={{
    position: "absolute",
    inset: 0,
    backgroundImage: `url(${background})`,
    backgroundSize: "cover",
    maskImage: backgroundMask,
    WebkitMaskImage: backgroundMask,
    maskComposite: "intersect",
    WebkitMaskComposite: "source-in"
  }} />}
            {}
            <div style={{
    position: "relative",
    padding: borderWidth
  }}>
                <div style={{
    borderRadius: innerRadius,
    overflow: "hidden",
    lineHeight: 0
  }}>
                    {link ? <a href={link}>{innerImage}</a> : innerImage}
                </div>
            </div>
        </div>;
};

export const ImmutableBadge = ({size = "sm"}) => {
  return <Tooltip tip="Property cannot be modified">
            <Badge icon="lock" color="gray" size={size}>immutable</Badge>
        </Tooltip>;
};

export const MutableBadge = ({size = "sm"}) => {
  return <Tooltip tip="Property is automatically updated by the system; cannot be modified directly">
            <Badge icon="feather" color="orange" size={size}>mutable</Badge>
        </Tooltip>;
};

<Framed background="https://assets.mirurobotics.com/docs/v04/images/users/background.jpeg" image="https://assets.mirurobotics.com/docs/v04/images/users/members/header:page.png" borderWidth={"24px 0 0 40px"} innerRadius={"8px 0 0 0"} />

A **user** is a person with a Miru account who can (or previously could) log in to a workspace and access its resources.

Users are identified by their email address and can only belong to one workspace. You cannot log in to multiple workspaces with the same email address.

## Properties

<ParamField path="first_name" type="string">
  <MutableBadge />

  The first name of the user. Must contain between 1 and 48 characters.

  Examples: `John`, `Jane`
</ParamField>

<ParamField path="last_name" type="string">
  <MutableBadge />

  The last name of the user. Must contain between 1 and 48 characters.

  Examples: `Doe`, `Smith`
</ParamField>

<ParamField path="email" type="string">
  <ImmutableBadge />

  The email address of the user.

  Examples: `john.doe@example.com`, `jane.smith@example.com`
</ParamField>

<ParamField path="role" type="enum">
  <MutableBadge />

  The user's [access role](/admin/users/access-control) in the workspace.

  Allowed values:

  * `member`
  * `admin`
  * `owner`
</ParamField>

<ParamField path="status" type="enum">
  <MutableBadge />

  The user's [status](/admin/users/overview#status).

  Allowed values:

  * `active`
  * `suspended`
  * `left`
</ParamField>

<ParamField path="avatar" type="image">
  <MutableBadge />

  The avatar of the user.
</ParamField>

## Status

To maintain an accurate audit trail of user activity, users cannot be deleted from a workspace. However, users can be suspended by an admin or leave the workspace themselves.

As such, there are three possible statuses for a user:

| Status      | Description                                    |
| ----------- | ---------------------------------------------- |
| `active`    | User can log in and access workspace resources |
| `suspended` | User's access was revoked by an admin          |
| `left`      | User has left the workspace                    |

Only `active` users can log in and access workspace resources. `suspended` and `left` users exist solely for auditing purposes—they cannot log in to the workspace or access any resources.

Users who have been suspended or left can be reinvited to the workspace at any time by an admin via [invites](/admin/users/invites#send-an-invite).
