Initial commit: YouTube Studio Flow (backend, frontend, infrastructure, docs)
This commit is contained in:
@@ -0,0 +1,133 @@
|
||||
# Team Variables API
|
||||
|
||||
Base path: `/api/v1/team-variables`
|
||||
|
||||
All endpoints require `Authorization: Bearer <jwt>`.
|
||||
|
||||
Related: [[07 - Render Engine]], [[04 - Database Schema]], [[02 - Description Engine]]
|
||||
|
||||
---
|
||||
|
||||
## GET /team-variables
|
||||
|
||||
List all team variables, ordered alphabetically by name.
|
||||
|
||||
**Minimum role:** Any authenticated team member
|
||||
|
||||
**Response:** `TeamVariable[]`
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"id": "cuid",
|
||||
"teamId": "cuid",
|
||||
"name": "sponsor_link",
|
||||
"value": "https://example.com/sponsor",
|
||||
"createdAt": "ISO datetime",
|
||||
"updatedAt": "ISO datetime"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## POST /team-variables
|
||||
|
||||
Create a new team variable.
|
||||
|
||||
**Minimum role:** `EDITOR`
|
||||
|
||||
**Request body:**
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "sponsor_link",
|
||||
"value": "https://example.com/sponsor"
|
||||
}
|
||||
```
|
||||
|
||||
| Field | Type | Required | Notes |
|
||||
|---|---|---|---|
|
||||
| `name` | string | Yes | Used as the token key: `{name}` in description blocks |
|
||||
| `value` | string | Yes | The string substituted at render time |
|
||||
|
||||
**Response:** The created `TeamVariable` object.
|
||||
|
||||
**Side effects:**
|
||||
- All non-deleted videos in the team are enqueued for background re-render (queue: `render`, job ID `render-{videoId}` — deduplicated).
|
||||
- Mutation is audit-logged under entity type `TeamVariable`.
|
||||
|
||||
---
|
||||
|
||||
## PATCH /team-variables/:id
|
||||
|
||||
Update an existing team variable.
|
||||
|
||||
**Minimum role:** `EDITOR`
|
||||
|
||||
**Request body** (all fields optional):
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "sponsor_link",
|
||||
"value": "https://new-sponsor.com"
|
||||
}
|
||||
```
|
||||
|
||||
**Response:** The updated `TeamVariable` object.
|
||||
|
||||
**Side effects:** Same as POST — full team re-render is enqueued, mutation is audit-logged.
|
||||
|
||||
---
|
||||
|
||||
## GET /team-variables/:id/usage
|
||||
|
||||
Return the description blocks that reference this variable by name token.
|
||||
|
||||
**Minimum role:** Any authenticated team member
|
||||
|
||||
**Response:**
|
||||
|
||||
```json
|
||||
{
|
||||
"blocks": [
|
||||
{ "id": "cuid", "name": "Sponsor Block" }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Blocks are matched by scanning their `content` field for the literal string `{name}` where `name` is the variable's current name. Only blocks belonging to the same team are returned.
|
||||
|
||||
> **Note:** This endpoint uses the variable's current name. If you rename a variable, existing blocks that still use the old token name will not appear here — and will silently resolve to an empty string at render time until updated.
|
||||
|
||||
---
|
||||
|
||||
## DELETE /team-variables/:id
|
||||
|
||||
Delete a team variable.
|
||||
|
||||
**Minimum role:** `EDITOR`
|
||||
|
||||
> **Note:** Every other destructive delete in the API (blocks, templates, collaborators, saved views) requires `ADMIN`. Team variable delete only requires `EDITOR`, despite triggering a full team re-render and silently breaking any block that references the deleted token. This appears to be an oversight — see the backlog.
|
||||
|
||||
**Response:**
|
||||
|
||||
```json
|
||||
{ "deleted": true }
|
||||
```
|
||||
|
||||
**Side effects:** Same as POST — full team re-render is enqueued, mutation is audit-logged.
|
||||
|
||||
> **Warning:** Deleting a variable does not remove references to its token from description blocks. Blocks that used `{name}` will continue to contain the token string; it will resolve to an empty string at render time.
|
||||
|
||||
---
|
||||
|
||||
## How variables are resolved at render time
|
||||
|
||||
Team variables form the baseline layer of variable resolution. When a video is rendered:
|
||||
|
||||
1. All team variables are loaded as a flat `Record<string, string>` map (name → value).
|
||||
2. Video-level variable overrides from `VideoConfig.variableValues` are merged on top — video-level values win.
|
||||
3. The combined map is used to substitute `{variable_name}` tokens in `VARIABLE`-type description blocks.
|
||||
|
||||
System variable tokens (`{video.*}`, `{collab.*}`) are skipped during this pass and resolved by dedicated resolvers. See [[07 - Render Engine]] for the full resolution order.
|
||||
Reference in New Issue
Block a user