66 lines
3.3 KiB
Markdown
66 lines
3.3 KiB
Markdown
# System Overview
|
|
|
|
YouTube Studio Flow is a multi-tenant SaaS tool for YouTube channel management. Teams connect their YouTube channels, import their video library, manage video metadata using a description template and block system, and push changes back to YouTube via the API.
|
|
|
|
## Tech Stack
|
|
|
|
| Layer | Technology |
|
|
|---|---|
|
|
| Frontend | Next.js 15 App Router, TypeScript, CSS Modules |
|
|
| Data fetching | TanStack Query v5 |
|
|
| Auth state | Zustand |
|
|
| Backend | NestJS 10, TypeScript |
|
|
| ORM | Prisma (PostgreSQL) |
|
|
| Queue | BullMQ + Redis |
|
|
| Auth | Google OAuth → JWT (access + refresh tokens) |
|
|
| YouTube integration | `googleapis` package, quota-tracked |
|
|
|
|
## Process Architecture
|
|
|
|
The backend runs as **two separate Node.js processes** from the same build:
|
|
|
|
| Process | Entry point | Role |
|
|
|---|---|---|
|
|
| API server | `src/main.ts` | HTTP API on port 3001 |
|
|
| Queue worker | `src/worker.ts` | BullMQ job processor (no HTTP) |
|
|
|
|
Both must be running for full functionality. The API enqueues jobs; the worker executes them.
|
|
|
|
## System Diagram
|
|
|
|
```
|
|
Browser (Next.js)
|
|
│
|
|
│ HTTP/REST (NEXT_PUBLIC_API_URL)
|
|
▼
|
|
NestJS API (:3001)
|
|
│
|
|
├──── PostgreSQL (Prisma)
|
|
├──── Redis (BullMQ queues)
|
|
│
|
|
└──── BullMQ worker process
|
|
│
|
|
├──── PostgreSQL (reads/writes)
|
|
└──── YouTube API (googleapis)
|
|
```
|
|
|
|
## Request Scoping
|
|
|
|
Every authenticated request is scoped to a team. The JWT payload contains `userId` and `teamId`. All database queries must filter by `channel: { teamId }` or direct `teamId` field. See [[02 - Backend]] for the auth pattern.
|
|
|
|
## Key Design Decisions
|
|
|
|
- **Denormalized `lintStatus`**: `Video.lintStatus` is a cached column. Any code path that deletes `LintResult` rows must recompute it manually — it is not computed on-the-fly.
|
|
- **YouTube token encryption**: OAuth tokens are AES-256 encrypted in the DB using `TOKEN_ENCRYPTION_KEY`. If this key changes all channels need re-authentication.
|
|
- **Queue deduplication**: BullMQ job IDs are used for deduplication. The pattern is `lint-{videoId}` for lint-once and `lint-{videoId}-{timestamp}` for forced reruns.
|
|
- **No shared code**: Backend and frontend are fully independent — no shared packages, no shared types. The frontend maintains its own API interface definitions in `api.ts`.
|
|
- **`hasPendingChanges` null-hash fallback**: `Video.lastSyncedHash` is set at import time to establish the YouTube baseline. For videos that existed before hashing was introduced (i.e. `lastSyncedHash IS NULL`), `findAll` falls back to computing a synthetic baseline from `youtubeDescription` and `recordingDate: null` and compares that against the current state hash. This means pre-existing videos correctly show "push pending" only when local changes diverge from the YouTube state, rather than always appearing as pending. Re-importing a channel resets the hash baseline and will clear any locally-pending changes that have not yet been pushed.
|
|
|
|
## Related
|
|
|
|
- [[02 - Backend]] — Module structure, patterns, shared services
|
|
- [[03 - Frontend]] — Routing, state management, API layer
|
|
- [[04 - Database Schema]] — All Prisma models
|
|
- [[05 - Queue System]] — BullMQ queues and processors
|
|
- [[06 - Authentication]] — OAuth flow, JWT, guards
|