Manage Folder Permissions & Sharing

Author: James Derick Billate
Reviewer:
Creation Date: July 2, 2026
Status: Approved and Merged
References: https://github.com/wyzlab/WyzQuests/issues/74

INTRODUCTION AND GOALS

Problem Summary: This feature is related to folder structures that consist of projects, quests, and adventures. Manage Folder Permissions and Sharing (MFPS) allows various individuals to collaborate within a folder without exposing too much information. It supports controlled folder access through permission levels assigned to existing WyzQuests accounts.

Goals and Non-Goals:

  • At first, all created folders are automatically in Private mode, meaning other accounts do not have the ability to access the folder.

  • Assignment of folder access is limited to view, edit, and admin for invited users, with owner used for the folder owner.

  • Email can be used to invite existing accounts.

  • Agency Admin does not automatically have the ability to access other folders created by members unless ownership or permission rules allow it.

  • Parent folder permission inheritance is not yet implemented.


HIGH-LEVEL ARCHITECTURE

System Diagram:

Frontend: Next.js, React, Tailwind CSS, Shadcn Components, Sonner toast.

Backend: RESTful API routes, TypeScript, Zod Validation, Clerk Authentication, agency ownership helpers, Supabase.

Database: Supabase Postgres with folder_permissions, project_folders, quest_folders, adventure_folders, and app_users.

Email: EmailService and renderShareFolderEmail.


DETAILED DESIGN & IMPLEMENTATION

Database Schema

create table public.folder_permissions (
id uuid not null default gen_random_uuid (),
folder_id uuid not null,
user_id uuid not null,
permission_level text not null default 'view'::text,
created_at timestamp with time zone not null default CURRENT_TIMESTAMP,
updated_at timestamp with time zone not null default CURRENT_TIMESTAMP,
constraint folder_permissions_pkey primary key (id),
constraint folder_permissions_unique unique (folder_id, user_id),
constraint folder_permissions_user_id_fkey foreign KEY (user_id) references app_users (id),
constraint folder_permissions_folder_id_exists_check check (folder_permissions_folder_exists (folder_id)),
constraint folder_permissions_permission_level_check check (
(
permission_level = any (
array[
'view'::text,
'edit'::text,
'admin'::text,
'owner'::text
]
)
)
)
) TABLESPACE pg_default;
 
create index IF not exists idx_folder_id on public.folder_permissions using btree (folder_id) TABLESPACE pg_default;
 
create index IF not exists idx_folder_permissions_user_id on public.folder_permissions using btree (user_id) TABLESPACE pg_default;
 
create trigger folder_permissions_updated_at_trigger BEFORE
update on folder_permissions for EACH row
execute FUNCTION update_folder_permissions_updated_at ();

Implementation Notes:

  • folder_id can reference a folder in project_folders, quest_folders, or adventure_folders.

  • folder_permissions_folder_exists(folder_id) validates that the folder exists in at least one supported folder table.

  • permission_level supports view, edit, admin, and owner.

  • folder_id + user_id is unique to prevent duplicate permission rows.

  • Delete triggers clean up permissions when project, quest, or adventure folders are deleted.

  • Owner permissions are assigned through assignOwnerPermission(folder_id, owner_id) where used by folder creation flows.

API Specification:

GET /api/folder/permissions
Fetches all accounts with specified permission levels in the folder.

URL Params: [folder_id]

Status

Return

401

Unauthorized Access

403

User Not Permitted

500

Internal Server Error

200 OK

Permission data returned, including user_id, permission_level, email, and name

POST /api/folder/permissions
Assigns a particular account to a permission level in the folder. Email notification is then sent.

URL Params: [folder_id]

Body: { email: string, permission_level: "view" | "edit" | "admin", folder_type: "project_folders" | "adventure_folders" | "quest_folders" }

Status

Return

401

Unauthorized Access

400

Invalid permissions data

403

User Not Permitted

404

User Not Found

409

Permission already exists for this user in the folder

500

Failed to validate existing permission

or Failed to add Permissions

200 OK

Permission added!

PATCH /api/folder/permissions
Reassigns a particular account to a different permission level.

URL Params: [folder_id]

Body: { permission_level: "view" | "edit" | "admin", user_id_permission: string }

Status

Return

401

Unauthorized Access

400

Invalid permissions data

403

User Not Permitted

500

Permission Not Updated

200 OK

Permission Updated

DELETE /api/folder/permissions
Removes a particular account from the folder and revokes all access to it.

