tenant

package
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Apr 23, 2026 License: GPL-3.0 Imports: 16 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type AddMemberInput

type AddMemberInput struct {
	UserID shared.ID `json:"user_id" validate:"required"`
	Role   string    `json:"role" validate:"required,oneof=admin member viewer"`
}

AddMemberInput represents the input for adding a member.

type BranchTypeRuleInput

type BranchTypeRuleInput struct {
	Pattern    string `json:"pattern" validate:"required,max=100"`
	MatchType  string `json:"match_type" validate:"required,oneof=exact prefix"`
	BranchType string `json:"branch_type" validate:"required,oneof=main develop feature release hotfix"`
}

BranchTypeRuleInput represents a single branch type mapping rule.

type CreateInvitationInput

type CreateInvitationInput struct {
	Email   string   `json:"email" validate:"required,email,max=254"`
	Role    string   `json:"-"`                                         // Internal use only - always set to "member" by handler
	RoleIDs []string `json:"role_ids" validate:"required,min=1,max=10"` // RBAC roles to assign (required, max 10)
}

CreateInvitationInput represents the input for creating an invitation. Note: All invited users are "member". Permissions come from RBAC roles (RoleIDs).

type CreateTenantInput

type CreateTenantInput struct {
	Name        string `json:"name" validate:"required,min=2,max=100"`
	Slug        string `json:"slug" validate:"required,min=3,max=100,slug"`
	Description string `json:"description" validate:"max=500"`
}

CreateTenantInput represents the input for creating a tenant.

type EmailJobEnqueuer

type EmailJobEnqueuer interface {
	EnqueueTeamInvitation(ctx context.Context, payload TeamInvitationJobPayload) error
}

EmailJobEnqueuer defines the interface for enqueueing email jobs.

type MemberStatusEmailNotifier

type MemberStatusEmailNotifier interface {
	SendMemberSuspendedEmail(ctx context.Context, recipientEmail, recipientName, teamName, actorName, tenantID string) error
	SendMemberReactivatedEmail(ctx context.Context, recipientEmail, recipientName, teamName, actorName, tenantID string) error
}

MemberStatusEmailNotifier sends transactional emails when a membership lifecycle event happens (suspend / reactivate). The concrete implementation is *app.EmailService; we depend on the interface here to keep the dependency direction clean.

type TeamInvitationJobPayload

type TeamInvitationJobPayload struct {
	RecipientEmail string
	InviterName    string
	TeamName       string
	Token          string
	ExpiresIn      time.Duration
	InvitationID   string
	TenantID       string
}

TeamInvitationJobPayload contains data for team invitation email jobs.

type TenantMembershipAdapter

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

TenantMembershipAdapter adapts the tenantdom.Repository to the TenantMembershipProvider interface. This allows authapp.SessionService to get all tenant IDs a user belongs to for cache invalidation.

func NewTenantMembershipAdapter

func NewTenantMembershipAdapter(repo tenantdom.Repository) *TenantMembershipAdapter

NewTenantMembershipAdapter creates a new TenantMembershipAdapter.

func (*TenantMembershipAdapter) GetUserTenantIDs

func (a *TenantMembershipAdapter) GetUserTenantIDs(ctx context.Context, userID shared.ID) ([]string, error)

GetUserTenantIDs returns all tenant IDs that a user belongs to. This is used by authapp.SessionService to invalidate permission cache across all tenants when a user's session is revoked.

type TenantService

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

TenantService handles tenant-related business operations. Note: Tenants are displayed as "Teams" in the UI.

func NewTenantService

func NewTenantService(repo tenantdom.Repository, log *logger.Logger, opts ...TenantServiceOption) *TenantService

NewTenantService creates a new TenantService.

func (*TenantService) AcceptInvitation

func (s *TenantService) AcceptInvitation(ctx context.Context, token string, userID shared.ID, userEmail string, actx auditapp.AuditContext) (*tenantdom.Membership, error)

AcceptInvitation accepts an invitation and creates a membership. userID is the local user ID (from users table) of the person accepting the invitation. userEmail is used to verify the invitation is intended for this user.

func (*TenantService) AddMember

func (s *TenantService) AddMember(ctx context.Context, tenantID string, input AddMemberInput, inviterUserID shared.ID, actx auditapp.AuditContext) (*tenantdom.Membership, error)

AddMember adds a user to a tenant. inviterUserID is the local user ID of the person inviting.

func (*TenantService) CleanupExpiredInvitations

func (s *TenantService) CleanupExpiredInvitations(ctx context.Context) (int64, error)

CleanupExpiredInvitations removes all expired invitations.

func (*TenantService) CreateInvitation

func (s *TenantService) CreateInvitation(ctx context.Context, tenantID string, input CreateInvitationInput, inviterUserID shared.ID, actx auditapp.AuditContext) (*tenantdom.Invitation, error)

CreateInvitation creates an invitation to join a tenant. inviterUserID is the local user ID (from users table) of the person sending the invitation.

func (*TenantService) CreateTenant

func (s *TenantService) CreateTenant(ctx context.Context, input CreateTenantInput, creatorUserID shared.ID, actx auditapp.AuditContext) (*tenantdom.Tenant, error)

CreateTenant creates a new tenant and adds the creator as owner. creatorUserID is the local user ID (from users table).

func (*TenantService) DeleteInvitation

func (s *TenantService) DeleteInvitation(ctx context.Context, invitationID string) error

DeleteInvitation cancels an invitation.

func (*TenantService) DeleteTenant

func (s *TenantService) DeleteTenant(ctx context.Context, actx auditapp.AuditContext, tenantID string) error

DeleteTenant deletes a tenant. The destructive nature means this MUST emit an audit event — without it the hash-chain can't prove who triggered the deletion, and operators have no forensic trail once the tenant's rows are CASCADE'd away. Tenant name is captured BEFORE delete so the audit row can name the victim even though the row no longer exists.

func (*TenantService) GetInvitationByToken

func (s *TenantService) GetInvitationByToken(ctx context.Context, token string) (*tenantdom.Invitation, error)

GetInvitationByToken retrieves an invitation by its token.

func (*TenantService) GetMemberStats

func (s *TenantService) GetMemberStats(ctx context.Context, tenantID string) (*tenantdom.MemberStats, error)

GetMemberStats retrieves member statistics for a tenant.

func (*TenantService) GetMembership

func (s *TenantService) GetMembership(ctx context.Context, userID shared.ID, tenantID string) (*tenantdom.Membership, error)

GetMembership retrieves a user's membership in a tenant. userID is the local user ID (from users table).

func (*TenantService) GetPentestSettings

func (s *TenantService) GetPentestSettings(ctx context.Context, tenantID string) (*tenantdom.PentestSettings, error)

GetPentestSettings returns the current pentest settings for a tenant. Returns system defaults if the tenant has not customized pentest settings.

func (*TenantService) GetRiskScoringSettings

func (s *TenantService) GetRiskScoringSettings(ctx context.Context, tenantID string) (*tenantdom.RiskScoringSettings, error)

GetRiskScoringSettings returns the current risk scoring settings for a tenant.

func (*TenantService) GetTenant

func (s *TenantService) GetTenant(ctx context.Context, tenantID string) (*tenantdom.Tenant, error)

GetTenant retrieves a tenant by ID.

func (*TenantService) GetTenantBySlug

func (s *TenantService) GetTenantBySlug(ctx context.Context, slug string) (*tenantdom.Tenant, error)

GetTenantBySlug retrieves a tenant by slug.

func (*TenantService) GetTenantSettings

func (s *TenantService) GetTenantSettings(ctx context.Context, tenantID string) (*tenantdom.Settings, error)

GetTenantSettings retrieves the typed settings for a tenant.

func (*TenantService) GetUserDisplayName

func (s *TenantService) GetUserDisplayName(ctx context.Context, userID shared.ID) string

GetUserDisplayName returns the display name for a user by their ID. Returns empty string if user not found or no userInfoProvider is configured.

func (*TenantService) ListMembers

func (s *TenantService) ListMembers(ctx context.Context, tenantID string) ([]*tenantdom.Membership, error)

ListMembers lists all members of a tenant.

func (*TenantService) ListMembersWithUserInfo

func (s *TenantService) ListMembersWithUserInfo(ctx context.Context, tenantID string) ([]*tenantdom.MemberWithUser, error)

ListMembersWithUserInfo lists all members of a tenant with user details.

func (*TenantService) ListPendingInvitations

func (s *TenantService) ListPendingInvitations(ctx context.Context, tenantID string) ([]*tenantdom.Invitation, error)

ListPendingInvitations lists pending invitations for a tenant.

func (*TenantService) ListUserTenants

func (s *TenantService) ListUserTenants(ctx context.Context, userID shared.ID) ([]*tenantdom.TenantWithRole, error)

ListUserTenants lists all tenants a user belongs to. userID is the local user ID (from users table).

func (*TenantService) LogAuditEvent

func (s *TenantService) LogAuditEvent(ctx context.Context, actx auditapp.AuditContext, event auditapp.AuditEvent)

LogAuditEvent logs an audit event via the tenant service's audit service. This is the public variant of logAudit, intended for use by handlers that need to log audit events for operations not managed by the service layer.

func (*TenantService) ReactivateMember

func (s *TenantService) ReactivateMember(ctx context.Context, membershipID string, actx auditapp.AuditContext) error

ReactivateMember restores a suspended member's access.

func (*TenantService) RemoveMember

func (s *TenantService) RemoveMember(ctx context.Context, membershipID string, actx auditapp.AuditContext) error

RemoveMember removes a member from a tenant.

func (*TenantService) ResendInvitation

func (s *TenantService) ResendInvitation(ctx context.Context, tenantID, invitationID string, actx auditapp.AuditContext) error

ResendInvitation re-enqueues the invitation email for a pending invitation. Does NOT change the token, expiry, or any other fields on the invitation row — just fires the email again. This lets admins recover from lost/spam-filtered invitation emails without having to delete + recreate (which invalidates the old token).

Returns ErrNotFound if the invitation doesn't exist, and ErrValidation if the invitation has already been accepted or has expired.

func (*TenantService) SearchMembersWithUserInfo

func (s *TenantService) SearchMembersWithUserInfo(ctx context.Context, tenantID string, filters tenantdom.MemberSearchFilters) (*tenantdom.MemberSearchResult, error)

SearchMembersWithUserInfo searches members with filtering and pagination.

func (*TenantService) SetMemberStatusEmailNotifier

func (s *TenantService) SetMemberStatusEmailNotifier(n MemberStatusEmailNotifier)

SetMemberStatusEmailNotifier injects the email notifier used by SuspendMember and ReactivateMember to tell the affected user what happened. Optional: when unset, the operations still succeed but the user is not notified.

func (*TenantService) SetMembershipCache

func (s *TenantService) SetMembershipCache(cache *accesscontrol.MembershipCacheService)

SetMembershipCache injects the membership cache so mutations (suspend / reactivate / role change / member removal) can drop the cached entry immediately. With the cache wired up, the middleware no longer hits the database on every request — but the same wiring is what guarantees a suspended user gets a 403 on their NEXT request instead of after the cache TTL expires.

func (*TenantService) SetPermissionServices

func (s *TenantService) SetPermissionServices(cacheSvc *accesscontrol.PermissionCacheService, versionSvc *accesscontrol.PermissionVersionService)

SetPermissionServices sets the permission cache and version services. This is used when services are initialized after TenantService.

func (*TenantService) SetRoleService

func (s *TenantService) SetRoleService(svc *accesscontrol.RoleService)

SetRoleService wires the RBAC role service after construction (used by services.go bootstrap where TenantService is built before RoleService — same pattern as SetMembershipCache).

