packages/database/schema/member.schema.ts - New nested permission structure:
interface TeamPermissions {
admin: { administrator, manageMembers, manageTeams }
content: { manageCategories, manageLabels, manageViews }
tasks: { create, editAny, deleteAny, assign, changeStatus, changePriority }
moderation: { manageComments, approveSubmissions, manageVotes }
}packages/database/src/index.ts:
hasOrgPermission(userId, orgId, "admin.manageTeams")- dot-notation pathsgetOrgPermissions(userId, orgId)- returns merged permissions across all teamsisPlatformAdmin(userId)- checksuser.role === 'admin'
Inheritance: Discord-style "most permissive wins" - if ANY team grants a permission, user has it.
God mode: Platform admins (user.role = 'admin') bypass all org-level permission checks.
packages/database/src/functions/organization.ts:
bootstrapOrganizationAdminTeam(orgId)- creates default "Administrators" team with full permsaddMemberToAdminTeam(orgId, memberId)- adds member to admin team
Called automatically on org creation.
/admin/settings/org/$orgId/teams- team list/admin/settings/org/$orgId/teams/new- create team/admin/settings/org/$orgId/teams/$teamId- edit team (General, Permissions, Members tabs)
All permission checks in apps/backend/routes/api/organization.ts and task.ts use traceOrgPermissionCheck() with the new dot-notation format.