types

package
v1.7.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 12, 2026 License: MIT Imports: 2 Imported by: 0

Documentation

Overview

Package types defines the domain models and types used by the organizations plugin.

Index

Constants

View Source
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"
}

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL