# 05 - Code Conventions Language and style conventions for all TypeScript/TSX code in YouTube Studio Flow. These apply to both the frontend and backend unless noted otherwise. For CSS-specific rules, see [[02 - CSS Conventions]]. --- ## Comments Default to writing no comments. Only add a comment when the **why** is non-obvious: a hidden constraint, a subtle invariant, a browser quirk, a workaround for a specific external bug, or behavior that would surprise a competent reader encountering it for the first time. If removing the comment wouldn't cause confusion, don't write it. **Never write:** - Comments that describe what the code does (the code already does that) - Multi-paragraph docstrings on functions or classes - Multi-line comment blocks - Cross-reference notes ("added for issue #123", "used by the sync feature") - Section dividers (`// --- helpers ---`) **Acceptable:** ```typescript // BullMQ silently drops jobs if Redis evicts keys — must use noeviction policy const client = new Redis({ maxmemoryPolicy: 'noeviction' }); // Single-pass replacement avoids re-substituting inside already-replaced values const result = template.replace(pattern, (match) => tokens[match] ?? match); ``` --- ## No premature abstraction Add abstractions exactly when they are needed, not before. Three similar lines of code is better than a helper function introduced speculatively for hypothetical future use. If a pattern appears twice, note it. If it appears three times with meaningful variation, consider abstracting. If the abstraction would be more complex than the repetition, don't. --- ## Error handling scope Only validate and handle errors at system boundaries: - User input (request bodies, form submissions) - External API calls (YouTube API, Google OAuth) - Queue job payloads at the processor entry point Trust internal code. Trust Prisma's type guarantees. Do not add defensive `try/catch` around internal service calls for errors that cannot happen under normal operation. --- ## No backwards-compat shims When changing or removing behavior, change or remove it. Do not leave: - Unused variables prefixed with `_` to signal "formerly used" - Re-exports of deleted types for "compatibility" - `// removed` comments where code used to be - Feature flags gating old vs. new behavior --- ## TypeScript - Use strict TypeScript throughout. `"strict": true` is set in both `tsconfig.json` files. - Avoid `any`. The only acceptable uses are at Prisma enum boundaries where the type system cannot express a legitimate constraint, and when interfacing with genuinely untyped external data (e.g. raw OAuth token payloads). - Use `as any` sparingly. If you reach for it, consider whether a type assertion (`as SpecificType`) or a type guard is more appropriate. - Prefer explicit return types on exported functions and service methods. Inference is acceptable for small private helpers. - Use `type` for object shapes and union types. Use `interface` for contracts intended to be extended or implemented. ```typescript // Object shape — use type type VideoFilters = { search?: string; status?: PrivacyStatus; page: number; }; // Extendable contract — use interface interface RenderInput { videoId: string; blockOrder: string[]; blockOverrides: Record; } ``` --- ## Naming conventions | Context | Convention | Examples | |---|---|---| | React components | PascalCase | `VideoTable`, `BlockEditor` | | CSS module classes | camelCase | `styles.clickableRow`, `styles.headerCell` | | TypeScript interfaces and types | PascalCase | `VideoFilters`, `RenderInput` | | Frontend API functions | camelCase verb + noun | `fetchVideos`, `updateVideo`, `createBlock` | | Backend service methods | camelCase verb + noun | `findAll`, `findOne`, `create`, `update`, `remove` | | Queue job name strings | kebab-case | `'lint'`, `'youtube-sync'`, `'bulk-metadata'` | | TanStack Query keys | array of strings | `['videos']`, `['video', id]`, `['blocks']` | | Zustand store files | camelCase with `use` prefix | `useAuthStore.ts`, `useUIStore.ts` | --- ## Import order Organize imports in this order within any TypeScript or TSX file. An empty line between each group: 1. React imports 2. Next.js imports (`next/navigation`, `next/image`, etc.) 3. Third-party libraries (`@tanstack/react-query`, `lucide-react`, etc.) 4. Internal aliases (`@/components/...`, `@/lib/...`, `@/store/...`) 5. Relative imports (`../utils`, `./helpers`) 6. Style imports (CSS modules, always last) ```typescript import { useState, useRef, forwardRef } from 'react'; import { useRouter } from 'next/navigation'; import { useQuery, useMutation } from '@tanstack/react-query'; import { Save, X } from 'lucide-react'; import Modal from '@/components/shared/Modal'; import { updateVideo } from '@/lib/api'; import { useAuthStore } from '@/store/useAuthStore'; import { formatDate } from '../utils/date'; import styles from './VideoEditor.module.css'; import f from '@/components/shared/FormField.module.css'; ``` --- ## No dead code Remove unused imports as you work. Remove unused variables. Remove unreachable branches. Delete unused files rather than leaving them in place. Do not leave `console.log` statements in committed code. Use the logger (`nestjs/common` `Logger` on the backend) for intentional output. --- ## Validation **Backend:** Use `class-validator` decorators on DTO classes. Every request body that reaches a controller must go through a validated DTO. ```typescript export class CreateBlockDto { @IsString() @IsNotEmpty() name: string; @IsEnum(BlockType) type: BlockType; @IsString() @IsOptional() content?: string; } ``` **Frontend:** Validate at the form submission boundary only. Inside a component, trust the types from `@/lib/api.ts`. Do not add runtime type checks on data returned by the API.