Skip to main content

Organization User

Organization User is a user’s membership in a specific organization, including org-level role, membership status, and site assignments.
// apps/azalt/src/server/db/types/organization.ts (simplified)
interface OrganizationUser {
  id: string;
  organizationId: string;
  userId: string;
  role: "VIEWER" | "COLLECTOR" | "APPROVER" | "MANAGER" | "OWNER";
  status: "ACTIVE" | "INVITED" | "INACTIVE";
  invitationToken?: string | null;
  invitationExpiresAt?: Date | null;
  tags?: string[] | null;
  createdAt: Date;
  updatedAt: Date;
}

At a Glance

  • One membership per (organization, user) pair
  • Role (RBAC) drives permissions; site assignments scope them
  • Status lifecycle: INVITED → ACTIVE → INACTIVE
  • Tags allow lightweight categorization/filters

Roles (RBAC)

  • Viewer: read-only access to assigned sites
  • Collector: can submit/edit data on assigned sites
  • Approver: can approve submissions within assigned sites
  • Manager: manage users, sites, forms within assigned sites
  • Owner: full organizational control
These roles drive authorization across server procedures via site- and role-scoped guards.

Status Lifecycle

  • INVITED (default): created via invitation; limited until acceptance
  • ACTIVE: full membership; operations allowed per role/scope
  • INACTIVE: disabled membership; no access
Invitations are email-based and time-limited. Accepting an invitation activates the membership and may set the user’s current organization if unset.

Constraints & Integrity

  • Unique membership per organization: (organizationId, userId)
  • Deleting a membership cascades its site assignments (via OrganizationUserSite FK)
  • Owner cannot grant themselves more than OWNER; privilege changes follow role guard rules

Site Access (ABAC)

Site access is assigned via the Organization User Site junction. Effective access includes all descendants of the directly assigned sites (computed with a recursive query). Assigning the root site grants access to the entire organization.

Typical Operations

  • List organization users (filtered by caller’s site access)
  • Invite a user with role and site assignments
  • Update a user’s role and optionally (re)assign sites
  • Assign sites to multiple users (bulk: replace/add/remove)
// tRPC (apps/azalt/src/server/api/routers/organization)
organizations.listUsers(): Array<{
  id, name, email, phone, image, status, role,
  createdAt, ownerId, assignedSites: { id, name }[]
}>

organizations.inviteUser({ email, role, assignedSiteIds })
organizations.updateUserRole({ userId, role, assignedSiteIds? })
organizations.updateUserSites({ userId, assignedSiteIds })
organizations.bulkUpdateUserRoles({ userIds, role })
organizations.bulkUpdateUserSites({ userIds, siteIds, operation: "replace" | "add" | "remove" })

Security & Filtering

  • Reads are restricted: viewers/collectors see users inside their accessible site tree; managers/owners see all.
  • Writes are restricted to managers/owners and only within sites they can access.
  • Row Level Security (RLS) and helper guards ensure context safety.

Tips & Edge Cases

  • Users with no site assignments still appear in lists (visible to managers/owners); their effective access is empty.
  • Inviting a user to the root site implicitly grants full organization access (root + descendants).
  • Bulk operations support replace, add, and remove semantics—prefer replace for idempotent updates.
  • User — global identity and profile
  • Organization User Site — site-level access for a membership