Server Overview
NestJS backend architecture, modules, and technology stack
The Cosmo backend is a NestJS REST API server located at packages/server. It serves all desktop, web, and CLI clients through a single API surface.
Technology Stack
| Layer | Technology |
|---|---|
| Framework | NestJS (Express adapter) |
| Database | PostgreSQL via Prisma ORM |
| Auth | Clerk (cloud) + custom JWT (CLI) |
| LLM | Anthropic Claude API |
| Storage | Cloudflare R2 / S3 (via S3-compatible SDK) |
| Billing | Stripe |
| Cache/Queue | Redis (Upstash) |
| Analytics | PostHog |
| Webhooks | Svix (Clerk) |
| Port | 4000 (default) |
| Global prefix | api/v1 |
Module Map
AppModule
├── AuthModule — JWT, OAuth, Clerk sync, org management
├── ChatModule — LLM streaming via SSE
├── WorkspacesModule — Workspace CRUD
├── TasksModule — Task management + AI reprioritization
├── TeamsModule — Team & membership management
├── ConnectorsModule — MCP connector instances
├── ConnectorProvidersModule — Provider registry
├── MCPOAuthModule — Server-mediated OAuth for integrations
├── WorkspaceSyncModule — File sync + SSE change feed
├── BillingModule — Stripe subscriptions + webhooks
├── MeteringModule — Token usage + quota enforcement
├── UpdatesModule — Desktop app release management
└── AdminModule — Internal enterprise + release adminStartup (main.ts)
On bootstrap:
- Creates NestJS app with
bodyParser: falseto allow raw body access for webhook signature verification. - Sets up raw body middleware for
/api/v1/billing/webhookand/api/v1/auth/webhook(Stripe + Svix need the raw bytes). - Configures CORS to allow requests from
localhost:3000,localhost:5173, Electronapp://origin, and127.0.0.1. - Sets up Clerk Frontend API proxy at
/__clerk/*— forwards toclerk.getcosmo.appwith proxy headers. This lets the Electron desktop app load Clerk fromlocalhost. - Applies global exception filter (catches unhandled errors, sends 5xx to PostHog).
- Sets global prefix
api/v1. - Listens on
process.env.PORT ?? 4000.
Auth Model
All endpoints (except webhooks and the public connector-providers list) require a Bearer token in the Authorization header.
Two token types are accepted by ClerkAuthGuard:
| Type | Format | Issued by |
|---|---|---|
| Cosmo JWT | Custom 30-day JWT | POST /api/v1/auth/exchange-token |
| Clerk JWT | Short-lived Clerk session token | Clerk SDK |
When a Clerk JWT is presented, the guard syncs user/org/membership data from Clerk into the local DB on first use. The guard attaches a RequestUser object to req.user:
interface RequestUser {
userId: string;
orgId: string;
orgRole: OrgRole;
}Tenant Isolation
Every query, every endpoint, every WebSocket message is scoped to orgId. There is no cross-tenant data access. The orgId is always derived from the verified JWT — it cannot be supplied by the client.
Storage Architecture
All file content lives in R2/S3 blob storage. PostgreSQL is a metadata index only — it holds StorageObject records with a storageKey (the blob key) but never the file bytes.
/{orgId}/shared/hub-memory/ ← Org-level hub memory
/{orgId}/shared/brand/ ← Brand assets
/{orgId}/shared/templates/ ← Shared templates
/{orgId}/teams/{teamId}/memory/ ← Team memory
/{orgId}/workspaces/{workspaceId}/ ← Workspace artifacts + memory
/{orgId}/personal/{userId}/ ← Personal drafts, user memoryError Handling
GlobalExceptionFilter catches all unhandled exceptions:
- Returns
{ statusCode, message, timestamp, path }JSON. - Sends only 5xx errors to PostHog (4xx errors are user mistakes, not bugs).
Environment Variables
| Variable | Description |
|---|---|
DATABASE_URL | PostgreSQL connection string |
CLERK_SECRET_KEY | Clerk backend secret |
CLERK_PUBLISHABLE_KEY | Clerk public key |
CLERK_PROXY_URL | Clerk Frontend API proxy URL |
CLERK_FAPI_HOST | Clerk Frontend API host |
CLERK_WEBHOOK_SECRET | Svix webhook verification secret |
ANTHROPIC_API_KEY | Claude API key |
STRIPE_SECRET_KEY | Stripe backend secret |
STRIPE_PUBLISHABLE_KEY | Stripe public key |
STRIPE_WEBHOOK_SECRET | Stripe webhook signing secret |
POSTHOG_API_KEY | PostHog project API key |
POSTHOG_HOST | PostHog host |
PORT | Server port (default: 4000) |
COSMO_SERVER_URL | Server's public URL |
COSMO_WEB_URL | Web app URL |
CORS_ORIGINS | Comma-separated allowed origins |