Implement posts API routes #29

Closed
opened 2026-05-19 19:51:45 -05:00 by erik · 2 comments
Owner

Goal

Implement the Slugkit posts management API for articles, links, and notes.

Spec: docs/specs/02-posts-routes.md

Requirements

  • Implement all post routes, request schemas, response schemas, lifecycle behavior, and validation from the spec.
  • Use post slug routes as documented; do not introduce ID-only or /posts/by-slug alternatives.
  • Support article, link, and note content types as specified.
  • Implement draft creation/update, explicit publish, and explicit unpublish behavior.
  • Represent authors with authorIds in requests and expanded authors in responses.
  • Represent tags with tagSlugs in requests and expanded tag objects in responses.
  • On create/update, find or create tags by slug as specified.
  • On update, omitted tagSlugs leaves tags unchanged and tagSlugs: [] removes all tags.
  • Return shared validation, auth, not-found, conflict, and not-implemented errors as appropriate.
  • Document every route in OpenAPI with the operation IDs from the spec.
  • Add tests for create/list/get/update/delete/publish/unpublish and tag/author behavior.

Acceptance criteria

  • Can create draft article, link, and note posts.
  • Can list posts and get a post by slug.
  • Can update post metadata/content without accidentally publishing.
  • Can explicitly publish and unpublish posts.
  • authorIds requests produce expanded authors responses.
  • tagSlugs requests produce expanded tag responses and obey omitted-vs-empty update semantics.
  • Validation failures use the shared error shape.
  • Every posts route appears in OpenAPI with the documented operation ID.
  • Relevant lint/test checks pass.

Dependencies

  • task-c272cbda
  • task-69937fe4
## Goal Implement the Slugkit posts management API for articles, links, and notes. Spec: `docs/specs/02-posts-routes.md` ## Requirements - Implement all post routes, request schemas, response schemas, lifecycle behavior, and validation from the spec. - Use post slug routes as documented; do not introduce ID-only or `/posts/by-slug` alternatives. - Support article, link, and note content types as specified. - Implement draft creation/update, explicit publish, and explicit unpublish behavior. - Represent authors with `authorIds` in requests and expanded `authors` in responses. - Represent tags with `tagSlugs` in requests and expanded tag objects in responses. - On create/update, find or create tags by slug as specified. - On update, omitted `tagSlugs` leaves tags unchanged and `tagSlugs: []` removes all tags. - Return shared validation, auth, not-found, conflict, and not-implemented errors as appropriate. - Document every route in OpenAPI with the operation IDs from the spec. - Add tests for create/list/get/update/delete/publish/unpublish and tag/author behavior. ## Acceptance criteria - [ ] Can create draft article, link, and note posts. - [ ] Can list posts and get a post by slug. - [ ] Can update post metadata/content without accidentally publishing. - [ ] Can explicitly publish and unpublish posts. - [ ] `authorIds` requests produce expanded `authors` responses. - [ ] `tagSlugs` requests produce expanded tag responses and obey omitted-vs-empty update semantics. - [ ] Validation failures use the shared error shape. - [ ] Every posts route appears in OpenAPI with the documented operation ID. - [ ] Relevant lint/test checks pass. ## Dependencies - task-c272cbda - task-69937fe4
Author
Owner

Synced from todu comment by @todu on 2026-05-23T00:55:03.963Z

PR Review: Approved

PR: #64

Summary

Reviewed PR #64 at commit 127d0d5. The PR implements the posts API vertical slice with SQLite persistence, protected post routes, draft/publish lifecycle behavior, author expansion, tag find-or-create assignment, shared error handling, OpenAPI coverage, tests, documentation updates, and the architecture parity note requested before this task.

Acceptance Criteria

  • Can create draft article, link, and note posts.
  • Can list posts and get a post by slug.
  • Can update post metadata/content without accidentally publishing.
  • Can explicitly publish and unpublish posts.
  • authorIds requests produce expanded authors responses.
  • tagSlugs requests produce expanded tag responses and obey omitted-vs-empty update semantics.
  • Validation failures use the shared error shape.
  • Every posts route appears in OpenAPI with the documented operation ID.
  • Relevant lint/test checks pass: make check, ./scripts/pre-pr.sh, manual smoke, and Forgejo CI passed.

Blocking Issues

None.

Warnings

None.

Verdict

Approved for merge after explicit human approval.

