Projects

API: Internal/Beta

The projects feature allow for collaboration between different users across the entire UCloud platform.

Rationale

This project establishes the core abstractions for projects and establishes an event stream for receiving updates about changes. Other services extend the projects feature and subscribe to these changes to create the full project feature.


⚠️ WARNING: The API listed on this page will likely change to conform with our API conventions. Be careful when building integrations. The following changes are expected:

  • RPC names will change to conform with the conventions

  • RPC request and response types will change to conform with the conventions

  • RPCs which return a page will be collapsed into a single browse endpoint

  • Some property names will change to be consistent with Resources


Definition

A project in UCloud is a collection of members which is uniquely identified by an id. All members are users identified by their username and have exactly one role. A user always has exactly one role. Each project has exactly one principal investigator (PI). The PI is responsible for managing the project, including adding and removing users.

Role Notes
PI The primary point of contact for projects. All projects have exactly one PI.
ADMIN Administrators are allowed to perform some project management. A project can have multiple admins.
USER Has no special privileges.

Table: The possible roles of a project, and their privileges within project management.

A project can be updated by adding/removing/changing any of its members. Such an update will trigger a new message on the event stream.

A project is sub-divided into groups:

Each project may have 0 or more groups. The groups can have 0 or more members. A group belongs to exactly one project, and the members of a group can only be from the project it belongs to.

Creating Projects and Sub-Projects

All projects create by end-users have exactly one parent project. Only UCloud administrators can create root-level projects, that is a project without a parent. This allows users of UCloud to create a hierarchy of projects. The project hierarchy plays a significant role in accounting.

Normal users can create a project through the grant application feature.

A project can be uniquely identified by the path from the root project to the leaf-project. As a result, the title of a project must be unique within a single project. titles are case-insensitive.

Permissions and memberships are not hierarchical. This means that a user must be explicitly added to every project they need permissions in. UCloud administrators can always create a sub-project in any given project. A setting exists for every project which allows normal users to create sub-projects.


Example: A project hierarchy

Figure 1: A storage hierarchy

Figure 1 shows a hierarchy of projects. Note that users deep in the hierarchy are not necessarily members of the projects further up in the hierarchy. For example, being a member of “IMADA” does not imply membership of “NAT”. A member of “IMADA” can be a member of “NAT” but they must be explicitly added to both projects.

None of the projects share any resources. Each individual project will have their own home directory. The administrators, or any other user, of “NAT” will not be able to read/write any files of “IMADA” unless they have explicitly been added to the “IMADA” project.

The Project Context

All requests in UCloud are executed in a particular context. The header of every request defines the context. For the HTTP backend this is done in the Project header. The absence of a project implies that the request is executed in the personal project context.

Figure 2: The UCloud user interface allows you to select context through a dropdown in the navigation header.


Example: Accessing the project context from a microservice

implement(Descriptions.call) {
    val project: String? = ctx.project // null implies the personal project
    ok(service.doSomething(project))
}

Table of Contents

1. Remote Procedure Calls
Name Description
allowsRenaming No description
allowsSubProjectRenaming No description
countSubProjects No description
fetchDataManagementPlan No description
listFavoriteProjects No description
listProjects No description
lookupById No description
lookupByIdBulk No description
lookupByPath No description
lookupPrincipalInvestigator No description
search No description
viewAncestors No description
viewMemberInProject No description
acceptInvite No description
archive No description
archiveBulk No description
changeUserRole No description
create No description
deleteMember No description
exists No description
invite No description
leaveProject No description
listIngoingInvites No description
listOutgoingInvites No description
listSubProjects No description
rejectInvite No description
rename No description
toggleRenaming No description
transferPiRole No description
updateDataManagementPlan No description
verifyMembership No description
viewProject No description
2. Data Models
Name Description
IngoingInvite No description
MemberInProject No description
OutgoingInvite No description
Project No description
ProjectMember No description
ProjectRole No description
UserProjectSummary No description
AcceptInviteRequest No description
AllowsRenamingRequest No description
ArchiveBulkRequest No description
ArchiveRequest No description
ChangeUserRoleRequest No description
CreateProjectRequest No description
DeleteMemberRequest No description
ExistsRequest No description
InviteRequest No description
ListFavoriteProjectsRequest No description
ListIngoingInvitesRequest No description
ListOutgoingInvitesRequest No description
ListProjectsRequest No description
ListSubProjectsRequest The base type for requesting paginated content.
LookupByIdBulkRequest No description
LookupByIdRequest No description
LookupByTitleRequest No description
ProjectSearchByPathRequest The base type for requesting paginated content.
RejectInviteRequest No description
RenameProjectRequest No description
ToggleRenamingRequest No description
TransferPiRoleRequest No description
UpdateDataManagementPlanRequest No description
ViewMemberInProjectRequest No description
ViewProjectRequest No description
AllowsRenamingResponse No description
ExistsResponse No description
FetchDataManagementPlanResponse No description
LookupPrincipalInvestigatorResponse No description
ViewMemberInProjectResponse No description

