Skip to main content

Overview

Organizations provide multi-tenant isolation in NeoSC, allowing you to separate users, workspaces, and resources by organizational boundaries. Each organization has its own domain, user pool, and workspace allocation.

Organization Model

The organization object tracks key metrics and configuration:
backend/server.py:105
class Organization(BaseModel):
    id: str                    # Unique organization identifier
    name: str                  # Organization display name
    domain: str                # Organization domain (e.g., "neogenesys.com")
    users_count: int = 0       # Number of users in the organization
    workspaces_count: int = 0  # Number of assigned workspaces
    created_at: datetime       # Organization creation timestamp

Use Cases

Enterprise Departments

Separate IT, Finance, and HR departments with isolated workspaces and users

Multi-Customer SaaS

Provide each customer with their own isolated environment

Development Environments

Isolate dev, staging, and production teams

Partner Access

Grant external partners access to specific workspaces

Listing Organizations

Retrieve all organizations accessible to the authenticated user:
curl -X GET "https://api.neosc.com/api/organizations" \
  -H "Authorization: Bearer YOUR_TOKEN"

Response Example

[
  {
    "id": "org-550e8400-e29b-41d4",
    "name": "Neogenesys",
    "domain": "neogenesys.com",
    "users_count": 45,
    "workspaces_count": 12,
    "created_at": "2026-01-15T10:00:00Z"
  },
  {
    "id": "org-660f9511-f39c-52e5",
    "name": "Partner Corp",
    "domain": "partnercorp.com",
    "users_count": 8,
    "workspaces_count": 3,
    "created_at": "2026-02-20T14:30:00Z"
  }
]

Default Organization

When a user registers without specifying an organization, they’re assigned to a default organization:
backend/server.py:747
@api_router.get("/organizations")
async def get_organizations(user: dict = Depends(get_current_user)):
    orgs = await db.organizations.find({}, {"_id": 0}).to_list(100)
    
    if not orgs:
        # Create default organization
        default_org = Organization(
            name=user.get('organization', 'Default Organization'),
            domain="neogenesys.com",
            users_count=1,
            workspaces_count=5
        )
        await db.organizations.insert_one(default_org.model_dump())
        orgs = [default_org.model_dump()]
    
    return orgs

User Registration with Organization

Assign users to organizations during registration:
backend/server.py:147
@api_router.post("/auth/register")
async def register(user_data: UserCreate):
    user = User(
        email=user_data.email,
        name=user_data.name,
        organization=user_data.organization or "Default Organization"
    )
    # ... create user
curl -X POST "https://api.neosc.com/api/auth/register" \
  -H "Content-Type: application/json" \
  -d '{
    "email": "user@neogenesys.com",
    "password": "secure_password",
    "name": "John Doe",
    "organization": "Neogenesys"
  }'

SSO Organization Mapping

When using Zitadel SSO, organizations are automatically extracted from the OIDC profile:
backend/server.py:228
@api_router.post("/auth/sso")
async def sso_login(sso_data: SSOLoginRequest):
    profile = sso_data.profile
    
    # Create new user from SSO
    user = User(
        email=email,
        name=name,
        organization=profile.get('org') or 
                     profile.get('urn:zitadel:iam:org:id') or 
                     'Zitadel SSO',
        role=user_role,
        mfa_enabled=True
    )
Zitadel organizations are mapped using the org claim or urn:zitadel:iam:org:id from the OIDC token.

Organization UI Display

The frontend displays organizations with metrics and visual cards:
frontend/src/pages/OrganizationsPage.jsx:68
<div className="grid gap-6 md:grid-cols-2 lg:grid-cols-3">
  {organizations.map((org) => (
    <div key={org.id} className="p-6 rounded-xl bg-card border">
      <div className="flex items-center gap-4 mb-4">
        <div className="w-14 h-14 rounded-xl bg-gradient-to-br from-cyan-500/20 to-orange-500/20">
          <Building2 className="w-7 h-7 text-primary" />
        </div>
        <div>
          <h3 className="text-lg font-semibold">{org.name}</h3>
          <div className="flex items-center gap-1.5 text-sm text-muted-foreground">
            <Globe className="w-3.5 h-3.5" />
            {org.domain}
          </div>
        </div>
      </div>

      <div className="grid grid-cols-2 gap-4 pt-4 border-t">
        <div className="flex items-center gap-2">
          <Users className="w-4 h-4" />
          <span className="font-medium">{org.users_count}</span>
          <span className="text-sm">Users</span>
        </div>
        <div className="flex items-center gap-2">
          <Monitor className="w-4 h-4" />
          <span className="font-medium">{org.workspaces_count}</span>
          <span className="text-sm">Workspaces</span>
        </div>
      </div>
    </div>
  ))}
</div>

User-Organization Relationship

Each user belongs to exactly one organization:
backend/server.py:41
class User(BaseModel):
    id: str
    email: str
    name: str
    organization: str = "Default Organization"  # Organization name
    role: str = "user"
    mfa_enabled: bool = True
    created_at: datetime

Workspace Isolation

While the current implementation shares workspaces globally, you can implement organization-specific workspace filtering:
Workspace Filtering Example
@api_router.get("/workspaces")
async def get_workspaces(user: dict = Depends(get_current_user)):
    # Filter workspaces by organization
    workspaces = await db.workspaces.find(
        {"organization": user['organization']},
        {"_id": 0}
    ).to_list(100)
    return workspaces

Creating Organizations (Future)

Organization creation will be available for admin users:
frontend/src/pages/OrganizationsPage.jsx:46
<Button 
  className="bg-primary hover:bg-primary/90"
  disabled
>
  <Plus className="w-4 h-4 mr-2" />
  New Organization
</Button>
Organizations are automatically created during user registration and SSO login. Manual organization creation through the UI is not currently available.

Audit Trail

All organization-related activities are tracked in audit logs:
Example Audit Events
- "create_organization" - New organization created
- "update_organization" - Organization settings changed
- "add_user_to_org" - User added to organization
- "remove_user_from_org" - User removed from organization

Multi-Tenancy Architecture

Domain-Based Access

Organizations use domain-based identification:
Example: Domain Validation
const userEmail = "john@neogenesys.com";
const domain = userEmail.split('@')[1];  // "neogenesys.com"

// Find matching organization
const org = organizations.find(o => o.domain === domain);

Best Practices

  • Use meaningful organization names that reflect business structure
  • Map domains to corporate email domains for SSO integration
  • Keep organization structure flat to avoid complexity
  • Plan for growth by reserving workspace capacity
  • Assign users to organizations during onboarding
  • Use SSO organization claims for automatic assignment
  • Monitor user_count metrics for license compliance
  • Implement organization-level admin roles
  • Allocate workspaces based on organization size
  • Set workspace quotas per organization
  • Monitor workspace_count for capacity planning
  • Implement billing based on organization metrics
  • Enforce organization boundaries in all API endpoints
  • Validate user organization membership before access
  • Audit cross-organization access attempts
  • Implement organization-specific security policies

Metrics and Reporting

User Count

Track the number of users per organization:
Calculate Users Count
users_count = await db.users.count_documents(
    {"organization": org_name}
)

Workspace Count

Monitor workspace allocation:
Calculate Workspaces Count
workspaces_count = await db.workspaces.count_documents(
    {"organization": org_name}
)

Future Enhancements

Custom Branding

Organization-specific logos, colors, and themes

Resource Quotas

Set CPU, memory, and storage limits per organization

Billing Integration

Per-organization usage tracking and billing

Organization Admin

Dedicated admin role for organization management

Users & Authentication

User registration and SSO integration

Workspaces

Workspace allocation and management

Security Policies

Organization-level security configuration

Audit Logs

Track organization activities

Build docs developers (and LLMs) love