_Synced from todu comment by @todu on 2026-05-23T00:55:03.963Z_ ## PR Review: Approved PR: https://forge.caradoc.com/erik/slugkit/pulls/64 ### Summary Reviewed PR #64 at commit `127d0d5`. The PR implements the posts API vertical slice with SQLite persistence, protected post routes, draft/publish lifecycle behavior, author expansion, tag find-or-create assignment, shared error handling, OpenAPI coverage, tests, documentation updates, and the architecture parity note requested before this task. ### Acceptance Criteria - [x] Can create draft article, link, and note posts. - [x] Can list posts and get a post by slug. - [x] Can update post metadata/content without accidentally publishing. - [x] Can explicitly publish and unpublish posts. - [x] `authorIds` requests produce expanded `authors` responses. - [x] `tagSlugs` requests produce expanded tag responses and obey omitted-vs-empty update semantics. - [x] Validation failures use the shared error shape. - [x] Every posts route appears in OpenAPI with the documented operation ID. - [x] Relevant lint/test checks pass: `make check`, `./scripts/pre-pr.sh`, manual smoke, and Forgejo CI passed. ### Blocking Issues None. ### Warnings None. ### Verdict Approved for merge after explicit human approval.
erik 2026-05-22 20:57:39 -05:00
Author
Owner

Synced from todu comment by @todu on 2026-05-23T01:52:35.541Z

Closing Summary

PR #64 merged: #64

Acceptance criteria evidence:

  • Can create draft article, link, and note posts: met — POST /api/v1/posts supports all three types and tests assert created posts have publishedAt: null.
  • Can list posts and get a post by slug: met — GET /api/v1/posts supports filters/pagination metadata and omits content in list items; GET /api/v1/posts/:slug returns full post content.
  • Can update post metadata/content without accidentally publishing: met — PUT /api/v1/posts/:slug updates slug/title/content and preserves publishedAt: null for drafts.
  • Can explicitly publish and unpublish posts: met — POST /posts/:slug/publish and /unpublish are implemented and tested.
  • authorIds requests produce expanded authors responses: met — migration adds minimal contacts/post_authors tables and tests verify authorIds expands to contact objects.
  • tagSlugs requests produce expanded tag responses and obey omitted-vs-empty update semantics: met — service creates tags from normalized slugs; tests verify omitted tagSlugs preserves tags and tagSlugs: [] clears them.
  • Validation failures use the shared error shape: met — route validation returns VALIDATION_ERROR; duplicate slugs return shared CONFLICT; missing posts return shared NOT_FOUND.
  • Every posts route appears in OpenAPI with the documented operation ID: met — OpenAPI includes list/create/get/update/delete/publish/unpublish operation IDs plus post request/response and error schemas; route tests assert coverage.
  • Relevant lint/test checks pass: met — make check, ./scripts/pre-pr.sh, manual smoke, PR review, and Forgejo CI passed.

Readiness: READY

_Synced from todu comment by @todu on 2026-05-23T01:52:35.541Z_ ## Closing Summary PR #64 merged: https://forge.caradoc.com/erik/slugkit/pulls/64 Acceptance criteria evidence: - Can create draft article, link, and note posts: met — `POST /api/v1/posts` supports all three types and tests assert created posts have `publishedAt: null`. - Can list posts and get a post by slug: met — `GET /api/v1/posts` supports filters/pagination metadata and omits content in list items; `GET /api/v1/posts/:slug` returns full post content. - Can update post metadata/content without accidentally publishing: met — `PUT /api/v1/posts/:slug` updates slug/title/content and preserves `publishedAt: null` for drafts. - Can explicitly publish and unpublish posts: met — `POST /posts/:slug/publish` and `/unpublish` are implemented and tested. - `authorIds` requests produce expanded `authors` responses: met — migration adds minimal contacts/post_authors tables and tests verify `authorIds` expands to contact objects. - `tagSlugs` requests produce expanded tag responses and obey omitted-vs-empty update semantics: met — service creates tags from normalized slugs; tests verify omitted `tagSlugs` preserves tags and `tagSlugs: []` clears them. - Validation failures use the shared error shape: met — route validation returns `VALIDATION_ERROR`; duplicate slugs return shared `CONFLICT`; missing posts return shared `NOT_FOUND`. - Every posts route appears in OpenAPI with the documented operation ID: met — OpenAPI includes list/create/get/update/delete/publish/unpublish operation IDs plus post request/response and error schemas; route tests assert coverage. - Relevant lint/test checks pass: met — `make check`, `./scripts/pre-pr.sh`, manual smoke, PR review, and Forgejo CI passed. Readiness: READY
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
erik/slugkit#29
No description provided.