# People

URL: https://developers.uidu.org/docs/domains/people

> Employees, contracts, pay and benefits, shifts and time clocks — private HR data for server-side tools and scripts.

* **Use it for:** [Server integration](https://developers.uidu.org/docs/paths/server-integration.md)
* **Reads:** Bearer (`apiKey`) — server-side only
* **Writes:** Bearer (`apiKey`) — server-side only
* **CLI:** `uidu employees`, `uidu employments`, `uidu offices`, `uidu roles`, `uidu ccnls`, `uidu time-clocks`, `uidu compensations`, `uidu benefits`, `uidu benefit-enrollments`
* **Auth:** what each token can do and where it may run — [Authentication](https://developers.uidu.org/docs/foundations/authentication.md)

People is uidu's HR module: employees, their contracts (employments) with pay and benefits,
scheduled shifts and time-clock punches. Use it for internal dashboards, payroll exports and
scripts that hire, change and end contracts. Everything here is private data, so every call —
read or write — runs server-side with an `apiKey` client.

## Mental model

```
Employee            HR record of a workspace user (userId) — employeeCode, kioskPin
  ├─→ Employment    a contract: startDate / endDate / endReason, jobTitle, employmentKind,
  │     │           ccnl, contractLevel, fteRatio, roleId, circleId, offices, working hours
  │     ├─→ Compensation       pay item: amount, currency, frequency, componentType, effectiveFrom
  │     └─→ BenefitEnrollment  the contract enrolled in a Benefit (workspace catalog)
  ├─→ Shifts        scheduled work — beginsAt / finishesAt / aasmState
  ├─→ TimeClocks    actual punches — beginsAt / finishesAt (null while still clocked in)
  └─→ TimeEntries   attributed hours, anchored to a Shift + TimeClock (schema only, not in the SDK)

Reference data an employment points at:
  Office (listOffices) · role Circle (listRoles) · org-unit Circle (listCircles) · CCNL (listCcnls)
```

* **The name is on the user.** An employee has no top-level `name`: read `employee.user?.name`
  (also `firstName`, `lastName`, `email`). Likewise the contract type is
  `currentEmployment.employmentKind.name` (e.g. `Tempo indeterminato`) — there is no
  `contractType` field on the API. It used to be a free string; uidu promoted it to an
  `EmploymentKind` record so each workspace configures its own, which is why writes take
  `employmentKindId`. Only the records `listEmploymentHistory` builds carry a flat
  `contractType` (a copy of `employmentKind.name`) for display.
* **Contract events are employment writes.** A hire (*assunzione*) is `createEmployment`; a
  variation (*variazione*) is a new `createEmployment`, or `updateEmployment` on the current one;
  a termination (*cessazione*) is `updateEmployment` with `endDate` + `endReason` — which is
  exactly what `terminateEmployment` sends. `deleteEmployment` erases the record; to end a contract,
  terminate it. `endReason` is one of `resignation`, `termination`,
  `contract_end`, `retirement`, `other`, or the finer-grained
  `resignation_just_cause`, `dismissal_just_cause`, `dismissal_subjective_reason`,
  `dismissal_objective_reason`, `collective_dismissal`, `mutual_agreement`, `probation_failed`,
  `death` and `business_closure`.
* **Units.** `fteRatio` is a fraction (`1.0` full-time, `0.5` half-time). Dates (`startDate`,
  `endDate`, `effectiveFrom`, `enrolledAt`, `weekStartingAt`) are `ISO8601Date` strings
  (`YYYY-MM-DD`); punches (`beginsAt`, `finishesAt`) are `ISO8601DateTime`. Compensation and
  benefit amounts are plain `Float`s in the given `currency` — not cents.
* **Schedules live on the employee, not the workspace.** `getEmployee` returns `todayTimeClocks`
  and `weeklyShifts` (first 20) for the week starting `weekStartingAt` — a required Monday date
  that `weekStartFor(date?)` computes in UTC: `weekStartFor(new Date('2026-05-15'))` →
  `'2026-05-11'`, `weekStartFor(new Date('2026-01-01'))` → `'2025-12-29'`; with no argument, the
  current week. A shift's `aasmState` is e.g. `planned`, `confirmed`, `completed`.
* **Reference data.** `listOffices` gives the ids for `employmentOfficesAttributes`
  (`[{ officeId, isPrimary }]`). `listCircles` returns two flavours of Circle told apart by
  `kind`: org units (an employment's `circleId`) and roles (`kind === 'role'`, an employment's
  `roleId`) — `listRoles` returns only the roles. `listKinds(client, { models })` reads the
  polymorphic `Kind` records; `listCcnls` is `listKinds` with `models: ['Ccnl']`. There is no
  list function for employment kinds: take an `employmentKind.id` from an existing employment.
* **Two kinds of CCNL record.** `listCcnls` returns `Kind`-tagged rows (`id`, `name`, `code`,
  `model`). `createCcnl` creates the first-class `Ccnl` record (code, sector, contract levels via
  `ccnlLevelsAttributes`), and that is the type `Employment.ccnl` / `ccnlId` point at. When you
  create a CCNL, use the id it returns (`ccnl.node.id`) as `ccnlId`.
* **Payload shapes.** Writes return `{ errors, … }` and never throw on validation. Creates wrap the
  record in an edge — `employee.node`, `employment.node`, `compensation.node`, `timeClock.node`,
  `ccnl.node`, `benefit.node`, `benefitEnrollment.node` — while updates return it directly
  (`employment`, `employee`, `compensation`).
* **Not in the SDK yet.** There is no workspace-wide list of shifts or time entries — iterate
  employees and read `weeklyShifts` per employee. Time entries, approving time off, and the
  `weeklyTimeOffs` / `monthlyTimeOffs` fields exist in the schema but aren't wrapped; reach them
  through [`executeAction`](https://developers.uidu.org/docs/paths/server-integration.md) where an action exists.

## Use cases

### HR dashboard of active contracts

Goal: a server-rendered table of everyone with an active contract, and a detail panel with an
employee's punches today and shifts this week.

```ts
// app/hr/data.ts — server-only
import {
  paginate,
  ListEmployeesDocument,
  getEmployee,
  weekStartFor,
} from '@uidu/client';
import { uiduAdmin } from '@/lib/uidu-admin'; // createClient({ workspace, apiKey })

export async function activeContracts() {
  const employees = await paginate(uiduAdmin, ListEmployeesDocument, {
    variables: { first: 100 },
    extract: (data) => data.currentWorkspace?.employees,
  });

  return employees
    .filter((e) => e.currentEmployment?.isActive)
    .map((e) => ({
      id: e.id,
      name: e.user?.name ?? e.user?.email, // the name is on the user
      code: e.employeeCode,
      jobTitle: e.currentEmployment?.jobTitle,
      contract: e.currentEmployment?.employmentKind?.name, // 'Tempo indeterminato'
      since: e.currentEmployment?.startDate,
    }));
}

export async function employeeWeek(id: string) {
  const employee = await getEmployee(uiduAdmin, {
    id,
    weekStartingAt: weekStartFor(), // Monday of this week, 'YYYY-MM-DD'
  });
  if (!employee) return null;

  return {
    name: employee.user?.name,
    fte: employee.currentEmployment?.fteRatio, // 1.0 = full-time
    level: employee.currentEmployment?.contractLevel,
    office: employee.currentEmployment?.primaryOffice?.name,
    clockedIn: employee.todayTimeClocks.some((tc) => !tc.finishesAt),
    shifts: (employee.weeklyShifts?.edges ?? []).map((edge) => ({
      begins: edge?.node?.beginsAt,
      ends: edge?.node?.finishesAt,
      state: edge?.node?.aasmState, // 'planned' | 'confirmed' | 'completed' | …
    })),
  };
}
```

* `listEmployees(uiduAdmin, { first: 50 })` returns one page as a flat array; `paginate` with
  `ListEmployeesDocument` walks them all — see
  [Pagination & field values](https://developers.uidu.org/docs/foundations/pagination-and-field-values.md).
* The list carries only a summary of the current employment (`jobTitle`, `employmentKind`,
  `isActive`, `startDate`); `contractLevel`, `classification`, `fteRatio`, `endDate` and
  `primaryOffice` come from `getEmployee`.

### Hire, change and terminate from a script

Goal: a payroll sync or an onboarding script that opens a contract for a new hire, adds the
salary and a benefit, and later closes the contract.

```ts
// scripts/hire.ts — Node, server-side
import {
  createEmployee,
  createEmployment,
  createCompensation,
  createBenefitEnrollment,
  terminateEmployment,
  listOffices,
  listRoles,
  listEmployees,
} from '@uidu/client';
import { uiduAdmin } from './uidu-admin';

declare const userId: string; // an existing workspace member
declare const benefitId: string; // from createBenefit, or your catalog

// 1. Reference data for the contract form
const [offices, roles, employees] = await Promise.all([
  listOffices(uiduAdmin),
  listRoles(uiduAdmin), // role-Circles → roleId
  listEmployees(uiduAdmin, { first: 50 }),
]);
// no list function for employment kinds: reuse one from an existing contract
const permanent = employees.find(
  (e) => e.currentEmployment?.employmentKind?.name === 'Tempo indeterminato',
)?.currentEmployment?.employmentKind?.id;

// 2. The HR record for an existing workspace user
const created = await createEmployee(uiduAdmin, {
  input: { attributes: { userId, employeeCode: 'E-0042' } },
});
if (created?.errors?.length) throw new Error(created.errors.map((e) => e.name).join(', '));
const employeeId = created!.employee!.node!.id; // creates wrap the record in `.node`

// 3. Hire (assunzione) = createEmployment
const hired = await createEmployment(uiduAdmin, {
  input: {
    attributes: {
      employeeId,
      startDate: '2026-11-01',
      jobTitle: 'Educatore',
      employmentKindId: permanent,
      roleId: roles[0]?.id,
      fteRatio: 0.5, // half-time
      employmentOfficesAttributes: [{ officeId: offices[0]!.id, isPrimary: true }],
    },
  },
});
const employmentId = hired!.employment!.node!.id;

// 4. Pay and benefits hang off the employment, not the employee
await createCompensation(uiduAdmin, {
  input: {
    attributes: {
      employmentId,
      amount: 1850, // a plain amount in `currency`, not cents
      currency: 'EUR',
      frequency: 'monthly',
      componentType: 'base',
      effectiveFrom: '2026-11-01',
    },
  },
});
await createBenefitEnrollment(uiduAdmin, {
  input: { attributes: { benefitId, employmentId, enrolledAt: '2026-11-01' } },
});

// 5. Later: termination (cessazione) closes the contract — it isn't deleted
const ended = await terminateEmployment(uiduAdmin, {
  id: employmentId,
  endDate: '2027-10-31',
  endReason: 'contract_end',
});
ended?.employment?.endDate; // updates return the record directly, no `.node`
```

* A **variation** (new level, new hours, new role) is either a new `createEmployment` from the
  change date — which `contractEvents` will report as a `variation` — or `updateEmployment`
  (`{ input: { id, attributes } }`) on the current contract when you don't need the history.
* `createBenefit` adds to the workspace's benefit catalog (`name`, `category`, `provider`,
  `employerCostAmount`, `employeeCostAmount`, …); its id is at `benefit.node.id`.
* Punches can be written too: `createTimeClock(uiduAdmin, { input: { attributes: { resourceId,
  beginsAt, finishesAt } } })`, the new punch at `timeClock.node`.
* The same writes from a terminal: `uidu employments create --attributes '{"employeeId",…}'`,
  `uidu employments update <id> --attributes '{"endDate","endReason"}'` — see
  [CLI commands](https://developers.uidu.org/docs/tools/cli/commands.md).

### Monthly report of hires, variations and terminations

Goal: the Italian monthly HR summary — *assunzioni*, *variazioni*, *cessazioni* — from the full
contract history.

```ts
import { listEmploymentHistory, contractEvents } from '@uidu/client';
import { uiduAdmin } from '@/lib/uidu-admin';

const history = await listEmploymentHistory(uiduAdmin, { first: 100 });
const events = contractEvents(history); // most recent first

const byMonth = events.reduce<Record<string, typeof events>>((acc, e) => {
  (acc[e.month] ??= []).push(e); // 'YYYY-MM'
  return acc;
}, {});

for (const [month, list] of Object.entries(byMonth)) {
  const count = (t: string) => list.filter((e) => e.type === t).length;
  console.log(month, {
    hires: count('hire'),
    variations: count('variation'),
    terminations: count('termination'),
  });
}

events
  .filter((e) => e.type === 'termination')
  .map((e) => `${e.date} ${e.employeeName} — ${e.contractType} (${e.endReason})`);
```

* `listEmploymentHistory` returns every employee with **all** their contracts (up to
  `employmentsFirst`, default 50), not just the current one. Each record is flattened:
  `{ id, name, employments: [{ id, startDate, endDate, endReason, jobTitle, employmentKind,
  contractType, ccnl, compensations }] }`, with `name` falling back to the user's email, then
  `'Senza nome'`. Compensations (first 20) come most recent `effectiveFrom` first.
* `contractEvents` rules: per employee, contracts are sorted by `startDate`; the earliest is a
  `hire`, every later one a `variation`, both on their start date; any contract with an `endDate`
  also yields a `termination` on it, carrying `endReason`. Contracts without a `startDate` are
  ignored. Each event has `date` (`YYYY-MM-DD`) and `month` (`YYYY-MM`) for grouping.
* `first`/`after` page the employees, but the flattened result carries no cursor: pass a
  `first` that covers the whole workforce.

## API at a glance

Every `@uidu/client` function in &#x2A;*People (HR)**, generated from the source — the [full reference](https://developers.uidu.org/docs/reference/client.md#people) has the rest of the SDK.

| Function                                                                                                             | Kind   | Auth   | CLI                          | Description                                                                                                                                                                                                                                                                                                                                                                                                             |
| -------------------------------------------------------------------------------------------------------------------- | ------ | ------ | ---------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [`contractEvents`](https://github.com/uidu-org/api.js/blob/main/packages/client/src/people.ts)                       | helper | —      | —                            | Flatten employment history into dated contract events, most recent first: - the employee's earliest contract is a `hire` (assunzione) on its start date; - every later contract is a `variation` (variazione) on its start date; - any contract with an end date yields a `termination` (cessazione) on it.                                                                                                             |
| [`createBenefit`](https://github.com/uidu-org/api.js/blob/main/packages/client/src/benefits.ts)                      | write  | Bearer | `benefits create`            | Create a benefit in the workspace's catalog (name, category, provider, employer/employee costs). Returns the payload (with `errors`) or null; it is at `benefit.node`.                                                                                                                                                                                                                                                  |
| [`createBenefitEnrollment`](https://github.com/uidu-org/api.js/blob/main/packages/client/src/benefit-enrollments.ts) | write  | Bearer | `benefit-enrollments create` | Enroll an employment in a benefit (`benefitId`, `employmentId`, `enrolledAt`). Returns the payload (with `errors`) or null; it is at `benefitEnrollment.node`.                                                                                                                                                                                                                                                          |
| [`createCcnl`](https://github.com/uidu-org/api.js/blob/main/packages/client/src/people.ts)                           | write  | Bearer | `ccnls create`               | Create a CCNL (national collective labor contract) — the first-class `Ccnl` record (code, sector, contract levels), distinct from the `Kind`-tagged rows `listCcnls` returns above. `Employment.ccnl` / `ccnlId` point at this first-class type. Requires a Bearer token (`apiKey`).                                                                                                                                    |
| [`createCompensation`](https://github.com/uidu-org/api.js/blob/main/packages/client/src/mutations.ts)                | write  | Bearer | `compensations create`       | Add a pay item to an employment (`attributes.employmentId`, `amount`, `currency`, `frequency`, `effectiveFrom`). Returns the payload (with `errors`) or null. The new item is at `compensation.node`.                                                                                                                                                                                                                   |
| [`createEmployee`](https://github.com/uidu-org/api.js/blob/main/packages/client/src/mutations.ts)                    | write  | Bearer | `employees create`           | Create the HR record for a workspace user (`attributes.userId`). Returns the payload (with `errors`) or null. The new employee is at `employee.node`.                                                                                                                                                                                                                                                                   |
| [`createEmployment`](https://github.com/uidu-org/api.js/blob/main/packages/client/src/mutations.ts)                  | write  | Bearer | `employments create`         | Hire: open a new employment (contract) for `attributes.employeeId` with its start date, kind, role and hours. Returns the payload (with `errors`) or null. The new employment is at `employment.node`.                                                                                                                                                                                                                  |
| [`createTimeClock`](https://github.com/uidu-org/api.js/blob/main/packages/client/src/mutations.ts)                   | write  | Bearer | `time-clocks create`         | Record a time-clock punch (`beginsAt`, optional `finishesAt`, `resourceId`). Returns the payload (with `errors`) or null. The new punch is at `timeClock.node`.                                                                                                                                                                                                                                                         |
| [`deleteCompensation`](https://github.com/uidu-org/api.js/blob/main/packages/client/src/mutations.ts)                | write  | Bearer | `compensations delete`       | Delete a pay item by `{ input: { id } }`. Returns the payload (with `errors`) or null.                                                                                                                                                                                                                                                                                                                                  |
| [`deleteEmployment`](https://github.com/uidu-org/api.js/blob/main/packages/client/src/mutations.ts)                  | write  | Bearer | `employments delete`         | Delete an employment by `{ input: { id } }` (to end a contract, use `terminateEmployment` instead). Returns the payload (with `errors`) or null.                                                                                                                                                                                                                                                                        |
| [`getEmployee`](https://github.com/uidu-org/api.js/blob/main/packages/client/src/people.ts)                          | read   | Bearer | —                            | One employee with current employment, today's time clocks and the shifts of the week starting `weekStartingAt` (see `weekStartFor`), or null.                                                                                                                                                                                                                                                                           |
| [`listCcnls`](https://github.com/uidu-org/api.js/blob/main/packages/client/src/people.ts)                            | read   | Bearer | `ccnls list`                 | List the CCNLs (national collective labor contracts) configured for the workspace — used for an employment's `ccnlId`.                                                                                                                                                                                                                                                                                                  |
| [`listCircles`](https://github.com/uidu-org/api.js/blob/main/packages/client/src/people.ts)                          | read   | Bearer | —                            | List the workspace circles. Circles come in two flavours distinguished by `kind`: org units (e.g. departments — used as an employment's `circleId`) and roles (`kind === 'role'` — used as an employment's `roleId`). Use `listRoles` when you only want the role-Circles.                                                                                                                                              |
| [`listEmployees`](https://github.com/uidu-org/api.js/blob/main/packages/client/src/people.ts)                        | read   | Bearer | `employees list`             | The workspace's employees with their current employment, as a flat array; page with `first`/`after`.                                                                                                                                                                                                                                                                                                                    |
| [`listEmploymentHistory`](https://github.com/uidu-org/api.js/blob/main/packages/client/src/people.ts)                | read   | Bearer | —                            | List every employee with their full employment (contract) history — not just the current one. Use `contractEvents` to turn this into a flat, dated list of hires, terminations and contract variations.                                                                                                                                                                                                                 |
| [`listKinds`](https://github.com/uidu-org/api.js/blob/main/packages/client/src/people.ts)                            | read   | Bearer | —                            | List `Kind` records for the given polymorphic models.                                                                                                                                                                                                                                                                                                                                                                   |
| [`listOffices`](https://github.com/uidu-org/api.js/blob/main/packages/client/src/people.ts)                          | read   | Bearer | `offices list`               | List the workspace offices — used for an employment's `employmentOfficesAttributes`.                                                                                                                                                                                                                                                                                                                                    |
| [`listRoles`](https://github.com/uidu-org/api.js/blob/main/packages/client/src/people.ts)                            | read   | Bearer | `roles list`                 | List only the role-Circles (structured job titles) — an employment's `roleId`.                                                                                                                                                                                                                                                                                                                                          |
| [`terminateEmployment`](https://github.com/uidu-org/api.js/blob/main/packages/client/src/mutations.ts)               | write  | Bearer | —                            | Terminate (cessazione) an employment by closing it with an end date and reason. Thin semantic wrapper over `updateEmployment`. `endReason` is one of: resignation, termination, contract\_end, retirement, other, resignation\_just\_cause, dismissal\_just\_cause, dismissal\_subjective\_reason, dismissal\_objective\_reason, collective\_dismissal, mutual\_agreement, probation\_failed, death, business\_closure. |
| [`updateCompensation`](https://github.com/uidu-org/api.js/blob/main/packages/client/src/mutations.ts)                | write  | Bearer | `compensations update`       | Update a pay item: `{ input: { id, attributes } }`. Returns the payload (with `errors`) or null.                                                                                                                                                                                                                                                                                                                        |
| [`updateEmployee`](https://github.com/uidu-org/api.js/blob/main/packages/client/src/mutations.ts)                    | write  | Bearer | `employees update`           | Update an employee's HR record (code, kiosk PIN, time-clock flags): `{ input: { id, attributes } }`. Returns the payload (with `errors`) or null.                                                                                                                                                                                                                                                                       |
| [`updateEmployment`](https://github.com/uidu-org/api.js/blob/main/packages/client/src/mutations.ts)                  | write  | Bearer | `employments update`         | Update an employment: `{ input: { id, attributes } }`; to end one, prefer `terminateEmployment`. Returns the payload (with `errors`) or null.                                                                                                                                                                                                                                                                           |
| [`weekStartFor`](https://github.com/uidu-org/api.js/blob/main/packages/client/src/people.ts)                         | helper | —      | —                            | Compute the Monday of the week containing `date` as an ISO8601 date string. Useful for the `weekStartingAt` argument required by `getEmployee` (and any other weekly-aggregated employee fields).                                                                                                                                                                                                                       |

**Types:** `Circle`, `CompensationRecord`, `ContractEvent`, `ContractEventType`, `Employee`, `EmployeeContracts`, `EmploymentRecord`, `Kind`, `Office`

**CLI:**

| Entity                | list | get | create | update | delete |
| --------------------- | :--: | :-: | :----: | :----: | :----: |
| `employees`           |   ✓  |  —  |    ✓   |    ✓   |    —   |
| `employments`         |   —  |  —  |    ✓   |    ✓   |    ✓   |
| `offices`             |   ✓  |  —  |    —   |    —   |    —   |
| `roles`               |   ✓  |  —  |    —   |    —   |    —   |
| `ccnls`               |   ✓  |  —  |    ✓   |    —   |    —   |
| `time-clocks`         |   —  |  —  |    ✓   |    —   |    —   |
| `compensations`       |   —  |  —  |    ✓   |    ✓   |    ✓   |
| `benefits`            |   —  |  —  |    ✓   |    —   |    —   |
| `benefit-enrollments` |   —  |  —  |    ✓   |    —   |    —   |
