Feature: An authenticated user can publish and unpublish an article As an authenticated RenewCMS user managing the CMS I want to flip an article's is_online flag from an HTTP endpoint So that a draft can be published to the public site and a published article can be pulled back offline, without deleting it Background: Given internal/domain/article.Repository already exposes UpdateIsOnline(id uint32, isOnline bool) (Article, error), and UpdateArticleUseCase.UpdateIsOnline delegates to it unchanged And UpdateArticleUseCase is already built in api/dependecyInjection.go as container.UpdateArticleUseCase, but before this slice no handler or route calls it And this slice adds Handler.PublishArticle and Handler.UnpublishArticle, backed by UpdateArticleUseCase.UpdateIsOnline(id, true) and UpdateIsOnline(id, false) And this slice mounts PATCH /v1/article/{id}/publish and PATCH /v1/article/{id}/unpublish inside the same jwtauth Verifier + Authenticator group as GET /v1/article/{id}, POST /v1/article/ and DELETE /v1/article/{id} in api/router.go, so both require a valid jwt cookie And a successful publish or unpublish answers 200 with the JSON body of the updated article.Article, the same shape GetArticle and PostArticle already return And an id that does not parse as a uint32 answers 400 with body apperr.IdUint32ErrorMessage, the same as GetArticle and DeleteArticle And an id absent from the article repository answers 404 with body apperr.ArticleNotFoundErrorMessage, backed by errors.Is(err, article.ErrArticleNotFound), the same as DeleteArticle already does per features/write_not_found_errors.feature And GET /v1/article/ with no jwt cookie only returns online articles, per features/public_article_listing.feature; this slice does not change that behavior, only feeds it Scenario: Publishing an offline article makes it online Given a valid jwt cookie for a user with id 1 And the article repository contains an offline article titled "Draft: Kitchen Remodel" with id 2 When the client sends PATCH /v1/article/2/publish with that cookie Then the response status is 200 And the response body is the article with id 2 and "is_online": true Scenario: Unpublishing an online article makes it offline Given a valid jwt cookie for a user with id 1 And the article repository contains an online article titled "Backyard Renovation Update" with id 1 When the client sends PATCH /v1/article/1/unpublish with that cookie Then the response status is 200 And the response body is the article with id 1 and "is_online": false Scenario: Publishing an already-online article is idempotent Given a valid jwt cookie for a user with id 1 And the article repository contains an online article with id 1 When the client sends PATCH /v1/article/1/publish with that cookie Then the response status is 200 And the response body is the article with id 1 and "is_online": true And no error is returned Scenario: Unpublishing an already-offline article is idempotent Given a valid jwt cookie for a user with id 1 And the article repository contains an offline article with id 2 When the client sends PATCH /v1/article/2/unpublish with that cookie Then the response status is 200 And the response body is the article with id 2 and "is_online": false And no error is returned Scenario Outline: Publishing or unpublishing an unknown article answers 404 Given a valid jwt cookie for a user with id 1 And the article repository has no article with id 9999 When the client sends PATCH /v1/article/9999/ with that cookie Then the response status is 404 And the response body is the text "Article not found" Examples: | action | | publish | | unpublish | Scenario Outline: A malformed id answers 400 before any repository call Given a valid jwt cookie for a user with id 1 When the client sends PATCH /v1/article/not-a-number/ with that cookie Then the response status is 400 And the response body is the text apperr.IdUint32ErrorMessage Examples: | action | | publish | | unpublish | Scenario Outline: Publish and unpublish require authentication Given no jwt cookie is sent And the article repository contains an article with id 1 When the client sends PATCH /v1/article/1/ without a cookie Then the response status is 401 Examples: | action | | publish | | unpublish | Scenario: Publishing an article makes it appear in the public online-only list Given a valid jwt cookie for a user with id 1 And the article repository contains an offline article titled "Draft: Kitchen Remodel" with id 2 When the client sends PATCH /v1/article/2/publish with that cookie And the client then sends GET /v1/article/ with no jwt cookie Then the response status of the second request is 200 And the response body of the second request is a JSON array containing the article with id 2 Scenario: Unpublishing an article removes it from the public online-only list Given a valid jwt cookie for a user with id 1 And the article repository contains an online article titled "Backyard Renovation Update" with id 1 When the client sends PATCH /v1/article/1/unpublish with that cookie And the client then sends GET /v1/article/ with no jwt cookie Then the response status of the second request is 200 And the article with id 1 is absent from the response body of the second request