URL Params: [folder_id]

Body: { user_id_permission: string }

Status

Return

401

Unauthorized Access

400

Invalid permissions data

403

User Not Permitted

500

Permission Not Revoked

200 OK

Permission Revoked

API Helpers

  • validateFolder(folder_type: string, folder_id: string, authContext): Checks the database if the folder exists and is connected with the authenticated user's allowed ownership scope.

  • validateUser(email: string): Checks if the user exists within the system and is a registered WyzQuests user.

  • validateEditPermission(folder_id: string, authContext): Validates if permission to edit/manage permissions is permitted to the requester. View-only users are denied.

  • validateViewPermission(folder_id: string, authContext): Validates if permission to view is permitted to the requester.

  • isFolderOwner(folder_id: string, authContext): Validates if the folder is created by the authenticated user or is within allowed agency resource ownership.

  • getFolderDetails(folder_type: string, folder_id: string): Fetches the folder name.

  • getUserName(user_id: string): Fetches the invitee username.

Core Logic and Workflow:

  • User signs in as Creator or Agency Admin.

  • User opens Content Library or Library.

  • User creates or selects a project, quest, or adventure folder.

  • User opens the folder menu and clicks Permissions.

  • FolderPermissionsModal fetches current permissions using GET.

  • User enters an existing WyzQuests account email.

  • User selects permission level.

  • POST validates payload, folder access, folder existence, and target user.

  • POST prevents duplicate permission rows.

  • Permission row is inserted.

  • Email notification is queued with after() using EmailService.

  • User can PATCH permission level or DELETE the permission.


INFRASTRUCTURE & OPERATIONS

Dependencies: This feature is primarily dependent on the folder structure of Quests, Adventures, and Projects. It is also connected with Agency Admin workflow and member collaboration. Zod validation is used for data integrity and correctness.

Monitoring and Alerting:

  • No major monitoring is needed because most functionality is CRUD of permissions to accounts being invited or revoked.

  • Most errors are displayed via toast notifications.

  • Monitor failed folder permission API calls.

  • Monitor email delivery failures for folder share notifications.

  • Monitor duplicate permission conflicts and user-not-found rates to improve UX.

Deployment Plan:

  • Migrate the tables of project_folders, adventure_folders, and quest_folders.

  • Ensure that CRUD APIs for all folder structures are implemented and work as intended.

  • Migrate the table of folder_permissions.

  • Ensure that CRUD APIs for folder permissions are implemented and work as intended.

  • Ensure folder permission cleanup triggers are deployed.

  • Ensure email service configuration is available.

  • Apply UI/UX testing to ensure endpoints are called with intended functions.


TESTING AND QUALITY ASSURANCE

Testing Strategy:

  • Sign in as a Creator or Agency Admin.

  • Navigate through the unified sidebar and choose Content Library for Creators or Library for Agency Admin.

  • Generate a folder for projects, quests, or adventures.

  • Click the kebab icon beside the folder name.

  • Click Permissions and input an email, then submit.

  • Do all CRUD functionalities to ensure API endpoints work accurately.

  • Verify GET returns current permission list.

  • Verify POST adds view, edit, and admin permissions.

  • Verify PATCH changes permission levels.

  • Verify DELETE revokes access.

  • Verify duplicate permission returns conflict.

  • Verify nonexistent email returns user not found.

  • Verify view-only users cannot manage permissions.

  • Verify email notification is sent after adding permission.

Known Limitations:

  • Currently a basic implementation of adding accounts with their respective folder permission levels.

  • No real logic of showing the shared folder yet in some user-facing surfaces may still need validation.

  • Acquisition of parent folder permission level per account is not yet implemented.

  • Pending invites for users who do not yet have WyzQuests accounts are not implemented.


MAINTENANCE AND SUPPORT

Troubleshooting:

  • Re-migrate the folder_permissions table if permission rows or constraints are missing.

  • Ensure that all APIs related to folder_permissions are implemented accurately.

  • Check if the target email belongs to an existing app_users record.

  • Check whether requester has owner, admin, or edit permission.

  • Check folder type matches project_folders, quest_folders, or adventure_folders.

  • Check email service if the account invite was sent successfully; if not, check Emailit/email provider limits.


Document Version

1.0 - Documentation draft, feature is merged, 07/02/2026

1.2 - Documentation draft, feature is merged, added documentation information 07/03/2026

1.3 - Enhanced documentation of MFPS, 07/10/2026


Was this article helpful?