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

# Security Model

> The Kodexa Fine-Grained Access Control (FGAC) system uses teams, roles, and permissions to govern access at organization and project levels.

Kodexa uses a **Fine-Grained Access Control (FGAC)** system built on teams, roles, and permissions. This model controls what users can see and do across the platform at both the organization and project levels.

## Overview

The security model has four key concepts:

1. **Users** are people who log in to the platform
2. **Teams** group users together
3. **Roles** define a set of permissions
4. **Assignments** grant a team a role at the organization or project level

```mermaid theme={null}
graph LR
    U[User] -->|member of| T[Team]
    T -->|assigned role in| O[Organization]
    T -->|assigned role in| P[Project]
    O -->|contains| P
    R[Role] -->|defines| Perms[Permissions]
    T ---|with role| R
```

Users never receive permissions directly. Instead, permissions flow through the team-role-assignment chain:

**User → Team → Assignment (org or project) → Role → Permissions**

<Note>
  A user's **platform role** (set when the user is first provisioned) is a separate concept from the FGAC roles, teams, and permissions described below. Platform roles decide which top-level surfaces a user can reach (Studio, Workflow, Knowledge); FGAC decides what that user can do with individual resources inside an organization or project.
</Note>

## Platform Roles & User Provisioning

In addition to the FGAC model, every user carries one or more **platform roles**. Platform roles are stored on the user record (not through teams or assignments) and gate access to the platform's top-level surfaces. They are distinct from the organization- and project-level FGAC roles described in the rest of this page.

### Platform Roles

| Role             | Description                                                                                                  |
| ---------------- | ------------------------------------------------------------------------------------------------------------ |
| `PLATFORM_ADMIN` | Full platform administrator. Bypasses FGAC permission checks.                                                |
| `SUPPORT`        | Support access.                                                                                              |
| `STUDIO`         | Access to the Studio surface.                                                                                |
| `WORKFLOW`       | Access to the Workflow surface.                                                                              |
| `WORKFLOW_KIOSK` | Restricted, task-mode kiosk access. Reaches the Workflow surface only, locked into the kiosk task-review UI. |
| `KNOWLEDGE`      | Access to the Knowledge surface.                                                                             |

A user with only `WORKFLOW_KIOSK` reaches the Workflow surface and is locked into the kiosk (task-review) UI. A user who holds both `WORKFLOW` and `WORKFLOW_KIOSK` can toggle kiosk mode on and off from their organization home.

### Default Role on Provisioning

When a new user signs in for the first time, the platform provisions their user record from the Auth0 identity token and assigns platform roles using the following precedence:

```mermaid theme={null}
flowchart TD
    A[New user first login] --> B{Email ends in @kodexa.com?}
    B -->|Yes| C[Roles = PLATFORM_ADMIN]
    B -->|No| D{Token provided any roles?}
    D -->|No| E[Roles = WORKFLOW_KIOSK]
    D -->|Yes| F[No platform role assigned; admin must grant one]
```

1. **`@kodexa.com` email → `PLATFORM_ADMIN`.** Users with a `kodexa.com` email address are automatically made platform admins. This takes precedence even when the token carries no roles.
2. **No token roles → `WORKFLOW_KIOSK`.** If the Auth0 token carries no roles for a non-`kodexa.com` user, the user defaults to the restricted `WORKFLOW_KIOSK` platform role (task-mode kiosk). This is the entry point for new users until an administrator grants broader roles.
3. **Token roles are not adopted as platform roles.** Roles carried in the identity token are recorded on the user record's raw `roles_json` field but are NOT copied into the platform-role set that gates surfaces. The `WORKFLOW_KIOSK` default is applied only when the token carries no roles; when the token does carry roles for a non-kodexa.com user, the platform neither forces the kiosk default nor grants any platform role from the token — the user starts with no platform roles until an administrator assigns them.

<Note>
  The default only applies at first provisioning. Once a user exists, an administrator changes their platform roles directly on the user record — for example, to grant `WORKFLOW`, `STUDIO`, or `KNOWLEDGE` access beyond the initial kiosk role.
</Note>

## Permission Format

Every permission is a `resource:action` pair. For example:

| Permission              | Meaning                       |
| ----------------------- | ----------------------------- |
| `document-family:read`  | Can read document families    |
| `task:lock`             | Can lock tasks                |
| `document-store:upload` | Can upload to document stores |
| `*:read`                | Can read any resource type    |
| `*:*`                   | Full access to everything     |

The `*` wildcard matches any resource type or action. This allows roles to grant broad access (like `*:read` for read-only) or full access (`*:*` for admins).

### Standard Actions

These actions map to standard CRUD operations:

| Action   | HTTP Method | Description          |
| -------- | ----------- | -------------------- |
| `create` | POST        | Create new resources |
| `read`   | GET         | View resources       |
| `update` | PUT/PATCH   | Modify resources     |
| `delete` | DELETE      | Remove resources     |

### Custom Actions

Beyond CRUD, the platform defines custom actions for domain-specific operations:

| Action            | Description                            |
| ----------------- | -------------------------------------- |
| `lock`            | Lock a document family or task         |
| `unlock`          | Unlock a document family or task       |
| `reprocess`       | Reprocess a document family            |
| `rename`          | Rename a document family               |
| `label`           | Add or remove labels                   |
| `assign`          | Manage assignees on tasks or documents |
| `assign-next`     | Auto-assign next available task        |
| `update-status`   | Change status of a task or document    |
| `upload`          | Upload files to stores or modules      |
| `export`          | Export document data                   |
| `assess`          | Assess a document family               |
| `manage-features` | Add or remove knowledge features       |
| `activate`        | Activate an assistant                  |
| `deactivate`      | Deactivate an assistant                |
| `trigger`         | Trigger an assistant event or schedule |
| `invoke`          | Invoke an agent                        |
| `cancel`          | Cancel an execution                    |

## Teams

Teams are the bridge between users and access control. A team belongs to an organization and can have any number of members.

```mermaid theme={null}
graph TD
    subgraph Organization
        T1[Extraction Team]
        T2[Review Team]
        T3[Admin Team]
    end

    U1[Alice] -->|member| T1
    U1 -->|member| T3
    U2[Bob] -->|member| T1
    U2 -->|member| T2
    U3[Carol] -->|member| T2
```

Key points about teams:

* A user can belong to multiple teams
* Each team has a unique slug within its organization (e.g., `extraction-team`)
* Teams are managed from the **Members & Teams** page in organization settings
* Task templates can reference teams by slug for automatic task routing

## Roles

Roles define what a team can do. The platform ships with **system-defined roles** that cover common access patterns. If you need a custom role tailored to your organization, contact Kodexa Support.

### System-Defined Roles

```mermaid theme={null}
graph TD
    subgraph "Organization-Level Roles"
        OO["org-owner<br/><i>Full access (non-removable)</i>"]
        OA["org-admin<br/><i>Full access</i>"]
        OM["org-member<br/><i>All resource operations</i>"]
        OV["org-viewer<br/><i>Read + export only</i>"]
    end

    subgraph "Project-Level Roles"
        PA["project-admin<br/><i>Full access</i>"]
        PE["project-editor<br/><i>CRUD + all custom actions, no delete</i>"]
        PC["project-contributor<br/><i>Create, read, update, upload</i>"]
        PV["project-viewer<br/><i>Read + export only</i>"]
    end

    OO -.->|"*:*"| ALL[All Permissions]
    OA -.->|"*:*"| ALL
    PA -.->|"*:*"| ALL
```

#### Organization Roles

| Role           | Permissions                   | Use Case                                                                        |
| -------------- | ----------------------------- | ------------------------------------------------------------------------------- |
| **org-owner**  | `*:*` (full access)           | The organization creator. Cannot be removed.                                    |
| **org-admin**  | `*:*` (full access)           | Administrators who manage teams, roles, and all resources.                      |
| **org-member** | All CRUD + all custom actions | Regular members who work with resources but don't manage teams or org settings. |
| **org-viewer** | `*:read`, `*:export`          | Stakeholders or auditors with read-only access across the org.                  |

#### Project Roles

| Role                    | Permissions                                              | Use Case                                                                             |
| ----------------------- | -------------------------------------------------------- | ------------------------------------------------------------------------------------ |
| **project-admin**       | `*:*` (full access)                                      | Project leads who manage all project resources.                                      |
| **project-editor**      | Create, read, update + all 17 custom actions (no delete) | Team members who actively work with documents, tasks, and knowledge.                 |
| **project-contributor** | Create, read, update, upload, update-status              | Users who submit data and update statuses but don't manage assignments or reprocess. |
| **project-viewer**      | Read + export                                            | Users who review results without modifying anything.                                 |

## Access Assignment

Teams receive roles through **assignments** at two levels:

```mermaid theme={null}
graph TD
    subgraph "Team: Extraction Team"
        TA1["Org Assignment<br/>Role: org-member<br/>Scope: Acme Corp"]
        TA2["Project Assignment<br/>Role: project-editor<br/>Scope: Invoice Project"]
        TA3["Project Assignment<br/>Role: project-viewer<br/>Scope: Contract Project"]
    end
```

### Organization-Level Assignment

When a team is assigned a role at the organization level, all team members receive those permissions across **every resource in the organization**.

```mermaid theme={null}
sequenceDiagram
    participant Admin
    participant API
    participant DB

    Admin->>API: POST /api/team-org-assignments
    Note right of Admin: { teamId, organizationId, roleId }
    API->>DB: Create assignment
    DB-->>API: Assignment created
    API-->>Admin: 201 Created
    Note over Admin,DB: All team members now have<br/>the role's permissions org-wide
```

### Project-Level Assignment

When a team is assigned a role at the project level, members receive those permissions only for **resources linked to that project**.

```mermaid theme={null}
sequenceDiagram
    participant Admin
    participant API
    participant DB

    Admin->>API: POST /api/team-project-assignments
    Note right of Admin: { teamId, projectId, roleId }
    API->>DB: Create assignment
    DB-->>API: Assignment created
    API-->>Admin: 201 Created
    Note over Admin,DB: Team members now have<br/>the role's permissions<br/>within this project only
```

## How Permission Checks Work

When a user makes an API request, the platform evaluates permissions in this order:

```mermaid theme={null}
flowchart TD
    A[API Request] --> B{User authenticated?}
    B -->|No| C[401 Unauthorized]
    B -->|Yes| D{Platform Admin?}
    D -->|Yes| E[Allowed]
    D -->|No| F{Check org-level<br/>permissions}
    F -->|Granted| E
    F -->|Not granted| G{Find projects<br/>linking this resource}
    G --> H{Check project-level<br/>permissions}
    H -->|Granted| E
    H -->|Not granted| I[403 Forbidden]
```

The check flow in detail:

1. **Authentication** -- Is the user logged in? If not, return 401.
2. **Platform Admin bypass** -- Platform admins (`platform_admin` role) skip all permission checks.
3. **Organization-level check** -- Look up the user's teams, find team-org assignments for this org, collect all permissions from assigned roles. If the required permission matches, allow.
4. **Project-level check** -- Find which projects this resource is linked to (via `project_resources`). For each project, look up the user's team-project assignments and check permissions. If any project grants the required permission, allow.
5. **Deny** -- If no check grants the permission, return 403.

### Effective Permissions

A user's effective permissions in a given context are the **union** of:

* Permissions from all org-level team assignments in that organization
* Permissions from all project-level team assignments for the relevant project

You can query a user's effective permissions:

```
GET /api/account/permissions?organizationId={orgId}&projectId={projectId}
```

Response:

```json theme={null}
{
  "permissions": ["*:create", "*:read", "*:update", "*:lock", "*:unlock", "..."],
  "organizationId": "org-123",
  "projectId": "proj-456"
}
```

## Complete Example

Here's a full example showing how Alice gets access to work on documents in the Invoice Project:

```mermaid theme={null}
graph LR
    subgraph Users
        Alice
    end

    subgraph "Acme Corp (Organization)"
        subgraph Teams
            ET[Extraction Team]
        end

        subgraph Projects
            IP[Invoice Project]
        end

        subgraph Roles
            PE[project-editor]
        end
    end

    Alice -->|member of| ET
    ET -->|assigned| TPA[Team-Project Assignment]
    TPA -->|in project| IP
    TPA -->|with role| PE

    PE -->|grants| P1["*:create"]
    PE -->|grants| P2["*:read"]
    PE -->|grants| P3["*:update"]
    PE -->|grants| P4["*:lock"]
    PE -->|grants| P5["*:unlock"]
    PE -->|grants| P6["...17 custom actions"]
```

**Setup steps:**

1. An admin creates the **Extraction Team** in Acme Corp
2. Alice is added as a **team member**
3. The team is given a **project-level assignment** in Invoice Project with the **project-editor** role
4. Alice can now create, read, update, lock, unlock, reprocess documents -- but **cannot delete** anything in Invoice Project

If Alice also needs read-only access to the Contract Project, the admin creates a second assignment for the Extraction Team in that project with the **project-viewer** role.

## API Endpoints

| Endpoint                                 | Purpose                                  |
| ---------------------------------------- | ---------------------------------------- |
| `GET/POST /api/teams`                    | Manage teams                             |
| `GET/POST /api/team-members`             | Manage team membership                   |
| `GET/POST /api/team-org-assignments`     | Assign teams to orgs with roles          |
| `GET/POST /api/team-project-assignments` | Assign teams to projects with roles      |
| `GET /api/roles`                         | List available roles                     |
| `GET /api/permissions`                   | List available permissions               |
| `GET /api/role-permissions`              | List role-permission links               |
| `GET /api/account/permissions`           | Get current user's effective permissions |
