# OpenWork Den Architecture Explained: den-api, den-web, and den-gateway Components

> Explore the OpenWork Den architecture. Understand den-api, den-web, and den-gateway components for Hono control, Next.js frontend proxy, and workflow automation.

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

---

**OpenWork Den uses a three-tier microservice architecture where den-api serves as the Hono-based control plane, den-web acts as a Next.js frontend proxy, and den-gateway provides a thin HTTP abstraction for automated workflows and CORS-free API access.**

The OpenWork Den ecosystem—found in the `different-ai/openwork` repository—provides the central control plane for organization management, user authentication, billing, and cloud workspace orchestration. Understanding the OpenWork Den architecture requires examining how these three specialized components interact to provide both human-facing interfaces and programmatic control.

## OpenWork Den Architecture Overview

The architecture follows a microservice pattern with clearly separated concerns:

| Component | Responsibility | Technology Stack |
|-----------|---------------|------------------|
| **den-api** | Backend control plane exposing HTTP APIs for auth, orgs, workers, and SCIM | Hono (Node.js), Zod, MySQL, Better Auth |
| **den-web** | Frontend web application with same-origin proxying to avoid CORS | Next.js (React/TypeScript), Tailwind CSS, Vercel |
| **den-gateway** | Thin HTTP gateway for test flows and cloud workspace scripts | TypeScript utilities, native `fetch` |

Authentication flows through **Better Auth** in `den-api`, with tokens propagated via `den-web`'s proxy routes or directly injected by `den-gateway` utilities.

## den-api: The Hono-Based Control Plane

The `den-api` package implements the entire Den API surface as modular Hono route groups. Located in `ee/apps/den-api/`, this component handles all persistent state for organizations, users, and cloud workers.

### Modular Route Structure

Routes are organized by domain in `ee/apps/den-api/src/routes/`:

- **`src/routes/auth/`** – Better Auth endpoints and desktop hand-off routes under `/v1/auth/*`
- **`src/routes/me/`** – Current user profile and organization list endpoints
- **`src/routes/org/`** – Organization CRUD operations and SCIM management
- **`src/routes/workers/`** – Worker lifecycle management, billing, and heartbeat monitoring

Each folder contains its own [`README.md`](https://github.com/different-ai/openwork/blob/main/README.md) for isolated discovery and documentation.

### Shared Validation and Type Safety

Request and response schemas use **TypeID** validation defined in [`ee/packages/utils/src/typeid.ts`](https://github.com/different-ai/openwork/blob/main/ee/packages/utils/src/typeid.ts) and re-exported through [`ee/apps/den-api/src/openapi.ts`](https://github.com/different-ai/openwork/blob/main/ee/apps/den-api/src/openapi.ts). This ensures consistent type safety across the API surface using Zod validation.

### Observability Configuration

The `den-api` supports pluggable observability via the `DEN_OBSERVABILITY_BACKEND` environment variable (`none`, `otel`, or `sentry`). Request access logs capture request-id, method, normalized route, status, and duration while redacting sensitive fields.

```typescript
// Simplified example from ee/apps/den-api/src/routes/org/index.ts
router.get('/orgs/:orgId', orgContext, async (c) => {
  const org = c.get('org');
  return c.json(org);
});

```

## den-web: Next.js Frontend and Same-Origin Proxy

The `den-web` component (`ee/apps/den-web/`) serves the user interface at `https://app.openworklabs.com`. Built with Next.js, it handles authentication flows and proxies requests to `den-api` to maintain same-origin security policies.

### Same-Origin Proxy Architecture

To avoid cross-origin resource sharing (CORS) restrictions, `den-web` implements server-side proxy routes:

- **`app/api/den/*`** – Forwards requests to the upstream Den API (`DEN_API_BASE`)
- **`app/api/auth/*`** – Proxies Better Auth callbacks for GitHub OAuth and email login

This architecture allows browser-based clients to call `/api/den/v1/cloud/instance` while the server forwards to the actual `den-api` endpoint with proper authentication headers.

### Desktop Hand-Off Integration

UI components like [`den-admin-panel.tsx`](https://github.com/different-ai/openwork/blob/main/den-admin-panel.tsx) and [`den-marketing-rail.tsx`](https://github.com/different-ai/openwork/blob/main/den-marketing-rail.tsx) generate deep-links using `DEN_WEB_OPENWORK_APP_CONNECT_URL`. These links open the OpenWork desktop client with pre-populated worker URLs and authentication tokens, bridging the web and desktop experiences.

### Root Layout Structure

The application shell is defined in [`ee/apps/den-web/app/layout.tsx`](https://github.com/different-ai/openwork/blob/main/ee/apps/den-web/app/layout.tsx):

```tsx
export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en" className="h-full">
      <body className="min-h-screen bg-[var(--dls-app-bg)] text-[var(--dls-text-primary)]">
        <DenShell>{children}</DenShell>
      </body>
    </html>
  );
}

```

## den-gateway: Automated Flow Gateway

`den-gateway` is not a standalone service but a **utility layer** used by automated test flows, particularly in [`evals/flows/den-gateway.flow.ts`](https://github.com/different-ai/openwork/blob/main/evals/flows/den-gateway.flow.ts). It provides CORS-free API access for cloud workspace overlay scripts and testing scenarios.

### Token Handling and Request Utilities

The gateway abstracts authentication complexity through helper functions:

- **`fetchJson`** – Wrapper around `fetch` with JSON parsing and error handling
- **`gatewayInstanceFetch`** – Pre-configured fetch with authorization headers and timeout handling via `withTimeout`
- **Token injection** – Automatically appends `Authorization: Bearer <token>` headers to requests

### Workspace Marker Operations

For testing persistence across updates, `den-gateway` provides utilities to write and read marker files in cloud workspaces. The `writeWorkspaceMarker` function in [`den-gateway.flow.ts`](https://github.com/different-ai/openwork/blob/main/den-gateway.flow.ts) demonstrates writing temporary files to verify workspace state persistence.

```typescript
// From evals/flows/den-gateway.flow.ts
const signIn = async (ctx) => {
  const res = await fetchJson(`${flowBase(ctx)}/api/auth/sign-in/email`, {
    method: 'POST',
    headers: { 'content-type': 'application/json', origin: flowBase(ctx) },
    body: JSON.stringify({ email, password })
  });
  if (!res.response.ok) throw new Error('Sign-in failed');
  return (res.body as any).token;
};

```

## Practical Implementation Examples

### Calling den-api from Node.js Scripts

When building automation outside the web interface, obtain a Bearer token through the Better Auth endpoint and call the API directly:

```typescript
import fetch from 'node-fetch';

const API_BASE = 'https://api.openworklabs.com';
const token = '<bearer-token-from-sign-in>';

async function listOrgs() {
  const res = await fetch(`${API_BASE}/v1/me/orgs`, {
    headers: { Authorization: `Bearer ${token}` }
  });
  const data = await res.json();
  console.log('Orgs:', data.orgs);
}

listOrgs().catch(console.error);

```

### Using den-web's Proxy from Browser Context

For client-side code running within the `den-web` origin, leverage the same-origin proxy to avoid handling CORS:

```javascript
async function getCurrentWorkspace() {
  const res = await fetch('/api/den/v1/cloud/instance', {
    credentials: 'include' // Cookies contain auth tokens from login flow
  });
  const { status, url } = await res.json();
  console.log(`Workspace status: ${status}, URL: ${url}`);
}

```

### Workspace File Operations via Gateway

For automated testing scenarios, use the gateway utilities to manipulate workspace files:

```typescript
// Inside a den-gateway flow context
await gatewayInstanceFetch(ctx, `/workspace/${workspaceId}/files/content`, {
  method: 'POST',
  body: JSON.stringify({
    path: 'demo-marker.txt',
    content: 'proof of persistence',
    force: true,
  })
});

```

## Summary

- **den-api** (`ee/apps/den-api/`) provides the core Hono-based REST API with MySQL persistence, organized into domain-specific route folders under `src/routes/`
- **den-web** (`ee/apps/den-web/`) delivers the Next.js frontend with critical proxy routes in `app/api/den/*` that enable same-origin API access without CORS complications
- **den-gateway** (implemented in [`evals/flows/den-gateway.flow.ts`](https://github.com/different-ai/openwork/blob/main/evals/flows/den-gateway.flow.ts)) offers a TypeScript utility layer for automated flows, handling Bearer token injection and workspace file operations
- Authentication flows through Better Auth in `den-api`, accessible via `den-web` proxy routes at `/api/auth/*` or directly for desktop hand-off at `/v1/auth/*`
- Observability spans all components via the `DEN_OBSERVABILITY_BACKEND` configuration supporting OpenTelemetry or Sentry

## Frequently Asked Questions

### What is the relationship between den-api and den-web?

**den-api** is the standalone backend service that exposes the full HTTP API for the OpenWork ecosystem, while **den-web** is the Next.js frontend that proxies requests to `den-api` through server-side routes in `app/api/den/*`. This proxy pattern allows the browser to make same-origin requests to `/api/den/*`, which the Next.js server then forwards to the actual `den-api` endpoint, eliminating CORS issues while maintaining security.

### How does authentication work across the OpenWork Den architecture?

Users authenticate via **Better Auth** endpoints mounted under `/api/auth/*` in `den-api`. The `den-web` application proxies these endpoints through `app/api/auth/*` routes, allowing the browser to complete OAuth flows and email sign-in without cross-origin requests. Upon successful authentication, the system issues a Bearer token stored in `localStorage` (for web) or passed directly to the desktop client (via `DEN_WEB_OPENWORK_APP_CONNECT_URL` deep-links) to authorize subsequent API calls.

### What is the purpose of den-gateway if den-api already provides HTTP endpoints?

**den-gateway** serves as a programmatic abstraction layer specifically designed for automated test flows and cloud workspace scripts. While `den-api` provides the raw HTTP interface, `den-gateway` (as seen in [`evals/flows/den-gateway.flow.ts`](https://github.com/different-ai/openwork/blob/main/evals/flows/den-gateway.flow.ts)) encapsulates token management, request timeouts, retry logic, and workspace file operations. This allows test scripts to interact with the Den ecosystem without implementing CORS workarounds or handling authentication header injection manually.

### How are TypeID schemas validated across the Den architecture?

TypeID validation is centralized in [`ee/packages/utils/src/typeid.ts`](https://github.com/different-ai/openwork/blob/main/ee/packages/utils/src/typeid.ts) and consumed by `den-api` through [`src/openapi.ts`](https://github.com/different-ai/openwork/blob/main/src/openapi.ts). This shared validation layer ensures that request and response schemas for organizations, users, and workers remain consistent across the API surface. The `den-api` uses Zod to enforce these schemas at route boundaries, providing type safety from the HTTP layer down to the MySQL database interactions.