Remote Procedure Calls

allowsRenaming

API: Internal/Beta Auth: Authenticated

Request Response Error
AllowsRenamingRequest AllowsRenamingResponse CommonErrorMessage

allowsSubProjectRenaming

API: Internal/Beta Auth: Authenticated

Request Response Error
AllowsRenamingRequest AllowsRenamingResponse CommonErrorMessage

countSubProjects

API: Internal/Beta Auth: Authenticated

Request Response Error
Unit Long CommonErrorMessage

fetchDataManagementPlan

API: Internal/Beta Auth: Users

Request Response Error
Unit FetchDataManagementPlanResponse CommonErrorMessage

listFavoriteProjects

API: Internal/Beta Auth: Authenticated

Request Response Error
ListFavoriteProjectsRequest Page<UserProjectSummary> CommonErrorMessage

listProjects

API: Internal/Beta Auth: Authenticated

Request Response Error
ListProjectsRequest Page<UserProjectSummary> CommonErrorMessage

lookupById

API: Internal/Beta Auth: Services

Request Response Error
LookupByIdRequest Project CommonErrorMessage

lookupByIdBulk

API: Internal/Beta Auth: Services

Request Response Error
LookupByIdBulkRequest List<Project> CommonErrorMessage

lookupByPath

API: Internal/Beta Auth: Services

Request Response Error
LookupByTitleRequest Project CommonErrorMessage

lookupPrincipalInvestigator

API: Internal/Beta Auth: Services

Request Response Error
Unit LookupPrincipalInvestigatorResponse CommonErrorMessage

viewAncestors

API: Internal/Beta Auth: Authenticated

Request Response Error
Unit List<Project> CommonErrorMessage

viewMemberInProject

API: Internal/Beta Auth: ADMIN, SERVICE, PROVIDER

Request Response Error
ViewMemberInProjectRequest ViewMemberInProjectResponse CommonErrorMessage

acceptInvite

API: Internal/Beta Auth: Authenticated

Request Response Error
AcceptInviteRequest Unit CommonErrorMessage

archive

API: Internal/Beta Auth: Authenticated

Request Response Error
ArchiveRequest Unit CommonErrorMessage

archiveBulk

API: Internal/Beta Auth: Authenticated

Request Response Error
ArchiveBulkRequest Unit CommonErrorMessage

changeUserRole

API: Internal/Beta Auth: Authenticated

Request Response Error
ChangeUserRoleRequest Unit CommonErrorMessage

create

API: Internal/Beta Auth: Authenticated

Request Response Error
CreateProjectRequest FindByStringId CommonErrorMessage

deleteMember

API: Internal/Beta Auth: Authenticated

Request Response Error
DeleteMemberRequest Unit CommonErrorMessage

exists

API: Internal/Beta Auth: Services

Request Response Error
ExistsRequest ExistsResponse CommonErrorMessage

invite

API: Internal/Beta Auth: Authenticated

Request Response Error
InviteRequest Unit CommonErrorMessage

leaveProject

API: Internal/Beta Auth: Authenticated

Request Response Error
Unit Unit CommonErrorMessage

listIngoingInvites

