Skip to main content

Projects Module

The Projects module provides multi-tenant namespaces in SOAT. Every resource (document, file, actor, conversation) belongs to a project. Projects also own policy documents, manage user membership, and issue project keys for programmatic access.

Overview

A Project is a top-level container that scopes all resources. Users access projects through membership, and their permissions within a project are determined by attached policy documents. Projects are identified by an id prefixed with proj_.

Data Model

FieldTypeDescription
idstringPublic identifier prefixed with proj_
namestringHuman-readable project name
createdAtstringISO 8601 creation timestamp
updatedAtstringISO 8601 last-updated timestamp

Key Concepts

Membership

Users are added to projects as members. Each membership associates the user with one or more policy documents that define what the user can do within that project. A user can be a member of multiple projects, each with different policies.

Policy Documents

Policy documents are scoped to a project and contain structured IAM statements. See IAM Module for the full policy format, evaluation logic, and examples.

Policy data model:

FieldTypeDescription
idstringPublic identifier prefixed with pol_
namestringHuman-readable label
descriptionstringOptional description
documentobjectPolicy document (see IAM)
projectIdstringID of the owning project
createdAtstringISO 8601 creation timestamp
updatedAtstringISO 8601 last-updated timestamp

Visibility Rules

  • Admin users see all projects.
  • project key callers are restricted to the project the key is scoped to.
  • Regular users see only projects they are members of.

Permissions

Project CRUD and management operations are restricted to admin users. The projects:GetProject action is used by the policy engine for listing and reading policies as a member.

ActionPermissionREST EndpointMCP Tool
List projectsAuthenticatedGET /api/v1/projectslist-projects
Get project by IDAuthenticatedGET /api/v1/projects/:idget-project
Create projectAdmin onlyPOST /api/v1/projects
Delete projectAdmin onlyDELETE /api/v1/projects/:id
List policiesprojects:GetProjectGET /api/v1/projects/:projectId/policies
Get policyprojects:GetProjectGET /api/v1/projects/:projectId/policies/:policyId
Create policyAdmin onlyPOST /api/v1/projects/:projectId/policies
Update policyAdmin onlyPUT /api/v1/projects/:projectId/policies/:policyId
Delete policyAdmin onlyDELETE /api/v1/projects/:projectId/policies/:policyId
Add memberAdmin onlyPOST /api/v1/projects/:projectId/members
Update member policiesAdmin onlyPUT /api/v1/projects/:projectId/members/:userId/policies
Get member policiesAdmin onlyGET /api/v1/projects/:projectId/members/:userId/policies

Create a Policy

POST /api/v1/projects/proj_abc123/policies
Authorization: Bearer <admin-token>
Content-Type: application/json

{
"name": "Read-only Documents",
"description": "Allows reading all documents",
"document": {
"version": "2025-01-01",
"statement": [
{
"effect": "Allow",
"action": ["documents:GetDocument", "documents:ListDocuments"],
"resource": ["*"]
}
]
}
}

Response 201 Created

{
"id": "pol_def456",
"name": "Read-only Documents",
"description": "Allows reading all documents",
"document": { "...": "..." },
"projectId": "proj_abc123",
"createdAt": "2025-01-01T00:00:00.000Z",
"updatedAt": "2025-01-01T00:00:00.000Z"
}

Add a Member to a Project

POST /api/v1/projects/proj_abc123/members
Authorization: Bearer <admin-token>
Content-Type: application/json

{
"userId": "user_def456",
"policyIds": ["pol_def456"]
}

Response 201 Created

Update Member Policies

PUT /api/v1/projects/proj_abc123/members/user_def456/policies
Authorization: Bearer <admin-token>
Content-Type: application/json

{
"policyIds": ["pol_def456", "pol_ghi789"]
}

Response 200 OK


Project Keys

Project Keys provide project key-based authentication for programmatic access to SOAT. Each key is scoped to a single project and bound to a single policy document. The raw key is returned only once at creation time — it cannot be retrieved afterwards.

Project Keys are identified by an id prefixed with key_.

Project Key Data Model

FieldTypeDescription
idstringPublic identifier prefixed with key_
namestringHuman-readable label
keyPrefixstringFirst 8 characters of the raw key (for lookup)
userIdstringPublic ID of the user who created the key
projectIdstringPublic ID of the project the key is scoped to
policyIdstringPublic ID of the attached policy
createdAtstringISO 8601 creation timestamp
updatedAtstringISO 8601 last-updated timestamp

The raw secret key is only returned in the POST response. Only keyPrefix and a bcrypt hash are stored.

Security Model

  • The raw key is a 32-byte random value prefixed with pk_.
  • Only the keyPrefix (first 8 characters) and a bcrypt hash of the full key are stored.
  • Authentication works by matching the prefix to candidate rows, then verifying the full key against each hash.

Intersection Authorization

When an project key is used to make a request, authorization applies intersection semantics:

  1. The owning user's project membership policies must allow the action.
  2. The key's own attached policy must also allow the action.

Both must independently evaluate to Allow. This ensures a key can never exceed the permissions of the user who created it.

Scoping

A project key is scoped to exactly one project. Requests made with the key can only access resources within that project. The project is resolved automatically from the key — callers do not need to specify the project explicitly.

Project Key Permissions

Project key operations require authentication. The creator of a key is the only user who can read or update it (ownership enforcement).

ActionPermissionREST EndpointMCP Tool
Create keyProject memberPOST /api/v1/project-keys
Get key by IDKey owner onlyGET /api/v1/project-keys/:id
Update key policyKey owner onlyPUT /api/v1/project-keys/:id