Manage genres, tropes, cast
TwistCue has three taxonomy tables, Genres, Tropes, Cast, plus a SeriesCast join. They all live under Catalog in the sidebar.
Genres
Section titled “Genres”Broad content buckets: “Romance”, “Thriller”, “Fantasy”, etc. Drive the top-level filter on the mobile discover screen and are the main input to the For You rail rules.
Fields:
| Field | Type | Notes |
|---|---|---|
slug | string, unique, kebab-case | Immutable after first use. |
name_i18n | JSON: {en, ar, id} | At least EN required. |
sort | int | Order in filter chips. Lower = earlier. |
active | bool | Inactive genres hide from mobile but stay attached to series for analytics. |
Rule of thumb: keep this short. 8–15 genres is healthy. If you’re above 20, you probably want tropes instead.
Tropes
Section titled “Tropes”Narrower narrative buckets: “Enemies to Lovers”, “Amnesia”, “CEO Romance”, “Time Loop”. Drive niche rails (“Because you love Enemies to Lovers…”) and analytics slicing.
Same field shape as genres. Rule of thumb: 30–60 tropes is where it starts paying off; below 30, they’re not doing enough work; above 100, you’re inventing them.
The people behind the show: actors, directors, writers. TwistCue is casting-forward: cast rails and cast-scoped discovery are a real part of the app.
Fields:
| Field | Type | Notes |
|---|---|---|
slug | string, unique | Auto from name; immutable after publish. |
name | string | Display name. Not localized in v2 (romanized name only). |
role_default | enum: actor / director / writer / producer | Applied when linked to a series unless overridden. |
photo_asset_id | FK → media_assets | Headshot (square recommended). |
bio_i18n | JSON: {en, ar, id} | Optional; renders on the cast profile page. |
active | bool |
SeriesCast (linking cast to series)
Section titled “SeriesCast (linking cast to series)”Each series has a Cast tab on the series detail page. Add cast members and assign per-series role (actor / director / writer / producer) and character name (for actors).
The join table series_cast looks like:
(series_id, cast_id, role, character_name, sort)Editing this from the API is a full-replace on PUT /v1/admin/series/:seriesId/cast: pass the complete desired array.
Gotchas
Section titled “Gotchas”- Deleting a genre/trope in use: the API refuses (
409 in_use) if any series still references it. Deactivate instead (active=false). - Cast merges: no built-in merge yet. If you accidentally created two cast rows for the same actor, delete the empty one and re-link.
- Localization matters for filter chips. If a genre’s
name_i18n.aris missing, the AR mobile UI falls back to EN: visually consistent but not ideal.
API calls
Section titled “API calls”| Action | Endpoint |
|---|---|
| Genres CRUD | GET/POST/PUT/DELETE /v1/admin/genres[/:id] |
| Tropes CRUD | GET/POST/PUT/DELETE /v1/admin/tropes[/:id] |
| Cast list | GET /v1/admin/cast |
| Cast CRUD | GET/POST/PUT/DELETE /v1/admin/cast[/:id] (planned nested routes; see API: Catalog) |
| Series cast (replace) | PUT /v1/admin/series/:seriesId/cast |
Full details in API: Catalog.