# Spaces, tasks & notes

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

> Create, update and delete the workspace's Spaces, tasks and notes from a server or the CLI.

* **Use it for:** [Server integration](https://developers.uidu.org/docs/paths/server-integration.md)
* **Reads:** none
* **Writes:** Bearer (`apiKey`) — server-side only
* **CLI:** `uidu tasks`, `uidu notes`, `uidu spaces`
* **Auth:** what each token can do and where it may run — [Authentication](https://developers.uidu.org/docs/foundations/authentication.md)

**Spaces** are the areas a uidu workspace is organised into (a team, a project, a department);
**tasks** are the work inside them and **notes** the workspace's documents. The SDK covers them
for provisioning and automation: seed a new Space with its starter tasks, open a task from an
external system, file a note from a webhook.

## Mental model

```
Workspace
  ├─→ Space   (name, kind, color, icon, isPrivate, isLocked, isHidden)
  │     └─→ Task   (name, body, spaceId, statusId, priority, startDate / endDate,
  │                 parentId, goalId, workspaceTagIds, private, doneAt)
  └─→ Note    (name, body, icon, isPrivate, folderId)
```

* **Write-only today.** There are no `listSpaces` / `getSpace`, `listTasks` / `getTask` or
  `listNotes` / `getNote` functions yet. Keep the ids the create calls return — in your own
  database, next to the external record they came from — if you need to update or delete those
  records later.
* **Every function is authoring**: it needs an account Bearer token (`apiKey` on the client) and
  runs under the workspace's permissions. Use it server-side (route handler, server action,
  script) or through the [CLI](https://developers.uidu.org/docs/tools/cli.md) — never from the browser, and not from a
  [custom app](https://developers.uidu.org/docs/paths/custom-app.md), whose session token is refused for tasks and notes.
* **Rich text** fields (`body`, `description`) take a Tiptap/ProseMirror JSON document
  (`{ type: 'doc', content: [...] }`).
* **Tasks.** `priority` is `low`, `normal`, `high` or `urgent`; `startDate` / `endDate` are
  `YYYY-MM-DD`. `parentId` makes a subtask, `goalId` links the task to a
  [goal](https://developers.uidu.org/docs/domains/goals.md), `statusId` places it in a status of its Space. A task is finished
  either by setting `doneAt`, or by moving it to a status whose state is `completed` — uidu
  derives the task's state from its status.
* **Notes don't belong to a Space**: their attributes have no `spaceId`. They live in the
  workspace, optionally in a folder (`folderId`).

**Payload shapes differ.** Each function returns the mutation payload with `errors` rather than
throwing — always check it. Where the record sits:

| Function              | Record at                                         |
| --------------------- | ------------------------------------------------- |
| `createSpace`         | `space.node` — `{ id, name }`, wrapped in an edge |
| `createNote`          | `note.node` — `{ id }`, wrapped in an edge        |
| `createTask`          | `task` — `{ id, name }`, **not** wrapped          |
| `update*` / `delete*` | `space` / `task` / `note` — `{ id }`              |

## Use cases

### Seed a new Space with its starter tasks

Goal: a provisioning script that creates a project Space and fills it with a checklist, one
item with a subtask.

```ts
// scripts/seed-launch.ts — server-side
import { createClient, createSpace, createTask } from '@uidu/client';

const uiduAdmin = createClient({
  workspace: process.env.UIDU_WORKSPACE!,
  apiKey: process.env.UIDU_API_KEY!, // never shipped to a browser
});

const space = await createSpace(uiduAdmin, {
  input: { attributes: { name: 'Product launch', isPrivate: false, color: '#22c55e' } },
});
if (space?.errors?.length) throw new Error(space.errors.map((e) => e.name).join(', '));
const spaceId = space!.space!.node!.id; // createSpace wraps the space in an edge

const doc = (text: string) => ({
  type: 'doc',
  content: [{ type: 'paragraph', content: [{ type: 'text', text }] }],
});

const release = await createTask(uiduAdmin, {
  input: {
    attributes: {
      name: 'Draft the press release',
      spaceId,
      priority: 'high', // 'low' | 'normal' | 'high' | 'urgent'
      startDate: '2026-10-12',
      endDate: '2026-10-16',
      body: doc('One page, two quotes.'),
    },
  },
});
const releaseId = release?.task?.id; // createTask is not wrapped: task.id

await createTask(uiduAdmin, {
  input: { attributes: { name: 'Collect the quotes', spaceId, parentId: releaseId } },
});
```

* Rename or lock the Space later with `updateSpace(uiduAdmin, { input: { id: spaceId,
  attributes: { name: 'Launch — Q4', isLocked: true } } })`; remove it with
  `deleteSpace(uiduAdmin, { input: { id: spaceId } })`.
* The same from a terminal: `uidu spaces create --attributes '{"name":"Product launch"}'`, then
  `uidu tasks create --attributes '{"name":"…","spaceId":"…"}'` — every verb in
  [CLI commands](https://developers.uidu.org/docs/tools/cli/commands.md).

### Create tasks from an external system

Goal: a webhook from an issue tracker (or a form, or a CRM) opens a task in uidu, and closes it
when the external item is resolved.

```ts
// app/api/webhooks/tracker/route.ts
import { createTask, updateTask, deleteTask } from '@uidu/client';
import { uiduAdmin } from '@/lib/uidu-admin'; // createClient({ workspace, apiKey })
import { db } from '@/lib/db'; // your own store: external id → uidu task id

export async function POST(req: Request) {
  const event = await req.json(); // verify the sender's signature first

  if (event.type === 'issue.opened') {
    const result = await createTask(uiduAdmin, {
      input: {
        attributes: {
          name: event.issue.title,
          spaceId: process.env.UIDU_SUPPORT_SPACE_ID,
          priority: event.issue.urgent ? 'urgent' : 'normal',
        },
      },
    });
    if (result?.errors?.length) {
      return Response.json({ errors: result.errors }, { status: 422 });
    }
    // no listTasks / getTask: this mapping is the only way back to the task
    await db.taskLinks.insert({ externalId: event.issue.id, taskId: result!.task!.id });
  }

  if (event.type === 'issue.resolved') {
    const link = await db.taskLinks.find(event.issue.id);
    if (link) {
      await updateTask(uiduAdmin, {
        input: { id: link.taskId, attributes: { doneAt: new Date().toISOString() } },
      });
    }
  }

  if (event.type === 'issue.deleted') {
    const link = await db.taskLinks.find(event.issue.id);
    if (link) await deleteTask(uiduAdmin, { input: { id: link.taskId } });
  }

  return new Response(null, { status: 204 });
}
```

* `UIDU_SUPPORT_SPACE_ID` and `db` stand for your own configuration and storage — the SDK
  doesn't provide them.
* Instead of `doneAt`, you can move the task with `statusId` to a status whose state is
  `completed`.

### File a note from a webhook

Goal: when a meeting tool posts a transcript summary, file it as a workspace note.

```ts
'use server';
import { createNote } from '@uidu/client';
import { uiduAdmin } from '@/lib/uidu-admin';

export async function fileMeetingNote(title: string, paragraphs: string[]) {
  const result = await createNote(uiduAdmin, {
    input: {
      attributes: {
        name: title,
        isPrivate: false,
        body: {
          type: 'doc',
          content: paragraphs.map((text) => ({
            type: 'paragraph',
            content: [{ type: 'text', text }],
          })),
        },
      },
    },
  });

  if (result?.errors?.length) return { ok: false, errors: result.errors };
  // like createSpace, the note comes wrapped in an edge — keep the id to edit it later
  return { ok: true, noteId: result!.note!.node!.id };
}
```

* Later edits: `updateNote(uiduAdmin, { input: { id: noteId, attributes: { name: 'Launch retro
  (final)' } } })`; `deleteNote(uiduAdmin, { input: { id: noteId } })` removes it. Both return
  `{ errors, note: { id } }`.

## API at a glance

Every `@uidu/client` function in **Spaces, tasks & notes**, generated from the source — the [full reference](https://developers.uidu.org/docs/reference/client.md#workspace) has the rest of the SDK.

| Function                                                                                       | Kind  | Auth   | CLI             | Description                                                                                                                 |
| ---------------------------------------------------------------------------------------------- | ----- | ------ | --------------- | --------------------------------------------------------------------------------------------------------------------------- |
| [`createNote`](https://github.com/uidu-org/api.js/blob/main/packages/client/src/notes.ts)      | write | Bearer | `notes create`  | Create a note. Returns the payload (with `errors`) or null; the new note is at `note.node`.                                 |
| [`createSpace`](https://github.com/uidu-org/api.js/blob/main/packages/client/src/spaces.ts)    | write | Bearer | `spaces create` | Create a space, the container tasks live in. Returns the payload (with `errors`) or null; the new space is at `space.node`. |
| [`createTask`](https://github.com/uidu-org/api.js/blob/main/packages/client/src/tasks.ts)      | write | Bearer | `tasks create`  | Create a task, usually in a space (`attributes.spaceId`). Returns the payload (with `errors`) or null.                      |
| [`deleteNote`](https://github.com/uidu-org/api.js/blob/main/packages/client/src/mutations.ts)  | write | Bearer | `notes delete`  | Delete a note by `{ input: { id } }`. Returns the payload (with `errors`) or null.                                          |
| [`deleteSpace`](https://github.com/uidu-org/api.js/blob/main/packages/client/src/mutations.ts) | write | Bearer | `spaces delete` | Delete a space by `{ input: { id } }`. Returns the payload (with `errors`) or null.                                         |
| [`deleteTask`](https://github.com/uidu-org/api.js/blob/main/packages/client/src/mutations.ts)  | write | Bearer | `tasks delete`  | Delete a task by `{ input: { id } }`. Returns the payload (with `errors`) or null.                                          |
| [`updateNote`](https://github.com/uidu-org/api.js/blob/main/packages/client/src/mutations.ts)  | write | Bearer | `notes update`  | Update a note: `{ input: { id, attributes } }`. Returns the payload (with `errors`) or null.                                |
| [`updateSpace`](https://github.com/uidu-org/api.js/blob/main/packages/client/src/mutations.ts) | write | Bearer | `spaces update` | Update a space: `{ input: { id, attributes } }`. Returns the payload (with `errors`) or null.                               |
| [`updateTask`](https://github.com/uidu-org/api.js/blob/main/packages/client/src/mutations.ts)  | write | Bearer | `tasks update`  | Update a task, e.g. its `statusId` or dates: `{ input: { id, attributes } }`. Returns the payload (with `errors`) or null.  |

**CLI:**

| Entity   | list | get | create | update | delete |
| -------- | :--: | :-: | :----: | :----: | :----: |
| `tasks`  |   —  |  —  |    ✓   |    ✓   |    ✓   |
| `notes`  |   —  |  —  |    ✓   |    ✓   |    ✓   |
| `spaces` |   —  |  —  |    ✓   |    ✓   |    ✓   |
