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

# WorkspaceGroupMembership

> WorkspaceGroupMembership represents a single person's membership within a workspace group, capturing the lifecycle from invitation through acceptance or revocat

WorkspaceGroupMembership represents a single person's membership within a workspace group, capturing the lifecycle from invitation through acceptance or revocation. It associates a People record with a WorkspaceGroup, carries the assigned role, invitation token, and status, and is soft-deleted on revocation so the audit trail is preserved. A partial unique index on (person\_pk, workspace\_group\_pk) WHERE deleted\_at IS NULL enforces the idempotent-invite guard at the schema level: at most one live membership per person-group pair, while allowing revoke-then-re-invite semantics.

| Naming                          | Value                             |
| ------------------------------- | --------------------------------- |
| Object                          | WorkspaceGroupMembership          |
| Resource type (JSON:API `type`) | `people`                          |
| Collection / records root       | — <sub>(not a records root)</sub> |
| REST base                       | `/v1/workspace-group-memberships` |
| Entity class                    | `WorkspaceGroupMembership`        |

<Note>
  **Internal object.** Not currently exposed on the public REST API. The operations below describe the intended contract.
</Note>

## API operations

| Operation | Method & path                                 | Status     |
| --------- | --------------------------------------------- | ---------- |
| List      | `GET /v1/workspace-group-memberships`         | 🟡 Planned |
| Retrieve  | `GET /v1/workspace-group-memberships/{id}`    | 🟡 Planned |
| Create    | `POST /v1/workspace-group-memberships`        | 🟡 Planned |
| Update    | `PATCH /v1/workspace-group-memberships/{id}`  | 🟡 Planned |
| Delete    | `DELETE /v1/workspace-group-memberships/{id}` | 🟡 Planned |

## Data model

### Attributes

| Field                            | Type                         | Required | Constraints                                              | Allowed values                    | Description                                                                                                                                                                                                             |
| -------------------------------- | ---------------------------- | -------- | -------------------------------------------------------- | --------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| workspace\_group\_membership\_id | string (UUID)                | ✅ Yes    | unique; generated by gen\_random\_uuid() at row creation | any valid UUID v4                 | Public stable identifier for the membership. Exposed as the JSON:API resource id. Never changes after creation.                                                                                                         |
| membership\_role                 | string (enum)                | ✅ Yes    | NOT NULL; DB default 'member'                            | owner \| admin \| member \| guest | The role assigned to the person within the group. Set at invitation time. Changeable via PATCH /v1/workspace-groups/memberships/:membership\_id by an owner or admin.                                                   |
| status                           | string (enum)                | ✅ Yes    | NOT NULL; DB default 'pending'                           | pending \| active                 | Lifecycle state of the membership. Starts as 'pending' on invitation; flips to 'active' when the invitee accepts via POST .../accept.                                                                                   |
| invite\_token                    | string (UUID) \| null        | ⚪ No     | unique; nullable                                         | any valid UUID v4, or null        | One-time cryptographic token sent to the invitee. Cleared (set to null) or consumed when the invitation is accepted. The accept endpoint validates this token; the membership\_id alone is not sufficient proof.        |
| is\_default                      | boolean                      | ✅ Yes    | NOT NULL; DB default false                               | true \| false                     | Marks whether this membership is the person's default group membership for the workspace. Used to determine the group selected by default in UI contexts. DB-defaulted to false.                                        |
| created\_at                      | 🔒 system — datetime         | ✅ Yes    | NOT NULL                                                 | ISO 8601 datetime                 | Timestamp of row creation. Set once by the onCreate MikroORM hook; never updated.                                                                                                                                       |
| updated\_at                      | 🔒 system — datetime \| null | ⚪ No     | nullable                                                 | ISO 8601 datetime, or null        | Timestamp of the most recent mutation. Set by onCreate and refreshed by onUpdate hooks.                                                                                                                                 |
| deleted\_at                      | 🔒 system — datetime \| null | ⚪ No     | nullable                                                 | ISO 8601 datetime, or null        | Soft-delete timestamp. Set when a membership is revoked. A non-null value excludes the row from active queries and from the partial unique index on (person\_pk, workspace\_group\_pk), allowing revoke-then-re-invite. |

### Relationships

| Name             | Type                         | Required          | Description                                                                                                                                                   |
| ---------------- | ---------------------------- | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| person           | to-one (ManyToOne)           | Yes — NOT NULL FK | The People record being granted membership in the group. FK: workspace\_group\_memberships.person\_pk → peoples.pk (ON DELETE RESTRICT by default).           |
| workspace\_group | to-one (ManyToOne)           | Yes — NOT NULL FK | The WorkspaceGroup this membership belongs to. FK: workspace\_group\_memberships.workspace\_group\_pk → workspace\_groups.pk (ON DELETE RESTRICT by default). |
| invited\_by      | to-one (ManyToOne, nullable) | No — nullable FK  | The People record of the actor who issued the invitation. Nullable; SET NULL on delete of the inviter. Null for system-created memberships.                   |

### System-computed

* workspace\_group\_membership\_id — generated by gen\_random\_uuid() at INSERT; unique constraint enforced at the DB level
* created\_at — set once by MikroORM onCreate hook (new Date()); never overwritten
* updated\_at — set by onCreate hook and refreshed on every UPDATE by onUpdate hook
* deleted\_at — set to current timestamp by the revocation path (WorkspaceGroupService.revokeMembership); NULL for live rows
* Partial unique index workspace\_group\_memberships\_person\_group\_active\_unique on (person\_pk, workspace\_group\_pk) WHERE deleted\_at IS NULL — enforced at the schema level; the service's idempotent-invite guard relies on this index to prevent duplicate pending/active memberships
* invite\_token — generated as a UUID by the service's invite flow (WorkspaceGroupService.inviteToGroup); consumed/cleared on accept; the token is the cryptographic proof validated by the accept endpoint rather than the membership\_id alone
* status transitions — 'pending' on creation (DB default); 'active' set by the service on a successful acceptInvite call; no direct user-patch path for status

## Example

```json theme={null}
{
  "data": {
    "type": "workspace-group-membership",
    "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "attributes": {
      "membership_role": "member",
      "status": "active",
      "invite_token": null,
      "is_default": false,
      "created_at": "2026-05-29T10:15:00.000Z",
      "updated_at": "2026-05-30T08:22:00.000Z"
    },
    "relationships": {
      "person": {
        "data": { "type": "people", "id": "b2c3d4e5-f6a7-8901-bcde-f12345678901" }
      },
      "workspace_group": {
        "data": { "type": "workspace-group", "id": "c3d4e5f6-a7b8-9012-cdef-123456789012" }
      },
      "invited_by": {
        "data": { "type": "people", "id": "d4e5f6a7-b8c9-0123-defa-234567890123" }
      }
    }
  }
}
```

<sub>Source: `apps/api/src/database/entities/WorkspaceGroupMembership.ts` · domain: workspace · tier: Platform</sub>
