diff --git a/.cursor/rules/global.mdc b/.cursor/rules/global.mdc index faee8ef68..9a2e8ed68 100644 --- a/.cursor/rules/global.mdc +++ b/.cursor/rules/global.mdc @@ -3,12 +3,6 @@ description: globs: alwaysApply: true --- -# CLAUDE.md - -This file provides guidance to Claude Code when working with code in this monorepo. - -**Note**: Many packages and apps have their own CLAUDE.md files with specific implementation details and patterns. Always check for a local CLAUDE.md when working in a specific directory. - ## Monorepo Structure This is a pnpm-based monorepo using Turborepo with the following structure: @@ -54,6 +48,58 @@ When writing code, follow this workflow to ensure code quality: - Keep business logic separate from infrastructure concerns - Use proper error handling at each level +## Environment Variables + +This project uses a centralized environment variable system: + +1. **All environment variables are defined at the root level** in a single `.env` file +2. **Turbo passes these variables** to all packages via the `globalEnv` configuration in `turbo.json` +3. **Individual packages validate** their required environment variables using the shared `@buster/env-utils` package + +### Setting Up Environment Variables + +1. Copy `.env.example` to `.env` at the project root: + ```bash + cp .env.example .env + ``` + +2. Fill in the required values in `.env` + +3. All packages will automatically have access to these variables through Turbo + +### Adding New Environment Variables + +When adding new environment variables: + +1. Add the variable to `.env.example` with a descriptive comment +2. Add the variable name to the `globalEnv` array in `turbo.json` +3. Update the package's `validate-env.js` script to include the new variable +4. Update the package's `env.d.ts` file with the TypeScript type definition + +### Migrating Packages to Centralized Env + +To migrate an existing package to use the centralized environment system: + +1. Remove any local `.env` files from the package +2. Add `@buster/env-utils` as a dependency: + ```json + "@buster/env-utils": "workspace:*" + ``` +3. Update the package's `scripts/validate-env.js` to use the shared utilities: + ```javascript + import { loadRootEnv, validateEnv } from '@buster/env-utils'; + + loadRootEnv(); + + const requiredEnv = { + DATABASE_URL: process.env.DATABASE_URL, + // ... other required variables + }; + + const { hasErrors } = validateEnv(requiredEnv); + if (hasErrors) process.exit(1); + ``` + ### 3. Ensure Type Safety ```bash # Build entire monorepo to check types @@ -202,18 +248,23 @@ export async function getWorkspaceSettingsHandler( ## Database Operations +### Query Organization +- **All database queries must be created as helper functions** in `@packages/database/src/queries/` +- **Organize by table** - Each table should have its own subdirectory (e.g., `assets/`, `chats/`, `users/`) +- **Type all queries** - Every query function must have properly typed parameters and return types +- **Export from index** - Each subdirectory should have an `index.ts` that exports all queries for that table +- **Reusable and composable** - Write queries as small, focused functions that can be composed together + ### Soft Delete and Upsert Practices - In our database, we never hard delete, we always use soft deletes with the `deleted_at` field - For update operations, we should almost always perform an upsert unless otherwise specified -``` -**Test Running Guidelines**: +## Test Running Guidelines - When running tests, use the following Turbo commands: - `turbo test:unit` for unit tests - `turbo test:integration` for integration tests - `turbo test` for running all tests -# important-instruction-reminders -Do what has been asked; nothing more, nothing less. -NEVER create files unless they're absolutely necessary for achieving your goal. -ALWAYS prefer editing an existing file to creating a new one. -NEVER proactively create documentation files (*.md) or README files. Only create documentation files if explicitly requested by the User. \ No newline at end of file + +## Pre-Completion Workflow +- Always run `turbo test:unit, lint, and build:dry-run` before making any pull request or finishing a feature, bugfix, etc. to ensure things make it through CI/CD +- You can run all these checks simultaneously with `turbo build:dry-run lint test:unit` \ No newline at end of file diff --git a/CLAUDE.md b/CLAUDE.md index 733d13c76..42cb7ebbe 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -259,10 +259,13 @@ export async function getWorkspaceSettingsHandler( ### Soft Delete and Upsert Practices - In our database, we never hard delete, we always use soft deletes with the `deleted_at` field - For update operations, we should almost always perform an upsert unless otherwise specified -``` -**Test Running Guidelines**: +## Test Running Guidelines - When running tests, use the following Turbo commands: - `turbo test:unit` for unit tests - `turbo test:integration` for integration tests - - `turbo test` for running all tests \ No newline at end of file + - `turbo test` for running all tests + +## Pre-Completion Workflow +- Always run `turbo test:unit, lint, and build:dry-run` before making any pull request or finishing a feature, bugfix, etc. to ensure things make it through CI/CD +- You can run all these checks simultaneously with `turbo build:dry-run lint test:unit` \ No newline at end of file diff --git a/apps/server/package.json b/apps/server/package.json index ba234b72c..1a536de44 100644 --- a/apps/server/package.json +++ b/apps/server/package.json @@ -7,8 +7,9 @@ } }, "scripts": { - "prebuild": "tsx scripts/validate-env.ts && pnpm run typecheck", + "prebuild": "[ \"$SKIP_ENV_CHECK\" = \"true\" ] || (tsx scripts/validate-env.ts && pnpm run typecheck)", "build": "tsup", + "build:dry-run": "tsup", "dev": "bun --watch src/index.ts", "dev:build": "tsup --watch", "lint": "biome check --write", diff --git a/apps/trigger/package.json b/apps/trigger/package.json index a4ef5871b..02758885c 100644 --- a/apps/trigger/package.json +++ b/apps/trigger/package.json @@ -6,8 +6,9 @@ "scripts": { "dev": "echo 'y' | npx trigger.dev@v4-beta dev", "deploy": "echo 'y' | npx trigger.dev@v4-beta deploy", - "prebuild": "tsx scripts/validate-env.ts", + "prebuild": "[ \"$SKIP_ENV_CHECK\" = \"true\" ] || tsx scripts/validate-env.ts", "build": "echo 'No build step required but we run it to make sure env is loaded' && tsc --noEmit", + "build:dry-run": "echo 'No build step required but we run it to make sure env is loaded' && tsc --noEmit", "lint": "biome check --write", "test": "vitest run", "test:watch": "vitest watch", diff --git a/package.json b/package.json index d01a37646..110c3bafd 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,7 @@ "scripts": { "ai:dev": "pnpm --filter @buster/ai dev", "build": "turbo build", + "build:dry-run": "SKIP_ENV_CHECK=true turbo run build:dry-run", "check": "biome check ${1:-.}", "check:fix": "biome check --write ${1:-.}", "ci:check": "pnpm run check && pnpm run typecheck", diff --git a/packages/access-controls/package.json b/packages/access-controls/package.json index 35ba227fd..d5a90c85c 100644 --- a/packages/access-controls/package.json +++ b/packages/access-controls/package.json @@ -13,8 +13,9 @@ "main": "dist/index.js", "types": "dist/index.d.ts", "scripts": { - "prebuild": "tsx scripts/validate-env.ts", + "prebuild": "[ \"$SKIP_ENV_CHECK\" = \"true\" ] || tsx scripts/validate-env.ts", "build": "tsc", + "build:dry-run": "tsc", "build:commonjs": "tsc --module commonjs --moduleResolution node", "build:commonjs:watch": "npm run build:commonjs && tsc --module commonjs --moduleResolution node --watch", "dev": "tsc --watch", diff --git a/packages/ai/package.json b/packages/ai/package.json index 2668d3d9d..23df39137 100644 --- a/packages/ai/package.json +++ b/packages/ai/package.json @@ -14,8 +14,9 @@ } }, "scripts": { - "prebuild": "tsx scripts/validate-env.ts", + "prebuild": "[ \"$SKIP_ENV_CHECK\" = \"true\" ] || tsx scripts/validate-env.ts", "build": "tsc", + "build:dry-run": "tsc", "typecheck": "tsc --noEmit", "dev": "tsc --watch", "dev:mastra": "mastra dev --dir src", diff --git a/packages/data-source/package.json b/packages/data-source/package.json index 8f04f4c7b..045063803 100644 --- a/packages/data-source/package.json +++ b/packages/data-source/package.json @@ -13,8 +13,9 @@ "main": "dist/index.js", "types": "dist/index.d.ts", "scripts": { - "prebuild": "tsx scripts/validate-env.ts", + "prebuild": "[ \"$SKIP_ENV_CHECK\" = \"true\" ] || tsx scripts/validate-env.ts", "build": "tsc", + "build:dry-run": "tsc", "build:commonjs": "tsc --module commonjs --moduleResolution node", "build:commonjs:watch": "npm run build:commonjs && tsc --module commonjs --moduleResolution node --watch", "lint": "biome check --write", diff --git a/packages/database/package.json b/packages/database/package.json index 14d030ddf..cf986be6f 100644 --- a/packages/database/package.json +++ b/packages/database/package.json @@ -19,8 +19,9 @@ "main": "dist/index.js", "types": "dist/index.d.ts", "scripts": { - "prebuild": "tsx scripts/validate-env.ts", + "prebuild": "[ \"$SKIP_ENV_CHECK\" = \"true\" ] || tsx scripts/validate-env.ts", "build": "tsc", + "build:dry-run": "tsc", "build:commonjs": "tsc --module commonjs --moduleResolution node", "build:commonjs:watch": "npm run build:commonjs && tsc --module commonjs --moduleResolution node --watch", "db:check": "drizzle-kit check", diff --git a/packages/rerank/package.json b/packages/rerank/package.json index f172efa26..ffc2ce76d 100644 --- a/packages/rerank/package.json +++ b/packages/rerank/package.json @@ -11,8 +11,9 @@ } }, "scripts": { - "prebuild": "tsx scripts/validate-env.ts", + "prebuild": "[ \"$SKIP_ENV_CHECK\" = \"true\" ] || tsx scripts/validate-env.ts", "build": "tsc", + "build:dry-run": "tsc", "typecheck": "tsc --noEmit", "test": "vitest run", "test:unit": "vitest run --exclude '**/*.int.test.ts' --exclude '**/*.integration.test.ts' --passWithNoTests", diff --git a/packages/sandbox/package.json b/packages/sandbox/package.json index 7ce8d1682..8a6b4058d 100644 --- a/packages/sandbox/package.json +++ b/packages/sandbox/package.json @@ -15,8 +15,9 @@ } }, "scripts": { - "prebuild": "tsx scripts/validate-env.ts", + "prebuild": "[ \"$SKIP_ENV_CHECK\" = \"true\" ] || tsx scripts/validate-env.ts", "build": "tsc", + "build:dry-run": "tsc", "typecheck": "tsc --noEmit", "dev": "tsc --watch", "lint": "biome check", diff --git a/packages/slack/package.json b/packages/slack/package.json index eb8ffa49b..f936f419d 100644 --- a/packages/slack/package.json +++ b/packages/slack/package.json @@ -15,8 +15,9 @@ } }, "scripts": { - "prebuild": "tsx scripts/validate-env.ts", + "prebuild": "[ \"$SKIP_ENV_CHECK\" = \"true\" ] || tsx scripts/validate-env.ts", "build": "tsc", + "build:dry-run": "tsc", "typecheck": "tsc --noEmit", "dev": "tsc --watch", "lint": "biome check --write", diff --git a/packages/stored-values/package.json b/packages/stored-values/package.json index 9cc692b68..64e61543b 100644 --- a/packages/stored-values/package.json +++ b/packages/stored-values/package.json @@ -19,8 +19,9 @@ "main": "dist/index.js", "types": "dist/index.d.ts", "scripts": { - "prebuild": "tsx scripts/validate-env.ts", + "prebuild": "[ \"$SKIP_ENV_CHECK\" = \"true\" ] || tsx scripts/validate-env.ts", "build": "tsc", + "build:dry-run": "tsc", "build:commonjs": "tsc --module commonjs --moduleResolution node", "build:commonjs:watch": "npm run build:commonjs && tsc --module commonjs --moduleResolution node --watch", "lint": "biome check --write", diff --git a/packages/test-utils/package.json b/packages/test-utils/package.json index a24ffaeb6..8bfcfc3eb 100644 --- a/packages/test-utils/package.json +++ b/packages/test-utils/package.json @@ -14,8 +14,9 @@ } }, "scripts": { - "prebuild": "tsx scripts/validate-env.ts", + "prebuild": "[ \"$SKIP_ENV_CHECK\" = \"true\" ] || tsx scripts/validate-env.ts", "build": "tsc", + "build:dry-run": "tsc", "typecheck": "tsc --noEmit", "lint": "biome check --write", "test": "vitest run", diff --git a/scripts/new-package.ts b/scripts/new-package.ts index 4ad741fd9..c50d75580 100755 --- a/scripts/new-package.ts +++ b/scripts/new-package.ts @@ -372,12 +372,15 @@ async function createPackageFiles(config: PackageConfig) { }, }, scripts: { - prebuild: "tsx scripts/validate-env.ts", + prebuild: "[ \"$SKIP_ENV_CHECK\" = \"true\" ] || tsx scripts/validate-env.ts", build: "tsc", + "build:dry-run": "tsc", typecheck: "tsc --noEmit", dev: "tsc --watch", lint: "biome check --write", test: "vitest run", + "test:unit": "vitest run --exclude '**/*.int.test.ts' --exclude '**/*.integration.test.ts' --passWithNoTests", + "test:integration": "vitest run **/*.int.test.ts **/*.integration.test.ts", "test:watch": "vitest watch", "test:coverage": "vitest run --coverage", }, diff --git a/scripts/prebuild.sh b/scripts/prebuild.sh new file mode 100644 index 000000000..6f1893db9 --- /dev/null +++ b/scripts/prebuild.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +# Skip env validation if SKIP_ENV_CHECK is set +if [ "$SKIP_ENV_CHECK" = "true" ]; then + echo "Skipping environment validation (dry-run build)" + exit 0 +fi + +# Otherwise run the validation script +tsx scripts/validate-env.ts \ No newline at end of file diff --git a/turbo.json b/turbo.json index a798a5e35..cb75e38b8 100644 --- a/turbo.json +++ b/turbo.json @@ -7,13 +7,18 @@ "dependsOn": ["^build"], "outputs": ["dist/**", ".next/**"] }, + "build:dry-run": { + "dependsOn": ["^build:dry-run"], + "outputs": ["dist/**", ".next/**"], + "env": ["SKIP_ENV_CHECK"] + }, "dev": { "cache": false, "persistent": true, "dependsOn": ["@buster/database#dev"] }, "lint": { - "dependsOn": ["^build", "^lint"] + "dependsOn": ["^lint"] }, "typecheck": { "dependsOn": ["^build"] @@ -22,7 +27,7 @@ "dependsOn": ["^build"] }, "test:unit": { - "dependsOn": ["^build"] + "dependsOn": ["^test:unit"] }, "test:integration": { "dependsOn": ["^build"]