app

package
v0.9.1 Latest Latest
Warning

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

Go to latest
Published: Oct 18, 2026 License: MIT Imports: 12 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var ErrNotFound = errors.New("admin: target user not found")

Functions

This section is empty.

Types

type AdminBillingChannel

type AdminBillingChannel struct {
	Name              string `json:"name"`
	Configured        bool   `json:"configured"`
	KeyMasked         string `json:"key_masked"`
	WebhookConfigured bool   `json:"webhook_configured"`
}

type AdminBillingConfig

type AdminBillingConfig struct {
	Channels []AdminBillingChannel `json:"channels"`
}

type AdminOrder

type AdminOrder struct {
	ID            string     `json:"id"`
	WorkspaceID   string     `json:"workspace_id"`
	WorkspaceName string     `json:"workspace_name"`
	UserID        string     `json:"user_id"`
	PlanCode      string     `json:"plan_code"`
	Interval      string     `json:"interval"`
	AmountCents   int        `json:"amount_cents"`
	Currency      string     `json:"currency"`
	Channel       string     `json:"channel"`
	Status        string     `json:"status"`
	ChannelRef    string     `json:"channel_ref,omitempty"`
	PaidAt        *time.Time `json:"paid_at,omitempty"`
	CanceledAt    *time.Time `json:"canceled_at,omitempty"`
	RefundedAt    *time.Time `json:"refunded_at,omitempty"`
	CreatedAt     time.Time  `json:"created_at"`
}

type AdminPAT

type AdminPAT struct {
	ID         string     `json:"id"`
	Name       string     `json:"name"`
	Prefix     string     `json:"prefix"`
	LastUsedAt *time.Time `json:"last_used_at,omitempty"`
	ExpiresAt  *time.Time `json:"expires_at,omitempty"`
	CreatedAt  time.Time  `json:"created_at"`
	RevokedAt  *time.Time `json:"revoked_at,omitempty"`
}

type AdminPaymentEvent

type AdminPaymentEvent struct {
	ID             string     `json:"id"`
	Channel        string     `json:"channel"`
	ChannelEventID string     `json:"channel_event_id"`
	EventType      string     `json:"event_type"`
	OrderID        string     `json:"order_id,omitempty"`
	ProcessStatus  string     `json:"process_status"`
	ProcessError   string     `json:"process_error,omitempty"`
	ProcessedAt    *time.Time `json:"processed_at,omitempty"`
	Processed      bool       `json:"processed"`
	CreatedAt      time.Time  `json:"created_at"`
}

type AdminPlanUpdateInput added in v0.8.0

type AdminPlanUpdateInput struct {
	Name     string         `json:"name"`
	Currency string         `json:"currency"`
	SortNo   int            `json:"sort_no"`
	Limits   map[string]int `json:"limits"`
}

AdminPlanUpdateInput is the full-replace payload for AdminUpdatePlan; the plan code rides in the request path and is never editable.

type AdminPlanView

type AdminPlanView struct {
	Code      string         `json:"code"`
	Name      string         `json:"name"`
	Currency  string         `json:"currency"`
	TrialDays int            `json:"trial_days"`
	SortNo    int            `json:"sort_no"`
	Limits    map[string]int `json:"limits"`
}

type AdminService

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

func NewAdminService

func NewAdminService(repo Repo, now Clock) *AdminService

func (*AdminService) AnalyticsSummary

func (s *AdminService) AnalyticsSummary(ctx context.Context, since time.Time) ([]AnalyticsSummary, error)

func (*AdminService) ChangePlan

func (s *AdminService) ChangePlan(ctx context.Context, p *webx.Principal, workspaceID, toPlan string) error

func (*AdminService) CountAudit

func (s *AdminService) CountAudit(ctx context.Context, q audit.ListQuery, actor string) (int, error)

func (*AdminService) CountUsers

func (s *AdminService) CountUsers(ctx context.Context, q, status string) (int, error)

func (*AdminService) CountWorkspaces

func (s *AdminService) CountWorkspaces(ctx context.Context, q string) (int, error)

func (*AdminService) DisableUser

func (s *AdminService) DisableUser(ctx context.Context, p *webx.Principal, userID string) error

func (*AdminService) EnableUser

func (s *AdminService) EnableUser(ctx context.Context, p *webx.Principal, userID string) error

func (*AdminService) ExportAuditCSV

func (s *AdminService) ExportAuditCSV(ctx context.Context, q audit.ListQuery, actor string, maxRows int, w io.Writer) (bool, error)

func (*AdminService) Impersonate

func (s *AdminService) Impersonate(ctx context.Context, p *webx.Principal, targetID string) (AdminUser, error)

func (*AdminService) ListAudit

func (s *AdminService) ListAudit(ctx context.Context, workspaceID string, limit int) ([]AuditEntry, error)

func (*AdminService) ListUsers

func (s *AdminService) ListUsers(ctx context.Context, q, status string, page, pageSize int) ([]AdminUser, error)

func (*AdminService) ListWorkspaces

func (s *AdminService) ListWorkspaces(ctx context.Context, q string, page, pageSize int) ([]AdminWorkspace, error)

func (*AdminService) QueryAudit

func (s *AdminService) QueryAudit(ctx context.Context, q audit.ListQuery, actor string) ([]AuditEntry, int, error)

func (*AdminService) SetPlatformAdmin

func (s *AdminService) SetPlatformAdmin(ctx context.Context, p *webx.Principal, userID string, isAdmin bool) error

func (*AdminService) Stats

func (s *AdminService) Stats(ctx context.Context) (*PlatformStats, error)

func (*AdminService) WithAuditor

func (s *AdminService) WithAuditor(a Auditor) *AdminService

func (*AdminService) WithSessionRevoker

func (s *AdminService) WithSessionRevoker(r SessionRevoker) *AdminService

type AdminUser

type AdminUser struct {
	ID              string     `json:"id"`
	Email           string     `json:"email"`
	DisplayName     string     `json:"display_name"`
	Status          string     `json:"status"`
	IsPlatformAdmin bool       `json:"is_platform_admin"`
	EmailVerified   bool       `json:"email_verified"`
	CreatedAt       time.Time  `json:"created_at"`
	LastLoginAt     *time.Time `json:"last_login_at,omitempty"`
}

type AdminUserDetail

type AdminUserDetail struct {
	User       AdminUser            `json:"user"`
	Sessions   []UserSession        `json:"sessions"`
	PATs       []AdminPAT           `json:"pats"`
	Workspaces []AdminUserWorkspace `json:"workspaces"`
}

type AdminUserWorkspace

type AdminUserWorkspace struct {
	ID        string    `json:"id"`
	Slug      string    `json:"slug"`
	Name      string    `json:"name"`
	Role      string    `json:"role"`
	CreatedAt time.Time `json:"created_at"`
}

type AdminWebhookDelivery

type AdminWebhookDelivery struct {
	ID             string     `json:"id"`
	WorkspaceID    string     `json:"workspace_id"`
	URL            string     `json:"url"`
	SubscriptionID string     `json:"subscription_id"`
	EventID        string     `json:"event_id"`
	EventType      string     `json:"event_type"`
	Status         string     `json:"status"`
	Attempts       int        `json:"attempts"`
	LastStatusCode int        `json:"last_status_code,omitempty"`
	LastError      string     `json:"last_error,omitempty"`
	DeliveredAt    *time.Time `json:"delivered_at,omitempty"`
	CreatedAt      time.Time  `json:"created_at"`
}

type AdminWorkspace

type AdminWorkspace struct {
	ID         string    `json:"id"`
	Slug       string    `json:"slug"`
	Name       string    `json:"name"`
	PlanCode   string    `json:"plan_code"`
	MemberCnt  int       `json:"member_count"`
	OwnerEmail *string   `json:"owner_email,omitempty"`
	CreatedAt  time.Time `json:"created_at"`
}

type AnalyticsEventRow

type AnalyticsEventRow struct {
	ID          int64          `json:"id"`
	WorkspaceID string         `json:"workspace_id,omitempty"`
	UserID      string         `json:"user_id,omitempty"`
	Type        string         `json:"event_type"`
	EntityType  string         `json:"entity_type,omitempty"`
	EntityID    string         `json:"entity_id,omitempty"`
	Payload     map[string]any `json:"payload"`
	CreatedAt   time.Time      `json:"created_at"`
}

