Ga naar hoofdinhoud

Coding Standards

This document describes the coding standards and conventions used across the ProBeya codebase. Following these ensures consistency and makes code reviews smoother.

Language​

The entire codebase is written in TypeScript. We use strict mode ("strict": true in tsconfig) everywhere. Avoid any types — use unknown and type narrowing instead.

Formatting​

We use Prettier for code formatting with the following configuration:

{
"semi": true,
"singleQuote": false,
"trailingComma": "all",
"printWidth": 100,
"tabWidth": 2,
"useTabs": false
}

Run pnpm format to format all files. The CI pipeline rejects unformatted code.

Linting​

We use ESLint with a custom configuration that extends:

  • @typescript-eslint/recommended
  • @typescript-eslint/strict-type-checked
  • eslint-plugin-react-hooks
  • eslint-plugin-import

Run pnpm lint to check for issues. Run pnpm lint:fix to auto-fix where possible.

File Structure​

Naming Conventions​

ElementConventionExample
Fileskebab-caseuser-profile.ts
React componentsPascalCase fileBoardView.tsx
Directorieskebab-casecustom-fields/
Variables and functionscamelCasegetUserById
Types and interfacesPascalCaseBoardConfig
ConstantsSCREAMING_SNAKE_CASEMAX_ITEMS_PER_PAGE
Database tablessnake_caseboard_items
API procedurescamelCase with dot notationitem.create

Imports​

Order imports in this sequence (enforced by ESLint):

  1. Node built-in modules (node:fs, node:path)
  2. External packages (react, drizzle-orm)
  3. Internal packages (@probeya/db, @probeya/validators)
  4. Relative imports (./components, ../utils)
import { createContext, useContext } from "react";
import { eq } from "drizzle-orm";

import { db } from "@probeya/db";
import { itemSchema } from "@probeya/validators";

import { BoardHeader } from "./board-header";
import { useBoard } from "../hooks/use-board";

React Conventions​

  • Use function declarations for components, not arrow functions:
    export function BoardView({ boardId }: { boardId: string }) {
    // ...
    }
  • Use named exports, not default exports.
  • Co-locate component-specific hooks, types, and utilities in the same directory.
  • Use Zustand for client-side state management — avoid prop drilling beyond 2 levels.

API Conventions​

  • All tRPC procedures must have Zod input validation.
  • Use the protectedProcedure base for authenticated endpoints.
  • Return consistent shapes — use the Result pattern for operations that can fail.
  • Log errors with structured context:
    logger.error("Failed to create item", { boardId, userId, error });

Database Conventions​

  • Use Drizzle ORM for all database interactions — no raw SQL in application code.
  • Always scope queries to the current organization using the withOrg middleware.
  • Use transactions for operations that modify multiple tables.
  • Prefer returning() over separate select queries after inserts/updates.

Error Handling​

  • Use tRPC error codes (TRPCError) for API errors.
  • Never expose internal error details to clients.
  • Log the full error server-side with context.
  • Provide user-friendly error messages in the response.
import { TRPCError } from "@trpc/server";

throw new TRPCError({
code: "NOT_FOUND",
message: "Board not found",
});