Comments System v2: Design Refresh, Spam Protection, HTMX & Reactions #43
Notifications
Total Time Spent: 1 hour 22 minutes
mark
1 hour 22 minutes
No due date set.
Dependencies
No dependencies set.
Reference: nohype/main-site#43
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Current State
The comment system is a functional MVP with:
Commentwith parent/reply (one level deep),is_approvedgating, IP tracking, 2000-char body limit/comments/post/, redirect back with?commented=1Proposed Improvements
1. Design Refresh — Align with Design Language
The comment section currently uses plain surface/border styling that feels disconnected from the rest of the site. Changes to bring it in line:
shadow-solid-dark/shadow-solid-lightoffset shadows on hover (matches article cards and featured sections)from-brand-cyan to-brand-pink) are good — consider making them slightly larger and adding a subtleshadow-neon-cyanglowtext-gradientutility for author names or ahover:text-brand-cyantransitionfont-mono text-xswhich is correctfocus:border-brand-pink— addfocus:shadow-neon-pinkfor the glow effect used elsewherehover:shadow-solid-*which is correct; ensure it matches the CTA style from hero sectionsbg-grid-patternbackground with centered textml-8left indent is fine but consider adding a left border accent inbrand-cyan(border-l-2 border-brand-cyan) instead of/alongside the indenttransition-all duration-300on comment cards for hover effects (scale, shadow, border-colour shift — like article cards)2. Spam Protection — Replace Manual Approval with Cloudflare Turnstile
Problem: Every comment requires manual approval. This doesn't scale and means legitimate comments sit in limbo.
Solution: Cloudflare Turnstile — a free, invisible CAPTCHA alternative.
Why Turnstile?
Implementation approach:
<script src="https://challenges.cloudflare.com/turnstile/v0/api.js" async defer></script>)<div class="cf-turnstile" data-sitekey="..."></div>inside each comment formcf-turnstile-responsetoken via POST tohttps://challenges.cloudflare.com/turnstile/v0/siteverifyinCommentCreateView.post()before savingTURNSTILE_SITE_KEYandTURNSTILE_SECRET_KEYin environment/settingsis_approveddefault toTruewhen Turnstile validates, keepFalseas fallback if Turnstile is not configuredModeration change: With Turnstile, shift from "approve everything" to "flag and review reported/suspicious comments". The existing Wagtail admin bulk actions can be repurposed for un-approving/removing flagged content.
3. HTMX Integration — No Page Reload, Live Updates
Problem: Comment submission triggers a full page reload. No way to see new comments without refreshing.
Implementation:
django-htmxto requirements and middlewarehtmx.org@2.x) in the base templatetemplates/comments/_comment_list.html— the full approved comments listtemplates/comments/_comment.html— single comment (with replies)templates/comments/_comment_form.html— the post formtemplates/comments/_reply_form.html— inline reply formCommentCreateViewto detectrequest.htmxand return the partial instead of redirectinghx-getwithhx-trigger="every 30s"on the comments container to fetch new comments periodically4. Comment Reactions (Likes/Hearts)
New feature: Allow users to react to comments without needing to post a reply.
Model:
Implementation:
hx-post="/comments/{id}/react/"withhx-swap="outerHTML"to update the reaction count inlinefont-mono text-xscount next to atext-brand-pinkheart icon, withhover:scale-110 transition-transformImplementation Order
Technical Notes
django-htmxdjango-csp) will need updating to allow Turnstile and HTMX script sourcesapps/comments/will need updating for HTMX partial responsesdata-comment-formattribute on the form is already there — likely intended for future JS useCommentReaction.session_keyGreat direction overall. This is a solid v2 target, and I think it solves real MVP pain.
Main risks / gotchas I’d address before implementation:
Comment.is_approvedmodel default toTrueglobally.False, then setcomment.is_approved = turnstile_okin the create view only when Turnstile is enabled and verification succeeds.success: also validatehostname(andactionif used) to prevent token replay/misuse.script-src 'self' 'nonce-...',connect-src 'self', and noframe-srcallowlist.hx-target="#comments-list"+hx-swap="beforeend"can break if the server returns full list HTML or form errors.422)Vary: HX-Request.every 30spolling + append behavior can duplicate comments.?after_id=), orouterHTML) instead of appending.order_by(created_at, id)) so UI order is deterministic.UniqueConstraint(modern replacement forunique_together).get_or_create+IntegrityError) and use atomic increments/F expressions for counts.3/mincomment limit will feel broken.Approve.UnapproveandDelete(or soft-hide), otherwise moderation workflow will regress.CommentReaction.session_keyin retention/anonymization policy and tests.Suggested sequence (slightly safer):
Extra tests that will pay off quickly: