Organization and Membership
This document describes organizations (tenants) and membership (users in orgs with roles): OrganizationService and MembershipService, protos, handlers, and how they relate to the dashboard and RBAC. For auth and session behavior, see auth and sessions.
Audience: Developers working on multi-tenancy, org admin flows, or RBAC.
Overview
- Organizations: Tenants; each has an id, name, and status (Active, Suspended). Defined in proto/organization/organization.proto.
- Membership: A user belongs to an org with a role: Owner, Admin, or Member. MembershipService manages add/remove/update-role and list. Org-admin actions (e.g. dashboard Members page) are restricted to RequireOrgAdmin (owner or admin); see platform RBAC.
OrganizationService
- Proto: backend/proto/organization/organization.proto. Handler: internal/organization/handler/grpc.go.
- RPCs:
- CreateOrganization: Create a new org by name and assign the creating user as owner. Public endpoint (no authentication required).
- GetOrganization: Get org by id.
- ListOrganizations: List orgs with pagination (common.Pagination).
- SuspendOrganization: Set org status to Suspended.
Organization message: id, name, status (OrganizationStatus: ACTIVE, SUSPENDED), created_at.
CreateOrganization
Creates a new organization with the given name and automatically assigns the creating user as the owner. The organization is created with active status (auto-activated for PoC). This is a public endpoint that does not require authentication, allowing newly registered users to create organizations before they can log in.
Request (CreateOrganizationRequest):
name(string, required): Organization name. Must be non-empty after trimming whitespace.user_id(string, required): ID of the user creating the organization. The user must exist in the system.
Response (CreateOrganizationResponse):
organization(Organization): The created organization with generatedid,name,status(ACTIVE), andcreated_attimestamp.
Validation:
namemust be non-empty after trimming whitespace. ReturnsInvalidArgumentif empty.user_idmust be non-empty after trimming whitespace. ReturnsInvalidArgumentif empty.- User must exist in the system. Returns
NotFoundif user does not exist.
Business Logic:
- Validates request parameters (
nameanduser_id). - Verifies the user exists by querying the user repository.
- Generates a unique organization ID (UUID).
- Creates the organization with:
- Generated
id - Provided
name statusset toACTIVE(auto-activated for PoC)created_atset to current UTC timestamp
- Generated
- Creates a membership record linking the user to the organization with
role=owner. - Returns the created organization.
Error Handling:
InvalidArgument(400): Missing or emptynameoruser_id.NotFound(404): User with the provideduser_iddoes not exist.Internal(500): Database error during organization or membership creation.
Security Considerations:
- This endpoint is public (no Bearer token required) because users need to create organizations before they can log in and obtain tokens.
- User validation ensures only registered users can create organizations.
- The creating user is automatically assigned the
ownerrole, giving them full administrative control. - Note: In the current PoC implementation, organization creation and membership creation are not wrapped in a database transaction. If membership creation fails after organization creation, the organization will remain in the database without an owner. In production, this should be implemented as a transaction to ensure atomicity.
Example Flow (two ways to obtain user_id):
-
After registration: User registers via
AuthService.Registerand receivesuser_id. User (or frontend) callsCreateOrganizationwithnameanduser_id. System creates organization and owner membership. User logs in using the returned organizationidasorg_id. -
From login page (existing or new user): User goes to the login page and uses the "Create new" flow. Frontend calls
AuthService.VerifyCredentials(email, password) to getuser_id, then callsCreateOrganizationwithnameanduser_id. System creates organization and owner membership. Frontend then logs the user in with the new org.
MembershipService
- Proto: backend/proto/membership/membership.proto. Handler: internal/membership/handler/grpc.go.
- RPCs:
- AddMember: Add a user to an org with a role (org_id, user_id, Role).
- RemoveMember: Remove a user from an org.
- UpdateRole: Change a member’s role (org_id, user_id, Role).
- ListMembers: List members of an org with pagination.
Role enum: ROLE_OWNER, ROLE_ADMIN, ROLE_MEMBER. Member message: id, user_id, org_id, role, created_at.
Org-admin operations (e.g. AddMember, RemoveMember, UpdateRole, ListMembers for the dashboard) are protected by RequireOrgAdmin so only owner or admin of that org can call them. The dashboard Members page uses API routes that call these RPCs; see Frontend Dashboard (Members section).
Organization Creation Flow
A user may obtain user_id from Register (after signup) or from VerifyCredentials (e.g. when using the login page "Create new" tab). With that user_id, they have no organization membership until they create or join an org. To log in, the user must either:
-
Create a new organization: Call
OrganizationService.CreateOrganizationwith theiruser_idand an organization name. Theuser_idcomes from Register or from VerifyCredentials. The system will:- Create the organization with
activestatus (auto-activated for PoC) - Create a membership record assigning the user as
owner - Return the organization
idwhich can be used asorg_idfor login
- Create the organization with
-
Join an existing organization: An organization owner or admin can add the user via
MembershipService.AddMember, then the user can log in with that organization'sid.
Auto-Activation Policy: For the PoC, organizations are automatically activated (status=ACTIVE) upon creation. In production, this would typically require platform administrator approval before activation.
Owner Assignment: When a user creates an organization, they are automatically assigned the owner role, giving them full administrative control over the organization, including the ability to add/remove members, update roles, configure policies, and manage sessions.
Transaction Considerations: Currently, organization creation and membership creation are performed sequentially without a database transaction. If membership creation fails after organization creation succeeds, the organization will exist without an owner. This is acceptable for PoC but should be addressed in production with proper transaction handling.