Hype StackHypeStack

Backend Overview

The backend lives in apps/backend/ and runs a Hono API server on Node.js. It uses Prisma for schema management, Kysely for typed queries, PostgreSQL for storage, and Redis (Valkey) for caching.

Folder structure

apps/backend/src/
  cache/         # Valkey (Redis) client and initialization
  config/        # Environment config, app constants
  db/            # Database client (Postgres + Kysely)
  features/      # Domain-organized business logic
  libs/          # Shared backend libraries and WebSocket setup
  middleware/     # Error handling, validation, auth, file uploads
  routes/        # HTTP route definitions (thin layer)
  sockets/       # WebSocket event definitions
  testing/       # Test utilities, mocks, setup
  utils/         # Shared helpers

Bootstrap order

At process start the server roughly does this:

Startup

  1. Validate env

    Zod parses process.env. Missing keys stop the process before ports open.

  2. Attach context

    Postgres, Valkey, storage, and other clients land on the Hono app context.

  3. Register sockets and routes

    WebSocket routers and HTTP routers mount under their prefixes.

  4. Global middleware

    CORS and the centralized error middleware wrap every request.

Request lifecycle

Authenticated HTTP request

  1. Global middleware

    CORS runs, then the error middleware wraps the rest of the chain.

  2. Route match

    Hono picks the feature router mounted from registerRoutes.

  3. Auth and permissions

    getAuthenticatedApp() runs withAuthUser. Routes add hasAccess({ action, subject }) when needed.

    After a starter pack
  4. Validation

    The validate middleware parses json or query input with Zod and types the handler.

  5. Module then db

    The thin route calls a feature module. The module calls queries or mutations. No business logic in the route file.

  6. JSON response or typed error

    Success returns ctx.json(...). Failures throw ApplicationError / AuthError / ValidationError and the error middleware formats the response (and reports unexpected errors to Sentry when configured).

Layer responsibilities

LayerResponsibilityMust not do
main / app bootstrapenv, context, mount routers, global middlewareOwn feature rules
Global middlewareCORS, centralized errorsFeature-specific DB writes
Route middlewareAuth, validate(), hasAccess(), uploadsOrchestrate multi-step business flows
Route handlerRead context, call one module, return JSONRaw SQL or provider SDK sprawl
Feature moduleBusiness rules and orchestrationKnow HTTP status codes
db/queries / db/mutationsPersistenceSession / request semantics beyond args

Key patterns

  • Features own business logic. Each domain (projects, notifications, auth) has its own folder in src/features/ with modules, database queries, mutations, and schemas. See How to organize features.

  • Routes are thin. Route files validate input, read context, call a module function, and return a response. No business logic in routes. See Routing.

  • No try/catch. A centralized error middleware handles all errors. Throw typed errors (ApplicationError, AuthError, ValidationError) and let the middleware do its job. Swallowing errors also skips Sentry.

  • Validation goes through Zod. Every route that accepts input uses the validate() middleware with a Zod schema. This powers both runtime validation and the end-to-end type bridge to the frontend SDK.

HyperFetch SDK generation

registerRoutes returns a typed Hono app. The frontend HyperFetch SDK is derived from that type, so a new route appears on sdk.* without a separate codegen step. Details: end-to-end type safety and HTTP.

Database access

  • Prisma for schema definition, migrations, and seeding
  • Kysely for typed SQL queries (reads and complex writes)
  • Prisma for inserts, Kysely for everything else

Reads go in db/queries/, writes go in db/mutations/. See Prisma and Kysely and Migrations.

Sponsor open source

Every purchase and sponsorship funds my 8+ years of work on open source given freely to the community. It keeps the lights on, funds new packs, and keeps the ecosystem alive. Even a small tier means a lot. Thank you!

Sponsor on GitHub