Linkit

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:

CallerGET /content-portal/summary
content@linkit.works (Content)200 {pending_apps:0, pending_posts:0}
design@linkit.works (Design)403
Organization / Commercial JWT403

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

EndpointPurpose
GET /api/v1/content-portal/summary{pending_apps, pending_posts}
GET /api/v1/content-portal/queue/appsApps waiting on logo / cover
GET /api/v1/content-portal/queue/postsPosts waiting on cover / attachment / rewrite
POST /api/v1/content-portal/apps/{id}/approvePromote staged app assets
POST /api/v1/content-portal/apps/{id}/reject{reason}
POST /api/v1/content-portal/posts/{id}/approvePromote 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.