Initial commit: YouTube Studio Flow (backend, frontend, infrastructure, docs)
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
# 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
|
||||
Reference in New Issue
Block a user