Get started
Folder management
Folder management is used to organize documents in a hierarchical structure. A folder is a group of documents which can be shared with users or teams. A document can be a single 2D grid note (board), a notebook, or a PDF.
Folder model
Name | Description |
---|---|
_id | Folder ID |
name | Folder name |
project | Project ID |
parent | Parent folder ID |
childrens | Array of { item: ID, itemType: string } |
users | Array of User ID |
teams | Array of Team ID |
inheritPermissions | Whether to inherit permissions from parent (default: true) |
createdAt | Folder created date |
updateDate | Last Update Date |
Supported document types
The childrens
array can contain different types of documents:
Type | Description |
---|---|
Folder | Subfolder for organizing content |
Board | 2D grid note/board |
Notebook | Notebook document |
Asset | Uploaded file (PDF, images, etc.) |
UserInputForm | Static output / user input form |
Each document type may have its own specific permission settings in addition to folder-level permissions.
Permission inheritance
Folders can be configured to either inherit permissions from their parent folder or maintain their own independent permissions:
-
Inheritance enabled (default):
- Folder automatically inherits user and team permissions from parent
- Changes to parent folder permissions propagate to child folders
- Moving folder to new parent updates permissions unless explicitly kept
-
Independent permissions:
- Set
inheritPermissions: false
to maintain separate permissions - Folder keeps its own user and team lists
- Parent folder permission changes don't affect this folder
- Moving folder preserves its permission settings
- Set
Nested Permission Resolution
When checking if a user has access to a document or folder, the system follows these rules:
-
Document Access Check:
Folder Structure:
Folder A
└── Folder B
└── Folder C
└── Document D
Access Path:
Document D → Folder C → Folder B → Folder AThe system checks permissions in this order:
- Document's own permissions (if it has independent permissions)
- Immediate parent folder (Folder C)
- Parent's parent folder (Folder B)
- Root parent folder (Folder A)
-
Permission Inheritance Chain:
- If any folder in the chain has
inheritPermissions: false
:- Only check that folder's permissions
- Stop checking higher-level folders
- Example:
Folder A (users: [1,2,3])
└── Folder B (inheritPermissions: true)
└── Folder C (inheritPermissions: false, users: [4,5])
└── Document D- Document D is only accessible by users [4,5]
- Even though it's in Folder A, users [1,2,3] cannot access it
- Folder C breaks the inheritance chain
- If any folder in the chain has
-
Moving Folders and Permissions:
Initial Structure:
Folder X (users: [1,2])
└── Folder A
└── Folder B (inheritPermissions: true)
└── Document 1
Folder Y (users: [3,4])
└── Folder C
└── Folder D (inheritPermissions: true)After moving Folder B to Folder D:
Folder X (users: [1,2])
└── Folder A
Folder Y (users: [3,4])
└── Folder C
└── Folder D (inheritPermissions: true)
└── Folder B (inheritPermissions: true)
└── Document 1Permission handling during move:
-
Default Behavior (keepPermissions: false):
- Folder B inherits permissions from new parent (Folder D)
- Document 1 now accessible by users [3,4]
- Original permissions from Folder A [1,2] are no longer applied
-
Keep Original (keepPermissions: true):
- Folder B keeps its inherited permissions from Folder A
- Document 1 still accessible by users [1,2]
- New parent permissions [3,4] not applied
-
Independent Permissions:
- If Folder B has inheritPermissions: false
- Its permissions remain unchanged during move
- Not affected by either old or new parent
-
Permission Check Algorithm
async function hasAccess(userId, itemId, userTeams = []) {
const item = await findItem(itemId);
if (!item) return false;
// Check if user/team has direct access to item
if (item.users?.includes(userId)) return true;
if (item.teams?.some(teamId => userTeams.includes(teamId))) return true;
// If item doesn't inherit and no direct access, deny
if (!item.inheritPermissions) return false;
// Follow permission chain up through parent folders
let currentFolder = await findFolder(item.parent);
while (currentFolder) {
// Check current folder permissions
if (currentFolder.users?.includes(userId)) return true;
if (currentFolder.teams?.some(teamId => userTeams.includes(teamId)))
return true;
// Stop if current folder doesn't inherit
if (!currentFolder.inheritPermissions) break;
// Move up to parent
currentFolder = await findFolder(currentFolder.parent);
}
// No access found in permission chain
return false;
}
Example permission chain scenarios:
Scenario 1: Basic Inheritance with Users
Folder A (users: [1,2])
└── Folder B (inheritPermissions: true)
└── Document X
Result: User 1 has access to Document X
Scenario 2: Basic Inheritance with Users and Teams
Folder A (users: [1], teams: ['team1'])
└── Folder B (inheritPermissions: true)
└── Folder C (inheritPermissions: true)
└── Document W
Result: User 1 and team1 members have access to Document W (full inheritance chain)
Scenario 3: Break in Inheritance Chain
Folder A (users: [1,2])
└── Folder B (inheritPermissions: false, users: [3])
└── Document Y
Result: User 1 cannot access Document Y
Scenario 4: Team Access
Folder A (teams: ['team1'])
└── Folder B (inheritPermissions: true)
└── Document Z
Result: Users in team1 have access to Document Z
Scenario 5: Mixed Inheritance
Folder A (users: [1], teams: ['team1'])
└── Folder B (inheritPermissions: true)
└── Folder C (inheritPermissions: false, users: [2])
└── Document W
Result: Only user 2 has access to Document W (Folder C breaks inheritance)