- Dev server:
bun run dev:backend(gRPC - 8069, HTTP - 8070) - Generate protobuf:
bun run gen(from proto/ directory) - DB migrations:
bunx drizzle-kit push - **Type Checking:
bunx tsgo
- Runtime: Bun with TypeScript ESNext, strict mode enabled
- Imports: Use
typekeyword for type-only imports (e.g.,import type { Foo } from "...") - Types: Always use explicit types for function parameters and return values; avoid
anyand do NOT cast which can be inferred [ or make it such that it can be inferred from context] - Error handling: Use custom error classes (APIKeyError, StorageError, etc.) with static factory methods; always include error type, message, and optional originalError
- Validation: Use Zod schemas for all request validation; catch ZodError and convert to domain errors
- Logging: Use the
WideEventLoggerfromerrors/logger; calllogger.emit()with aWideEventobject for request-scoped logging andlogger.lifecycle()/logger.lifecycleWarning()for server lifecycle events - Naming: camelCase for variables/functions, PascalCase for classes/types/enums, SCREAMING_SNAKE_CASE for constants
- Database: Use Drizzle ORM with transactions; validate all inputs before DB operations; handle unique constraint violations explicitly
- Dates: Only use the Luxon
DateTimemodule; never use built-inDate. ALWAYS work in UTC:DateTime.utc()— neverDateTime.now()orDateTime.local()DateTime.fromISO(str, { zone: "utc" })— never omit{ zone: "utc" }option- Use
dt.toUTC()on any DateTime that might enter with a local zone
- The Storage Factory can only return 1 adapter for ALL events, so either all events use Postgres or all events use Clickhouse.