Initial commit: YouTube Studio Flow (backend, frontend, infrastructure, docs)

This commit is contained in:
2026-08-11 12:27:44 +02:00
commit d5af006443
304 changed files with 74604 additions and 0 deletions
@@ -0,0 +1,160 @@
# 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<string, BlockOverride>;
}
```
---
## 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.