API: Internal/Beta Auth: Authenticated

Request Response Error
ListIngoingInvitesRequest Page<IngoingInvite> CommonErrorMessage

listOutgoingInvites

API: Internal/Beta Auth: Authenticated

Request Response Error
ListOutgoingInvitesRequest Page<OutgoingInvite> CommonErrorMessage

listSubProjects

API: Internal/Beta Auth: Authenticated

Request Response Error
ListSubProjectsRequest PageV2<MemberInProject> CommonErrorMessage

rejectInvite

API: Internal/Beta Auth: Authenticated

Request Response Error
RejectInviteRequest Unit CommonErrorMessage

rename

API: Internal/Beta Auth: Authenticated

Request Response Error
RenameProjectRequest Unit CommonErrorMessage

toggleRenaming

API: Internal/Beta Auth: Authenticated

Request Response Error
ToggleRenamingRequest Unit CommonErrorMessage

transferPiRole

API: Internal/Beta Auth: Authenticated

Request Response Error
TransferPiRoleRequest Unit CommonErrorMessage

updateDataManagementPlan

API: Internal/Beta Auth: Users

Request Response Error
UpdateDataManagementPlanRequest Unit CommonErrorMessage

verifyMembership

API: Internal/Beta Auth: Authenticated

Request Response Error
Unit Unit CommonErrorMessage

viewProject

API: Internal/Beta Auth: Authenticated

Request Response Error
ViewProjectRequest UserProjectSummary CommonErrorMessage

Data Models

IngoingInvite

API: Internal/Beta

data class IngoingInvite(
    val project: String,
    val title: String,
    val invitedBy: String,
    val timestamp: Long,
)
Properties
project: String
title: String
invitedBy: String
timestamp: Long

MemberInProject

API: Internal/Beta

data class MemberInProject(
    val role: ProjectRole?,
    val project: Project,
)
Properties
role: ProjectRole?
project: Project

OutgoingInvite

API: Internal/Beta

data class OutgoingInvite(
    val username: String,
    val invitedBy: String,
    val timestamp: Long,
)
Properties
username: String
invitedBy: String
timestamp: Long

Project

API: Internal/Beta

data class Project(
    val id: String,
    val title: String,
    val parent: String?,
    val archived: Boolean,
    val fullPath: String?,
)
Properties
id: String
title: String
parent: String?
archived: Boolean
fullPath: String?

ProjectMember

API: Internal/Beta

data class ProjectMember(
    val username: String,
    val role: ProjectRole,
    val memberOfAnyGroup: Boolean?,
)
Properties
username: String
role: ProjectRole
memberOfAnyGroup: Boolean?

ProjectRole

API: Internal/Beta

enum class ProjectRole {
    PI,
    ADMIN,
    USER,
}
Properties
PI
ADMIN
USER

UserProjectSummary

API: Internal/Beta

data class UserProjectSummary(
    val projectId: String,
    val title: String,
    val whoami: ProjectMember,
    val needsVerification: Boolean,
    val isFavorite: Boolean,
    val archived: Boolean,
    val parent: String?,
    val ancestorPath: String?,
)
Properties
projectId: String
title: String
whoami: ProjectMember
needsVerification: Boolean
isFavorite: Boolean
archived: Boolean
parent: String?
ancestorPath: String?

AcceptInviteRequest

API: Internal/Beta

data class AcceptInviteRequest(
    val projectId: String,
)
Properties
projectId: String

AllowsRenamingRequest

API: Internal/Beta

data class AllowsRenamingRequest(
    val projectId: String,
)
Properties
projectId: String

ArchiveBulkRequest

API: Internal/Beta

data class ArchiveBulkRequest(
    val projects: List<UserProjectSummary>,
)
Properties
projects: List<UserProjectSummary>

ArchiveRequest

API: Internal/Beta

data class ArchiveRequest(
    val archiveStatus: Boolean,
)
Properties
archiveStatus: Boolean

ChangeUserRoleRequest

API: Internal/Beta

data class ChangeUserRoleRequest(
    val projectId: String,
    val member: String,
    val newRole: ProjectRole,
)
Properties
projectId: String
member: String
newRole: ProjectRole

CreateProjectRequest

API: Internal/Beta

data class CreateProjectRequest(
    val title: String,
    val parent: String?,
    val principalInvestigator: String?,
)
Properties
title: String
parent: String?
principalInvestigator: String?

DeleteMemberRequest

API: Internal/Beta

data class DeleteMemberRequest(
    val projectId: String,
    val member: String,
)
Properties
projectId: String
member: String

ExistsRequest

API: Internal/Beta

data class ExistsRequest(
    val projectId: String,
)
Properties
projectId: String

InviteRequest

API: Internal/Beta

data class InviteRequest(
    val projectId: String,
    val usernames: List<String>,
)
Properties
projectId: String
usernames: List<String>

ListFavoriteProjectsRequest

API: Internal/Beta

data class ListFavoriteProjectsRequest(
    val user: String?,
    val itemsPerPage: Int,
    val page: Int,
    val archived: Boolean,
    val showAncestorPath: Boolean?,
)
Properties
user: String?
itemsPerPage: Int
page: Int
archived: Boolean
showAncestorPath: Boolean?

ListIngoingInvitesRequest

API: Internal/Beta

data class ListIngoingInvitesRequest(
    val itemsPerPage: Int?,
    val page: Int?,
)
Properties
itemsPerPage: Int?
page: Int?

ListOutgoingInvitesRequest

API: Internal/Beta

data class ListOutgoingInvitesRequest(
    val itemsPerPage: Int?,
    val page: Int?,
)
Properties
itemsPerPage: Int?
page: Int?

ListProjectsRequest

API: Internal/Beta

data class ListProjectsRequest(
    val user: String?,
    val itemsPerPage: Int?,
    val page: Int?,
    val archived: Boolean?,
    val noFavorites: Boolean?,
    val showAncestorPath: Boolean?,
)
Properties
user: String?
itemsPerPage: Int?
page: Int?
archived: Boolean?
noFavorites: Boolean?
showAncestorPath: Boolean?

ListSubProjectsRequest

API: Internal/Beta

The base type for requesting paginated content.

data class ListSubProjectsRequest(
    val itemsPerPage: Int?,
    val next: String?,
    val consistency: PaginationRequestV2Consistency?,
    val itemsToSkip: Long?,
)

Paginated content can be requested with one of the following consistency guarantees, this greatly changes the semantics of the call:

Consistency Description
PREFER Consistency is preferred but not required. An inconsistent snapshot might be returned.
REQUIRE Consistency is required. A request will fail if consistency is no longer guaranteed.

The consistency refers to if collecting all the results via the pagination API are consistent. We consider the results to be consistent if it contains a complete view at some point in time. In practice this means that the results must contain all the items, in the correct order and without duplicates.

If you use the PREFER consistency then you may receive in-complete results that might appear out-of-order and can contain duplicate items. UCloud will still attempt to serve a snapshot which appears mostly consistent. This is helpful for user-interfaces which do not strictly depend on consistency but would still prefer something which is mostly consistent.

The results might become inconsistent if the client either takes too long, or a service instance goes down while fetching the results. UCloud attempts to keep each next token alive for at least one minute before invalidating it. This does not mean that a client must collect all results within a minute but rather that they must fetch the next page within a minute of the last page. If this is not feasible and consistency is not required then PREFER should be used.


📝 NOTE: Services are allowed to ignore extra criteria of the request if the next token is supplied. This is needed in order to provide a consistent view of the results. Clients should provide the same criterion as they paginate through the results.


Properties
itemsPerPage: Int? Requested number of items per page. Supported values: 10, 25, 50, 100, 250.
next: String? A token requesting the next page of items
consistency: PaginationRequestV2Consistency? Controls the consistency guarantees provided by the backend
itemsToSkip: Long? Items to skip ahead

LookupByIdBulkRequest

API: Internal/Beta

data class LookupByIdBulkRequest(
    val ids: List<String>,
)
Properties
ids: List<String>

LookupByIdRequest

API: Internal/Beta

data class LookupByIdRequest(
    val id: String,
)
Properties
id: String

LookupByTitleRequest

API: Internal/Beta

data class LookupByTitleRequest(
    val title: String,
)
Properties
title: String

ProjectSearchByPathRequest

API: Internal/Beta

The base type for requesting paginated content.

data class ProjectSearchByPathRequest(
    val path: String,
    val itemsPerPage: Int?,
    val next: String?,
    val consistency: PaginationRequestV2Consistency?,
    val itemsToSkip: Long?,
    val includeFullPath: Boolean?,
)

Paginated content can be requested with one of the following consistency guarantees, this greatly changes the semantics of the call:

Consistency Description
PREFER Consistency is preferred but not required. An inconsistent snapshot might be returned.
REQUIRE Consistency is required. A request will fail if consistency is no longer guaranteed.

The consistency refers to if collecting all the results via the pagination API are consistent. We consider the results to be consistent if it contains a complete view at some point in time. In practice this means that the results must contain all the items, in the correct order and without duplicates.

If you use the PREFER consistency then you may receive in-complete results that might appear out-of-order and can contain duplicate items. UCloud will still attempt to serve a snapshot which appears mostly consistent. This is helpful for user-interfaces which do not strictly depend on consistency but would still prefer something which is mostly consistent.

The results might become inconsistent if the client either takes too long, or a service instance goes down while fetching the results. UCloud attempts to keep each next token alive for at least one minute before invalidating it. This does not mean that a client must collect all results within a minute but rather that they must fetch the next page within a minute of the last page. If this is not feasible and consistency is not required then PREFER should be used.


📝 NOTE: Services are allowed to ignore extra criteria of the request if the next token is supplied. This is needed in order to provide a consistent view of the results. Clients should provide the same criterion as they paginate through the results.


Properties
path: String
itemsPerPage: Int? Requested number of items per page. Supported values: 10, 25, 50, 100, 250.
next: String? A token requesting the next page of items
consistency: PaginationRequestV2Consistency? Controls the consistency guarantees provided by the backend
itemsToSkip: Long? Items to skip ahead
includeFullPath: Boolean?

RejectInviteRequest

API: Internal/Beta

data class RejectInviteRequest(
    val username: String?,
    val projectId: String,
)
Properties
username: String?
projectId: String

RenameProjectRequest

API: Internal/Beta

data class RenameProjectRequest(
    val id: String,
    val newTitle: String,
)
Properties
id: String
newTitle: String

ToggleRenamingRequest

API: Internal/Beta

data class ToggleRenamingRequest(
    val projectId: String,
)
Properties
projectId: String

TransferPiRoleRequest

API: Internal/Beta

data class TransferPiRoleRequest(
    val newPrincipalInvestigator: String,
)
Properties
newPrincipalInvestigator: String

UpdateDataManagementPlanRequest

API: Internal/Beta

data class UpdateDataManagementPlanRequest(
    val id: String,
    val dmp: String?,
)
Properties
id: String
dmp: String?

ViewMemberInProjectRequest

API: Internal/Beta

data class ViewMemberInProjectRequest(
    val projectId: String,
    val username: String,
)
Properties
projectId: String
username: String

ViewProjectRequest

API: Internal/Beta

data class ViewProjectRequest(
    val id: String,
)
Properties
id: String

AllowsRenamingResponse

API: Internal/Beta

data class AllowsRenamingResponse(
    val allowed: Boolean,
)
Properties
allowed: Boolean

ExistsResponse

API: Internal/Beta

data class ExistsResponse(
    val exists: Boolean,
)
Properties
exists: Boolean

FetchDataManagementPlanResponse

API: Internal/Beta

data class FetchDataManagementPlanResponse(
    val dmp: String?,
)
Properties
dmp: String?

LookupPrincipalInvestigatorResponse

API: Internal/Beta

data class LookupPrincipalInvestigatorResponse(
    val principalInvestigator: String,
)
Properties
principalInvestigator: String

ViewMemberInProjectResponse

API: Internal/Beta

data class ViewMemberInProjectResponse(
    val member: ProjectMember,
)
Properties
member: ProjectMember