Built-in Roles in Kaneo’s Permission System: Viewer, Member, and Admin Explained
Kaneo compiles three core workspace roles—viewer, member, and admin—into its permission package via the DEFAULT_ROLE_NAMES constant, while treating the owner role as a separate system-level designation.
The open-source project management platform Kaneo (available at usekaneo/kaneo) implements a hierarchical permission system using built-in roles that determine access levels across workspaces. These predefined roles form the foundation for all authorization checks, ensuring that workspace members have appropriate capabilities for their responsibilities without requiring manual permission configuration.
The Three Built-in Roles in Kaneo
According to the source code in packages/permissions/src/index.ts, Kaneo defines exactly three compiled-in workspace roles through the DEFAULT_ROLE_NAMES constant. These roles provide tiered access control ranging from read-only observation to full administrative capabilities.
Viewer (Read-Only Access)
The viewer role provides read-only access to workspace resources. Users assigned this role can view tasks, projects, and workspace data but cannot modify them. This role suits stakeholders who need visibility into project progress without the ability to create or edit content.
Member (Standard Contributor)
The member role represents the standard contributor level. Members can create tasks, add comments, and perform most day-to-day project management actions. This role targets active team members who contribute to workstreams but do not require administrative privileges over the workspace configuration.
Admin (Full Workspace Administration)
The admin role grants full workspace administration capabilities. Admins can manage tasks, projects, users, and workspace settings, including the ability to modify or delete resources created by other users. This role is reserved for team leads and workspace managers who need complete control over the environment.
Where Built-in Roles Are Defined in the Source Code
The canonical definition of built-in roles resides in packages/permissions/src/index.ts, where the system exports the DEFAULT_ROLE_NAMES constant as a frozen array:
// packages/permissions/src/index.ts
export const DEFAULT_ROLE_NAMES = ["viewer", "member", "admin"] as const;
This TypeScript as const assertion ensures type safety throughout the application, allowing the compiler to enforce that role strings match only these three values.
Important Distinction: The owner role exists at the system level (automatically assigned to the workspace creator) but is not part of the compiled-in DEFAULT_ROLE_NAMES set. The owner designation is handled separately in the workspace creation logic found in apps/api/src/auth.ts.
Implementing Permission Checks with Built-in Roles
Kaneo leverages these built-in roles for middleware-based authorization. The requireWorkspacePermission function from @kaneo/permissions validates that the authenticated member’s role satisfies the required action.
// Permission check in a route controller
import { requireWorkspacePermission } from "@kaneo/permissions";
import { createRoute } from "your-router";
export const createTask = createRoute({
method: "post",
path: "/tasks",
middleware: [requireWorkspacePermission("task:create")],
handler: async (req, res) => {
// Task creation logic executes only for members and admins
}
});
When creating workspace members programmatically, you must specify one of the built-in role names:
// Creating workspace members with different access levels
const member = await createWorkspaceMember({ role: "member" });
// → Can create tasks and comment, but cannot delete tasks
const admin = await createWorkspaceMember({ role: "admin" });
// → Full management capabilities including user administration
const viewer = await createWorkspaceMember({ role: "viewer" });
// → Read-only access to project data
Seeding Default Roles in New Workspaces
When a workspace is created, Kaneo automatically seeds the database with records for each built-in role. The utility in apps/api/src/utils/seed-default-workspace-roles.ts handles this initialization:
// Seeding default roles for a new workspace
import { DEFAULT_ROLE_NAMES, defaultRolePayloads } from "@kaneo/permissions";
async function seedDefaultRoles(workspaceId: string) {
for (const name of DEFAULT_ROLE_NAMES) {
await db.insertInto("workspace_role")
.values({
workspace_id: workspaceId,
name,
...defaultRolePayloads[name]
})
.execute();
}
}
This ensures that every workspace starts with the complete permission structure defined in the workspace_role table.
Custom Roles and Fallback Behavior
While Kaneo provides these three built-in roles, the system also supports custom roles defined in the workspace_role database table. When resolving permissions, the system first checks for a custom role matching the member’s assignment. If the specific custom role is missing or undefined, Kaneo falls back to the built-in role of the same name, ensuring that the DEFAULT_ROLE_NAMES always serve as the authoritative baseline for access control.
Summary
- Kaneo defines three built-in roles—viewer, member, and admin—through the
DEFAULT_ROLE_NAMESconstant inpackages/permissions/src/index.ts. - The viewer role provides read-only access, member enables standard contributions, and admin grants full workspace management.
- The owner role exists separately at the system level and is automatically assigned to workspace creators, distinct from the compiled-in set.
- Built-in roles serve as the fallback mechanism when custom roles are undefined, ensuring consistent permission resolution.
Frequently Asked Questions
What are the three built-in roles in Kaneo?
Kaneo defines three core workspace roles: viewer (read-only access to tasks and projects), member (ability to create tasks and comments), and admin (full workspace management including user and settings control). These are compiled into the application via the DEFAULT_ROLE_NAMES constant.
How do I assign a built-in role to a workspace member?
Assign a built-in role by passing one of the three valid strings—"viewer", "member", or "admin"—to the role parameter when calling createWorkspaceMember(). The system validates this against the DEFAULT_ROLE_NAMES array defined in the permissions package.
Is the owner role a built-in role in Kaneo?
No, the owner role is not part of the built-in DEFAULT_ROLE_NAMES set. According to the source code in apps/api/src/auth.ts, the owner designation is added automatically for the workspace creator at the system level, separate from the three compiled-in roles.
Where are the default roles defined in the Kaneo codebase?
The default roles are defined in packages/permissions/src/index.ts as the exported constant DEFAULT_ROLE_NAMES = ["viewer", "member", "admin"]. This file also contains the defaultRolePayloads object used during workspace seeding, while database seeding logic resides in apps/api/src/utils/seed-default-workspace-roles.ts.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →