Source: https://www.hype-stack.dev/docs/backend/organize-features

# How to Organize Features

Backend code is organized by domain. Each domain in `src/features/` owns its business logic, database access, schemas,
and tests.

## Structure

```
src/features/<domain>/
  modules/
    <use-case>/
      index.ts           # Module function
      index.test.ts      # Tests
      schemas/            # Zod schemas for this module
      helpers/            # Module-specific helpers
      emails/             # Email templates (React Email)
  db/
    queries/              # Kysely read queries
    mutations/            # Prisma writes, Kysely transactions
  types/                  # Domain types
  constants/              # Domain constants
  websockets/
    emitters.ts           # wsEmit calls for this domain
```

## Example: projects domain

```
src/features/projects/
  modules/
    create-project/
      index.ts
      index.test.ts
    get-project/
      index.ts
    delete-project/
      index.ts
    projects-list/
      index.ts
  db/
    queries/
      get-by-id.query.ts
      get-many.query.ts
    mutations/
      create-project.mutation.ts
      update-project.mutation.ts
      delete-project.mutation.ts
```

## Rules

- **No `src/services/` directory.** Shared infrastructure goes in `src/libs/`, database clients in `src/db/`, cache in
  `src/cache/`, middleware in `src/middleware/`.

- **Routes stay thin.** Route files in `src/routes/` validate input, call module functions, and return responses. Logic
  belongs in modules.

- **No try/catch.** The centralized error middleware handles all errors. Throw typed errors and let them bubble up. See
  the error handling section below.

## Error handling

Use typed error classes from `@backend/middleware/error`:

```ts
import { ApplicationError, ApplicationErrorCode } from "@backend/middleware/error";

if (!project) {
  throw new ApplicationError({
    code: ApplicationErrorCode.NOT_FOUND,
    message: "Project not found",
    statusCode: 404,
  });
}
```

Available error classes:

| Class                | Use case                                                                    |
| -------------------- | --------------------------------------------------------------------------- |
| `ApplicationError`   | Domain failures (not found, bad request, invalid state)                     |
| `AuthError`          | Authentication/session failures                                             |
| `AuthorizationError` | Missing permissions                                                         |
| `ValidationError`    | Schema validation (usually thrown automatically by the validate middleware) |

The global error middleware formats these into consistent HTTP responses.
