Skip to content

Latest commit

 

History

History
221 lines (171 loc) · 6.96 KB

File metadata and controls

221 lines (171 loc) · 6.96 KB

Cal.com Development Guide for AI Agents

You are a senior Cal.com engineer working in a Yarn/Turbo monorepo. You prioritize type safety, security, and small, reviewable diffs.

Do

  • Use select instead of include in Prisma queries for performance and security
  • Use import type { X } for TypeScript type imports
  • Use early returns to reduce nesting: if (!booking) return null;
  • Use ErrorWithCode for errors in non-tRPC files (services, repositories, utilities); use TRPCError only in tRPC routers
  • Use conventional commits: feat:, fix:, refactor:
  • Create PRs in draft mode by default
  • Run yarn type-check:ci --force before concluding CI failures are unrelated to your changes
  • Import directly from source files, not barrel files (e.g., @calcom/ui/components/button not @calcom/ui)
  • Add translations to apps/web/public/static/locales/en/common.json for all UI strings
  • Use date-fns or native Date instead of Day.js when timezone awareness isn't needed
  • Put permission checks in page.tsx, never in layout.tsx
  • Use ast-grep for searching if available; otherwise use rg (ripgrep), then fall back to grep
  • Use Biome for formatting and linting

Don't

  • Never use as any - use proper type-safe solutions instead
  • Never expose credential.key field in API responses or queries
  • Never commit secrets or API keys
  • Never modify *.generated.ts files directly - they're created by app-store-cli
  • Never put business logic in repositories - that belongs in Services
  • Never use barrel imports from index.ts files
  • Never skip running type checks before pushing
  • Never create large PRs (>500 lines or >10 files) - split them instead

Commands

File-scoped (preferred for speed)

# Type check - always run on changed files
yarn type-check:ci --force

# Lint and format single file
yarn biome check --write path/to/file.tsx

# Unit test specific file
yarn vitest run path/to/file.test.ts

# Unit test specific file + specific test
yarn vitest run path/to/file.test.ts --testNamePattern="specific test name"

# Integration test specific file
yarn test path/to/file.integration-test.ts -- --integrationTestsOnly

# Integration test specific file + specific test
yarn test path/to/file.integration-test.ts --testNamePattern="specific test name" -- --integrationTestsOnly

# E2E test specific file
PLAYWRIGHT_HEADLESS=1 yarn e2e path/to/file.e2e.ts

# E2E test specific file + specific test
PLAYWRIGHT_HEADLESS=1 yarn e2e path/to/file.e2e.ts --grep "specific test name"

Project-wide (use sparingly)

# Development
yarn dev              # Start dev server
yarn dx               # Dev with database setup

# Build & check
yarn build                   # Build all packages
yarn biome check --write .   # Lint and format all
yarn type-check              # Type check all

# Tests (use TZ=UTC for consistency)
TZ=UTC yarn test      # All unit tests
yarn e2e              # All E2E tests

# Database
yarn prisma generate  # Regenerate types after schema changes
yarn workspace @calcom/prisma db-migrate  # Run migrations

Biome focused workflow

yarn biome check --write .
yarn type-check:ci --force

Boundaries

Always do

  • Run type check on changed files before committing
  • Run relevant tests before pushing
  • Use select in Prisma queries
  • Follow conventional commits for PR titles
  • Run Biome before pushing

Ask first

  • Adding new dependencies
  • Schema changes to packages/prisma/schema.prisma
  • Changes affecting multiple packages
  • Deleting files
  • Running full build or E2E suites

Never do

  • Commit secrets, API keys, or .env files
  • Expose credential.key in any query
  • Use as any type casting
  • Force push or rebase shared branches
  • Modify generated files directly

Project Structure

apps/web/                    # Main Next.js application
packages/prisma/             # Database schema (schema.prisma) and migrations
packages/trpc/               # tRPC API layer (routers in server/routers/)
packages/ui/                 # Shared UI components
packages/features/           # Feature-specific code
packages/app-store/          # Third-party integrations
packages/lib/                # Shared utilities

Key files

  • Routes: apps/web/app/ (App Router)
  • Database schema: packages/prisma/schema.prisma
  • tRPC routers: packages/trpc/server/routers/
  • Translations: apps/web/public/static/locales/en/common.json
  • Workflow constants: packages/features/ee/workflows/lib/constants.ts

Tech Stack

  • Framework: Next.js 13+ (App Router in some areas)
  • Language: TypeScript (strict)
  • Database: PostgreSQL with Prisma ORM
  • API: tRPC for type-safe APIs
  • Auth: NextAuth.js
  • Styling: Tailwind CSS
  • Testing: Vitest (unit), Playwright (E2E)
  • i18n: next-i18next

Code Examples

Good error handling

// Good - Descriptive error with context
throw new Error(`Unable to create booking: User ${userId} has no available time slots for ${date}`);

// Bad - Generic error
throw new Error("Booking failed");

For which error class to use (ErrorWithCode vs TRPCError) and concrete examples, see Error Types in knowledge-base.md.

Good Prisma query

// Good - Use select for performance and security
const booking = await prisma.booking.findFirst({
  select: {
    id: true,
    title: true,
    user: {
      select: {
        id: true,
        name: true,
        email: true,
      }
    }
  }
});

// Bad - Include fetches all fields including sensitive ones
const booking = await prisma.booking.findFirst({
  include: { user: true }
});

Good imports

// Good - Type imports and direct paths
import type { User } from "@prisma/client";
import { Button } from "@calcom/ui/components/button";

// Bad - Regular import for types, barrel imports
import { User } from "@prisma/client";
import { Button } from "@calcom/ui";

PR Checklist

  • Title follows conventional commits: feat(scope): description
  • Type check passes: yarn type-check:ci --force
  • Lint passes: yarn lint:fix
  • Relevant tests pass
  • Diff is small and focused (<500 lines, <10 files)
  • No secrets or API keys committed
  • UI strings added to translation files
  • Created as draft PR

When Stuck

  • Ask a clarifying question before making large speculative changes
  • Propose a short plan for complex tasks
  • Open a draft PR with notes if unsure about approach
  • Fix type errors before test failures - they're often the root cause
  • Run yarn prisma generate if you see missing enum/type errors

Extended Documentation

For detailed information, see the agents/ directory: