Content portal
Review staged app artwork and blog copy; patch a published post
Content portal
Eight /api/v1/content-portal/* routes are mounted (PgContentPortalRepository). They are not 501. A caller who is not operator type Content gets 403 Content portal access only.
Live 2026-09-10:
| Caller | GET /content-portal/summary |
|---|---|
content@linkit.works (Content) | 200 {pending_apps:0, pending_posts:0} |
design@linkit.works (Design) | 403 |
| Organization / Commercial JWT | 403 |
Public GET /api/v1/posts is a different family (blog reads, Guard::Public). The queue is this page; the published output is the posts list.
The sibling design portal (/api/v1/design-portal/*) is also mounted. A merchant JWT receives 403 Design portal access only. (Creative / design type). Do not treat that as unmounted.
Quick reference
| Endpoint | Purpose |
|---|---|
GET /api/v1/content-portal/summary | {pending_apps, pending_posts} |
GET /api/v1/content-portal/queue/apps | Apps waiting on logo / cover |
GET /api/v1/content-portal/queue/posts | Posts waiting on cover / attachment / rewrite |
POST /api/v1/content-portal/apps/{id}/approve | Promote staged app assets |
POST /api/v1/content-portal/apps/{id}/reject | {reason} |
POST /api/v1/content-portal/posts/{id}/approve | Promote staged post assets |
POST /api/v1/content-portal/posts/{id}/reject | {reason} |
PATCH /api/v1/content-portal/posts/{id} | Direct edit of a published post |
Errors use the platform envelope — {data, message, status}.
Summary
GET /api/v1/content-portal/summary{ "pending_apps": 0, "pending_posts": 0 }A repository failure on this read is 500 here (failed to read the content summary: …). Go answered zeroes.
Queues
GET /api/v1/content-portal/queue/apps
GET /api/v1/content-portal/queue/posts{"items":[…]}. App rows carry pending_logo_approval / pending_cover_approval. Post rows carry the staged cover / attachment / rewrite flags. List failure: 500 Failed to list apps queue. / Failed to list posts queue.
Approve / reject
All four answer {"id":"…"} only — even an approve that rewrote half the row.
Reject body { "reason": "…" }. Approve ignores reason if sent. Missing id: 404 App not found. / Post not found. Save failure: 400 (Go's BadRequestError), not 500.
A malformed reject body is 400 on v2. Go discarded json.Unmarshal errors and still rejected. That is the one documented divergence in this module.
Direct edit
PATCH /api/v1/content-portal/posts/{id}Five optional pointers: title, excerpt, content, category, status. Absent and empty differ — {"title":""} clears the column; {} leaves it. The React editor sends only keys the operator set.
Success is the post's PublicExport (200). Miss: 404 Post not found. Persist failure: 400 Failed to update post.