# OpenSEO Project Structure Explained: Full-Stack TypeScript Architecture Guide

> Explore the OpenSEO project structure a full-stack TypeScript architecture organized into layers for entry points, server handlers, routing, API surfaces, workflows, and database access.

- Repository: [Every App/open-seo](https://github.com/every-app/open-seo)
- Tags: architecture
- Published: 2026-08-13

---

**The OpenSEO project is a full-stack TypeScript application built on TanStack React-Start and Drizzle ORM, organized into clear layers for entry points, server handlers, routing, API surfaces, workflows, and database access.**

This comprehensive guide examines how the **OpenSEO project structure** separates concerns across UI, server logic, data models, and infrastructure. Whether you're contributing to the codebase, self-hosting, or studying modern full-stack patterns, understanding this architecture reveals how the every-app/open-seo repository delivers SEO automation through a type-safe, maintainable design.

## Entry Point and Application Bootstrap

The application boots from [`src/start.ts`](https://github.com/every-app/open-seo/blob/main/src/start.ts), which creates the TanStack React-Start instance with mandatory middleware.

```typescript
// src/start.ts – creates startInstance with CSRF middleware
import { createStart, createCsrfMiddleware } from '@tanstack/react-start';

export const startInstance = createStart({
  middleware: [createCsrfMiddleware()],
});

```

This file registers `globalServerFunctionMiddleware`, ensuring all server functions execute with consistent request wrapping and security headers before reaching business logic.

## Server Handler and Request Routing

The Cloudflare Workers entry point lives in [`src/server.ts`](https://github.com/every-app/open-seo/blob/main/src/server.ts). This handler determines authentication mode and routes requests across four distinct paths.

**Three authentication modes** are supported:
- `hosted` – full SaaS with OAuth
- `cloudflare_access` – Cloudflare Access integration
- `local_noauth` – development bypass

The `fetch` function in [`src/server.ts`](https://github.com/every-app/open-seo/blob/main/src/server.ts) implements this routing logic:

| Route prefix | Handler | Destination |
|-------------|---------|-------------|
| `/agents/*` | `routeChatAgents` | Durable Object chat agents |
| `/auth/*` | `openSeoOAuthProvider` | Hosted OAuth flow |
| `/api/gsc/oauth/callback`, `/api/*` | `handleSelfHostedOpenSeoMcpRequest` | Self-hosted MCP |
| All other paths | `appFetch` | TanStack React UI |

Each request wraps the PostgreSQL client via `withPgClient`, ensuring database connections are managed consistently across all execution paths.

## Typed Routing System

Navigation relies on [`src/routeTree.gen.ts`](https://github.com/every-app/open-seo/blob/main/src/routeTree.gen.ts), an auto-generated file providing compile-time type safety for every route.

```typescript
// Using the typed route tree in components
import { useNavigate } from '@tanstack/react-router';
import { routeTree } from '@/routeTree.gen';

function ProjectNavigation() {
  const navigate = useNavigate();
  
  // TypeScript ensures 'routeTree.projects' exists
  return (
    <button onClick={() => navigate({ to: routeTree.projects })}>
      View Projects
    </button>
  );
}

```

Route files map directly to `src/routes/...`, with the generator ensuring any file addition or rename propagates type changes immediately.

## API Surface and Server Functions

The **MCP (Meta Control Plane)** exposes REST-like endpoints through files in `src/serverFunctions/*.ts`. These functions execute in the same Worker context as the requesting UI, sharing database connections and authentication state.

**Key server function modules:**
- [`src/serverFunctions/keywords.ts`](https://github.com/every-app/open-seo/blob/main/src/serverFunctions/keywords.ts) – keyword research and suggestions
- [`src/serverFunctions/rank-tracking.ts`](https://github.com/every-app/open-seo/blob/main/src/serverFunctions/rank-tracking.ts) – position monitoring
- [`src/serverFunctions/audit.ts`](https://github.com/every-app/open-seo/blob/main/src/serverFunctions/audit.ts) – site audit triggers and results

```typescript
// Calling a server function from client code
import { $keywords } from '@/serverFunctions/keywords';

async function fetchSuggestions(query: string) {
  // Executes in Worker, returns typed response
  const result = await $keywords.search({ query });
  return result.suggestions;
}

```

The `$` prefix convention distinguishes server-callable functions from regular utilities, with TypeScript enforcing parameter and return types across the network boundary.

## Background Workflows

Long-running operations execute as workflow classes in `src/server/workflows/*.ts`. These handle CPU-intensive or time-delayed tasks without blocking user requests.

**Core workflow implementations:**
- [`SiteAuditWorkflow.ts`](https://github.com/every-app/open-seo/blob/main/SiteAuditWorkflow.ts) – comprehensive site crawling and analysis
- [`RankCheckWorkflow.ts`](https://github.com/every-app/open-seo/blob/main/RankCheckWorkflow.ts) – scheduled position checking across search engines

Workflows instantiate via direct API calls or the Worker's `scheduled` export in [`src/server.ts`](https://github.com/every-app/open-seo/blob/main/src/server.ts), enabling cron-like execution for recurring SEO monitoring.

```typescript
// Scheduling a rank check from server code
import { runScheduledRankChecks } from '@/server/features/rank-tracking/services/scheduledRankChecks';

export const $rankTracking = {
  async schedule(projectId: string) {
    await runScheduledRankChecks({ PROJECT_ID: projectId });
    return { status: 'queued' };
  },
};

```

## Database Layer and Schema

Drizzle ORM provides type-safe database access with dual-target support for SQLite (Cloudflare D1) and PostgreSQL.

| Component | Location | Purpose |
|-----------|----------|---------|
| Core schema | [`src/db/schema.ts`](https://github.com/every-app/open-seo/blob/main/src/db/schema.ts) | Table definitions shared across dialects |
| Postgres client | [`src/db/pg/client.ts`](https://github.com/every-app/open-seo/blob/main/src/db/pg/client.ts) | Connection pooling and query execution |
| D1/SQLite adapter | [`src/db/index.ts`](https://github.com/every-app/open-seo/blob/main/src/db/index.ts) | Edge runtime compatibility |
| Migrations | `drizzle-pg/` | PostgreSQL-specific migration files |

The schema duplication in `drizzle-pg/` allows identical TypeScript types while optimizing for each database's capabilities—critical for supporting both Cloudflare's D1 (SQLite) in production and PostgreSQL in self-hosted deployments.

## Shared Utilities and Authentication

Cross-cutting concerns live in dedicated directories with comprehensive test coverage.

**Shared utilities (`src/shared/*.ts`):**
- [`keyword-locations.ts`](https://github.com/every-app/open-seo/blob/main/keyword-locations.ts) – geographic targeting logic
- [`gsc.ts`](https://github.com/every-app/open-seo/blob/main/gsc.ts) – Google Search Console API wrappers
- [`billing.ts`](https://github.com/every-app/open-seo/blob/main/billing.ts) – subscription and usage tracking

**Authentication modules (`src/lib/auth-*.ts`):**
- [`auth-config.ts`](https://github.com/every-app/open-seo/blob/main/auth-config.ts) – OAuth provider creation via `createOpenSeoOAuthProvider`
- Turnstile captcha validation for bot protection
- Session management across auth modes

Protected routes apply middleware from `src/middleware/ensure-user/*.ts`, enforcing authorization before handler execution.

## Documentation, Testing, and Scripts

The repository includes operational guides and comprehensive test suites.

| Directory | Contents |
|-----------|----------|
| `docs/*.md` | Self-hosting guides including [`SELF_HOSTING_DOCKER.md`](https://github.com/every-app/open-seo/blob/main/SELF_HOSTING_DOCKER.md) |
| `src/**/*.test.ts` | Unit tests for utilities and server functions |
| `e2e/*.spec.ts` | Playwright end-to-end tests for critical user flows |
| `scripts/*.ts` | Data seeding, migration utilities, and operational tools |

## Summary

- **OpenSEO project structure** separates concerns across eight distinct layers: entry point, server handler, routing, API surface, workflows, database, shared utilities, and authentication
- [`src/server.ts`](https://github.com/every-app/open-seo/blob/main/src/server.ts) routes requests across agents, OAuth, MCP, and UI paths with `withPgClient` wrapping every database interaction
- Server functions in `src/serverFunctions/*.ts` execute type-safe RPC calls within the same Worker context as the requesting UI
- Background workflows in `src/server/workflows/*.ts` handle audits and rank checks without blocking user requests
- Drizzle ORM with dual schema support enables identical types across D1 (SQLite) and PostgreSQL deployments
- Auto-generated [`src/routeTree.gen.ts`](https://github.com/every-app/open-seo/blob/main/src/routeTree.gen.ts) provides compile-time navigation safety throughout the React application

## Frequently Asked Questions

### What framework does OpenSEO use for its frontend and backend?

OpenSEO builds on **TanStack React-Start** for server-rendered React applications, with **Drizzle ORM** handling database operations. This combination provides type safety from database schema through API responses to UI components, all executing within Cloudflare Workers for edge deployment.

### How does OpenSEO handle authentication for different deployment modes?

The [`src/server.ts`](https://github.com/every-app/open-seo/blob/main/src/server.ts) handler determines authentication mode via `getAuthMode`, supporting three configurations: `hosted` for full SaaS OAuth, `cloudflare_access` for enterprise Cloudflare Access integration, and `local_noauth` for development environments. Each mode routes through appropriate handlers in `src/lib/auth-*.ts` files.

### Where are API endpoints defined in the OpenSEO codebase?

API endpoints reside in `src/serverFunctions/*.ts` as TypeScript functions rather than traditional route handlers. These server functions—such as `$keywords.search` in [`src/serverFunctions/keywords.ts`](https://github.com/every-app/open-seo/blob/main/src/serverFunctions/keywords.ts)—are wrapped by `globalServerFunctionMiddleware` and callable from client code with full type safety via the `$` prefix convention.

### How does OpenSEO manage background jobs like site audits?

Long-running tasks execute as workflow classes in `src/server/workflows/*.ts`. The [`SiteAuditWorkflow.ts`](https://github.com/every-app/open-seo/blob/main/SiteAuditWorkflow.ts) and [`RankCheckWorkflow.ts`](https://github.com/every-app/open-seo/blob/main/RankCheckWorkflow.ts) classes run either through direct invocation from server functions or via the `scheduled` export in [`src/server.ts`](https://github.com/every-app/open-seo/blob/main/src/server.ts) for cron-triggered execution, leveraging Cloudflare Durable Objects for state persistence.