func (*TenantService) SetSessionService

func (s *TenantService) SetSessionService(sessionService *authapp.SessionService)

SetSessionService injects the session service so SuspendMember and RemoveMember can revoke all of the user's sessions immediately. Without it, suspended users can still hit JWT-claim-scoped routes (e.g. /api/v1/me/*) until their JWT expires.

func (*TenantService) SetUserService

func (s *TenantService) SetUserService(u *UserService)

SetUserService injects the user service so the suspend/reactivate notifier can resolve a recipient name + email from the user id on the membership row. Optional alongside SetMemberStatusEmailNotifier.

func (*TenantService) SuspendMember

func (s *TenantService) SuspendMember(ctx context.Context, membershipID string, actx auditapp.AuditContext) error

SuspendMember suspends a member's access to a tenant. The membership row stays in the database (preserving audit trail, ownership attribution, and compliance evidence), but the user's access is immediately revoked: sessions are invalidated, permission cache cleared, and JWT exchange should check membership status.

func (*TenantService) UpdateAPISettings

func (s *TenantService) UpdateAPISettings(ctx context.Context, tenantID string, input UpdateAPISettingsInput, actx auditapp.AuditContext) (*tenantdom.Settings, error)

UpdateAPISettings updates only the API settings.

func (*TenantService) UpdateBranchSettings

func (s *TenantService) UpdateBranchSettings(ctx context.Context, tenantID string, input UpdateBranchSettingsInput, actx auditapp.AuditContext) (*tenantdom.Settings, error)

UpdateBranchSettings updates only the branch naming convention settings.

func (*TenantService) UpdateBrandingSettings

func (s *TenantService) UpdateBrandingSettings(ctx context.Context, tenantID string, input UpdateBrandingSettingsInput, actx auditapp.AuditContext) (*tenantdom.Settings, error)

UpdateBrandingSettings updates only the branding settings.

func (*TenantService) UpdateGeneralSettings

func (s *TenantService) UpdateGeneralSettings(ctx context.Context, tenantID string, input UpdateGeneralSettingsInput, actx auditapp.AuditContext) (*tenantdom.Settings, error)

UpdateGeneralSettings updates only the general settings.

func (*TenantService) UpdateMemberRole

func (s *TenantService) UpdateMemberRole(ctx context.Context, membershipID string, input UpdateMemberRoleInput, actx auditapp.AuditContext) (*tenantdom.Membership, error)

UpdateMemberRole updates a member's role.

func (*TenantService) UpdatePentestSettings

func (s *TenantService) UpdatePentestSettings(ctx context.Context, tenantID string, input UpdatePentestSettingsInput, actx auditapp.AuditContext) (*tenantdom.Settings, error)

UpdatePentestSettings updates only the pentest settings.

func (*TenantService) UpdateRiskScoringSettings

func (s *TenantService) UpdateRiskScoringSettings(ctx context.Context, tenantID string, rs tenantdom.RiskScoringSettings, actx auditapp.AuditContext) (*tenantdom.Settings, error)

UpdateRiskScoringSettings updates only the risk scoring settings.

func (*TenantService) UpdateSecuritySettings

func (s *TenantService) UpdateSecuritySettings(ctx context.Context, tenantID string, input UpdateSecuritySettingsInput, actx auditapp.AuditContext) (*tenantdom.Settings, error)

UpdateSecuritySettings updates only the security settings.

func (*TenantService) UpdateTenant

func (s *TenantService) UpdateTenant(ctx context.Context, tenantID string, input UpdateTenantInput) (*tenantdom.Tenant, error)

UpdateTenant updates a tenant's information.

func (*TenantService) UpdateTenantSettings

func (s *TenantService) UpdateTenantSettings(ctx context.Context, tenantID string, settings tenantdom.Settings, actx auditapp.AuditContext) (*tenantdom.Settings, error)

UpdateTenantSettings updates all tenant settings.

type TenantServiceOption

