Initial commit: YouTube Studio Flow (backend, frontend, infrastructure, docs)
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
# Campaigns API
|
||||
|
||||
Base path: `/api/v1/campaigns`
|
||||
|
||||
All endpoints require `Authorization: Bearer <jwt>`.
|
||||
|
||||
Related: [[08 - Campaigns]], [[07 - Render Engine]], [[04 - Database Schema]]
|
||||
|
||||
---
|
||||
|
||||
## GET /campaigns
|
||||
|
||||
List all campaigns for the current team, ordered by `startAt` descending (most recent first).
|
||||
|
||||
**Minimum role:** Any authenticated team member
|
||||
|
||||
**Response:** `CampaignSummary[]`
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"id": "cuid",
|
||||
"name": "Summer Sale 2026",
|
||||
"startAt": "2026-06-01T00:00:00.000Z",
|
||||
"endAt": "2026-08-31T23:59:59.000Z",
|
||||
"status": "active"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
| Field | Type | Notes |
|
||||
|---|---|---|
|
||||
| `id` | string | cuid |
|
||||
| `name` | string | Display name of the campaign |
|
||||
| `startAt` | ISO datetime | Campaign window start (inclusive) |
|
||||
| `endAt` | ISO datetime \| null | Campaign window end (inclusive). `null` means open-ended |
|
||||
| `status` | string | Free-form status string, default `"active"`. **Must be exactly `"active"` (lowercase) for the campaign to be treated as active** — see warning below. |
|
||||
|
||||
> **Warning:** `Campaign.status` is a free-form `String` column with no enum constraint. The `DESC_OUTDATED_SPONSOR_COPY` lint rule checks `status !== 'active'` (exact lowercase match). Any other value — `"ACTIVE"`, `"paused"`, `"inactive"`, `"disabled"`, or any typo — is treated as inactive: the campaign's blocks are excluded from rendering and all videos referencing them receive a lint ERROR. There is no input validation at the API or DB level. See the backlog.
|
||||
|
||||
> **Note:** The full `notes` field and the linked `blocks` relation are not included in this response. Campaigns are read here for display and for populating dropdowns when assigning blocks to a campaign. Full campaign management (create, update, delete, assign blocks) is not exposed via the REST API — it is managed directly in the database or through future admin tooling.
|
||||
|
||||
---
|
||||
|
||||
## How campaigns affect rendering
|
||||
|
||||
Campaign blocks are `CAMPAIGN`-type `DescriptionBlock` rows linked to a campaign via `campaignId`. At render time, the engine checks whether `startAt ≤ now ≤ endAt` for each linked campaign. If the window is active, all of that campaign's blocks are automatically appended to the rendered description — regardless of whether they appear in the video's `blockOrder`. If the window is inactive, they are silently omitted.
|
||||
|
||||
This is the only block type that bypasses `blockOrder`. See [[07 - Render Engine]] for the full rendering pipeline.
|
||||
|
||||
---
|
||||
|
||||
## Current limitations
|
||||
|
||||
Campaign CRUD (create, update, delete) and block assignment are not yet exposed through the API. The `GET /campaigns` endpoint exists to allow the frontend to display campaign names and populate selectors. Full campaign management requires direct database access or a future admin interface. See **Campaign CRUD API** in [[01 - Technical Debt and Future Work]].
|
||||
Reference in New Issue
Block a user