About cBlog

Tagline: Confluence blogs, beautifully reimagined.

💡 The Inspiration

Confluence is a powerful collaboration platform used by teams worldwide, but its blog experience felt... dated. While modern blogging platforms like Medium, Dev.to, and LinkedIn offer sleek interfaces with rich interactions—reactions, beautiful typography, and seamless navigation—Confluence blogs remained stuck in a more utilitarian design paradigm.

The question was simple: What if we could bring the best of modern blogging to Confluence?

That's where cBlog was born. The vision was to create a native Forge app that would transform how teams read, discover, and engage with blog posts in their Confluence workspace, without leaving the platform they already use daily.

🎯 The Mission

To create a beautiful, interactive blog reading experience within Confluence that:

  • Presents blog posts with modern, magazine-quality typography
  • Enables emotional engagement through LinkedIn-style reactions
  • Makes discovery effortless with elegant navigation
  • Renders rich Confluence content (ADF format) perfectly
  • Feels native to both Confluence and modern web expectations

🛠️ How We Built It

Architecture Overview

cBlog is built on Atlassian Forge, leveraging both UI Kit and Custom UI capabilities:

Backend (Resolver)

  • Node.js 22.x runtime on ARM64 architecture
  • Forge Resolver for API gateway and business logic
  • Direct integration with Confluence REST APIs (v2)
  • Forge Storage API for persistent reaction data

Frontend (Custom UI)

  • React 18 with modern hooks architecture
  • Tailwind CSS for responsive, utility-first styling
  • Custom ADF (Atlassian Document Format) renderer
  • Real-time interaction with backend via Forge Bridge

Key Technical Components

1. Blog Discovery Engine

// Pagination-aware fetching to retrieve ALL blog posts
const getAllBlogPosts = async () => {
  let allResults = [];
  let cursor = null;

  do {
    const response = await api.requestConfluence(
      route`/wiki/api/v2/blogposts?limit=250${cursor ? `&cursor=${cursor}` : ''}`
    );
    const data = await response.json();
    allResults.push(...data.results);
    cursor = data._links?.next ? extractCursor(data._links.next) : null;
  } while (cursor);

  return allResults;
};

2. ADF Content Renderer

Built a comprehensive renderer supporting 25+ ADF node types:

  • Rich text (bold, italic, code, underline, strike)
  • Structural elements (headings, paragraphs, lists)
  • Media (images, embeds with Confluence URL resolution)
  • Advanced components (tables, panels, code blocks)
  • Inline elements (mentions, emojis, dates, status badges)

3. Reaction System

Implemented a LinkedIn-inspired reaction mechanism:

  • 6 reaction types: Like 👍, Love ❤️, Insightful 💡, Celebrate 🎉, Support 🤝, Funny 😂
  • User-specific reaction tracking (one reaction per user per post)
  • Toggle behavior (click again to remove)
  • Real-time count aggregation
  • Persistent storage using Forge Storage API
// Reaction data structure
{
  counts: { like: 15, love: 8, insightful: 12 },
  userReactions: { 'user-123': 'like', 'user-456': 'love' }
}

4. Modern UI/UX

  • Gradient headers with decorative elements
  • Card-based layouts with subtle shadows and hover effects
  • Smooth transitions and animations
  • Responsive design (mobile, tablet, desktop)
  • Accessible color contrast and semantic HTML

📚 What We Learned

Technical Insights

  1. Forge Custom UI vs UI Kit Trade-offs

    • UI Kit is limited to Forge-specific components (no standard React components)
    • Custom UI offers full React flexibility but requires separate build pipeline
    • Static file serving requires careful path configuration
  2. Confluence API Complexity

    • API v2 uses cursor-based pagination (not page numbers)
    • Media URLs require complex resolution (contentId, mediaId, collection)
    • Author information requires separate user API calls (caching essential)
  3. ADF is Powerful but Challenging

    • Deeply nested JSON structure requires recursive rendering
    • Many edge cases (empty paragraphs, newlines in text, image fallbacks)
    • Different node types have inconsistent attribute patterns
  4. Storage Patterns

    • Forge Storage is key-value based (no SQL-like queries)
    • Denormalization necessary (store both counts and user mappings)
    • Atomic updates important for concurrent reactions

Development Lessons

  • Start Simple, Iterate: Built basic list view first, then added detail view, then reactions
  • User Experience First: Prioritized polish over feature count
  • Progressive Enhancement: App works with degraded experiences if APIs fail
  • Defensive Programming: Extensive error handling and fallbacks throughout

🚧 Challenges We Faced

1. Image Rendering Mystery

Problem: Confluence media nodes contain IDs but not direct URLs

Journey:

  • Initial attempts: Tried direct media API endpoints → 404s
  • Discovered: Need contentId from collection attribute
  • Attempted: Multiple URL patterns (/download/attachments/, /wiki/download/...)
  • Solution: Implemented fallback chain with onError retry logic

2. User Information Enrichment

Problem: Blog API returns only authorId (UUID), not names/pictures

Solution:

  • Built user detail cache to avoid repeated API calls
  • Implemented Promise.all for parallel user fetching
  • Added graceful degradation (show UUID prefix if API fails)
  • Profile picture fallback to generated avatar circles

3. Pagination Cursor Extraction

Problem: Confluence API v2 returns cursor as URL parameter, not directly

Challenge:

// API returns: "_links": { "next": "/wiki/api/v2/blogposts?cursor=abc123..." }
// Need to extract: "abc123..."

Solution:

const extractCursor = (nextUrl) => {
  const url = new URL(nextUrl, 'https://dummy.com');
  return url.searchParams.get('cursor');
};

4. React in Forge Constraints

Problem: UI Kit doesn't support standard React components

Learning Curve:

  • Can't use <div>, <span>, <strong> → Must use UI Kit equivalents
  • Decided to use Custom UI for blog viewer (full React freedom)
  • Required setting up separate build pipeline with react-scripts

5. Real-time State Management

Problem: Reactions need to update immediately without page refresh

Implementation:

  • Optimistic UI updates (update state before backend confirms)
  • Loading states to prevent double-clicks
  • Error recovery (revert state if backend fails)
  • Smooth animations for visual feedback

6. Deployment & Testing Workflow

Challenge: Forge requires deploy → install cycle for testing

Workflow Developed:

# Development
forge tunnel  # Hot reload for code changes

# Manifest changes
forge deploy --non-interactive
forge install --upgrade --non-interactive

# Production
forge deploy --environment production

🎨 Design Philosophy

  1. Content First: Typography and readability are paramount
  2. Familiar Yet Fresh: Use known patterns (like LinkedIn reactions) but make them feel native
  3. Progressive Disclosure: Show essentials first, details on demand
  4. Performance Matters: Lazy loading, caching, and optimized rendering
  5. Fail Gracefully: Every API call has a fallback plan

🚀 Future Vision

While cBlog v1 focuses on reading and reacting, the roadmap includes:

  • Comments System: Threaded discussions on blog posts
  • Search & Filters: Find posts by author, space, date, or reactions
  • Bookmarking: Save favorite posts for later
  • Analytics Dashboard: Insights on most-read and most-reacted posts
  • Author Tools: Publishing interface within the app
  • Notifications: Get alerted when posts you care about get updates

🏆 Impact

cBlog demonstrates that enterprise tools don't have to sacrifice user experience. By bringing consumer-grade polish to Confluence, we're showing that:

  • Teams can have delightful internal tools
  • Modern web patterns work in enterprise contexts
  • Forge enables rapid innovation on Atlassian platforms
  • Small improvements in UX create outsized engagement gains

The average employee spends hours per week in Confluence. If we can make that time even 10% more enjoyable and productive, we've created real value.

🙏 Acknowledgments

Built with love for the Confluence and Forge communities. Special thanks to:

  • The Atlassian Forge team for an incredible platform
  • The React community for excellent tooling
  • Every developer who's shared Forge insights and patterns
  • Teams everywhere who deserve better tools

Tech Stack: Forge | React | Node.js | Confluence API | Tailwind CSS
Status: Production-ready ✨
License: Built for the Forge community

Share this project:

Updates