type TenantServiceOption func(*TenantService)

TenantServiceOption is a functional option for TenantService.

func WithEmailEnqueuer

func WithEmailEnqueuer(enqueuer EmailJobEnqueuer) TenantServiceOption

WithEmailEnqueuer sets the email job enqueuer for TenantService.

func WithTenantAuditService

func WithTenantAuditService(auditService *auditapp.AuditService) TenantServiceOption

WithTenantAuditService sets the audit service for TenantService.

func WithTenantPermissionCacheService

func WithTenantPermissionCacheService(svc *accesscontrol.PermissionCacheService) TenantServiceOption

WithTenantPermissionCacheService sets the permission cache service for TenantService. This enables immediate cache invalidation when members are removed.

func WithTenantPermissionVersionService

func WithTenantPermissionVersionService(svc *accesscontrol.PermissionVersionService) TenantServiceOption

WithTenantPermissionVersionService sets the permission version service for TenantService. This enables version cleanup when members are removed.

func WithTenantRoleService

func WithTenantRoleService(svc *accesscontrol.RoleService) TenantServiceOption

WithTenantRoleService wires the RBAC role service for invitation role assignment. Without it, invitation.RoleIDs() is silently dropped on accept — security audit finding.

func WithUserInfoProvider

func WithUserInfoProvider(provider UserInfoProvider) TenantServiceOption

WithUserInfoProvider sets the user info provider for TenantService.

type UpdateAPISettingsInput

type UpdateAPISettingsInput struct {
	APIKeyEnabled bool     `json:"api_key_enabled"`
	WebhookURL    string   `json:"webhook_url" validate:"omitempty,url"`
	WebhookSecret string   `json:"webhook_secret"`
	WebhookEvents []string `json:"webhook_events"`
}

UpdateAPISettingsInput represents input for updating API settings.

type UpdateBranchSettingsInput

type UpdateBranchSettingsInput struct {
	TypeRules []BranchTypeRuleInput `json:"type_rules" validate:"dive"`
}

UpdateBranchSettingsInput represents input for updating branch naming convention settings.

type UpdateBrandingSettingsInput

type UpdateBrandingSettingsInput struct {
	PrimaryColor string `json:"primary_color" validate:"omitempty"`
	LogoDarkURL  string `json:"logo_dark_url" validate:"omitempty,url"`
	LogoData     string `json:"logo_data" validate:"omitempty"` // Base64 encoded logo (max 150KB)
}

UpdateBrandingSettingsInput represents input for updating branding settings.

type UpdateGeneralSettingsInput

type UpdateGeneralSettingsInput struct {
	Timezone string `json:"timezone" validate:"omitempty"`
	Language string `json:"language" validate:"omitempty,oneof=en vi ja ko zh"`
	Industry string `json:"industry" validate:"omitempty,max=100"`
	Website  string `json:"website" validate:"omitempty,url,max=500"`
}

UpdateGeneralSettingsInput represents input for updating general settings.

type UpdateMemberRoleInput

type UpdateMemberRoleInput struct {
	Role string `json:"role" validate:"required,oneof=admin member viewer"`
}

UpdateMemberRoleInput represents the input for updating a member's role.

type UpdatePentestSettingsInput

type UpdatePentestSettingsInput struct {
	CampaignTypes []tenantdom.ConfigOption `json:"campaign_types"`
	Methodologies []tenantdom.ConfigOption `json:"methodologies"`
}

UpdatePentestSettingsInput represents input for updating pentest settings.

type UpdateProfileInput

type UpdateProfileInput struct {
	Name      *string `validate:"omitempty,max=255"`
	Phone     *string `validate:"omitempty,max=50"`
	AvatarURL *string `validate:"omitempty,max=500,url"`
}

UpdateProfileInput represents the input for updating a user profile.

type UpdateSecuritySettingsInput

