Architecture Overview
Relevant source files
The following files were used as context for generating this wiki page:This project is a modern, full-stack TypeScript monorepo built with Turborepo. It features a "contract-based" architecture, where a shared contract package defines the API interface, ensuring type safety between the React frontend and the Hono backend. The architecture is designed for high performance and a streamlined developer experience, leveraging tools like ORPC for type-safe RPC, Drizzle ORM for database interactions, and the TanStack ecosystem for frontend development.
The core principle is to have a single source of truth for the API's structure, which is consumed by both the server for implementation and the client for making type-safe requests. This eliminates entire classes of bugs related to API-client mismatches and provides excellent autocompletion and static analysis across the entire stack.
Sources: README.md:3-8
Monorepo Structure
The project is organized as a monorepo using pnpm workspaces and managed by Turborepo. The structure separates applications (apps) from shared logic (packages), promoting code reuse and maintainability.
Sources: README.md:30-38, package.json:3
This diagram shows the high-level folder structure and the primary dependencies between the applications and shared packages.
The following table describes the purpose of each major directory:
| Package/App | Description | Source -
| apps/api | Hono API server with ORPC for handling backend logic and requests. | README.md:33 -
| apps/web | React frontend application built with TanStack Router. | README.md:34 -
| packages/contract | Defines the API contract and schemas, serving as the single source of truth. | README.md:37 -
| packages/db | Contains the database schema (Drizzle ORM) and access layer. | README.md:38 -
| packages/ui | A set of shared, unstyled, accessible UI components using Radix UI. | README.md:39, packages/ui/package.json:2 -
Sources: README.md:32-39
Backend Architecture (apps/api)
The backend is a Hono web server running on Node.js. It's designed to be lightweight and fast. Its primary responsibilities are to implement the API contract, handle business logic, and interact with the database.
Sources: README.md:21, apps/api/package.json:15
This diagram illustrates the key components of the backend server.
Key Components
- Hono: An "ultrafast" web framework used as the foundation for the API server.
Sources: README.md:21, apps/api/package.json:15 - ORPC: A type-safe RPC framework. The server uses
@orpc/serverto create RPC endpoints that automatically align with the sharedcontractpackage.
Sources: README.md:22, apps/api/package.json:11 - Database (Drizzle ORM): The project uses Drizzle ORM for a type-safe SQL query experience, connecting to a PostgreSQL database. The
packages/dbcontains the schema definitions.
Sources: README.md:26-27, packages/db/package.json:18 - Authentication: Handled by the
better-authlibrary, which is configured with a Drizzle adapter to manage users, sessions, and accounts in the database.
Sources: README.md:23, apps/api/src/lib/auth.ts:5 - API Documentation: OpenAPI specifications are automatically generated from the
contractpackage using@orpc/openapi. These are served via@scalar/hono-api-referencefor an interactive documentation UI.
Sources: README.md:24, apps/api/src/handlers/openapi.ts:4-10
Frontend Architecture (apps/web)
The frontend is a modern React 19 application built with a focus on type-safety and developer experience, heavily utilizing the TanStack ecosystem.
Sources: README.md:15, apps/web/package.json:19
This diagram shows the main libraries and data flow within the frontend application.
Key Components
- React 19 & Vinxi: The core UI library and build tool.
Sources: README.md:15, apps/web/package.json:19,30 - TanStack Router: Provides a type-safe, file-based routing solution. Routes are defined in the
src/routesdirectory.
Sources: README.md:16, apps/web/README.md:31 - TanStack Query: Manages asynchronous state and server data fetching, providing caching, refetching, and more.
Sources: README.md:17, apps/web/README.md:100 - Styling: A combination of Tailwind CSS for utility-first styling and Radix UI (via the shared
uipackage) for unstyled, accessible component primitives.
Sources: README.md:19-20, packages/ui/package.json:12 - API Client: While not fully implemented, the architecture is designed for a type-safe client (e.g., using
@orpc/client) that consumes thecontractpackage to make requests to the backend.
Sources: README.md:4
The contract Package: The Core of the Architecture
The packages/contract is the most critical piece of this architecture. It serves as a single source of truth for the API's shape, defining all procedures, inputs, and outputs.
Sources: README.md:37, packages/contract/README.md:3
Contract Definition
The contract is an object that organizes API procedures into namespaces (e.g., auth, planet). It is built using @orpc/contract.
Sources: packages/contract/src/contract/index.ts:1-19
// packages/contract/src/contract/index.ts
import { me, signin, signup } from "./auth";
import { createPlanet, findPlanet, listPlanets, updatePlanet } from "./planet";
import { sse } from "./sse";
export const contract = {
auth: {
signup,
signin,
me,
},
planet: {
list: listPlanets,
create: createPlanet,
find: findPlanet,
update: updatePlanet,
},
sse,
};
Schema Definition with Zod
The inputs and outputs for each procedure are defined using Zod schemas. This provides runtime validation on the server and static type inference on the client. The @orpc/zod library enhances Zod with features like file uploads (oz.file()).
Sources: packages/contract/src/schemas/planet.ts:1-22, packages/contract/package.json:16
// packages/contract/src/schemas/planet.ts
import { oz } from "@orpc/zod";
import { z } from "zod";
import { UserSchema } from "./user";
// ...
export const NewPlanetSchema = z.object({
name: z.string(),
description: z.string().optional(),
image: oz.file().type("image/*").optional(),
});
export const PlanetSchema = z.object({
id: z.number().int().min(1),
name: z.string(),
description: z.string().optional(),
imageUrl: z.string().url().optional(),
creator: UserSchema,
});
End-to-End Data Flow
The contract-based approach enables a fully type-safe data flow from the frontend to the database and back.
This sequence diagram illustrates a hypothetical request to create a planet.
- Client Request: The React frontend uses a type-safe client to call
planet.create. The arguments are statically typed based on theNewPlanetSchemafrom thecontractpackage. - Server Handling: The Hono server receives the request. The ORPC middleware uses the same
contractpackage to validate the incoming data against the Zod schema. - Database Interaction: The server logic interacts with the database via Drizzle ORM, which also provides type safety at the database level.
- Server Response: The server shapes the database result to match the
PlanetSchemafrom thecontractbefore sending it back to the client. - Client Receives Data: The React client receives the data, which is already typed correctly, allowing for safe access to properties like
data.idwithout manual type casting.
Sources: README.md, packages/contract/src/contract/index.ts, apps/api/src/middlewares/db.ts:1-8
Summary
The architecture of this project is centered around a shared API contract that enforces type safety across the full stack. By using a Turborepo monorepo, it effectively separates concerns into distinct applications (web, api) and reusable modules (contract, db, ui). This setup, combined with modern tools like Hono, Drizzle, and the TanStack ecosystem, creates a robust, maintainable, and highly productive development environment for building full-stack TypeScript applications.
Sources: README.md:3-8