(modeling commons): Comments#43
Merged
omargfh merged 51 commits intoJul 21, 2026
Merged
Conversation
- createComment factory (uuid id, trimmed content validation via rules.limits.comment.content), assertNotDeleted, assertParentMatchesModel, assertCanEdit, assertCanDelete - CommentNotFoundError, CommentDeletedError, CommentBodyInvalidError, ParentCommentMismatchError - COMMENT_TREE_DEFAULTS (2 replies x 3 levels) for the future query layer
- create/update-comment request DTOs, sourcing content bounds from rules.ts (limits.comment.content) instead of a duplicated literal - list-comments query DTO intersecting the shared paginated query with a createdAt/updatedAt/likes sort - recursive comment response DTO (Type.Cyclic + Type.Ref, this typebox version has no Type.Recursive) with a nested Paginated<Comment> replies envelope, plus its paginated-list wrapper - model-comment.schemas.ts route params, naming the model param `id` (not `modelId`) to match resolveModel()'s hard-read of request.params.id
- Prisma-backed ModelCommentRepository (port, impl, mock) mirroring model-author's file split; every read hydrates user + likedByMe via a single filtered _count include, no per-row round trips. - listTopLevel/listReplies use paginate() with one findMany + count; addLikeTx/removeLikeTx keep likesCount in sync with the like rows. - Extend ModelCommentEntity with optional user/likedByMe so the repository's hydrated reads and plain writes share one type.
…ations - Add create/updateContent/softDelete/like/unlike, each transactional with model_comment.created/updated/deleted event audit; likes are not audited. - Post-commit, fire-and-forget email notification to a model's authors (minus the commenter, plus a differing parent author on replies) via the mail module. - Add model_comment.created/updated/deleted to the shared KnownEvents union. - Add src/modules/model-comment/index.ts to wire the module's DI types (repository, domain, service) into the global Dependencies interface.
- Register all seven /v1/models/:id/comments... routes, mirroring model-author.route.ts's fastify.get/post/patch/delete style. - Complete the awilix Dependencies declaration in model-comment/index.ts (modelCommentMapper, listCommentsQuery, getCommentQuery), moving the mapper's inline declare global into it so there's a single source.
Covers create/list/get/edit/delete/like routes under /v1/models/:id/comments per doc/discussion-plan.md §13: tombstones, bounded reply-tree embedding (2 x 3 levels), auth/permission checks, per-author email notification (mail-capture spy on mailService), and Event audit rows for create/update/delete with none for likes. Not executed in this environment: Docker/postgres is unavailable here, so the hand-authored add_model_comment migration remains unverified and this suite has not been run against a real database.
…access Add resolveComment preHandler hook that 404s when :commentId doesn't belong to the :id model, closing an IDOR where a comment from a private model could be read via a public model's path.
sendMail's param type was accidentally the nodemailer Mail class (instance methods/props) instead of Mail.Options, so no plain content object could ever satisfy it structurally, forcing the `as never` cast. Point unsubscribeUrl at the real support inbox instead of a non-existent /unsubscribe route.
expandCommentTree exposed replies.count from the raw DB page.count even after childless tombstone replies were filtered from replies.data. A deleted node whose only reply was itself a childless tombstone kept replies.count:1 with an empty data array, so the top-level filter (which keys off replies !== undefined) wrongly kept the tombstone, and the frontend rendered a "Continue this thread (1)" that fetched nothing. Now the count is corrected for replies dropped from the fetched page, and replies is left unset when the corrected count is 0 - consistent for both deleted and live nodes, and shared by get-comment.query.ts via the same expandCommentTree.
…n openapi.json Registers the recursive comment schema via fastify.addSchema with a stable $id (mirrors the ApiErrorResponse pattern) instead of inlining the cyclic Type.Cyclic schema into both the single-comment and paginated-list routes. @fastify/swagger only hoists addSchema'd schemas into components/schemas, so the inlined copies left the internal replies.data $ref dangling and broke generate:types (openapi-typescript couldn't resolve it).
… likes - expandCommentTree no longer drops childless tombstones; reports raw reply count - sort default is likes (desc); drop the unused updatedAt option - reconcile query specs to the always-keep behavior
- migrateLegacyComments maps postings -> ModelComment via legacyId (idempotent) - two-pass parent linking; soft-deleted postings imported as tombstones - skips postings whose model was not migrated; drops Q&A flags and legacy title - adds ModelComment(+Like) to WIPE_TARGET truncate list and report counters
- legacy postings stored <->< and >->&rt; (non-standard) with CRLF endings - decodeLegacyBody unescapes entities and normalizes newlines to LF - new frontend renders plaintext, so raw entities/CRLF showed literally
- new sort=newest maps to createdAt desc - repository toOrderBy now honors orderBy.param instead of hardcoding asc - createdAt stays asc (oldest-first), likes stays desc (default)
omargfh
marked this pull request as ready for review
July 21, 2026 21:12
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.