Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/paramveer-cyber/Deployaar/llms.txt

Use this file to discover all available pages before exploring further.

The Four-Layer Rule is the central architectural constraint of Deployaar. Every feature — whether it’s creating a feature request, approving a PRD, or triggering the coding agent — must be implemented by flowing code top-to-bottom through exactly four layers in order. No layer is allowed to skip the one directly below it. A frontend component cannot import a service. A tRPC route cannot query the database directly. A database query file cannot contain business logic. This constraint is enforced by convention and code review, and it is what makes every part of the system independently testable and easy to reason about.

The Four Layers

LayerLocationResponsibility
Layer 4 — Frontend Hooksapps/web/hooks/*React Query wrappers around tRPC client calls. The only place in the frontend that talks to the server. Components call these hooks; they never call tRPC directly.
Layer 3 — tRPC Routespackages/trpc/server/routes/*Thin procedure layer. Validates all input with Zod schemas, calls exactly one service function, and returns the result. Contains no business logic.
Layer 2 — Servicespackages/services/*All business logic lives here — AI calls, GitHub API calls, billing enforcement, Inngest event dispatch, and orchestration between multiple database queries. Never imported directly by the frontend.
Layer 1 — DB Queriespackages/database/queries/*Raw Drizzle ORM queries only. Each sub-folder corresponds to one domain (e.g., feature-request, prd, agent-run). No business logic, no AI calls, no side effects.
The packages/database/queries/ directory contains query modules for every domain in the platform: agent-run, billing, clarification, feature-request, feature-task, github, github-webhook-delivery, organization, prd, project, project-repository, pull-request-review, and user-settings. Each is a standalone module that services import individually.

Why This Matters

Strict layering produces three concrete engineering benefits:
  1. Testability — Services can be unit tested by mocking only the DB query functions they import. No HTTP server, no browser, no tRPC plumbing required.
  2. Clear ownership — When a bug is reported, the layer it lives in is immediately obvious. Incorrect data returned? Look in a query file. Wrong business rule applied? Look in a service. Bad user-facing error message? Look in a tRPC route.
  3. Frontend isolation — The frontend (apps/web) has zero knowledge of database schemas, AI providers, or GitHub credentials. It only ever sees the types that tRPC exposes. This means the entire backend can be refactored without touching a single React component, as long as the tRPC procedure signatures stay stable.

Layer Violations (Anti-patterns)

Never violate layer boundaries. The following patterns are explicitly prohibited:
  • Importing a service directly into a Next.js page or componentimport { generatePrd } from "@repo/services/prd" inside apps/web/ is forbidden. Services run on the API server and may reference secrets, GitHub tokens, and database connections that must not reach the browser bundle.
  • Putting business logic in a DB query file — A file under packages/database/queries/ must only contain Drizzle queries. Billing plan assertions, AI model resolution, and status transition guards all belong in packages/services/.
  • Calling the database directly from a tRPC route — A route in packages/trpc/server/routes/ must not import from packages/database/. It must call a service, which in turn calls a query. This ensures business logic enforcement is never bypassed by a shortcut in the route layer.

tRPC Route Structure

Every route in packages/trpc/server/routes/ follows a consistent two-file pattern:
  • models.ts — Zod schemas for all procedure inputs and any shared types for that domain
  • route.ts — tRPC procedures that import from models.ts for validation and from packages/services/* for execution
All route routers are assembled into the top-level serverRouter in packages/trpc/server/index.ts:
// packages/trpc/server/index.ts
export const serverRouter = router({
  health: healthRouter,
  github: githubRouter,
  organization: organizationRouter,
  invitation: invitationRouter,
  cron: cronRouter,
  project: projectRouter,
  featureRequest: featureRequestRouter,
  prd: prdRouter,
  featureTask: featureTaskRouter,
  pullRequestReview: pullRequestReviewRouter,
  agentRun: agentRunRouter,
  billing: billingRouter,
  userSettings: userSettingsRouter,
});
A correctly structured tRPC route calling a service looks like this:
// packages/trpc/server/routes/feature-request/route.ts
import { z } from "zod";
import { publicProcedure, router } from "../../trpc";
import { createFeatureRequest } from "@repo/services/feature-request";
import { CreateFeatureRequestInput } from "./models";

export const featureRequestRouter = router({
  create: publicProcedure
    .input(CreateFeatureRequestInput)
    .mutation(async ({ input, ctx }) => {
      return createFeatureRequest(ctx.user.id, input);
    }),
});
The route does three things only: import the input schema, call one service function, and return the result. All validation is handled by Zod at the .input() boundary before the service is ever called.
Demo and read-only account enforcement is implemented entirely at Layer 3. A demoReadOnlyProcedure middleware wrapper throws a FORBIDDEN tRPC error on all mutation procedures when the authenticated user is a read-only demo account. Because the check sits in the tRPC layer, it applies uniformly to every mutation across every domain — no service-level guard needed.

Build docs developers (and LLMs) love