type UpdateSecuritySettingsInput struct {
	SSOEnabled            bool     `json:"sso_enabled"`
	SSOProvider           string   `json:"sso_provider" validate:"omitempty,oneof=saml oidc"`
	SSOConfigURL          string   `json:"sso_config_url" validate:"omitempty,url"`
	MFARequired           bool     `json:"mfa_required"`
	SessionTimeoutMin     int      `json:"session_timeout_min" validate:"omitempty,min=15,max=480"`
	IPWhitelist           []string `json:"ip_whitelist"`
	AllowedDomains        []string `json:"allowed_domains"`
	EmailVerificationMode string   `json:"email_verification_mode" validate:"omitempty,oneof=auto always never"`
}

UpdateSecuritySettingsInput represents input for updating security settings.

type UpdateTenantInput

type UpdateTenantInput struct {
	Name        *string `json:"name" validate:"omitempty,min=2,max=100"`
	Slug        *string `json:"slug" validate:"omitempty,min=3,max=100,slug"`
	Description *string `json:"description" validate:"omitempty,max=500"`
	LogoURL     *string `json:"logo_url" validate:"omitempty,url,max=500"`
}

UpdateTenantInput represents the input for updating a tenant.

type UserInfoProvider

type UserInfoProvider interface {
	GetUserNameByID(ctx context.Context, id shared.ID) (string, error)
}

UserInfoProvider defines methods to fetch user information for emails.

type UserService

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

UserService handles user-related business operations.

func NewUserService

func NewUserService(repo userdom.Repository, log *logger.Logger) *UserService

NewUserService creates a new UserService.

func (*UserService) GetByEmail

func (s *UserService) GetByEmail(ctx context.Context, email string) (*userdom.User, error)

GetByEmail retrieves a user by their email.

func (*UserService) GetByIDs

func (s *UserService) GetByIDs(ctx context.Context, ids []shared.ID) ([]*userdom.User, error)

GetByIDs retrieves multiple users by their IDs (shared.ID format).

func (*UserService) GetByKeycloakID

func (s *UserService) GetByKeycloakID(ctx context.Context, keycloakID string) (*userdom.User, error)

GetByKeycloakID retrieves a user by their Keycloak ID.

func (*UserService) GetOrCreateFromLocalToken

func (s *UserService) GetOrCreateFromLocalToken(ctx context.Context, userID, email, name string) (*userdom.User, error)

GetOrCreateFromLocalToken gets an existing user by ID from local JWT claims. This is used by the UserSync middleware for local auth.

IMPORTANT: For OSS/local auth, we do NOT auto-create users from JWT tokens. Users MUST register through the /api/v1/auth/register endpoint first. This prevents creating passwordless users that cannot login.

func (*UserService) GetProfile

func (s *UserService) GetProfile(ctx context.Context, userID string) (*userdom.User, error)

GetProfile retrieves a user's profile by ID.

func (*UserService) GetUsersByIDs

func (s *UserService) GetUsersByIDs(ctx context.Context, userIDs []string) ([]*userdom.User, error)

GetUsersByIDs retrieves multiple users by their IDs (string format).

func (*UserService) SetSessionService

func (s *UserService) SetSessionService(sessionService *authapp.SessionService)

SetSessionService sets the session service for revoking sessions. This enables immediate session revocation when user is suspended.

func (*UserService) SyncFromKeycloak

func (s *UserService) SyncFromKeycloak(ctx context.Context, claims *keycloak.Claims) (*userdom.User, error)

SyncFromKeycloak syncs a user from Keycloak claims. This is called by middleware on each authenticated request. It creates the user if not exists, or updates their info if exists.

func (*UserService) UpdatePreferences

func (s *UserService) UpdatePreferences(ctx context.Context, userID string, prefs userdom.Preferences) (*userdom.User, error)

UpdatePreferences updates a user's preferences.

func (*UserService) UpdateProfile

func (s *UserService) UpdateProfile(ctx context.Context, userID string, input UpdateProfileInput) (*userdom.User, error)

UpdateProfile updates a user's profile.

Jump to

Keyboard shortcuts

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