How the Core Logic of Open-SEO Is Organized in the `src` Directory: A Complete Architecture Guide
The Open-SEO src directory follows a feature-first layered architecture separating entry points, API surfaces, business logic services, data repositories, shared utilities, database schema, middleware, and client-side code.
This guide unpacks exactly how every-app/open-seo structures its TypeScript codebase. Whether you're contributing a new feature or tracing a bug, understanding this hierarchy will help you navigate the repository efficiently.
Entry Point Layer: Bootstrapping the Application
Every request begins in two critical files at the root of src.
src/start.ts— Builds the TanStack React-Start handler that powers the application's routing and rendering.src/server.ts— Implements the Cloudflare Workerfetchentry point. This file routes incoming requests to API functions, OAuth handlers, self-hosted MCP endpoints, or Durable Object agents before falling back to the TanStack start handler.
In src/server.ts, you'll find the central dispatch logic that distinguishes between /agents/* paths, OAuth flows, and standard page requests.
API Surface Layer: Server Functions
The src/serverFunctions/*.ts files define the contract between client and server. Each file registers one or more server functions using createServerFn with explicit HTTP methods.
For example, src/serverFunctions/dashboard.ts demonstrates the standard pattern: apply middleware, validate with Zod, then delegate to a service. These functions are consumed by the front-end through TanStack Query hooks.
Key files in this layer include dashboard.ts and rank-tracking.ts.
Feature Modules: Where Business Logic Lives
The heart of Open-SEO lives under src/server/features/<domain>/. Each feature (rank-tracking, SAM, audit, backlinks) contains two subdirectories:
services/— Pure business logic without I/O concernsrepositories/— Typed database queries using the schema-generated types
Rank-Tracking Service Example
src/server/features/rank-tracking/services/RankTrackingService.ts encapsulates the complete rank-tracking algorithm:
// Core service implementation (excerpt)
async function addKeywords(
configId: string,
projectId: string,
keywords: string[],
) {
// Validate the config belongs to the project
await getValidatedConfig(configId, projectId);
// Remove duplicates, enforce limits
const existing = await RankTrackingRepository.getKeywordsForConfig(configId);
const available = MAX_KEYWORDS_PER_CONFIG - existing.length;
const rows = keywords
.map(k => k.trim().toLowerCase())
.filter((k, i, arr) => k && arr.indexOf(k) === i && !existing.some(e => e.keyword === k))
.slice(0, available)
.map(k => ({ id: crypto.randomUUID(), configId, keyword: k }));
// Insert new rows in a single DB transaction
await RankTrackingRepository.insertKeywords(rows);
}
The corresponding RankTrackingRepository in src/server/features/rank-tracking/repositories/RankTrackingRepository.ts handles all SQL/D1 operations, keeping the service layer database-agnostic.
Shared Utilities: Cross-Cutting Concerns
The src/shared/*.ts directory contains reusable helpers imported by multiple services and UI components. One critical example is src/shared/keyword-locations.ts, which resolves market and location codes:
import { resolveMarket } from "@/shared/keyword-locations";
These utilities enforce consistency across features—whether normalizing domains, mapping color scales, or calculating credit costs.
Database Schema Layer
All PostgreSQL/D1 table definitions live in src/db/*.ts. Key files include:
src/db/schema.ts— Centralized table definitions for projects, rank-tracking configurations, audit results, and moresrc/db/provider.ts— Creates a typed database client per request with proper connection handling
Services never interact with the database directly. They call repository functions, which use the schema-generated types for compile-time safety.
Middleware Layer: Request Processing Pipeline
The src/middleware/*.ts files implement cross-cutting concerns:
src/middleware/ensureUser.ts— Validates Cloudflare Access tokens, local development mode, or self-hosted authentication tokensrequireProjectContext— Injects the current project into handler context after authorization
Middleware is applied globally in src/server.ts or selectively to individual server functions via .middleware(requireProjectContext).
Client-Side Layer: React Components and Hooks
The user interface lives in src/routes/*.tsx and src/client/**/*.ts. Route files render pages, while client hooks like useSearchHistory call the server functions defined in src/serverFunctions/.
This separation ensures the client remains thin—complex logic stays on the server, exposed only through typed function calls.
Complete Request Flow: From Browser to Database
Tracing a rank-tracking keyword addition illustrates how these layers interact:
// Server-function exposed to the client
export const addKeywordsToConfig = createServerFn({ method: "POST" })
.middleware(requireProjectContext)
.validator(addKeywordsSchema)
.handler(async ({ context, input }) => {
await RankTrackingService.addKeywords(
input.configId,
context.projectId,
input.keywords,
);
return { ok: true };
});
- Front-end calls
addKeywordsToConfigvia TanStack Query - Middleware (
requireProjectContext) resolves and injects the project - Service (
RankTrackingService.addKeywords) validates business rules, deduplicates keywords, enforces limits - Repository (
RankTrackingRepository.insertKeywords) executes the database transaction - Response serializes
{ ok: true }back to the client
This server-function → middleware → service → repository → DB pattern repeats consistently across every feature.
Key Source Files Reference
| File | Purpose |
|---|---|
src/server.ts |
Main request handler and router |
src/serverFunctions/dashboard.ts |
Example server-function with validation |
src/server/features/rank-tracking/services/RankTrackingService.ts |
Core rank-tracking algorithm |
src/server/features/rank-tracking/repositories/RankTrackingRepository.ts |
Rank-tracking data access |
src/shared/keyword-locations.ts |
Market resolution utility |
src/db/schema.ts |
Centralized table definitions |
src/middleware/ensureUser.ts |
Authentication validation |
Summary
- Feature-first organization — Each domain lives under
src/server/features/<domain>/with isolated services and repositories - Clear separation of concerns — API surfaces are thin wrappers; business logic lives in services; data access is repository-only
- Shared utilities centralized — Cross-cutting helpers in
src/shared/prevent duplication - Middleware pipeline — Reusable auth and context injection applied consistently
- End-to-end type safety — Database schema feeds through repositories to services to server functions
This architecture makes Open-SEO maintainable at scale: locate any logic by feature, extend functionality without side effects, and trace requests through a predictable layered flow.
Frequently Asked Questions
What is the purpose of src/server.ts in Open-SEO?
src/server.ts serves as the Cloudflare Worker entry point that routes all incoming requests. It handles /agents/* paths for Durable Object chat agents, OAuth authentication flows, self-hosted MCP endpoints, and falls back to the TanStack React-Start handler for standard page requests. This single file orchestrates the entire request dispatch pipeline.
How does Open-SEO separate business logic from database access?
Business logic lives in src/server/features/<domain>/services/*.ts files like RankTrackingService.ts, which contain pure algorithms with no direct database calls. These services delegate all I/O to repositories in src/server/features/<domain>/repositories/*.ts. This separation allows testing business rules in isolation and swapping database implementations without touching core logic.
Where should I add a new feature in the Open-SEO codebase?
Create a new directory under src/server/features/<your-feature>/ containing services/ and repositories/ subdirectories. Implement your business logic in a service file, data access in a repository file, then expose functionality through a new file in src/serverFunctions/. Add any cross-cutting utilities to src/shared/ if multiple features need them.
How does authentication work across the Open-SEO architecture?
Authentication is handled by src/middleware/ensureUser.ts, which validates Cloudflare Access tokens in production, bypasses checks in local development, or accepts self-hosted tokens. This middleware integrates into src/server.ts for global protection and can be selectively applied to individual server functions via .middleware(requireProjectContext) or similar middleware chains.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →