{"openapi":"3.0.3","info":{"title":"HuanChain DevForum API (DEV.to / Forem Compatible)","version":"1.0.0","description":"Full-Stack Developer Community & Technical Publishing REST API for **forum.huanchain.online**. Powered by **Next.js 15 App Router**, **Upstash Serverless Redis (L1/L2 Cache & Persistent Community Store)**, and **DEV.to Forem Aggregation**.","contact":{"name":"HuanChain Core Engineering","url":"https://huanchain.online","email":"huanchain@rgp.asia"},"license":{"name":"MIT","url":"https://opensource.org/licenses/MIT"}},"servers":[{"url":"https://forum-huanchain-online.vercel.app","description":"Production Edge Server (forum.huanchain.online)"},{"url":"http://localhost:3006","description":"Local Development Server (:3006)"}],"tags":[{"name":"Articles","description":"Read, filter, search, and publish technical Markdown articles (Forem + Redis Community Store)"},{"name":"Reactions","description":"Multi-emoji reactions (❤️ Heart, 🦄 Unicorn, 🤯 Mindblown, 🙌 Raised Hands, 🔥 Fire) & 🔖 Reading List Bookmarks stored in Redis"},{"name":"Comments","description":"Nested discussion threads & Markdown comments persisted in Redis"},{"name":"Tags","description":"Developer topic tags with custom hex colors & summaries"},{"name":"Media","description":"Developer podcast episodes & video tech talks"},{"name":"Users & Telemetry","description":"Developer profiles & Upstash Redis real-time metrics"}],"paths":{"/api/articles":{"get":{"tags":["Articles"],"summary":"List developer articles (Relevant, Latest, Top, Tag, Search)","description":"Returns a merged feed of HuanChain Redis community posts and live DEV.to Forem articles enriched with real-time Redis reaction & view counters.","parameters":[{"name":"page","in":"query","schema":{"type":"integer","default":1},"description":"Pagination page number (starts at 1)"},{"name":"per_page","in":"query","schema":{"type":"integer","default":24,"maximum":50},"description":"Number of articles per page"},{"name":"state","in":"query","schema":{"type":"string","enum":["rising","fresh","all"],"default":"rising"},"description":"Feed sort mode: rising (Relevant), fresh (Latest)"},{"name":"top","in":"query","schema":{"type":"integer","enum":[1,7,30,365]},"description":"Return top articles over the last N days (7 = Week, 30 = Month, 365 = Year)"},{"name":"tag","in":"query","schema":{"type":"string","example":"nextjs"},"description":"Filter articles by tag slug (e.g. webdev, ai, react, redis)"},{"name":"username","in":"query","schema":{"type":"string","example":"huanchain"},"description":"Filter articles by author username"},{"name":"q","in":"query","schema":{"type":"string","example":"redis"},"description":"Full-text search keyword across title, description, and tags"}],"responses":{"200":{"description":"Paginated list of articles with Redis telemetry metadata","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ArticlesFeedResponse"}}}}}},"post":{"tags":["Articles"],"summary":"Publish a new Markdown article to Redis Community Store","description":"Creates and persists a new developer article in Upstash Redis (`huanchain:forum:articles:v1`) with automatic Markdown-to-HTML rendering and reading time calculation.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateArticleRequest"}}}},"responses":{"201":{"description":"Article created and persisted in Redis","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"article":{"$ref":"#/components/schemas/Article"}}}}}},"400":{"description":"Validation error (missing title or body_markdown)"}}}},"/api/articles/{id}":{"get":{"tags":["Articles"],"summary":"Get single article detail by ID or slug","description":"Fetches full article body HTML, Markdown, author profile, and increments the real-time view counter in Redis.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","example":"9900001"},"description":"Article numeric ID or slug"}],"responses":{"200":{"description":"Full article object with body_html and reactions breakdown","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"article":{"$ref":"#/components/schemas/Article"}}}}}},"404":{"description":"Article not found"}}},"delete":{"tags":["Articles"],"summary":"Delete a community article by ID","description":"Removes a community-authored article from Upstash Redis (`huanchain:forum:articles:v1`).","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","example":"9900001"}}],"responses":{"200":{"description":"Article deleted"}}}},"/api/articles/{id}/react":{"post":{"tags":["Reactions"],"summary":"Increment multi-emoji reaction or bookmark on an article","description":"Atomically increments a reaction counter (`like`, `unicorn`, `exploding_head`, `raised_hands`, `fire`, `bookmark`) in Upstash Redis hash `huanchain:forum:reactions:v1`.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","example":"9900001"},"description":"Article ID"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["reaction"],"properties":{"reaction":{"type":"string","enum":["like","unicorn","exploding_head","raised_hands","fire","bookmark"],"example":"unicorn"},"baseCount":{"type":"integer","example":42}}}}}},"responses":{"200":{"description":"Updated reaction counts breakdown","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"articleId":{"type":"string","example":"9900001"},"reactions":{"$ref":"#/components/schemas/ReactionCounts"}}}}}}}}},"/api/articles/{id}/comments":{"get":{"tags":["Comments"],"summary":"Get nested comments thread for an article","description":"Returns merged Redis community comments and upstream DEV.to nested discussion threads.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","example":"9900001"}}],"responses":{"200":{"description":"List of nested comments","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","example":true},"total":{"type":"integer","example":6},"comments":{"type":"array","items":{"$ref":"#/components/schemas/Comment"}}}}}}}}},"post":{"tags":["Comments"],"summary":"Post a new comment or nested reply on an article","description":"Persists a new Markdown comment or reply to Upstash Redis (`huanchain:forum:comments:v1:{id}`).","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","example":"9900001"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCommentRequest"}}}},"responses":{"201":{"description":"Comment created and saved in Redis"}}}},"/api/tags":{"get":{"tags":["Tags"],"summary":"List popular developer tags & colors","description":"Returns curated HuanChain & DEV.to tags with hex background/text colors and post counts.","responses":{"200":{"description":"Array of ForumTag objects"}}}},"/api/podcasts":{"get":{"tags":["Media"],"summary":"List developer podcast episodes","parameters":[{"name":"per_page","in":"query","schema":{"type":"integer","default":24}}],"responses":{"200":{"description":"List of podcast episodes"}}}},"/api/videos":{"get":{"tags":["Media"],"summary":"List developer video articles & streams","parameters":[{"name":"per_page","in":"query","schema":{"type":"integer","default":24}}],"responses":{"200":{"description":"List of video articles"}}}},"/api/users/{username}":{"get":{"tags":["Users & Telemetry"],"summary":"Get developer profile and published articles by username","parameters":[{"name":"username","in":"path","required":true,"schema":{"type":"string","example":"huanchain"}}],"responses":{"200":{"description":"Developer profile and authored articles"}}}},"/api/stats":{"get":{"tags":["Users & Telemetry"],"summary":"Get Redis storage mode & live forum telemetry","responses":{"200":{"description":"Real-time community stats and Redis health","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForumStats"}}}}}}},"/api/openapi":{"get":{"tags":["Users & Telemetry"],"summary":"Get raw OpenAPI 3.0.3 JSON specification","responses":{"200":{"description":"OpenAPI 3.0.3 JSON document"}}}}},"components":{"schemas":{"ReactionCounts":{"type":"object","properties":{"like":{"type":"integer","example":54},"unicorn":{"type":"integer","example":28},"exploding_head":{"type":"integer","example":19},"raised_hands":{"type":"integer","example":15},"fire":{"type":"integer","example":12},"bookmark":{"type":"integer","example":31},"total":{"type":"integer","example":128}}},"Article":{"type":"object","properties":{"id":{"type":"integer","example":9900001},"title":{"type":"string","example":"Launching forum.huanchain.online — Full-Stack DEV.to Clone with Next.js 15 & Redis"},"description":{"type":"string"},"readable_publish_date":{"type":"string","example":"Nov 2"},"published_at":{"type":"string","format":"date-time"},"slug":{"type":"string"},"path":{"type":"string"},"url":{"type":"string"},"comments_count":{"type":"integer","example":6},"public_reactions_count":{"type":"integer","example":128},"reading_time_minutes":{"type":"integer","example":5},"cover_image":{"type":"string","nullable":true},"tag_list":{"type":"array","items":{"type":"string"},"example":["nextjs","redis","webdev","opensource"]},"isCommunityPost":{"type":"boolean","example":true},"views":{"type":"integer","example":1840},"reactions":{"$ref":"#/components/schemas/ReactionCounts"}}},"ArticlesFeedResponse":{"type":"object","properties":{"success":{"type":"boolean","example":true},"total":{"type":"integer","example":26},"page":{"type":"integer","example":1},"redisMode":{"type":"string","example":"upstash-rest"},"articles":{"type":"array","items":{"$ref":"#/components/schemas/Article"}}}},"CreateArticleRequest":{"type":"object","required":["title","body_markdown"],"properties":{"title":{"type":"string","example":"Building Resilient Microservices with Upstash Redis & Next.js 15"},"description":{"type":"string","example":"Step-by-step architectural guide to low-latency edge caching."},"body_markdown":{"type":"string","example":"## Introduction\n\nUsing **Upstash Redis** with Next.js 15 App Router gives sub-5ms reads..."},"cover_image":{"type":"string","example":"https://images.unsplash.com/photo-1555066931-4365d14bab8c?auto=format&fit=crop&w=1200&q=80"},"tag_list":{"type":"array","items":{"type":"string"},"example":["nextjs","redis","webdev","typescript"]},"author_name":{"type":"string","example":"Jacky Huan"},"author_username":{"type":"string","example":"huanchain"}}},"Comment":{"type":"object","properties":{"id_code":{"type":"string","example":"hc-comment-1"},"created_at":{"type":"string","format":"date-time"},"body_html":{"type":"string"},"body_markdown":{"type":"string"},"isCommunityComment":{"type":"boolean","example":true}}},"CreateCommentRequest":{"type":"object","required":["body_markdown"],"properties":{"body_markdown":{"type":"string","example":"Great article! The Redis SWR pattern works like a charm."},"parent_id":{"type":"string","nullable":true,"example":null},"author_name":{"type":"string","example":"Dev Contributor"},"author_username":{"type":"string","example":"dev_member"}}},"ForumStats":{"type":"object","properties":{"totalArticlesServed":{"type":"integer","example":1502},"communityPostsCount":{"type":"integer","example":2},"totalReactions":{"type":"integer","example":212},"totalComments":{"type":"integer","example":44},"totalViews":{"type":"integer","example":2800},"redisMode":{"type":"string","example":"upstash-rest"},"syncedAt":{"type":"string","format":"date-time"}}}}}}