Skip to main content

Projects

A Project groups videos, personas, world states, summaries, claims, and annotations under a shared owner with a member roster and optional video assignment rules. Project-scoped data is visible to project members; the project's role determines what each member can do.

Lifecycle​

POST   /api/projects                       create
GET /api/projects list projects the requester can read
GET /api/projects/:projectId read one
PUT /api/projects/:projectId update name, description, settings
DELETE /api/projects/:projectId delete

POST /api/projects accepts:

{
"name": "Field study A",
"description": "Optional",
"slug": "field-study-a",
"ownerGroupId": null
}

Ownership is implicit at create time: if ownerGroupId is provided, the project is group-owned and the caller must be a group_admin or group_owner of that group; otherwise the authenticated user becomes the project's ownerUserId. Either way the creator is added as project_owner in ProjectMembership. Group-owned projects inherit access through the group's role assignments. Project settings are not accepted on create; edit them via PUT /api/projects/:projectId.

Members​

POST   /api/projects/:projectId/members              body { userId, role }
GET /api/projects/:projectId/members
PUT /api/projects/:projectId/members/:userId body { role }
DELETE /api/projects/:projectId/members/:userId

role is one of:

project_owner      full project admin + content
project_manager content + limited project admin (no delete project)
annotator create / read / update / delete own content; read all
reviewer read all; review action on annotation/summary/claim
viewer read-only

The role determines which RolePermission rows match for project scope. See Reference > RBAC permissions for the full action × subject matrix per role.

Adding, updating, or removing a member calls invalidateUserAbilities(userId) on the affected user so their ability is rebuilt on the next request.

Project-scoped resources​

GET /api/projects/:projectId/personas
GET /api/projects/:projectId/world
PUT /api/projects/:projectId/world

Personas, world states, summaries, claims, and annotations all carry an optional projectId column. When set, the row is project-scoped and visible to project members per their role; when NULL, the row is personal to its owner.

WorldState has a (userId, projectId) unique constraint, so each user has at most one personal world state and one world state per project they belong to.

Ownership​

Project.ownerUserId is the ownership column for ability checks. Owners can do anything inside the project regardless of the RolePermission matrix. There is no API for transferring ownership after creation; PUT /api/projects/:projectId only updates name, description, settings, and isArchived.

Deleting a project cascades to ProjectMembership and clears projectId on dependent content rows (the FK uses SetNull so data survives).

See also​