ou

package module
v0.0.0-...-77e2b90 Latest Latest
Warning

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

Go to latest
Published: Feb 24, 2026 License: MIT Imports: 9 Imported by: 0

README

OU Plugin

Organization Unit plugin for Leeforge CMS. Provides hierarchical organization management with materialized-path tree structure, membership tracking, and datascope integration.

Quick Start

import (
    ou "github.com/leeforge/plugins/ou"
    oufactory "github.com/leeforge/plugins/ou/factory"
)

// 1. Register factory (before plugin Enable)
services.Register(ou.ServiceKeyOUFactory, oufactory.NewEntFactory(entClient))

// 2. Register plugin
runtime.Register(&ou.OUPlugin{})

Plugin Metadata

Field Value
Name ou
Version 1.0.0
Dependencies None
Module github.com/leeforge/plugins/ou

Architecture

ou/                            # https://github.com/leeforge/plugins/tree/main/ou
├── plugin.go                  # Plugin lifecycle (Enable)
├── ports.go                   # ServiceFactory interface
├── scope_resolver.go          # Datascope resolver (OU_SELF / OU_SUBTREE)
├── doc.go                     # Package documentation
├── shared/
│   └── errors.go              # Shared error sentinels
├── organization/
│   ├── handler.go             # HTTP handlers
│   ├── service.go             # Business logic (tree, members, subtree)
│   └── dto.go                 # Request/Response DTOs
└── factory/
    └── ent_factory.go         # Default Ent-backed factory

ServiceFactory

Host application must provide a ServiceFactory registered under ServiceKeyOUFactory:

const ServiceKeyOUFactory = "adapter.ou.factory"

type ServiceFactory interface {
    NewOrganizationService() *organizationmod.Service
    Models() []any
}

The built-in factory.EntFactory provides a default implementation backed by core/server/ent.Client.

HTTP Routes

All routes are registered under /ou/organizations:

Method Path Handler Description
POST /ou/organizations CreateOrganization Create organization (supports parent for hierarchy)
GET /ou/organizations/tree GetOrganizationTree Get full organization tree for current domain
POST /ou/organizations/{id}/members AddOrganizationMember Add user as organization member

Request/Response DTOs

CreateOrganizationRequest
{
  "code": "engineering",
  "name": "Engineering Department",
  "parentId": "uuid-of-parent (optional)"
}
AddOrganizationMemberRequest
{
  "userId": "uuid-of-user",
  "isPrimary": true
}
OrganizationResponse
{
  "id": "uuid",
  "domainId": "uuid",
  "parentId": "uuid or null",
  "code": "engineering",
  "name": "Engineering Department",
  "path": "company/engineering"
}
OrganizationTreeNode
{
  "id": "uuid",
  "domainId": "uuid",
  "parentId": null,
  "code": "company",
  "name": "Company",
  "path": "company",
  "children": [
    {
      "id": "uuid",
      "domainId": "uuid",
      "parentId": "uuid",
      "code": "engineering",
      "name": "Engineering",
      "path": "company/engineering",
      "children": []
    }
  ]
}

Datascope Integration

The plugin registers a ScopeResolver for OU-based data filtering:

Scope Type Constant Description
OU_SELF datascope.ScopeOUSelf Data within user's primary organization
OU_SUBTREE datascope.ScopeOUSubtree Data within user's organization and all children

The resolver relies on these service methods:

  • GetPrimaryOrganizationID(ctx, domainID, userID) — Find user's primary org
  • ListOrganizationUserIDs(ctx, domainID, orgID) — All users in one org
  • ListSubtreeUserIDs(ctx, domainID, orgID) — All users in org subtree

Service Keys

Key Type Description
adapter.ou.factory ServiceFactory Resolved during Enable
ou.organization.service *organization.Service Organization CRUD + queries
datascope.resolver.ou *ScopeResolver OU scope resolver

Error Sentinels

Organization errors (organization package)
organization.ErrDomainContextMissing  // Missing domain context in request
organization.ErrInvalidDomainID       // Invalid domain ID format
organization.ErrOrganizationNotFound  // Organization not found in domain
organization.ErrMemberAlreadyExists   // User already member of organization
Plugin errors (shared package)
shared.ErrNilAppContext       // Plugin Enable called with nil AppContext
shared.ErrNilServiceRegistry  // Plugin Enable called with nil ServiceRegistry

Materialized Path

Organizations use materialized-path hierarchy. The path field stores the full ancestry chain separated by /:

company
company/engineering
company/engineering/backend
company/engineering/frontend
company/sales

This enables efficient subtree queries using PathHasPrefix.

Ent Models

The plugin requires these Ent schemas (provided by core/server/ent):

  • Organization — Organization entity with code, name, path, domain, parent reference
  • OrganizationMember — Membership (user-organization-domain mapping with isPrimary flag)

Documentation

Overview

Package ou provides the Organization Unit plugin for hierarchical organization management within tenant domains.

Index

Constants

View Source
const ServiceKeyOUFactory = "adapter.ou.factory"

Variables

This section is empty.

Functions

This section is empty.

Types

type OUPlugin

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

OUPlugin implements the optional organization-unit plugin.

func (*OUPlugin) Dependencies

func (p *OUPlugin) Dependencies() []string

func (*OUPlugin) Enable

func (p *OUPlugin) Enable(_ context.Context, app *plugin.AppContext) error

func (*OUPlugin) Name

func (p *OUPlugin) Name() string

func (*OUPlugin) RegisterModels

func (p *OUPlugin) RegisterModels() []any

RegisterModels declares OU-related Ent models for plugin runtime collection.

func (*OUPlugin) RegisterRoutes

func (p *OUPlugin) RegisterRoutes(router chi.Router)

func (*OUPlugin) Version

func (p *OUPlugin) Version() string

type ScopeResolver

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

ScopeResolver resolves OU-specific data scopes.

func NewScopeResolver

func NewScopeResolver(orgSvc organizationScopeService) *ScopeResolver

func (*ScopeResolver) Resolve

func (r *ScopeResolver) Resolve(
	_ context.Context,
	userID uuid.UUID,
	_ uuid.UUID,
	scopeType datascope.ScopeType,
	_ string,
) (*datascope.FilterCondition, error)

func (*ScopeResolver) ScopeTypes

func (r *ScopeResolver) ScopeTypes() []datascope.ScopeType

type ServiceFactory

type ServiceFactory interface {
	NewOrganizationService() *organizationmod.Service
	Models() []any
}

ServiceFactory creates OU plugin services using app-owned adapters.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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