Documentation
¶
Overview ¶
Package types defines the domain models and types used by the organizations plugin.
Index ¶
Constants ¶
const ( // RoleOwner is the organization owner role — full control. RoleOwner = "owner" // RoleAdmin is the organization admin role — can manage members and teams. RoleAdmin = "admin" // RoleMember is the base organization membership role — read access. RoleMember = "member" // RoleTeamLead is the team lead role — can manage team members. RoleTeamLead = "lead" )
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Invitation ¶ added in v1.7.0
type Invitation struct {
ID string `json:"id"` // Unique invitation identifier
OrganizationID string `json:"organizationId"` // Target organization ID (FK)
TeamID *string `json:"teamId"` // Optional team ID (nil = org-level)
Email string `json:"email"` // Invitee email address
Role string `json:"role"` // Role on acceptance ("admin" or "member")
InviterID string `json:"inviterId"` // User who created the invitation (FK)
TokenHash string `json:"-"` // SHA-256 hash of the raw token (never exposed)
Status string `json:"status"` // "pending", "accepted", "declined", "expired"
ExpiresAt time.Time `json:"expiresAt"` // When the invitation expires
CreatedAt time.Time `json:"createdAt"` // When the invitation was created
UpdatedAt time.Time `json:"updatedAt"` // Last status update timestamp
}
Invitation represents a pending invitation to join an organization or team.
Invitations are created by org admins/owners and sent to prospective members via email. A single type covers both org-level and team-level invitations: a nil TeamID means it's an org-level invitation (user will become a member of the organization), while a non-nil TeamID means the user is invited directly to a specific team (and becomes an org member implicitly upon acceptance).
Database Table: invitation Unique Constraint: token_hash Foreign Keys: organization_id → organization.id, team_id → team.id,
inviter_id → auth.users.id
Status Values:
- "pending": Invitation created, awaiting response
- "accepted": Invitee accepted, member records created
- "declined": Invitee declined
- "expired": Past expires_at without acceptance
Security: The raw token is a cryptographically random 32-byte value, base64url-encoded, returned at creation time and never stored. Only the SHA-256 hash (TokenHash) is persisted so a DB leak does not allow bulk-accepting invitations.
Example:
{
"id": "inv_abc123",
"organizationId": "org_xyz789",
"teamId": null,
"email": "newuser@example.com",
"role": "member",
"inviterId": "user_456",
"status": "pending",
"expiresAt": "2024-01-08T00:00:00Z",
"createdAt": "2024-01-01T00:00:00Z",
"updatedAt": "2024-01-01T00:00:00Z"
}
type Member ¶
type Member struct {
ID string `json:"id"` // Unique membership identifier
UserID string `json:"userId"` // User ID (foreign key)
OrganizationID string `json:"organizationId"` // Organization ID (foreign key)
Role string `json:"role"` // Member role ("owner", "admin", "member")
CreatedAt time.Time `json:"createdAt"` // When the user joined the organization
UpdatedAt time.Time `json:"updatedAt"` // Last role update timestamp
}
Member represents a user's membership in an organization with a role.
Members link users to organizations with role-based permissions. The role determines what actions the user can perform within the organization.
Database Table: members Unique Constraint: (user_id, organization_id) Foreign Keys: user_id → auth.users.id, organization_id → organization.id
Roles:
- "owner": Full control, can delete organization and manage all settings
- "admin": Can invite/remove members, create teams, but cannot delete org
- "member": Read access to organization resources, cannot manage
Example:
{
"id": "mem_xyz789",
"userId": "user_123",
"organizationId": "org_abc123",
"role": "admin",
"createdAt": "2024-01-01T00:00:00Z",
"updatedAt": "2024-01-01T00:00:00Z"
}
type Organization ¶
type Organization struct {
ID string `json:"id"` // Unique organization identifier
Name string `json:"name"` // Display name (e.g., "Acme Corporation")
Slug string `json:"slug"` // URL-friendly identifier (e.g., "acme-corp")
CreatedAt time.Time `json:"createdAt"` // When the organization was created
UpdatedAt time.Time `json:"updatedAt"` // Last update timestamp
}
Organization represents a workspace, company, or tenant in a multi-tenant system.
Organizations are the top-level container for resources in a multi-tenant application. Each organization has members with roles and can contain teams for hierarchical access.
Database Table: organization Unique Constraint: slug (for URL-friendly access like /org/acme-corp)
Example:
{
"id": "org_abc123",
"name": "Acme Corporation",
"slug": "acme-corp",
"createdAt": "2024-01-01T00:00:00Z",
"updatedAt": "2024-01-01T00:00:00Z"
}
type OrganizationStore ¶
type OrganizationStore interface {
// CreateOrganization creates a new organization.
//
// Parameters:
// - ctx: Request context
// - id: Unique organization ID
// - name: Organization display name
// - slug: URL-friendly identifier (must be unique)
// - createdAt, updatedAt: Timestamps
//
// Returns:
// - error: Duplicate slug or database error
CreateOrganization(ctx context.Context, id, name, slug string, createdAt, updatedAt time.Time) error
// GetOrganization retrieves an organization by ID.
GetOrganization(ctx context.Context, id string) (Organization, error)
// GetOrganizationBySlug retrieves an organization by slug.
// Used for URL routing like /org/acme-corp.
GetOrganizationBySlug(ctx context.Context, slug string) (Organization, error)
// UpdateOrganization updates organization name and/or slug.
UpdateOrganization(ctx context.Context, id, name, slug string, updatedAt time.Time) error
// DeleteOrganization deletes an organization.
// Should cascade delete members, teams, and team members.
DeleteOrganization(ctx context.Context, id string, updatedAt time.Time) error
// ListUserOrganizations retrieves all organizations a user is a member of.
ListUserOrganizations(ctx context.Context, userID string, offset, limit int) ([]Organization, error)
CountUserOrganizations(ctx context.Context, userID string) (int, error)
// CreateMember adds a user to an organization with a role.
//
// Valid roles: "owner", "admin", "member"
CreateMember(ctx context.Context, id, userID, orgID, role string, createdAt, updatedAt time.Time) error
// GetMember retrieves a user's membership in an organization.
GetMember(ctx context.Context, userID, orgID string) (Member, error)
// Deprecated: Use OrganizationStoreCapabilities.HasOrgRole instead.
IsOrganizationMember(ctx context.Context, userID, orgID string) (bool, error)
// Deprecated: Use HasOrgRole instead.
IsOwnerOrAdmin(ctx context.Context, userID, orgID string) (bool, error)
// IsOwner checks if a user is the organization owner.
// Returns true only if role is "owner".
IsOwner(ctx context.Context, userID, orgID string) (bool, error)
// UpdateMemberRole changes a member's role.
// Caller should verify permissions before calling.
UpdateMemberRole(ctx context.Context, userID, orgID, role string, updatedAt time.Time) error
// RemoveMember removes a user from an organization.
// Should also remove from all teams in the organization.
RemoveMember(ctx context.Context, userID, orgID string) error
// ListOrganizationMembers retrieves all members of an organization.
ListOrganizationMembers(ctx context.Context, orgID string, offset, limit int) ([]Member, error)
CountOrganizationMembers(ctx context.Context, orgID string) (int, error)
// CreateTeam creates a new team within an organization.
CreateTeam(ctx context.Context, id, orgID, name, description string, createdAt, updatedAt time.Time) error
// GetTeam retrieves a team by ID.
GetTeam(ctx context.Context, id string) (Team, error)
// ListTeams retrieves all teams in an organization.
ListTeams(ctx context.Context, orgID string, offset, limit int) ([]Team, error)
CountTeams(ctx context.Context, orgID string) (int, error)
// UpdateTeam updates team name and/or description.
UpdateTeam(ctx context.Context, id, name, description string, updatedAt time.Time) error
// DeleteTeam deletes a team.
// Should cascade delete team members.
DeleteTeam(ctx context.Context, id string) error
// CreateTeamMember adds a user to a team with a role.
//
// Valid roles: "lead", "member"
// User must be an organization member.
CreateTeamMember(ctx context.Context, id, teamID, userID, role string, createdAt, updatedAt time.Time) error
// GetTeamMember retrieves a user's team membership.
GetTeamMember(ctx context.Context, teamID, userID string) (TeamMember, error)
// ListTeamMembers retrieves all members of a team.
ListTeamMembers(ctx context.Context, teamID string, offset, limit int) ([]TeamMember, error)
CountTeamMembers(ctx context.Context, teamID string) (int, error)
// UpdateTeamMemberRole changes a team member's role.
UpdateTeamMemberRole(ctx context.Context, teamID, userID, role string, updatedAt time.Time) error
// RemoveTeamMember removes a user from a team.
RemoveTeamMember(ctx context.Context, teamID, userID string) error
}
OrganizationStore defines the interface for organization storage operations.
This interface abstracts database operations for multi-tenant organization management, including organizations, members, teams, and team members.
Thread Safety: Implementations must be safe for concurrent use from multiple goroutines.
Transaction Considerations: Several operations should be atomic (e.g., CreateOrganization + CreateMember). Implementations should handle this appropriately.
type OrganizationStoreCapabilities ¶ added in v1.7.0
type OrganizationStoreCapabilities interface {
// HasOrgRole checks whether the user has any of the given org-level roles.
HasOrgRole(ctx context.Context, userID, orgID string, roles ...string) (bool, error)
// HasTeamRole checks whether the user has any of the given team-level roles.
HasTeamRole(ctx context.Context, userID, teamID string, roles ...string) (bool, error)
// CanAccessTeam checks whether a user can access a team (org member AND team
// member, any role in each).
CanAccessTeam(ctx context.Context, userID, teamID string) (bool, error)
// CreateInvitation stores a new invitation.
CreateInvitation(ctx context.Context, inv Invitation) error
// GetInvitationByID retrieves an invitation by its ID.
GetInvitationByID(ctx context.Context, id string) (Invitation, error)
// GetInvitationByTokenHash retrieves an invitation by its token hash.
GetInvitationByTokenHash(ctx context.Context, tokenHash string) (Invitation, error)
// ListInvitations returns a paginated list of invitations for an org.
ListInvitations(ctx context.Context, orgID string, teamID string, offset, limit int) ([]Invitation, error)
// CountInvitations returns the total number of invitations matching filters.
CountInvitations(ctx context.Context, orgID string, teamID string) (int, error)
// UpdateInvitationStatus updates the status of an invitation.
UpdateInvitationStatus(ctx context.Context, id, status string, updatedAt time.Time) error
// DeleteInvitation removes an invitation by its ID.
DeleteInvitation(ctx context.Context, id string) error
}
OrganizationStoreCapabilities adds the role-check and invitation operations introduced after v1.6.
The default store implements it. The organizations plugin requires this capability at Init, so a custom store written against the v1.6 OrganizationStore interface keeps compiling, but must implement these methods to use the plugin's role and invitation features.
type Team ¶
type Team struct {
ID string `json:"id"` // Unique team identifier
OrganizationID string `json:"organizationId"` // Parent organization ID
Name string `json:"name"` // Team display name
Description string `json:"description"` // Team purpose/description
CreatedAt time.Time `json:"createdAt"` // When the team was created
UpdatedAt time.Time `json:"updatedAt"` // Last update timestamp
}
Team represents a group within an organization.
Teams provide hierarchical organization within a tenant, allowing for department-level or project-level access control. Teams belong to a single organization and can have members with team-specific roles.
Database Table: team Foreign Key: organization_id → organization.id
Use Cases:
- Department teams ("Engineering", "Sales", "Marketing")
- Project teams ("Product Launch", "Q4 Initiative")
- Access control groups ("Beta Testers", "Premium Features")
Example:
{
"id": "team_def456",
"organizationId": "org_abc123",
"name": "Engineering",
"description": "Software development team",
"createdAt": "2024-01-01T00:00:00Z",
"updatedAt": "2024-01-01T00:00:00Z"
}
type TeamMember ¶
type TeamMember struct {
ID string `json:"id"` // Unique team membership identifier
TeamID string `json:"teamId"` // Team ID (foreign key)
UserID string `json:"userId"` // User ID (foreign key)
Role string `json:"role"` // Team role ("lead", "member")
CreatedAt time.Time `json:"createdAt"` // When the user joined the team
UpdatedAt time.Time `json:"updatedAt"` // Last role update timestamp
}
TeamMember represents a user's membership in a team with a role.
Team members must also be members of the parent organization. Teams provide an additional layer of access control within an organization.
Database Table: team_member Unique Constraint: (team_id, user_id) Foreign Keys: team_id → team.id, user_id → auth.users.id
Roles:
- "lead": Can manage team members and settings
- "member": Participate in team activities
Example:
{
"id": "tmem_ghi789",
"teamId": "team_def456",
"userId": "user_123",
"role": "lead",
"createdAt": "2024-01-01T00:00:00Z",
"updatedAt": "2024-01-01T00:00:00Z"
}