type AnalyticsRecentEvents

type AnalyticsRecentEvents interface {
	Recent(ctx context.Context, eventType string, limit int) ([]AnalyticsEventRow, error)
}

type AnalyticsSummary

type AnalyticsSummary struct {
	EventType string    `json:"event_type"`
	Count     int       `json:"count"`
	LastAt    time.Time `json:"last_at"`
}

type AnnouncementRequest

type AnnouncementRequest struct {
	Target string `json:"target"`
	UserID string `json:"user_id"`
	Title  string `json:"title"`
	Body   string `json:"body"`
	Link   string `json:"link"`
}

type AnnouncementResult

type AnnouncementResult struct {
	Target string `json:"target"`
	Sent   int    `json:"sent"`
	Failed int    `json:"failed"`
}

type Announcer

type Announcer interface {
	Notify(ctx context.Context, input NotifyInput) error
	AllActiveUserIDs(ctx context.Context) ([]string, error)
}

type AuditEntry

type AuditEntry struct {
	ID            string         `json:"id"`
	WorkspaceID   string         `json:"workspace_id,omitempty"`
	ActorType     string         `json:"actor_type"`
	ActorID       string         `json:"actor_id,omitempty"`
	ActorSnapshot map[string]any `json:"actor_snapshot"`
	Action        string         `json:"action"`
	ResourceType  string         `json:"resource_type"`
	ResourceID    string         `json:"resource_id,omitempty"`
	Metadata      map[string]any `json:"metadata"`
	CreatedAt     time.Time      `json:"created_at"`
}

type Auditor

type Auditor interface {
	Record(ctx context.Context, workspaceID *string, p *webx.Principal, action, resourceType, resourceID string, meta map[string]any)
}

type BillingAdminOps

type BillingAdminOps interface {
	ListAllOrders(ctx context.Context, workspaceID, status string, limit, offset int) ([]AdminOrder, int, error)

	ListPaymentEvents(ctx context.Context, workspaceID string, limit, offset int) ([]AdminPaymentEvent, int, error)

	AdminCancelPendingOrder(ctx context.Context, actor *webx.Principal, orderID string) error

	RunExpiryNow(ctx context.Context) (int, error)

	RunOverageNow(ctx context.Context) (int, error)

	ListPlanCodes(ctx context.Context) ([]string, error)

	ListPlanViews(ctx context.Context) ([]AdminPlanView, error)

	AdminUpdatePlan(ctx context.Context, actor *webx.Principal, code string, input AdminPlanUpdateInput) (AdminPlanView, error)

	MarkOrderPaid(ctx context.Context, actor *webx.Principal, orderID string) error

	BillingConfig(ctx context.Context) (AdminBillingConfig, error)

	TestChannelConnection(ctx context.Context, channel string) error

	AdminCancelSubscription(ctx context.Context, actor *webx.Principal, workspaceID string) error
}

type BillingOpsService

type BillingOpsService struct {
	*AdminService
	// contains filtered or unexported fields
}

func NewBillingOpsService

func NewBillingOpsService(base *AdminService) *BillingOpsService

func (*BillingOpsService) AdminCancelOrder

func (s *BillingOpsService) AdminCancelOrder(ctx context.Context, p *webx.Principal, orderID string) error

func (*BillingOpsService) AdminCancelSubscription

func (s *BillingOpsService) AdminCancelSubscription(ctx context.Context, p *webx.Principal, workspaceID string) error

func (*BillingOpsService) AdminMarkOrderPaid

func (s *BillingOpsService) AdminMarkOrderPaid(ctx context.Context, p *webx.Principal, orderID string) error

func (*BillingOpsService) AdminRedeliver

func (s *BillingOpsService) AdminRedeliver(ctx context.Context, p *webx.Principal, deliveryID string) (AdminWebhookDelivery, error)

func (*BillingOpsService) AdminUpdatePlan added in v0.8.0

