Como Implementei um Sistema de Comentários Gratuito com GitHub Issues

✨ Ter um sistema de comentários em um blog é essencial para construir uma comunidade e gerar discussões interessantes. Mas hospedar seu próprio banco de dados para comentários pode ser complicado e caro. E se você pudesse usar o GitHub como seu backend de comentários, completamente de graça?

🤔 O Problema dos Comentários

Quando decidi construir este blog em Go, enfrentei o clássico dilema dos comentários:

  • WordPress? Exige PHP e um banco de dados.
  • Disqus? Gratuito, mas carregado de rastreadores e anúncios.
  • Discourse? Poderoso, mas exige hospedagem separada.
  • Firebase/Supabase? Começa gratuito, mas pode ficar caro com o crescimento.

Eu queria uma solução que fosse:

  1. Totalmente gratuita (mesmo com escala)
  2. Sem hospedagem separada de banco de dados
  3. Controlada por mim (sem depender de plataformas externas)
  4. Com moderação simplificada
  5. Integrável facilmente com minha aplicação Go

💡 A Epifania: GitHub Issues como Sistema de Comentários

Um dia, enquanto navegava pelo GitHub, percebi algo: Issues já são um sistema de comentários completo!

Issue = Post principal
Comentários na Issue = Respostas

E o melhor de tudo: a API do GitHub é gratuita para uso público e já oferece tudo que eu precisava:

  • Autenticação (via token de API)
  • Armazenamento persistente
  • Sistema de notificação por email
  • Markdown rico para formatação
  • Avatares de usuários
  • Moderação (posso fechar/deletar issues)

🛠️ A Arquitetura da Solução

Para implementar esse sistema, criei uma arquitetura simples em Go:

1. Modelo de Dados

// Comment representa um comentário baseado em GitHub Issue
type Comment struct {
	ID        int       `json:"id"`
	Body      string    `json:"body"`
	Author    string    `json:"author"`
	AvatarURL string    `json:"avatar_url"`
	CreatedAt time.Time `json:"created_at"`
	PostID    string    `json:"post_id"`
	URL       string    `json:"url"`
	Replies   []Reply   `json:"replies,omitempty"`
	IsAdmin   bool      `json:"is_admin"`
}

// Reply representa uma resposta a um comentário
type Reply struct {
	ID        int       `json:"id"`
	Body      string    `json:"body"`
	Author    string    `json:"author"`
	AvatarURL string    `json:"avatar_url"`
	CreatedAt time.Time `json:"created_at"`
	IsAdmin   bool      `json:"is_admin"`
}

2. Serviço de Comentários

O coração do sistema é o CommentService, que interage com a API do GitHub:

type CommentService struct {
	Owner      string
	Repo       string
	Token      string
	APIBaseURL string
	GithubUser string
}

Este serviço implementa métodos para:

  • GetComments(postID string): Busca comentários de um post específico
  • CreateComment(request CommentRequest): Cria um novo comentário
  • GetReplies(commentID int): Busca respostas de um comentário
  • CreateReply(request ReplyRequest): Cria uma resposta a um comentário

3. API REST

Para expor essa funcionalidade para o frontend, implementei endpoints REST:

func (h *CommentHandler) Register(mux chi.Router) {
	mux.Route("/api/comments", func(r chi.Router) {
		r.Get("/{postID}", h.getComments)
		r.Post("/{postID}", h.createComment)
		r.Post("/{commentID}/reply", h.createReply)
	})
}

4. Integração com GitHub

O segredo está em como usar a API do GitHub para gerenciar comentários:

Como Armazenar Comentários

  • Cada comentário é uma Issue no repositório configurado
  • Cada post do blog é identificado por uma label ("comment:slug-do-post")
  • Comentários aninhados são comentários do GitHub na Issue

Criação de Comentário (Formulário → GitHub Issue)

// Cria uma nova Issue para representar o comentário
issueData := struct {
	Title  string   `json:"title"`
	Body   string   `json:"body"`
	Labels []string `json:"labels"`
}{
	Title:  fmt.Sprintf("Comment by %s", request.Name),
	Body:   fmt.Sprintf("%s\n\n---\nEmail: %s", request.Body, request.Email),
	Labels: []string{"comment:" + request.PostID},
}

// Envia para API do GitHub
url := fmt.Sprintf("%s/repos/%s/%s/issues", s.APIBaseURL, s.Owner, s.Repo)
// ... código para enviar requisição HTTP ...

Recuperação de Comentários (GitHub Issues → Frontend)

// Busca Issues com a label específica do post
url := fmt.Sprintf("%s/repos/%s/%s/issues?labels=comment:%s&state=all", 
	s.APIBaseURL, s.Owner, s.Repo, postID)

// ... código para processar resposta e criar objetos Comment ...

// Para cada comentário, busca suas respostas
replies, err := s.GetReplies(comment.ID)
if err == nil && len(replies) > 0 {
	comment.Replies = replies
}

🎭 Identificação de Administradores

Um detalhe interessante é como identifico comentários do administrador do blog:

// Se NÃO foi criado pelo formulário, é um comentário direto do GitHub feito pelo administrador
isAdmin := !wasCreatedViaForm

Comentários feitos diretamente no GitHub pelo administrador são marcados como "admin", recebendo estilo visual diferenciado na interface.

🚀 Vantagens Desta Abordagem

Usar o GitHub como backend para comentários trouxe várias vantagens:

  1. Custo zero - GitHub oferece API gratuita para repositórios públicos
  2. Sem banco de dados - GitHub armazena tudo
  3. Notificações automáticas - recebo email quando alguém comenta
  4. Anti-spam integrado - GitHub já tem proteção contra bots
  5. Backup automático - tudo está no GitHub, sempre seguro
  6. Moderação fácil - posso gerenciar pelo próprio GitHub
  7. Markdown nativo - suporte completo à formatação rica

🧠 Aspectos Técnicos Interessantes

A implementação revelou alguns desafios interessantes:

1. Parsing de Comentários

O formato dos comentários do GitHub não é exatamente o que eu precisava para o blog, então tive que fazer parsing cuidadoso:

// Verificamos se o comentário parece ter sido criado pelo formulário do site
wasCreatedViaForm := strings.Contains(issue.Body, "---\nEmail:") && 
                    strings.HasPrefix(issue.Title, "Comment by ")

// Define o autor com base na origem do comentário
var author string
if wasCreatedViaForm {
    // Comentário do formulário: extrai o nome do título "Comment by Nome"
    author = strings.TrimPrefix(issue.Title, "Comment by ")
} else {
    // Comentário direto do GitHub: usa o nome de usuário do GitHub
    author = issue.User.Login
}

2. Gerenciamento de Token

O token de acesso à API do GitHub é sensível, então precisei gerenciá-lo com cuidado:

token := os.Getenv("GITHUB_TOKEN")
if token == "" {
    return nil, fmt.Errorf("GITHUB_TOKEN não configurado")
}

3. Estrutura de Respostas Aninhadas

Armazenar e recuperar respostas aninhadas exigiu atenção especial para manter a estrutura:

// Busca respostas para este comentário
replies, err := s.GetReplies(comment.ID)
if err == nil && len(replies) > 0 {
    comment.Replies = replies
}

🌐 Experiência do Usuário

Para o usuário final, a experiência é perfeita:

  1. Formulário simples para adicionar comentários
  2. Resposta imediata após submissão
  3. Carregamento rápido de comentários existentes
  4. Suporte a respostas aninhadas para criar conversas
  5. Identificação de comentários do autor do blog

🧩 A Natureza Emergente das Conversas

O que me fascina sobre sistemas de comentários é como eles representam um sistema complexo emergente. Cada comentário individual é simples, mas juntos criam uma rede de ideias interconectadas onde:

  • Tópicos emergem naturalmente na discussão
  • Clusters de ideias se formam em torno de pontos controversos
  • Nós centrais (comentários populares) atraem mais respostas
  • Propriedades de rede livre de escala aparecem na distribuição de respostas

É como uma rede neural social, onde cada comentário é um neurônio conectando-se a outros para formar um tecido de pensamento coletivo.

🔮 Futuras Melhorias

Algumas ideias para o futuro:

  1. Autenticação OAuth para comentar diretamente como usuário GitHub
  2. Reações (curtir, aplaudir) além de comentários
  3. Notificações para usuários quando receberem respostas
  4. Visualização de rede para ver a estrutura da conversa
  5. Análise de sentimento para identificar tópicos polêmicos

🔚 Conclusão

Implementar um sistema de comentários usando GitHub Issues foi uma solução elegante e econômica. Em vez de reinventar a roda ou pagar por serviços, aproveitei a infraestrutura existente do GitHub para criar uma experiência de alta qualidade sem custo.

Esta abordagem demonstra um princípio importante: às vezes, a melhor solução não é construir algo novo, mas conectar sistemas existentes de formas criativas.

E você, já pensou em usar GitHub para algo além de código? Quais outros serviços poderiam ser reimaginados como backends para aplicações web? Deixe seu comentário abaixo!


🎨 O Background Interativo deste Post

Enquanto você lê este artigo, observe o fascinante sistema complexo se desenrolando no background. O que você está vendo é uma rede de comentários emergente - uma visualização interativa de como as ideias se conectam e fluem em um sistema de discussão.

Cada nó colorido representa um comentário, e as linhas entre eles representam respostas ou conexões temáticas. Observe como:

  • Clusters de comentários relacionados se formam naturalmente
  • Hubs (comentários populares) atraem mais conexões
  • Cascatas de informação se propagam quando uma ideia ganha tração
  • Novos comentários aparecem e buscam conexões com a conversa existente

Este sistema simula o fenômeno de homofilia (tendência de ideias semelhantes se agruparem) e difusão em rede (como informações se espalham através de conexões sociais).

Interaja com o background:

  • Mova o mouse para introduzir novos "comentários" e veja como se integram à rede
  • Clique para criar um comentário influente que atrairá mais conexões
  • Observe padrões emergentes na formação de comunidades de pensamento

Esta visualização é inspirada pela teoria de redes complexas e pelo conceito de "fitness landscape" em sistemas adaptativos complexos - onde ideias competem, evoluem e se agrupam, criando um ecossistema de pensamento coletivo em constante evolução!