# OpenWork Den Organization Management System Architecture: Typed Contracts and Pure Functions

> Explore the OpenWork Den organization management system architecture. Discover typed contracts and pure functions that transform JSON into strongly-typed objects and generate UI-ready access flags.

- Repository: [Different AI/openwork](https://github.com/different-ai/openwork)
- Tags: architecture
- Published: 2026-07-31

---

**The OpenWork Den organization management system architecture is built on a centralized type layer and pure JavaScript parsing functions that transform loose JSON API responses into strongly-typed objects, while a single permission calculator exposes boolean access flags that bind directly to the UI.**

The `different-ai/openwork` repository powers multi-tenant organization management through its **Den** core service. The Den architecture stores and exposes all organization-level data—members, invitations, roles, teams, API keys, SCIM, SSO, and branding—via a type-safe front-end module. Every contract, parser, and permission helper lives in a single, side-effect-free utility file that the React application consumes through a dedicated provider.

## Core Data Model and Typed Contracts in OpenWork Den

All domain types are exported as plain TypeScript type aliases from [`ee/apps/den-web/app/(den)/_lib/den-org.ts`](https://github.com/different-ai/openwork/blob/dev/ee/apps/den-web/app/(den)/_lib/den-org.ts). These are deliberately class-free so they can be imported by React components, server-side helpers, and unit tests without side effects.

The most important contracts include:

- **`DenOrgSummary`** — Minimal org information for the org selector.
- **`DenOrgMember`** — A user or pending invite embedded with a profile.
- **`DenOrgInvitation`** — Pending email invite state.
- **`DenOrgTeam`** — Logical member grouping, optionally SCIM-managed.
- **`DenOrgRole`** — Custom role with a permission map.
- **`DenCanonicalRole`** — The built-in union `"owner" | "super-admin" | "admin" | "member"`.
- **`DenOrgAccessFlags`** — Computed booleans that drive UI enable/disable decisions.
- **`DenOrgApiKey`** — Metadata for programmatic access.
- **`DenOrgScimConnection`** and **`DenOrgSsoConnection`** — External SCIM and SSO integration descriptors.
- **`DenManagedBrandAsset`** — Uploaded logo or icon asset.
- **`DenOrganizationMetadata`** — Free-form JSON blob for custom settings such as desktop version whitelists or required SSO enforcement.

## Pure Parsing and Validation Functions

Because the Den API returns loosely-typed JSON, the module provides **pure parsing functions** that validate shape and coerce values before the data reaches the UI layer.

- **`parseOrganizationMetadata(metadata: string | null)`** — Safely `JSON.parse`s the metadata string and returns a typed object or `null`.
- **`parseOrgListPayload(payload: unknown)`** — Converts the `/v1/me/orgs` response into `{ orgs, activeOrgId, activeOrgSlug }`.
- **`parseOrgContextPayload(payload: unknown)`** — Parses the full organization context including org, current member, members, invitations, roles, and teams.
- **`parseOrgApiKeysPayload`**, **`parseOrgScimPayload`**, **`parseOrgSsoPayload`** — Dedicated parsers for API keys, SCIM, and SSO endpoints.
- **`isAssignableOrgRole`** and **`canRefreshInvitationRole`** — Business-rule helpers that protect built-in roles from improper assignment.

The parsers rely on low-level type guards such as `isRecord`, `asString`, `asBoolean`, and `asStringArray`. By keeping parsing pure, components downstream can trust the resulting objects and avoid runtime `any` checks.

## Permission Calculation with `getOrgAccessFlags`

The most frequently consumed function in the Den architecture is **`getOrgAccessFlags`**. It takes a raw role string, an `isOwner` boolean, and an optional array of role definitions, then returns a flat boolean map that the UI binds directly to buttons and menu items.

```typescript
export function getOrgAccessFlags(
  roleValue: string,
  isOwner: boolean,
  _roleDefinitions: readonly DenOrgRole[] = []
): DenOrgAccessFlags {
  const canonicalRole = getHighestCanonicalRole(roleValue, isOwner);
  const resolvedIsOwner = canonicalRole === "owner";
  const isSuperAdmin = canonicalRole === "super-admin";
  const isAdminRole = canonicalRole === "admin";
  const isAdmin = resolvedIsOwner || isSuperAdmin || isAdminRole;
  const canManageSettings = resolvedIsOwner || isSuperAdmin;

  return {
    canonicalRole,
    isOwner: resolvedIsOwner,
    isSuperAdmin,
    isAdminRole,
    isMember: canonicalRole === "member",
    isAdmin,
    canViewSettings: isAdmin,
    canManageSettings,
    canManageSecurityConfiguration: canManageSettings,
    canInviteMembers: isAdmin,
    canCancelInvitations: isAdmin,
    canManageMembers: isAdmin,
    canRemoveMembers: isAdmin,
    canManageRoles: canManageSettings,
    canManageTeams: isAdmin,
    canManageApiKeys: canManageSettings,
    canManageScim: canManageSettings,
    canManageSso: canManageSettings,
    canTransferOwnership: resolvedIsOwner,
    canDeleteOrganization: resolvedIsOwner,
    canStartSeatCheckout: isAdmin,
  };
}

```

As implemented in `different-ai/openwork`, this same matrix powers both the Den UI and the back-end service checks. A component can call it directly:

```typescript
import { getOrgAccessFlags } from '@/app/(den)/_lib/den-org';

const flags = getOrgAccessFlags(currentMember.role, currentMember.isOwner);

if (flags.canInviteMembers) {
  // Render "Invite Member" button
}

```

## Route Helpers and Navigation

The front-end generates org-scoped URLs through a family of pure functions that prepend `/dashboard` and encode query parameters. These helpers are consumed throughout the Den web app, including in [`ee/apps/den-web/app/(den)/_providers/den-flow-provider.tsx`](https://github.com/different-ai/openwork/blob/dev/ee/apps/den-web/app/(den)/_providers/den-flow-provider.tsx).

```typescript
export function getOrgDashboardRoute(_orgSlug?: string | null): string {
  return "/dashboard";
}
export function getMarketplaceOnboardingRoute(_orgSlug?: string | null): string {
  return `${getOrgDashboardRoute(_orgSlug)}/onboarding`;
}
export function getJoinOrgRoute(invitationId: string): string {
  return `/join-org?invite=${encodeURIComponent(invitationId)}`;
}
export function getWorkspaceClaimRoute(token: string): string {
  return `/workspace-claim?token=${encodeURIComponent(token)}`;
}

```

These utilities guarantee consistent navigation after sign-in, invitation acceptance, or workspace claim.

## Brand Assets and Feature Flags

Each org can customize branding and behavior through the **`metadata`** JSON blob. Small accessor functions read this blob safely after it has been parsed:

- **`getAllowedDesktopVersionsFromMetadata`** — Returns a deduplicated allow-list of desktop client versions.
- **`getRequireSsoFromMetadata`** — Reads whether SSO enforcement is active.
- **`getManagedBrandAssetFromMetadata`** — Extracts a stored logo or icon asset.
- **`getManagedBrandIconUrl`** — Convenience wrapper that returns the icon URL directly.

A typical read looks like this:

```typescript
import {
  parseOrganizationMetadata,
  getManagedBrandIconUrl,
} from '@/app/(den)/_lib/den-org';

const meta = parseOrganizationMetadata(org.metadata);
const brandIcon = meta ? getManagedBrandIconUrl(org.metadata) : null;

```

All metadata parsing lives alongside the core types in [`den-org.ts`](https://github.com/different-ai/openwork/blob/main/den-org.ts), keeping org-level concerns centralized.

## End-to-End Data Flow in the OpenWork Den System

The Den organization management system architecture follows a predictable pipeline from authentication to rendering:

1. **Authentication** — `DenFlowProvider` obtains a JWT and enters the org routing layer.
2. **Directory Load** — `loadOrgDirectory()` calls `/v1/me/orgs` and feeds the raw response to `parseOrgListPayload`.
3. **Context Load** — `loadOrgContext()` fetches `/v1/orgs/:slug` and runs `parseOrgContextPayload` to produce a `DenOrgContext`.
4. **Permission Resolution** — `getOrgAccessFlags` derives the current user's boolean capability map.
5. **UI Binding** — Components consume typed data directly, e.g., `<MemberList members={ctx.members} />`, with no additional runtime validation.
6. **Navigation** — Route helpers generate consistent, org-scoped links for deep pages.

For production, the Den service is packaged via the Den web and API Helm charts located in [`dev/packaging/helm/openwork-ee/templates/den-api.yaml`](https://github.com/different-ai/openwork/blob/main/dev/packaging/helm/openwork-ee/templates/den-api.yaml) and [`templates/den-web.yaml`](https://github.com/different-ai/openwork/blob/main/templates/den-web.yaml).

Unit tests in [`den-org.brand-icon.test.mts`](https://github.com/different-ai/openwork/blob/dev/ee/apps/den-web/app/(den)/_lib/den-org.brand-icon.test.mts) and [`den-org.selection.test.mts`](https://github.com/different-ai/openwork/blob/dev/ee/apps/den-web/app/(den)/_lib/den-org.selection.test.mts) guard the parsing utilities, while integration tests in [`dev/apps/app/tests/den-web-org-access.test.ts`](https://github.com/different-ai/openwork/blob/main/dev/apps/app/tests/den-web-org-access.test.ts) validate the full auth-to-dashboard flow.

## Summary

The OpenWork Den organization management system architecture is founded on a **type-first, pure-function** design:

- **Typed contracts** in [`den-org.ts`](https://github.com/different-ai/openwork/blob/main/den-org.ts) keep the codebase safe and IDE-friendly.
- **Pure parsers** validate and coerce raw JSON into trusted objects.
- **`getOrgAccessFlags`** exposes a flat boolean map for direct UI binding.
- **Route generators** create consistent, org-scoped dashboard URLs.
- **Metadata accessors** read custom branding and feature flags without leaking implementation details.

This centralized module is wired into the React front-end through `DenFlowProvider`, making it straightforward to extend org-level settings without touching unrelated UI code.

## Frequently Asked Questions

### What file contains the core types and parsers for the OpenWork Den architecture?

All core types, parsing functions, permission helpers, and route builders live in [`ee/apps/den-web/app/(den)/_lib/den-org.ts`](https://github.com/different-ai/openwork/blob/dev/ee/apps/den-web/app/(den)/_lib/den-org.ts). This single module is imported by React components, server-side helpers, and unit tests across the Den web app.

### How does the Den system calculate what an organization member is allowed to do?

The system calls **`getOrgAccessFlags(roleValue, isOwner, roleDefinitions)`**, which resolves the highest canonical role and returns an object of booleans such as `canInviteMembers`, `canDeleteOrganization`, and `canManageSso`. Both the UI and the back-end rely on this same function to enforce access control consistently.

### Where does the organization data flow begin after a user signs in?

After sign-in, the **`DenFlowProvider`** in [`ee/apps/den-web/app/(den)/_providers/den-flow-provider.tsx`](https://github.com/different-ai/openwork/blob/dev/ee/apps/den-web/app/(den)/_providers/den-flow-provider.tsx) manages the JWT and triggers `loadOrgDirectory()`. That helper calls `/v1/me/orgs` and uses `parseOrgListPayload` to populate the org selector or auto-select the active organization.

### How are custom branding and feature flags stored in the Den system?

They are stored in a free-form **`metadata`** JSON field on the organization object. Helper functions such as `parseOrganizationMetadata`, `getManagedBrandIconUrl`, and `getRequireSsoFromMetadata` safely extract values from this blob, allowing per-org logos, icon assets, and SSO enforcement without schema migrations.