---
title: "People Directory"
description: "The People Directory module provides a robust API for managing members within an organization. It allows for the creation, retrieval, updating, and deletion of individual members, as well as bulk c..."
last_updated: "2026-05-06T07:29:41.620964+00:00"
canonical_url: "https://www.doc0.dev/docs/49c89830-117b-4def-8edc-b5bcc50766e0/technical/section-3/people-directory"
---

<details>
<summary>Relevant source files</summary>

The following files were used as context for generating this wiki page:

- [apps/api/src/people/people.service.ts](https://github.com/blade47/comp/blob/main/apps/api/src/people/people.service.ts)
- [apps/api/src/people/people.controller.ts](https://github.com/blade47/comp/blob/main/apps/api/src/people/people.controller.ts)
- [apps/api/src/people/utils/member-queries.ts](https://github.com/blade47/comp/blob/main/apps/api/src/people/utils/member-queries.ts)
- [apps/api/src/people/utils/member-validator.ts](https://github.com/blade47/comp/blob/main/apps/api/src/people/utils/member-validator.ts)
- [apps/api/src/people/dto/create-people.dto.ts](https://github.com/blade47/comp/blob/main/apps/api/src/people/dto/create-people.dto.ts)
- [apps/api/src/people/dto/bulk-create-people.dto.ts](https://github.com/blade47/comp/blob/main/apps/api/src/people/dto/bulk-create-people.dto.ts)
- [apps/api/src/people/people.module.ts](https://github.com/blade47/comp/blob/main/apps/api/src/people/people.module.ts)
</details>

The People Directory module provides a robust API for managing members within an organization. It allows for the creation, retrieval, updating, and deletion of individual members, as well as bulk creation operations. This module integrates user management with device management capabilities, enabling the association of members with devices and the ability to unlink or remove specific hosts.

Designed as a NestJS module, it follows a clear separation of concerns, with a controller handling API requests, a service encapsulating business logic, and dedicated utility classes for database queries and data validation. This structure ensures maintainability, scalability, and adherence to best practices for API development.

## Architecture Overview

The People Directory module is structured around the standard NestJS pattern of Controllers, Services, and Modules, augmented by specialized utility classes for database interactions and validation. This layered architecture ensures that business logic is decoupled from HTTP concerns and data access.

<Callout title="Key Components" variant="info">
- **`PeopleController`**: Handles incoming HTTP requests, routes them to the appropriate service methods, and formats responses.
- **`PeopleService`**: Contains the core business logic for member management, orchestrating interactions with validators, query helpers, and external services like `FleetService`.
- **`MemberValidator`**: Provides methods to validate the existence of organizations, users, and member relationships, ensuring data integrity before operations proceed.
- **`MemberQueries`**: Encapsulates all direct database interactions related to members, using Prisma ORM.
- **`FleetService`**: An external dependency used by `PeopleService` to manage devices (hosts) associated with members in FleetDM.
</Callout>

The following diagram illustrates the high-level request flow within the People Directory module:


Sources:
[apps/api/src/people/people.controller.ts](https://github.com/blade47/comp/blob/main/apps/api/src/people/people.controller.ts#L36-L40)
[apps/api/src/people/people.service.ts](https://github.com/blade47/comp/blob/main/apps/api/src/people/people.service.ts#L10-L15)
[apps/api/src/people/utils/member-validator.ts](https://github.com/blade47/comp/blob/main/apps/api/src/people/utils/member-validator.ts#L3-L4)
[apps/api/src/people/utils/member-queries.ts](https://github.com/blade47/comp/blob/main/apps/api/src/people/utils/member-queries.ts#L3-L4)

## API Endpoints

The `PeopleController` exposes a comprehensive set of RESTful API endpoints for managing organizational members. All endpoints are protected by `HybridAuthGuard` and require an `X-Organization-Id` header (or API key authentication).

<Accordions>
<Accordion title="Authentication and Authorization">
All endpoints are secured using `HybridAuthGuard`, which supports both session-based and API key authentication. The `X-Organization-Id` header is crucial for scoping operations to a specific organization. The `DELETE /:id/host/:hostId` endpoint further enforces role-based access control, requiring the authenticated user to have an 'owner' role.
Sources: [apps/api/src/people/people.controller.ts](https://github.com/blade47/comp/blob/main/apps/api/src/people/people.controller.ts#L36-L40), [apps/api/src/people/people.controller.ts](https://github.com/blade47/comp/blob/main/apps/api/src/people/people.controller.ts#L220)
</Accordion>
</Accordions>

| Method | Path                 | Description                                    | Request Body (DTO)         | Response DTO               | Required Roles |
| :----- | :------------------- | :--------------------------------------------- | :------------------------- | :------------------------- | :------------- |
| `GET`  | `/people`            | Retrieve all members in an organization        | N/A                        | `PeopleResponseDto[]`      | N/A            |
| `POST` | `/people`            | Create a new member                            | `CreatePeopleDto`          | `PeopleResponseDto`        | N/A            |
| `POST` | `/people/bulk`       | Bulk create multiple members                   | `BulkCreatePeopleDto`      | `{ created: [], errors: [], summary: {} }` | N/A            |
| `GET`  | `/people/:id`        | Retrieve a member by ID                        | N/A                        | `PeopleResponseDto`        | N/A            |
| `PATCH`| `/people/:id`        | Update an existing member                      | `UpdatePeopleDto`          | `PeopleResponseDto`        | N/A            |
| `DELETE`| `/people/:id/host/:hostId` | Remove a specific host from a member's devices | N/A                        | `{ success: true }`        | `owner`        |
| `DELETE`| `/people/:id`        | Delete a member                                | N/A                        | `{ success: true, deletedMember: {} }` | N/A            |
| `PATCH`| `/people/:id/unlink-device` | Unlink all devices from a member           | N/A                        | `PeopleResponseDto`        | N/A            |

Sources: [apps/api/src/people/people.controller.ts](https://github.com/blade47/comp/blob/main/apps/api/src/people/people.controller.ts#L43-L280)

## Core Services and Logic

### PeopleService

The `PeopleService` is the central component for all business logic related to member management. It orchestrates operations by calling `MemberValidator` for data integrity checks, `MemberQueries` for database interactions, and `FleetService` for device management.

Key methods include:

*   `findAllByOrganization(organizationId: string)`: Retrieves all active members for a given organization.
*   `findById(memberId: string, organizationId: string)`: Fetches a single member by their ID within an organization.
*   `create(organizationId: string, createData: CreatePeopleDto)`: Creates a new member after validating the organization, user, and ensuring the user is not already a member.
*   `bulkCreate(organizationId: string, bulkCreateData: BulkCreatePeopleDto)`: Handles the creation of multiple members, performing individual validations and then a bulk database insert for valid entries. It returns a summary of successful and failed creations.
*   `updateById(memberId: string, organizationId: string, updateData: UpdatePeopleDto)`: Updates an existing member's details. Includes validation for `userId` changes to prevent duplicate memberships.
*   `deleteById(memberId: string, organizationId: string)`: Deactivates or removes a member from an organization.
*   `unlinkDevice(memberId: string, organizationId: string)`: Disassociates all devices from a member. This involves removing hosts from FleetDM based on the member's `fleetDmLabelId` and deleting associated `Device` records from the local database.
*   `removeHostById(memberId: string, organizationId: string, hostId: number)`: Removes a specific host from a member's associated devices in FleetDM.

Sources: [apps/api/src/people/people.service.ts](https://github.com/blade47/comp/blob/main/apps/api/src/people/people.service.ts#L17-L255)

### MemberValidator

The `MemberValidator` class provides static methods to ensure the validity of entities and relationships before performing operations. This prevents common data integrity issues and provides clear error messages.

*   `validateOrganization(organizationId: string)`: Checks if an organization with the given ID exists. Throws `NotFoundException` if not found.
*   `validateUser(userId: string)`: Checks if a user with the given ID exists. Throws `NotFoundException` if not found.
*   `validateMemberExists(memberId: string, organizationId: string)`: Confirms that a member exists and is active within the specified organization. Throws `NotFoundException` if not found.
*   `validateUserNotMember(userId: string, organizationId: string, excludeMemberId?: string)`: Ensures that a user is not already an active member of the organization. An optional `excludeMemberId` allows this check to be used during updates where the member's own ID should be ignored. Throws `BadRequestException` if the user is already a member.

Sources: [apps/api/src/people/utils/member-validator.ts](https://github.com/blade47/comp/blob/main/apps/api/src/people/utils/member-validator.ts#L3-L59)

### MemberQueries

The `MemberQueries` class acts as a data access layer, abstracting direct Prisma ORM calls for member-related operations. It defines a standard `MEMBER_SELECT` object to ensure consistent data retrieval across different queries.

*   `MEMBER_SELECT`: A constant object defining the fields to be selected when querying member data, including nested user information.
*   `findAllByOrganization(organizationId: string)`: Retrieves all members for an organization, ordered by creation date.
*   `findByIdInOrganization(memberId: string, organizationId: string)`: Finds a specific member by ID within an organization.
*   `createMember(organizationId: string, createData: CreatePeopleDto)`: Inserts a new member record into the database.
*   `updateMember(memberId: string, updateData: UpdatePeopleDto)`: Updates an existing member record. Handles `fleetDmLabelId` specifically to allow setting it to `null`.
*   `findMemberForDeletion(memberId: string, organizationId: string)`: Retrieves minimal member and user information specifically for the deletion process.
*   `deleteMember(memberId: string)`: Deletes a member record from the database.
*   `unlinkDevice(memberId: string)`: Updates a member's record by setting `fleetDmLabelId` to `null`.
*   `bulkCreateMembers(organizationId: string, memberData: CreatePeopleDto[])`: Performs a `createMany` operation for multiple members, then fetches the newly created members for the response. `skipDuplicates` is used to prevent errors if a user is already a member.

Sources: [apps/api/src/people/utils/member-queries.ts](https://github.com/blade47/comp/blob/main/apps/api/src/people/utils/member-queries.ts#L7-L135)

## Data Transfer Objects (DTOs)

The module uses DTOs for defining the structure of data exchanged between the client and the API, ensuring strong typing and validation.


Sources:
[apps/api/src/people/dto/create-people.dto.ts](https://github.com/blade47/comp/blob/main/apps/api/src/people/dto/create-people.dto.ts#L7-L49)
[apps/api/src/people/dto/bulk-create-people.dto.ts](https://github.com/blade47/comp/blob/main/apps/api/src/people/dto/bulk-create-people.dto.ts#L7-L35)

### `CreatePeopleDto`

This DTO defines the data required to create a single new member.

```typescript
export class CreatePeopleDto {
  userId: string;
  role: string;
  department?: Departments;
  isActive?: boolean;
  fleetDmLabelId?: number;
  jobTitle?: string;
}
```
Sources: [apps/api/src/people/dto/create-people.dto.ts](https://github.com/blade47/comp/blob/main/apps/api/src/people/dto/create-people.dto.ts#L7-L49)

### `BulkCreatePeopleDto`

This DTO is used for the bulk creation endpoint and contains an array of `CreatePeopleDto` objects. It includes validation for array size.

```typescript
export class BulkCreatePeopleDto {
  @IsArray()
  @ArrayMinSize(1)
  @ArrayMaxSize(1000)
  @ValidateNested({ each: true })
  @Type(() => CreatePeopleDto)
  members: CreatePeopleDto[];
}
```
Sources: [apps/api/src/people/dto/bulk-create-people.dto.ts](https://github.com/blade47/comp/blob/main/apps/api/src/people/dto/bulk-create-people.dto.ts#L7-L35)

## Request Flows

### Create Member Flow

This sequence diagram illustrates the process of creating a new member through the API.

```mermaid
sequenceDiagram
    participant Client
    participant Controller as PeopleController
    participant Service as PeopleService
    participant Validator as MemberValidator
    participant Queries as MemberQueries
    participant DB as Database

    Client->>Controller: POST /people (CreatePeopleDto)
    Controller->>Service: create(orgId, createData)
    Service->>Validator: validateOrganization(orgId)
    Validator->>DB: Query Organization
    DB-->>Validator: Organization exists
    Validator-->>Service: Success
    Service->>Validator: validateUser(userId)
    Validator->>DB: Query User
    DB-->>Validator: User exists
    Validator-->>Service: Success
    Service->>Validator: validateUserNotMember(userId, orgId)
    Validator->>DB: Query Member by userId & orgId
    DB-->>Validator: No existing member
    Validator-->>Service: Success
    Service->>Queries: createMember(orgId, createData)
    Queries->>DB: Insert new Member record
    DB-->>Queries: New Member record
    Queries-->>Service: PeopleResponseDto
    Service-->>Controller: PeopleResponseDto
    Controller-->>Client: 201 Created (PeopleResponseDto)
```
Sources: [apps/api/src/people/people.controller.ts](https://github.com/blade47/comp/blob/main/apps/api/src/people/people.controller.ts#L90-L107), [apps/api/src/people/people.service.ts](https://github.com/blade47/comp/blob/main/apps/api/src/people/people.service.ts#L78-L106)

### Unlink Device Flow

This sequence diagram details the process of unlinking devices from a member, which involves interactions with both the local database and the external FleetDM system.

```mermaid
sequenceDiagram
    participant Client
    participant Controller as PeopleController
    participant Service as PeopleService
    participant Queries as MemberQueries
    participant FleetService
    participant DB as Database
    participant FleetDM as FleetDM System

    Client->>Controller: PATCH /people/:id/unlink-device
    Controller->>Service: unlinkDevice(memberId, orgId)
    Service->>Queries: findByIdInOrganization(memberId, orgId)
    Queries->>DB: Query Member
    DB-->>Queries: Member record (with fleetDmLabelId)
    Queries-->>Service: PeopleResponseDto
    alt Member has fleetDmLabelId
        Service->>FleetService: removeHostsByLabel(fleetDmLabelId)
        FleetService->>FleetDM: API Call to remove hosts
        FleetDM-->>FleetService: Removal Result
        FleetService-->>Service: Removal Result
    end
    Service->>DB: Delete Device records for memberId
    DB-->>Service: Deletion Result
    Service->>Queries: unlinkDevice(memberId)
    Queries->>DB: Update Member (set fleetDmLabelId = null)
    DB-->>Queries: Updated Member record
    Queries-->>Service: PeopleResponseDto
    Service-->>Controller: PeopleResponseDto
    Controller-->>Client: 200 OK (PeopleResponseDto)
```
Sources: [apps/api/src/people/people.controller.ts](https://github.com/blade47/comp/blob/main/apps/api/src/people/people.controller.ts#L263-L280), [apps/api/src/people/people.service.ts](https://github.com/blade47/comp/blob/main/apps/api/src/people/people.service.ts#L190-L255)

## People Module Configuration

The `PeopleModule` is a standard NestJS module that aggregates the `PeopleController` and `PeopleService`. It also imports `AuthModule` for authentication capabilities and provides `FleetService` as a dependency to `PeopleService`.

```typescript
import { Module } from '@nestjs/common';
import { AuthModule } from '../auth/auth.module';
import { FleetService } from '../lib/fleet.service';
import { PeopleController } from './people.controller';
import { PeopleService } from './people.service';

@Module({
  imports: [AuthModule],
  controllers: [PeopleController],
  providers: [PeopleService, FleetService],
  exports: [PeopleService],
})
export class PeopleModule {}
```
The module exports `PeopleService`, making it available for injection into other modules if needed.
Sources: [apps/api/src/people/people.module.ts](https://github.com/blade47/comp/blob/main/apps/api/src/people/people.module.ts#L1-L14)

## Sitemap

See the full [sitemap](https://www.doc0.dev/docs/49c89830-117b-4def-8edc-b5bcc50766e0/llms.txt) for all pages in this wiki.