func (s *BillingOpsService) AdminUpdatePlan(ctx context.Context, p *webx.Principal, code string, input AdminPlanUpdateInput) (AdminPlanView, error)

AdminUpdatePlan is a pass-through to the billing domain, which validates, writes and audits (admin.plan_change with from/to snapshots) — a single audit source, so the admin side records nothing extra here.

func (*BillingOpsService) BillingConfig

func (s *BillingOpsService) BillingConfig(ctx context.Context) (AdminBillingConfig, error)

func (*BillingOpsService) ListOrders

func (s *BillingOpsService) ListOrders(ctx context.Context, workspaceID, status string, page, pageSize int) ([]AdminOrder, int, error)

func (*BillingOpsService) ListPaymentEvents

func (s *BillingOpsService) ListPaymentEvents(ctx context.Context, workspaceID string, page, pageSize int) ([]AdminPaymentEvent, int, error)

func (*BillingOpsService) ListPlanViews

func (s *BillingOpsService) ListPlanViews(ctx context.Context) ([]AdminPlanView, error)

func (*BillingOpsService) ListPlans

func (s *BillingOpsService) ListPlans(ctx context.Context) ([]string, error)

func (*BillingOpsService) ListWebhookDeliveries

func (s *BillingOpsService) ListWebhookDeliveries(ctx context.Context, workspaceID, status string, page, pageSize int) ([]AdminWebhookDelivery, int, error)

func (*BillingOpsService) RunExpiry

func (s *BillingOpsService) RunExpiry(ctx context.Context, p *webx.Principal) (int, error)

func (*BillingOpsService) RunOverage

func (s *BillingOpsService) RunOverage(ctx context.Context, p *webx.Principal) (int, error)

func (*BillingOpsService) TestChannelConnection

func (s *BillingOpsService) TestChannelConnection(ctx context.Context, channel string) error

func (*BillingOpsService) WithBillingOps

func (s *BillingOpsService) WithBillingOps(ops BillingAdminOps) *BillingOpsService

func (*BillingOpsService) WithWebhookOps

func (s *BillingOpsService) WithWebhookOps(ops WebhookAdminOps) *BillingOpsService

type Clock

type Clock func() time.Time

type NotifyInput

type NotifyInput struct {
	UserID string
	Type   string
	Title  string
	Body   string
	Link   string

	DedupKey string
}

type PlatformStats

type PlatformStats struct {
	TotalUsers      int `json:"total_users"`
	ActiveUsers     int `json:"active_users"`
	TotalWorkspaces int `json:"total_workspaces"`
	PaidWorkspaces  int `json:"paid_workspaces"`
	NewUsers7d      int `json:"new_users_7d"`
	NewUsers30d     int `json:"new_users_30d"`
}

type QuotaGranter

type QuotaGranter interface {
	Grant(ctx context.Context, workspaceID, key, reason, refID string, amount int, now time.Time) (bool, error)
}

type Repo

type Repo interface {
	GetStats(ctx context.Context) (*PlatformStats, error)

	ListUsers(ctx context.Context, q, status string, limit, offset int) ([]AdminUser, error)

	CountUsers(ctx context.Context, q, status string) (int, error)

	SetUserStatus(ctx context.Context, userID, status string) error
	SetPlatformAdmin(ctx context.Context, userID string, isAdmin bool) error
	GetUserByID(ctx context.Context, userID string) (AdminUser, bool, error)

	ListWorkspaces(ctx context.Context, q string, limit, offset int) ([]AdminWorkspace, error)

	CountWorkspaces(ctx context.Context, q string) (int, error)

	GetWorkspaceByID(ctx context.Context, id string) (AdminWorkspace, bool, error)

	ListWorkspaceMembers(ctx context.Context, workspaceID string) ([]WsMember, error)

	ChangePlan(ctx context.Context, workspaceID, toPlan, actor, reason string, now time.Time) (fromPlan string, err error)

	PlanExists(ctx context.Context, code string) (bool, error)

	ListAudit(ctx context.Context, workspaceID string, limit int) ([]AuditEntry, error)

	QueryAudit(ctx context.Context, q audit.ListQuery) ([]AuditEntry, int, error)

	UserIDsByEmailPrefix(ctx context.Context, emailPrefix string, limit int) ([]string, error)

	QueryAuditExt(ctx context.Context, q audit.ListQuery, actorIDs []string) ([]AuditEntry, int, error)

	ExportAuditCSV(ctx context.Context, q audit.ListQuery, actorIDs []string, maxRows int, w io.Writer) (truncated bool, err error)

	ExportUserdata(ctx context.Context, userID string) (map[string]any, error)

	ListSSOProviders(ctx context.Context) ([]SSOProviderRow, error)

	AnalyticsSummary(ctx context.Context, since time.Time) ([]AnalyticsSummary, error)
}

type SSOProviderRow

type SSOProviderRow struct {
	WorkspaceID   string    `json:"workspace_id"`
	WorkspaceSlug string    `json:"workspace_slug"`
	WorkspaceName string    `json:"workspace_name"`
	IssuerURL     string    `json:"issuer_url"`
	ClientID      string    `json:"client_id"`
	Scopes        string    `json:"scopes"`
	SecretSealed  bool      `json:"secret_sealed"`
	CreatedAt     time.Time `json:"created_at"`
	UpdatedAt     time.Time `json:"updated_at"`
}

type SessionRevoker

type SessionRevoker interface {
	RevokeAllUserSessions(ctx context.Context, userID string) error
}

type UserDetailProvider

type UserDetailProvider interface {
	GetUser(ctx context.Context, userID string) (AdminUser, bool, error)

	ListSessions(ctx context.Context, userID string) ([]UserSession, error)

	RevokeAllSessions(ctx context.Context, userID string) error

	RevokeSessionByID(ctx context.Context, userID, sessionID string) error

	SendPasswordReset(ctx context.Context, email string) error

	ResendEmailVerification(ctx context.Context, userID, email string) error

	MarkEmailVerified(ctx context.Context, userID string) error

	ListPATs(ctx context.Context, userID string) ([]AdminPAT, error)

	RevokePAT(ctx context.Context, userID, patID string) error

	DeleteAccount(ctx context.Context, actorEmail, userID string) error
}

type UserOpsService

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

func NewUserOpsService

func NewUserOpsService(base *AdminService) *UserOpsService

func (*UserOpsService) AdminDeleteUser

func (s *UserOpsService) AdminDeleteUser(ctx context.Context, p *webx.Principal, userID, confirmEmail string) error

func (*UserOpsService) AdminResetPassword

func (s *UserOpsService) AdminResetPassword(ctx context.Context, p *webx.Principal, userID string) error

func (*UserOpsService) ExportUserdata

func (s *UserOpsService) ExportUserdata(ctx context.Context, _ *webx.Principal, userID string) (map[string]any, error)

func (*UserOpsService) GetUserDetail

func (s *UserOpsService) GetUserDetail(ctx context.Context, userID string) (*AdminUserDetail, error)

func (*UserOpsService) KickSession

func (s *UserOpsService) KickSession(ctx context.Context, p *webx.Principal, userID, sessionID string) error

func (*UserOpsService) KickUser

func (s *UserOpsService) KickUser(ctx context.Context, p *webx.Principal, userID string) error

func (*UserOpsService) ListUserPATs

func (s *UserOpsService) ListUserPATs(ctx context.Context, userID string) ([]AdminPAT, error)

func (*UserOpsService) MarkVerified

func (s *UserOpsService) MarkVerified(ctx context.Context, p *webx.Principal, userID string) error

func (*UserOpsService) ResendVerification

func (s *UserOpsService) ResendVerification(ctx context.Context, p *webx.Principal, userID string) error

func (*UserOpsService) RevokeUserPAT

func (s *UserOpsService) RevokeUserPAT(ctx context.Context, p *webx.Principal, userID, patID string) error

func (*UserOpsService) WithUserOps

func (*UserOpsService) WithWorkspaceLister

func (s *UserOpsService) WithWorkspaceLister(w WorkspaceLister) *UserOpsService

type UserSession

type UserSession struct {
	ID         string     `json:"id"`
	Device     string     `json:"device"`
	IPHash     string     `json:"ip_hash"`
	CreatedAt  time.Time  `json:"created_at"`
	LastSeenAt time.Time  `json:"last_seen_at"`
	ExpiresAt  time.Time  `json:"expires_at"`
	RevokedAt  *time.Time `json:"revoked_at,omitempty"`
}

type WebhookAdminOps

type WebhookAdminOps interface {
	ListAllDeliveries(ctx context.Context, workspaceID, status string, limit, offset int) ([]AdminWebhookDelivery, int, error)

	AdminRedeliver(ctx context.Context, deliveryID string) (AdminWebhookDelivery, error)
}

type WorkspaceAdminOps

type WorkspaceAdminOps interface {
	UpdateMemberRole(ctx context.Context, actor *webx.Principal, wsID, targetUserID, newRole string) error
	RemoveMember(ctx context.Context, actor *webx.Principal, wsID, targetUserID string) error
	DeleteWorkspace(ctx context.Context, actor *webx.Principal, wsID string) error

	TransferOwnership(ctx context.Context, actor *webx.Principal, wsID, newOwnerUserID string) error
}

type WorkspaceLister

type WorkspaceLister interface {
	ListUserWorkspaces(ctx context.Context, userID string) ([]AdminUserWorkspace, error)
}

type WsDetail

type WsDetail struct {
	AdminWorkspace
	Members []WsMember `json:"members"`
}

type WsMember

type WsMember struct {
	UserID      string    `json:"user_id"`
	Email       string    `json:"email"`
	DisplayName string    `json:"display_name"`
	Role        string    `json:"role"`
	CreatedAt   time.Time `json:"created_at"`
}

type WsOpsService

type WsOpsService struct {
	*AdminService
	// contains filtered or unexported fields
}

func NewWsOpsService

func NewWsOpsService(base *AdminService) *WsOpsService

func (*WsOpsService) AdminDeleteWorkspace

func (s *WsOpsService) AdminDeleteWorkspace(ctx context.Context, p *webx.Principal, workspaceID, confirm string) error

func (*WsOpsService) AdminRemoveMember

func (s *WsOpsService) AdminRemoveMember(ctx context.Context, p *webx.Principal, workspaceID, targetUserID string) error

func (*WsOpsService) AdminTransferOwnership

func (s *WsOpsService) AdminTransferOwnership(ctx context.Context, p *webx.Principal, workspaceID, newOwnerUserID string) error

func (*WsOpsService) AdminUpdateMemberRole

func (s *WsOpsService) AdminUpdateMemberRole(ctx context.Context, p *webx.Principal, workspaceID, targetUserID, newRole string) error

func (*WsOpsService) GetWorkspaceDetail

func (s *WsOpsService) GetWorkspaceDetail(ctx context.Context, workspaceID string) (*WsDetail, error)

func (*WsOpsService) GrantQuota

func (s *WsOpsService) GrantQuota(ctx context.Context, p *webx.Principal, workspaceID, key, reason, ref string, amount int) error

func (*WsOpsService) ListSSOProviders

func (s *WsOpsService) ListSSOProviders(ctx context.Context) ([]SSOProviderRow, error)

func (*WsOpsService) RecentEvents

func (s *WsOpsService) RecentEvents(ctx context.Context, eventType string, limit int) ([]AnalyticsEventRow, error)

func (*WsOpsService) SendAnnouncement

func (s *WsOpsService) SendAnnouncement(ctx context.Context, p *webx.Principal, req AnnouncementRequest) (*AnnouncementResult, error)

func (*WsOpsService) WithAnalyticsEvents

func (s *WsOpsService) WithAnalyticsEvents(a AnalyticsRecentEvents) *WsOpsService

func (*WsOpsService) WithAnnouncer

func (s *WsOpsService) WithAnnouncer(a Announcer) *WsOpsService

func (*WsOpsService) WithQuotaGranter

func (s *WsOpsService) WithQuotaGranter(g QuotaGranter) *WsOpsService

func (*WsOpsService) WithWorkspaceOps

func (s *WsOpsService) WithWorkspaceOps(ops WorkspaceAdminOps) *WsOpsService

Jump to

Keyboard shortcuts

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