organizations

package
v1.4.0 Latest Latest
Warning

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

Go to latest
Published: Mar 13, 2026 License: MIT Imports: 17 Imported by: 0

Documentation

Overview

Package organizations provides multi-tenancy and team management for Aegis.

This plugin enables SaaS applications to manage multiple organizations (workspaces, companies, tenants) with member roles and team hierarchies. It implements a complete RBAC (Role-Based Access Control) system for organizational resources.

Multi-Tenancy Architecture:

  • Organization: Top-level tenant (e.g., "Acme Corp", "Tech Startup")
  • Members: Users with roles in an organization (owner, admin, member)
  • Teams: Groups within an organization (e.g., "Engineering", "Sales")
  • Team Members: Users with roles in a team (lead, member)

Role Hierarchy:

Organization Roles:
  - owner: Full control, can delete organization, manage all members
  - admin: Can manage members, teams, but cannot delete organization
  - member: Read access to organization resources

Team Roles:
  - lead: Can manage team members and settings
  - member: Participate in team activities

Common Use Cases:

  • SaaS with company workspaces (Slack, Notion, GitHub)
  • Project management tools with teams
  • Enterprise apps with department hierarchies
  • Multi-tenant platforms with access control

Database Schema:

  • organization: Stores organization metadata (id, name, slug)
  • members: Links users to organizations with roles
  • team: Stores team metadata within organizations
  • team_member: Links users to teams with roles

Example Setup:

// Create organization plugin
orgPlugin := organizations.New(nil, plugins.DialectPostgres)

// User creates organization
org, _ := orgPlugin.CreateOrganization(ctx, "Acme Corp", "acme", user.ID)
// User is automatically added as owner

// Owner adds admin
orgPlugin.AddOrganizationMember(ctx, org.ID, adminUserID, "admin")

// Admin creates team
team, _ := orgPlugin.CreateTeam(ctx, org.ID, "Engineering", "Dev team")

// Admin adds team member
orgPlugin.AddTeamMember(ctx, team.ID, devUserID, "member")

Security Features:

  • All routes require authentication (RequireAuthMiddleware)
  • Role-based middleware (RequireOrganizationMember, RequireOrganizationAdmin, RequireOrganizationOwner)
  • Foreign key constraints prevent orphaned records
  • Cascade deletes when organization is deleted

Index

Constants

View Source
const (
	// Request schemas
	SchemaCreateOrganizationRequest    = "CreateOrganizationRequest"
	SchemaUpdateOrganizationRequest    = "UpdateOrganizationRequest"
	SchemaAddOrganizationMemberRequest = "AddOrganizationMemberRequest"
	SchemaUpdateMemberRoleRequest      = "UpdateMemberRoleRequest"
	SchemaCreateTeamRequest            = "CreateTeamRequest"
	SchemaUpdateTeamRequest            = "UpdateTeamRequest"
	SchemaAddTeamMemberRequest         = "AddTeamMemberRequest"
	SchemaUpdateTeamMemberRoleRequest  = "UpdateTeamMemberRoleRequest"

	// Response schemas
	SchemaOrganization     = "Organization"
	SchemaOrganizationList = "OrganizationList"
	SchemaTeam             = "Team"
	SchemaTeamList         = "TeamList"
	SchemaMember           = "Member"
	SchemaMemberList       = "MemberList"
	SchemaTeamMember       = "TeamMember"
	SchemaTeamMemberList   = "TeamMemberList"
)

Schema names for OpenAPI specification generation.

These constants define the OpenAPI schema names for organizations request/response types. They are used in route metadata to generate accurate API documentation with typed request/response examples.

Variables

This section is empty.

Functions

func GetMigrations

func GetMigrations(dialect plugins.Dialect) ([]plugins.Migration, error)

GetMigrations returns all database migrations for the organizations plugin.

This function loads migrations from embedded SQL files and returns them in version order.

Version Numbering:

  • Version 001+: Migrations from migrations/<dialect>/<version>_<description>.<up|down>.sql

Migration File Format:

  • Up migration: 001_initial.up.sql
  • Down migration: 001_initial.down.sql

Parameters:

  • dialect: Database dialect (postgres, mysql, sqlite)

Returns:

  • []plugins.Migration: Sorted list of migrations (oldest first)
  • error: If migration files cannot be read or parsed

func GetSchema

func GetSchema(dialect plugins.Dialect) (*plugins.Schema, error)

GetSchema returns the database schema for the organizations plugin.

The schema defines tables for multi-tenant organization management:

  • organization: Organization metadata (id, name, slug, disabled)
  • members: Organization membership with roles (owner, admin, member)
  • team: Team metadata within organizations
  • team_member: Team membership with roles (lead, member)

All tables include created_at and updated_at timestamps.

Parameters:

  • dialect: Database dialect (postgres, mysql)

Returns:

  • *plugins.Schema: Schema definition with SQL DDL
  • error: If dialect is not supported

func GetSchemaRequirements

func GetSchemaRequirements(dialect plugins.Dialect) []plugins.SchemaRequirement

GetSchemaRequirements returns schema validation requirements for the organizations plugin.

This function defines structural requirements that must be satisfied for the plugin to function correctly. The Init() method validates these requirements at startup.

Validation Checks:

  • Table existence: organization, members, team, team_member
  • Column existence: All required columns in each table
  • Column properties: Data types, nullability (not implemented yet)

These checks help detect schema drift, incomplete migrations, or manual schema changes.

Parameters:

  • dialect: Database dialect (postgres, mysql)

Returns:

  • []plugins.SchemaRequirement: List of validation requirements

Types

type AddOrganizationMemberRequest

type AddOrganizationMemberRequest struct {
	UserID string `json:"userId"` // User ID to add
	Role   string `json:"role"`   // Member role ("admin" or "member")
}

AddOrganizationMemberRequest represents a request to add a member to an organization.

Validation Rules:

  • userId: Required (must be a valid user ID in the system)
  • role: Required, must be "admin" or "member" ("owner" cannot be assigned this way)

Example:

{
  "userId": "user_xyz789",
  "role": "admin"
}

Security Note: The "owner" role cannot be assigned via this endpoint to prevent privilege escalation. Ownership is assigned during organization creation or via explicit transfer (if implemented).

func (AddOrganizationMemberRequest) Validate

func (r AddOrganizationMemberRequest) Validate() error

Validate validates the add organization member request.

type AddTeamMemberRequest

type AddTeamMemberRequest struct {
	UserID string `json:"userId"`
	Role   string `json:"role"`
}

AddTeamMemberRequest represents a request to add a member to a team.

func (AddTeamMemberRequest) Validate

func (r AddTeamMemberRequest) Validate() error

Validate validates the add team member request.

type CreateOrganizationRequest

type CreateOrganizationRequest struct {
	Name string `json:"name"` // Organization display name
	Slug string `json:"slug"` // URL-friendly identifier (must be unique)
}

CreateOrganizationRequest represents a request to create an organization.

Validation Rules:

  • name: Required, 1-100 characters (organization display name)
  • slug: Required, 3-50 characters, lowercase alphanumeric + hyphens only

Example:

{
  "name": "Acme Corporation",
  "slug": "acme-corp"
}

func (CreateOrganizationRequest) Validate

func (r CreateOrganizationRequest) Validate() error

Validate validates the create organization request.

Returns:

  • error: Validation error if name or slug is invalid

type CreateTeamRequest

type CreateTeamRequest struct {
	Name        string `json:"name"`        // Team display name
	Description string `json:"description"` // Team purpose/description
}

CreateTeamRequest represents a request to create a team within an organization.

Validation Rules:

  • name: Required, 1-100 characters (team display name)
  • description: Optional, max 500 characters (team purpose)

Example:

{
  "name": "Engineering",
  "description": "Software development team"
}

func (CreateTeamRequest) Validate

func (r CreateTeamRequest) Validate() error

Validate validates the create team request.

type DefaultOrganizationStore

type DefaultOrganizationStore struct {
	// contains filtered or unexported fields
}

DefaultOrganizationStore implements OrganizationStore using a SQL database.

This implementation uses sqlc-generated type-safe queries to manage organizations, members, teams, and team members in PostgreSQL, MySQL, or SQLite.

Database Tables:

  • organization: Organization metadata (id, name, slug)
  • members: Organization membership with roles
  • team: Team metadata within organizations
  • team_member: Team membership with roles

Constraints:

  • organization.slug: UNIQUE (for URL routing)
  • members(user_id, organization_id): UNIQUE (one membership per user per org)
  • team_member(team_id, user_id): UNIQUE (one membership per user per team)
  • Foreign keys with CASCADE DELETE for referential integrity

