Skip to content

Code Best Practices

TypeScript

Mandatory Type Safety Requirements

  • ZERO any types: Absolutely NO any types allowed in production code - all types must be explicit.
  • NO unknown without proper guards: Replace unknown with specific types or implement proper type guards.
  • Strict TypeScript: Enable strict: true and all strict mode flags in tsconfig.json.
  • Shared types: Cross-feature types belong under src/types/ or are re-exported from there (see Type placement).
  • Import consistency: Use proper type imports (import type { }) for type-only imports.

Type placement (apps and packages)

  1. Scope: Each app/package owns its own src/types/ (flat files; match existing names such as domain.ts, ui-chrome-theme.ts). No repo-root types/.
  2. Zod-first domain: Define schemas in the owning module (schemas/, lib/validations/, etc.); export application types with z.infer<typeof Schema>. Re-export from src/types/ or src/types/index.ts when multiple features import the same shape. Prefer import type { Page } from '@/types' (CMS) or import type { Course } from '@/types/domain' (LMS) over importing validation modules from UI unless the file owns parsing.
  3. Shared non-Zod types: Enums, session augmentations, feature flags, theme tokens, rate-limit keys → src/types/<topic>.ts.
  4. Feature-local types: A types.ts beside a feature folder is allowed when only that feature uses them; promote to src/types/ when a second unrelated module imports them.
  5. Component props: Every component exposes an explicit FooProps type (same file or adjacent). Move to src/types/ only when reused outside the component tree.
  6. Packages: Cross-CMS/LMS wire shapes → @open-learning-hub/widget-wire-schemas; renderer adapters → widget-renderers; shared UI → @open-learning-hub/ui. Do not copy package types into app types/.
  7. Database: Table shapes stay in src/db/types.ts (Kysely); do not duplicate row types in UI types/ unless widely needed.
  8. Do not hand-duplicate Zod-inferred domain interfaces in types/; re-export or infer from the schema module.

Component Type Safety Standards

  • Props interfaces: Every component must have an explicitly defined FooProps type (colocated unless shared; see Type placement).
  • Generic constraints: Use proper generic constraints for reusable components.
  • Event handlers: Properly type all event handlers with specific Event types.
  • Refs: Use proper ref typing with useRef<HTMLElementType>(null).
  • State typing: Explicitly type all useState hooks and state variables.

Data Type Requirements

  • API responses: Create specific interfaces for all API response types.
  • Strict boolean typing: Use boolean types, not string unions for boolean states.
  • Null safety: Properly handle nullable fields with union types (| null | undefined).

Type Organization Structure

  • Type exports: Use proper type imports and exports across the component tree.
  • Naming conventions: Use PascalCase for types and interfaces.
  • Documentation: Add JSDoc comments for complex types and interfaces.
  • Section organization: Group related types with clear section headers and comments.

Import Path Conventions

  • Use @/ for any import that resolves under an app or package src/ directory.
  • Use @tests/ for Vitest harness and test helper imports (tests/ in LMS, test/ in CMS).
  • Use @messages/ for locale JSON imports from app-level messages/.
  • Use @scripts/ only in tests that intentionally consume monorepo-level scripts.
  • Keep short colocated relative imports (../actions, ../_components) when files are in the same route segment.
  • Avoid deep relative imports (../../../...) for cross-feature imports; prefer aliases instead.
  • For report-only auditing, run npm run audit:imports (canonical flags and script details: Root Scripts Reference).

Editing Constraints

  • Default to ASCII when editing or creating files unless the target file already relies on Unicode characters and the change requires them.
  • Preserve existing formatting conventions (spacing, newline endings) unless intentionally refactoring for consistency.
  • Avoid reverting or overwriting user-authored changes that are unrelated to the current task.
  • Prefer updating existing modules over duplicating functionality in new files.

Next.js (Frontend)

  • Favor React Server Components (RSC) where possible.
  • Minimize 'use client' directives.
  • When using Radix asChild with next-intl Link, keep the composition in a client module if the primitive itself is "use client" (see packages/ui/AGENTS.md section "asChild across RSC boundary") to avoid Slot/cloneElement failures across the RSC boundary.
  • Performance optimizations:
    • add generateStaticParams: fetch all published course slugs only.
    • generateMetadata: set title/description/OG image from published courses only.
    • revalidate = 60 to all relevant pages.
    • Add ISR: Await params in dynamic routes (you already updated [slug] and nested [entrySlug]).
    • UI & UX - course cards: consider prefetching for faster navigation.
  • Wire up Portable Text rendering for content using @portabletext/react.
  • Use shadcn for the UI Components.
  • Static Generation Security:
    • Implement proper access control in both static and dynamic routes.
  • Server Components: Prefer over client components.
  • Props Interface: Always define prop types.
  • Component naming: PascalCase exports for React components (see 031-file-naming.mdc for kebab-case filenames).
  • File Organization: One component per file.
  • Image Optimization:
    • Use Next.js Image with proper sizing.
    • Next.js Image component used throughout.
    • Google profile images properly configured.
  • Code Splitting:
    • Dynamic imports for heavy components.
    • Authentication code loads only when needed.
    • Admin components lazy-loaded.
    • Database access via Kysely is server-only — never import it from a client component.
  • Input Validation: Validate user inputs (Zod schemas at every API and server-action boundary).
  • Data listing consistency: Follow 055-data-listing-patterns.mdc for table-first rendering, single-search default UX, URL-driven server filtering, and shared pagination.

File Organization

Directory Structure

  • src/app/: Next.js App Router pages and layouts.
  • components/: Reusable React components.
  • lib/: Utility functions and shared logic.
  • types/: Shared TypeScript types and barrels (see Type placement).
  • .cursor/rules/: Project documentation.

Component Organization

  • One component per file.
  • Co-locate related components in subdirectories.
  • Use index files for clean imports.
  • Group components by feature or domain.

Utility Organization

  • Group related utilities in separate files.
  • Use descriptive file names.
  • Export utilities from index files when appropriate.
  • Keep utilities pure and testable.

API Route Organization

  • Organize API routes by feature or domain.
  • Use route handlers for API endpoints.
  • Keep route handlers focused and single-purpose.
  • Implement proper error handling and validation.

Server Actions

  • Co-locate server actions with the route segment that owns them, using actions.ts or _actions.ts under the relevant src/app/ segment.
  • Shared cross-route helpers live in src/lib/ or feature-specific utility modules and are called by the co-located action; client components should not invoke shared persistence helpers directly.
  • Keep action inputs Zod-validated at the boundary and re-check authorization inside the action, even when the surrounding route already performed a guard check.

CSS Best Practices

  • Tailwind CSS: Primary styling approach.
  • Component Classes: Use shadcn/ui component classes.
  • Responsive Design: Mobile-first approach.
  • Dark Mode: Support both light and dark themes.

Key Architectural Principles

  1. Security First: All content access is controlled by published status.
  2. Type Safety: Full TypeScript coverage with strict typing.
  3. Component Reusability: Modular components with clear interfaces.
  4. Performance: ISR with 60-second revalidation for fresh content.
  5. Accessibility: Semantic HTML and proper navigation structure.
  6. Responsive Design: Mobile-first approach with Tailwind CSS.
  7. Content Management: CMS for non-technical users.

Official Documentation