/v1/trainee/content, router traineeContentRouter in src/modules/content/content.routes.ts. Handlers are in createTraineeContentController in content.controller.ts.
Lane: trainee. The router mounts authenticateTrainee only, without the app access guard. All three routes are GET, so preview tokens work. See Authentication.
Visibility rules
A trainee sees a content item when all of these hold:- it belongs to the trainee’s studio,
isPublishedistrue,- it is not restricted, or it is restricted and a
ContentItemUnlockrow exists for this trainee.
isRestricted) are hidden from every trainee until they are unlocked for that trainee. An unlock is written either by a coach from the web (source: "manual") or by an automation flow’s unlock step (source: "automation"), through unlockContentForClient in content-unlocks.ts. The unlock time is returned as unlockedAt so the app can show a “new” badge.
One exception: the item linked from the studio’s live home banner can be opened by id even when it is not published. It still has to pass the restricted check.
Endpoints
GET /v1/trainee/content
Lists the content items the trainee can see.
Auth: trainee token.
string
recipe, video, knowledge, pdf, other or link.string
Case-insensitive match on the title.
number
default:"1"
Positive integer.
number
default:"100"
Positive integer, at most 500.
sortOrder ascending, then createdAt descending. There is no filter by category, tag or featured flag on the server. The app filters the returned list.
Response: 200.
string
recipe, video, knowledge, pdf, other or link. For other, otherLabel holds the coach’s own label.string | null
image, video, youtube, pdf, link or none.array | null
Recipe steps. Each is
{ type, text } with type step or tip.number | null
Recipe macros as flat columns, for the whole recipe and per serving. The coach types the grams. All are
null when not set.object | null
The item’s category.
null means the general bucket.array
Studio-wide tags attached to the item, ordered by name.
boolean
Drives the featured strip in the app.
string | null
When this trainee was granted a restricted item.
null for unrestricted items.total is the count of all matching items, not just the page. The response does not echo page or pageSize.
Errors: VALIDATION (422) when type is not one of the six values or the paging values are out of range.
GET /v1/trainee/content/taxonomy
Returns every content category and tag of the studio, so the app can show folders that have no items yet.
Auth: trainee token.
No parameters. Both lists are ordered by sortOrder, then creation time.
Response: 200.
ContentCategory and ContentTag records. Default categories are created with the studio and carry a systemKey. The exact column list beyond id, name and sortOrder follows the Prisma models.
Errors: none beyond the lane errors.
GET /v1/trainee/content/:id
Returns one content item.
Auth: trainee token.
string
required
The content item id.