Thread Safety: This store is safe for concurrent use through database transactions.

func NewDefaultOrganizationStore

func NewDefaultOrganizationStore(db *sql.DB) *DefaultOrganizationStore

NewDefaultOrganizationStore creates a new DefaultOrganizationStore backed by SQL.

The provided database connection must have the organization schema applied.

Parameters:

  • db: Active SQL database connection

Returns:

  • *DefaultOrganizationStore: Configured store ready for use

func (*DefaultOrganizationStore) CreateMember

func (s *DefaultOrganizationStore) CreateMember(ctx context.Context, id, userID, orgID, role string, createdAt, updatedAt time.Time) error

CreateMember adds a member to an organization.

func (*DefaultOrganizationStore) CreateOrganization

func (s *DefaultOrganizationStore) CreateOrganization(ctx context.Context, id, name, slug string, createdAt, updatedAt time.Time) error

CreateOrganization creates a new organization.

func (*DefaultOrganizationStore) CreateTeam

func (s *DefaultOrganizationStore) CreateTeam(ctx context.Context, id, orgID, name, description string, createdAt, updatedAt time.Time) error

CreateTeam creates a new team within an organization.

func (*DefaultOrganizationStore) CreateTeamMember

func (s *DefaultOrganizationStore) CreateTeamMember(ctx context.Context, id, teamID, userID, role string, createdAt, updatedAt time.Time) error

CreateTeamMember adds a member to a team.

func (*DefaultOrganizationStore) DeleteOrganization

func (s *DefaultOrganizationStore) DeleteOrganization(ctx context.Context, id string, updatedAt time.Time) error

DeleteOrganization soft deletes an organization.

func (*DefaultOrganizationStore) DeleteTeam

func (s *DefaultOrganizationStore) DeleteTeam(ctx context.Context, id string) error

DeleteTeam deletes a team.

func (*DefaultOrganizationStore) GetMember

func (s *DefaultOrganizationStore) GetMember(ctx context.Context, userID, orgID string) (Member, error)

GetMember retrieves a specific member from an organization.

func (*DefaultOrganizationStore) GetOrganization

func (s *DefaultOrganizationStore) GetOrganization(ctx context.Context, id string) (Organization, error)

GetOrganization retrieves an organization by its ID.

func (*DefaultOrganizationStore) GetOrganizationBySlug

func (s *DefaultOrganizationStore) GetOrganizationBySlug(ctx context.Context, slug string) (Organization, error)

GetOrganizationBySlug retrieves an organization by its slug.

func (*DefaultOrganizationStore) GetTeam

func (s *DefaultOrganizationStore) GetTeam(ctx context.Context, id string) (Team, error)

GetTeam retrieves a team by its ID.

func (*DefaultOrganizationStore) GetTeamMember

func (s *DefaultOrganizationStore) GetTeamMember(ctx context.Context, teamID, userID string) (TeamMember, error)

GetTeamMember retrieves a specific team member.

func (*DefaultOrganizationStore) IsOrganizationMember

func (s *DefaultOrganizationStore) IsOrganizationMember(ctx context.Context, userID, orgID string) (bool, error)

IsOrganizationMember checks if a user is a member of an organization.

func (*DefaultOrganizationStore) IsOwner

func (s *DefaultOrganizationStore) IsOwner(ctx context.Context, userID, orgID string) (bool, error)

IsOwner checks if a user is the owner of an organization.

func (*DefaultOrganizationStore) IsOwnerOrAdmin

func (s *DefaultOrganizationStore) IsOwnerOrAdmin(ctx context.Context, userID, orgID string) (bool, error)

IsOwnerOrAdmin checks if a user is an owner or admin of an organization.

func (*DefaultOrganizationStore) ListOrganizationMembers

func (s *DefaultOrganizationStore) ListOrganizationMembers(ctx context.Context, orgID string) ([]Member, error)

ListOrganizationMembers retrieves all members of an organization.

func (*DefaultOrganizationStore) ListTeamMembers

func (s *DefaultOrganizationStore) ListTeamMembers(ctx context.Context, teamID string) ([]TeamMember, error)

ListTeamMembers retrieves all members of a team.

func (*DefaultOrganizationStore) ListTeams

func (s *DefaultOrganizationStore) ListTeams(ctx context.Context, orgID string) ([]Team, error)

ListTeams retrieves all teams in an organization.

func (*DefaultOrganizationStore) ListUserOrganizations

func (s *DefaultOrganizationStore) ListUserOrganizations(ctx context.Context, userID string) ([]Organization, error)

ListUserOrganizations retrieves all organizations for a user.

func (*DefaultOrganizationStore) RemoveMember

func (s *DefaultOrganizationStore) RemoveMember(ctx context.Context, userID, orgID string) error

RemoveMember removes a member from an organization.

func (*DefaultOrganizationStore) RemoveTeamMember

func (s *DefaultOrganizationStore) RemoveTeamMember(ctx context.Context, teamID, userID string) error

RemoveTeamMember removes a member from a team.

func (*DefaultOrganizationStore) UpdateMemberRole

func (s *DefaultOrganizationStore) UpdateMemberRole(ctx context.Context, userID, orgID, role string, updatedAt time.Time) error

UpdateMemberRole updates a member's role in an organization.

func (*DefaultOrganizationStore) UpdateOrganization

func (s *DefaultOrganizationStore) UpdateOrganization(ctx context.Context, id, name, slug string, updatedAt time.Time) error

UpdateOrganization updates an organization's details.

func (*DefaultOrganizationStore) UpdateTeam

func (s *DefaultOrganizationStore) UpdateTeam(ctx context.Context, id, name, description string, updatedAt time.Time) error

UpdateTeam updates a team's details.

func (*DefaultOrganizationStore) UpdateTeamMemberRole

func (s *DefaultOrganizationStore) UpdateTeamMemberRole(ctx context.Context, teamID, userID, role string, updatedAt time.Time) error

UpdateTeamMemberRole updates a team member's role.

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) ([]Organization, 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)

	// IsOrganizationMember checks if a user is a member (any role).
	// Used by middleware for access control.
	IsOrganizationMember(ctx context.Context, userID, orgID string) (bool, error)

	// IsOwnerOrAdmin checks if a user has admin privileges.
	// Returns true if role is "owner" or "admin".
	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) ([]Member, 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) ([]Team, 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) ([]TeamMember, 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 Plugin

type Plugin struct {
	// contains filtered or unexported fields
}

Plugin implements multi-tenant organization and team management.

This plugin provides complete CRUD operations for organizations, members, teams, and team members with role-based access control.

Components:

  • sessionService: User authentication for protected routes
  • store: Database persistence for organizations, members, teams
  • dialect: SQL dialect (PostgreSQL, MySQL, SQLite)

Endpoints Provided:

Organizations: POST, GET, PUT, DELETE /organizations
Members: POST, GET, PATCH, DELETE /organizations/:id/members
Teams: POST, GET, PUT, DELETE /teams, /organizations/:id/teams
Team Members: POST, GET, PATCH, DELETE /teams/:teamId/members

func New

func New(store OrganizationStore, dialect ...plugins.Dialect) *Plugin

New creates a new organizations plugin for multi-tenancy management.

Parameters:

  • store: Organization storage implementation (nil = use DefaultOrganizationStore)
  • dialect: Database dialect (defaults to PostgreSQL)

Returns:

  • *Plugin: Initialized plugin ready for Init() call

Example:

plugin := organizations.New(nil, plugins.DialectPostgres)

func (*Plugin) AddOrganizationMember added in v1.2.1

func (p *Plugin) AddOrganizationMember(ctx context.Context, orgID, userID, role string) error

AddOrganizationMember adds a user to an organization with a specified role.

This method creates a membership record linking the user to the organization. The caller must verify admin/owner permissions before calling this method.

Valid Roles:

  • "owner": Full control (only one owner per organization recommended)
  • "admin": Can manage members and teams
  • "member": Read-only access to organization resources

Parameters:

  • ctx: Request context
  • orgID: Organization ID
  • userID: User ID to add
  • role: Membership role ("owner", "admin", "member")

Returns:

  • error: Database error or duplicate membership

func (*Plugin) AddOrganizationMemberHandler

func (p *Plugin) AddOrganizationMemberHandler(w http.ResponseWriter, r *http.Request)

AddOrganizationMemberHandler adds a member to an organization

func (*Plugin) AddTeamMember added in v1.2.1

func (p *Plugin) AddTeamMember(ctx context.Context, teamID, userID, role string) error

AddTeamMember adds a user to a team with a specified role.

func (*Plugin) AddTeamMemberHandler

func (p *Plugin) AddTeamMemberHandler(w http.ResponseWriter, r *http.Request)

AddTeamMemberHandler adds a member to a team

func (*Plugin) CreateOrganization added in v1.2.1

func (p *Plugin) CreateOrganization(ctx context.Context, name, slug, ownerID string) (*Organization, error)

CreateOrganization creates a new organization and adds the creator as owner.

This method performs two database operations atomically:

  1. Create organization record
  2. Create member record with role="owner" for creator

Parameters:

  • ctx: Request context
  • name: Organization display name (e.g., "Acme Corporation")
  • slug: URL-friendly identifier (e.g., "acme-corp")
  • ownerID: User ID of the organization creator

Returns:

  • *Organization: Created organization with metadata
  • error: Database error or duplicate slug error

func (*Plugin) CreateOrganizationHandler

func (p *Plugin) CreateOrganizationHandler(w http.ResponseWriter, r *http.Request)

CreateOrganizationHandler creates a new organization with the user as owner.

This endpoint allows any authenticated user to create an organization. The creator is automatically assigned the "owner" role with full administrative privileges.

Endpoint:

  • Method: POST
  • Path: /organizations
  • Auth: Required (any authenticated user)

Request Body:

{
  "name": "Acme Corporation",
  "slug": "acme-corp"
}

Validation:

  • name: Required, 1-100 characters
  • slug: Required, 3-50 characters, lowercase alphanumeric with hyphens only

Response (201 Created):

{
  "success": true,
  "organization": {
    "id": "org_abc123",
    "name": "Acme Corporation",
    "slug": "acme-corp",
    "createdAt": "2024-01-01T00:00:00Z",
    "updatedAt": "2024-01-01T00:00:00Z"
  }
}

func (*Plugin) CreateTeam added in v1.2.1

func (p *Plugin) CreateTeam(ctx context.Context, orgID, name, description string) (*Team, error)

CreateTeam creates a new team within an organization.

func (*Plugin) CreateTeamHandler

func (p *Plugin) CreateTeamHandler(w http.ResponseWriter, r *http.Request)

CreateTeamHandler creates a new team within an organization

func (*Plugin) DeleteOrganization added in v1.2.1

func (p *Plugin) DeleteOrganization(ctx context.Context, id string) error

DeleteOrganization soft-deletes an organization.

func (*Plugin) DeleteOrganizationHandler

func (p *Plugin) DeleteOrganizationHandler(w http.ResponseWriter, r *http.Request)

DeleteOrganizationHandler deletes an organization

func (*Plugin) DeleteTeam added in v1.2.1

func (p *Plugin) DeleteTeam(ctx context.Context, id string) error

DeleteTeam deletes a team.

func (*Plugin) DeleteTeamHandler

func (p *Plugin) DeleteTeamHandler(w http.ResponseWriter, r *http.Request)

DeleteTeamHandler deletes a team

func (*Plugin) Dependencies

func (p *Plugin) Dependencies() []plugins.Dependency

Dependencies returns plugin dependencies

func (*Plugin) Description

func (p *Plugin) Description() string

Description returns the plugin description

func (*Plugin) EnrichUser added in v1.2.1

func (p *Plugin) EnrichUser(ctx context.Context, user *core.EnrichedUser) error

EnrichUser implements plugins.UserEnricher to add organization memberships.

This method is called automatically by the authentication system after user lookup. It adds the user's organization memberships to the EnrichedUser, making them available in API responses without requiring separate queries.

Fields Added:

  • "organizations" ([]map[string]any): List of organizations the user belongs to, each containing id, name, and slug fields.

Parameters:

  • ctx: Request context
  • user: EnrichedUser to populate with organization data

Returns:

  • error: Always nil (organization lookup failure is not an error)

func (*Plugin) GetMigrations

func (p *Plugin) GetMigrations() []plugins.Migration

GetMigrations returns the plugin migrations

func (*Plugin) GetOrganization added in v1.2.1

func (p *Plugin) GetOrganization(ctx context.Context, id string) (Organization, error)

GetOrganization retrieves an organization by ID.

func (*Plugin) GetOrganizationHandler

func (p *Plugin) GetOrganizationHandler(w http.ResponseWriter, r *http.Request)

GetOrganizationHandler retrieves details of a specific organization.

This endpoint returns organization metadata. Requires membership in the organization.

Endpoint:

  • Method: GET
  • Path: /organizations/:id
  • Auth: Required (must be organization member)

Path Parameters:

  • id: Organization ID

Response (200 OK):

{
  "success": true,
  "organization": {
    "id": "org_abc123",
    "name": "Acme Corporation",
    "slug": "acme-corp",
    "createdAt": "2024-01-01T00:00:00Z",
    "updatedAt": "2024-01-01T00:00:00Z"
  }
}

func (*Plugin) GetSchemas

func (p *Plugin) GetSchemas() []plugins.Schema

GetSchemas returns all schemas for all supported dialects

func (*Plugin) GetTeam added in v1.2.1

func (p *Plugin) GetTeam(ctx context.Context, id string) (*Team, error)

GetTeam retrieves a team by ID.

func (*Plugin) GetTeamHandler

func (p *Plugin) GetTeamHandler(w http.ResponseWriter, r *http.Request)

GetTeamHandler gets a specific team

func (*Plugin) GetUserOrganizations added in v1.2.1

func (p *Plugin) GetUserOrganizations(ctx context.Context, userID string) ([]*Organization, error)

GetUserOrganizations retrieves all organizations for a user.

func (*Plugin) Init

func (p *Plugin) Init(ctx context.Context, aegis plugins.Aegis) error

Init initializes the organizations plugin with Aegis services.

This method validates database schema requirements and stores the session service for authentication middleware.

Initialization Steps:

  1. Initialize store if not provided (DefaultOrganizationStore)
  2. Build schema validation requirements (tables, foreign keys)
  3. Validate schema via Aegis
  4. Store session service for protected routes

Required Tables:

  • organization: Organization metadata
  • members: Organization membership with roles
  • team: Team metadata within organizations
  • team_member: Team membership with roles

Parameters:

  • ctx: Initialization context
  • aegis: Aegis interface providing services and DB

Returns:

  • error: Schema validation error if tables don't exist

func (*Plugin) IsOrganizationMember added in v1.2.1

func (p *Plugin) IsOrganizationMember(ctx context.Context, userID, orgID string) bool

IsOrganizationMember checks if a user is a member of an organization.

This method is used by middleware to enforce organization access control. Returns true only if the user has any role (owner, admin, or member).

Parameters:

  • ctx: Request context
  • userID: User ID to check
  • orgID: Organization ID

Returns:

  • bool: true if user is a member with any role

func (*Plugin) IsOwner added in v1.2.1

func (p *Plugin) IsOwner(ctx context.Context, userID, orgID string) bool

IsOwner checks if a user is the owner of an organization.

This method enforces permission requirements for destructive actions:

  • Deleting organization
  • Transferring ownership
  • Changing admin roles

Parameters:

  • ctx: Request context
  • userID: User ID to check
  • orgID: Organization ID

Returns:

  • bool: true if user has owner role

func (*Plugin) IsOwnerOrAdmin added in v1.2.1

func (p *Plugin) IsOwnerOrAdmin(ctx context.Context, userID, orgID string) bool

IsOwnerOrAdmin checks if a user is an owner or admin of an organization.

This method enforces permission requirements for administrative actions:

  • Updating organization settings
  • Adding/removing members
  • Creating/deleting teams

Parameters:

  • ctx: Request context
  • userID: User ID to check
  • orgID: Organization ID

Returns:

  • bool: true if user has owner or admin role

func (*Plugin) ListOrganizationMembers added in v1.2.1

func (p *Plugin) ListOrganizationMembers(ctx context.Context, orgID string) ([]*Member, error)

ListOrganizationMembers lists all members of an organization.

func (*Plugin) ListOrganizationMembersHandler

func (p *Plugin) ListOrganizationMembersHandler(w http.ResponseWriter, r *http.Request)

ListOrganizationMembersHandler lists organization members.

func (*Plugin) ListOrganizationsHandler

func (p *Plugin) ListOrganizationsHandler(w http.ResponseWriter, r *http.Request)

ListOrganizationsHandler lists all organizations the user is a member of.

This endpoint returns all organizations where the user has any membership (owner, admin, or member role).

Endpoint:

  • Method: GET
  • Path: /organizations
  • Auth: Required

Response (200 OK):

{
  "success": true,
  "organizations": [
    {"id": "org_1", "name": "Acme Corp", "slug": "acme", ...},
    {"id": "org_2", "name": "Tech Inc", "slug": "tech", ...}
  ]
}

func (*Plugin) ListTeamMembers added in v1.2.1

func (p *Plugin) ListTeamMembers(ctx context.Context, teamID string) ([]*TeamMember, error)

ListTeamMembers lists all members of a team.

func (*Plugin) ListTeamMembersHandler

func (p *Plugin) ListTeamMembersHandler(w http.ResponseWriter, r *http.Request)

ListTeamMembersHandler lists team members

func (*Plugin) ListTeams added in v1.2.1

func (p *Plugin) ListTeams(ctx context.Context, orgID string) ([]*Team, error)

ListTeams lists all teams in an organization.

func (*Plugin) ListTeamsHandler

func (p *Plugin) ListTeamsHandler(w http.ResponseWriter, r *http.Request)

ListTeamsHandler lists teams in an organization.

func (*Plugin) MountRoutes

func (p *Plugin) MountRoutes(r router.Router, prefix string)

MountRoutes registers HTTP routes for the organizations plugin

func (*Plugin) Name

func (p *Plugin) Name() string

Name returns the plugin name

func (*Plugin) ProvidesAuthMethods

func (p *Plugin) ProvidesAuthMethods() []string

ProvidesAuthMethods returns the provided auth methods

func (*Plugin) RemoveOrganizationMember added in v1.2.1

func (p *Plugin) RemoveOrganizationMember(ctx context.Context, userID, orgID string) error

RemoveOrganizationMember removes a user from an organization.

func (*Plugin) RemoveOrganizationMemberHandler

func (p *Plugin) RemoveOrganizationMemberHandler(w http.ResponseWriter, r *http.Request)

RemoveOrganizationMemberHandler removes a member from an organization

func (*Plugin) RemoveTeamMember added in v1.2.1

func (p *Plugin) RemoveTeamMember(ctx context.Context, teamID, userID string) error

RemoveTeamMember removes a user from a team.

func (*Plugin) RemoveTeamMemberHandler

func (p *Plugin) RemoveTeamMemberHandler(w http.ResponseWriter, r *http.Request)

RemoveTeamMemberHandler removes a member from a team

func (*Plugin) RequireOrganizationAdminMiddleware

func (p *Plugin) RequireOrganizationAdminMiddleware() func(http.Handler) http.Handler

RequireOrganizationAdminMiddleware enforces admin or owner privileges.

This middleware ensures the authenticated user has administrative privileges (owner or admin role) in the organization. Regular members are denied access.

Use Cases:

  • Adding/removing organization members
  • Creating/deleting teams
  • Updating organization settings

Permission Requirements:

  • Owner role: Allowed ✓
  • Admin role: Allowed ✓
  • Member role: Denied ✗

Request Flow:

  1. Get authenticated user from context
  2. Extract organization ID from path parameter ":id"
  3. Check if user has owner OR admin role
  4. If yes → continue, if no → 403 Forbidden

func (*Plugin) RequireOrganizationMemberMiddleware

func (p *Plugin) RequireOrganizationMemberMiddleware() func(http.Handler) http.Handler

RequireOrganizationMemberMiddleware enforces organization membership.

This middleware ensures the authenticated user is a member of the organization specified in the URL path parameter ":id". It allows any role (owner, admin, member).

Use Cases:

  • Viewing organization details
  • Listing organization members
  • Viewing teams

Request Flow:

  1. Get authenticated user from context (set by RequireAuthMiddleware)
  2. Extract organization ID from path parameter ":id"
  3. Check if user is a member (any role)
  4. If yes → continue to handler, if no → 403 Forbidden

Example:

r.GET("/organizations/:id",
    requireAuth(
        plugin.RequireOrganizationMemberMiddleware()(
            http.HandlerFunc(handler),
        ),
    ),
)

func (*Plugin) RequireOrganizationOwnerMiddleware

func (p *Plugin) RequireOrganizationOwnerMiddleware() func(http.Handler) http.Handler

RequireOrganizationOwnerMiddleware enforces owner-only access.

This middleware ensures the authenticated user is the organization owner. This is the highest privilege level and is required for destructive operations.

Use Cases:

  • Deleting organization (permanent)
  • Transferring ownership
  • Changing other members' roles to admin

Permission Requirements:

  • Owner role: Allowed ✓
  • Admin role: Denied ✗
  • Member role: Denied ✗

Request Flow:

  1. Get authenticated user from context
  2. Extract organization ID from path parameter ":id"
  3. Check if user has owner role (exact match)
  4. If yes → continue, if no → 403 Forbidden

Best Practice: Only one owner per organization is recommended. Multiple owners complicate permission management and deletion workflows.

func (*Plugin) RequiresTables

func (p *Plugin) RequiresTables() []string

RequiresTables returns required tables

func (*Plugin) UpdateMemberRole added in v1.2.1

func (p *Plugin) UpdateMemberRole(ctx context.Context, orgID, userID, role string) error

UpdateMemberRole updates a user's role in an organization.

func (*Plugin) UpdateMemberRoleHandler

func (p *Plugin) UpdateMemberRoleHandler(w http.ResponseWriter, r *http.Request)

UpdateMemberRoleHandler updates a member's role

func (*Plugin) UpdateOrganization added in v1.2.1

func (p *Plugin) UpdateOrganization(ctx context.Context, id, name, slug string) error

UpdateOrganization updates an organization's name and slug.

func (*Plugin) UpdateOrganizationHandler

func (p *Plugin) UpdateOrganizationHandler(w http.ResponseWriter, r *http.Request)

UpdateOrganizationHandler updates an organization

func (*Plugin) UpdateTeam added in v1.2.1

func (p *Plugin) UpdateTeam(ctx context.Context, id, name, description string) error

UpdateTeam updates a team's name and description.

func (*Plugin) UpdateTeamHandler

func (p *Plugin) UpdateTeamHandler(w http.ResponseWriter, r *http.Request)

UpdateTeamHandler updates a team

func (*Plugin) UpdateTeamMemberRole added in v1.2.1

func (p *Plugin) UpdateTeamMemberRole(ctx context.Context, teamID, userID, role string) error

UpdateTeamMemberRole updates a user's role in a team.

func (*Plugin) UpdateTeamMemberRoleHandler

func (p *Plugin) UpdateTeamMemberRoleHandler(w http.ResponseWriter, r *http.Request)

UpdateTeamMemberRoleHandler updates a team member's role

func (*Plugin) Version

func (p *Plugin) Version() string

Version returns the plugin version

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

type UpdateMemberRoleRequest

type UpdateMemberRoleRequest struct {
	Role string `json:"role"` // New role ("admin" or "member")
}

UpdateMemberRoleRequest represents a request to update a member's role.

Validation Rules:

  • role: Required, must be "admin" or "member"

Example:

{
  "role": "admin"
}

Security Note: Cannot update to "owner" role via this endpoint. Ownership transfer requires a separate flow with additional safeguards.

func (UpdateMemberRoleRequest) Validate

func (r UpdateMemberRoleRequest) Validate() error

Validate validates the update member role request.

type UpdateOrganizationRequest

type UpdateOrganizationRequest struct {
	Name string `json:"name"` // Updated organization name
	Slug string `json:"slug"` // Updated URL-friendly identifier
}

UpdateOrganizationRequest represents a request to update an organization.

Validation Rules:

  • name: Required, 1-100 characters
  • slug: Required, 3-50 characters, lowercase alphanumeric + hyphens only

Note: Both fields must be provided even if only updating one. The handler will apply the new values.

func (UpdateOrganizationRequest) Validate

func (r UpdateOrganizationRequest) Validate() error

Validate validates the update organization request.

type UpdateTeamMemberRoleRequest

type UpdateTeamMemberRoleRequest struct {
	Role string `json:"role"`
}

UpdateTeamMemberRoleRequest represents a request to update a team member's role.

func (UpdateTeamMemberRoleRequest) Validate

func (r UpdateTeamMemberRoleRequest) Validate() error

Validate validates the update team member role request.

type UpdateTeamRequest

type UpdateTeamRequest struct {
	Name        string `json:"name"`
	Description string `json:"description"`
}

UpdateTeamRequest represents a request to update a team.

func (UpdateTeamRequest) Validate

func (r UpdateTeamRequest) Validate() error

Validate validates the update team request.

Directories

Path Synopsis
internal

Jump to

Keyboard shortcuts

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