https://github.com/wanlucas/hacker-news-app
https://github.com/wanlucas/hacker-news-app
ruby ruby-on-rails vue vuejs websockets
Last synced: 3 months ago
JSON representation
- Host: GitHub
- URL: https://github.com/wanlucas/hacker-news-app
- Owner: wanlucas
- Created: 2025-08-11T04:39:03.000Z (11 months ago)
- Default Branch: master
- Last Pushed: 2025-08-12T20:40:27.000Z (11 months ago)
- Last Synced: 2025-11-11T18:26:26.297Z (8 months ago)
- Topics: ruby, ruby-on-rails, vue, vuejs, websockets
- Language: Ruby
- Homepage: https://hacker-news-app-nu.vercel.app
- Size: 138 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# Hacker News Real-time Client
Uma aplicação full-stack moderna que consome a API do Hacker News com cache inteligente, atualizações em tempo real via WebSocket e interface Vue.js responsiva.
## 🚀 Como Iniciar a Aplicação
### Pré-requisitos
- Docker e Docker Compose
### 🔧 Instalação e Execução
#### Usando Docker (Recomendado)
```bash
# Clone o repositório
git clone
cd bee
# Inicie a aplicação completa
docker-compose up
# Para rebuild após mudanças
docker-compose up --build
```
**URLs de Acesso:**
- Frontend (Vue.js): http://localhost:5173
- Backend API (Rails): http://localhost:3000
- API Endpoints: http://localhost:3000/api/stories
#### Execução Local (Desenvolvimento)
**Backend (Rails):**
```bash
cd server
bundle install
rails server -p 3000
```
**Frontend (Vue.js):**
```bash
npm install
npm run dev
```
### 🌍 Variáveis de Ambiente
#### Frontend (Client)
- VITE_SOCKET_URL=ws://localhost:3000/cable
- VITE_API_URL=http://localhost:3000
- VITE_DEBUG=true
#### Backend (Server)
- CLIENT_URL=http://localhost:5173
## 🏗️ Arquitetura da Aplicação
### 📋 Visão Geral
A aplicação segue uma arquitetura limpa com separação clara de responsabilidades, implementando patterns de design sólidos e práticas modernas de desenvolvimento.
```
┌─────────────────┐ WebSocket ┌──────────────────┐
│ Vue.js Client │◄──────────────────┤ Rails API │
│ │ │ │
│ • Components │ HTTP API │ • Controllers │
│ • Composables │◄──────────────────┤ • Services │
│ • Services │ │ • Jobs │
└─────────────────┘ │ • Channels │
└──────────────────┘
│
┌──────────────────┐
│ Hacker News API │
│ │
│ • Stories │
│ • Comments │
│ • Items │
└──────────────────┘
```
### 🎯 Backend (Rails API)
#### 🔗 Injeção de Dependências
A aplicação utiliza um **Service Factory** para gerenciar dependências de forma limpa:
```ruby
# app/services/service_factory.rb
class ServiceFactory
def self.hacker_news_service
HackerNewsService.new(
http_client: HttpClient.new('https://hacker-news.firebaseio.com/v0'),
cache_repository: Repositories::Cache::Rails.new,
broadcasting_service: BroadcastingService.new,
logger: Rails.logger
)
end
end
```
**Vantagens:**
- ✅ Baixo acoplamento entre componentes
- ✅ Fácil substituição de dependências para testes
- ✅ Configuração centralizada
- ✅ Facilita mocking em testes unitários
#### 🎨 Repository Pattern
Implementação do padrão Repository para abstração do cache:
```ruby
# Abstração base
class Repositories::Cache::Base
def read(key); end
def write(key, value, options = {}); end
def exist?(key); end
def delete(key); end
end
# Implementação Rails
class Repositories::Cache::Rails < Base
# Implementação usando Rails.cache
end
```
**Benefícios:**
- ✅ Abstração da camada de persistência
- ✅ Facilita troca de engines de cache
- ✅ Testabilidade melhorada
- ✅ Separação de responsabilidades
#### 💾 Sistema de Cache Inteligente
A aplicação implementa uma estratégia de cache com **Stale-While-Revalidate**:
```ruby
# app/lib/cached_api.rb
class CachedApi
def load_cache(key, revalidate_fn:)
data = @cache_repository.read(key)
# Retorna cache válido imediatamente
return data if cache_is_valid?(key)
if data.nil?
# Cache miss - busca dados fresh
data = revalidate_fn.call
elsif !@cache_repository.exist?("#{key}_lock")
# Cache stale - atualiza em background
background_refresh(key, revalidate_fn)
end
data
end
end
```
**Características:**
- 🚀 **Performance**: Retorna dados em cache instantaneamente
- 🔄 **Freshness**: Atualiza dados em background quando stale
- 🔒 **Concorrência**: Lock mechanism previne múltiplas atualizações
- ⚡ **Graceful Degradation**: Continua servindo cache stale se API falhar
#### 🔄 Jobs Assíncronos e Worker Periódico
**Job de Atualização:**
```ruby
# app/jobs/stories_update_job.rb
class StoriesUpdateJob < ApplicationJob
def perform
ServiceFactory.hacker_news_service.update_cache
end
end
```
**Worker Periódico:**
```ruby
# config/initializers/periodic_jobs.rb
Thread.new do
loop do
StoriesUpdateJob.perform_now
sleep 5.minutes
end
end
```
**Benefícios:**
- ⏰ Atualizações automáticas a cada 5 minutos
- 🔄 Mantém cache sempre atualizado
- 📊 Broadcast de novos dados via WebSocket
#### 🌐 HTTP Client Robusto
```ruby
# app/services/http_client.rb
class HttpClient
def get(endpoint)
# Implementação com tratamento de erros
# Logging detalhado
# Parsing JSON automático
end
end
```
**Features:**
- 🔍 Logging detalhado de requests
- ⚠️ Error handling customizado
- 🔄 Retry logic implícito
- 📊 Debugging tools integrados
#### ⚡ Paralelização Inteligente
O serviço utiliza **threading** para otimizar fetching de dados:
```ruby
# Busca stories em paralelo (batches de 10)
ids.each_slice(10) do |batch|
threads = batch.map do |id|
Thread.new { fetch_story(id) }
end
threads.each(&:join)
end
# Busca comments em paralelo (batches de 30)
ids.each_slice(30) do |batch|
threads = batch.map do |id|
Thread.new { fetch_comment(id) }
end
end
```
**Vantagens:**
- 🚀 Redução significativa de latência
- 📊 Throughput otimizado
- 🔒 Thread-safe com Mutex
- ⚖️ Load balancing automático
#### 📡 WebSocket Real-time
```ruby
# app/channels/stories_channel.rb
class StoriesChannel < ActionCable::Channel::Base
def subscribed
stream_from "stories_updates"
end
def self.broadcast_new_stories(stories)
ActionCable.server.broadcast('stories_updates', {
type: 'new_stories',
data: stories
})
end
end
```
## 🧪 Testes Automatizados
### 📋 Estrutura de Testes
```ruby
# test/services/hacker_news_service_test.rb
class HackerNewsServiceTest < ActiveSupport::TestCase
def setup
@http_client = mock_http_client
@cache_repository = mock_cache_repository
@broadcasting_service = mock_broadcasting_service
@logger = mock_logger
end
test "should return stories from cache when valid" do
# Testa comportamento de cache válido
end
test "should fetch fresh data on cache miss" do
# Testa cache miss scenario
end
end
```
**Cobertura de Testes:**
- ✅ **Unit Tests**: Serviços, repositories, jobs
- ✅ **Integration Tests**: APIs, controllers
- ✅ **Mock Objects**: Isolamento de dependências
- ✅ **Edge Cases**: Error handling, timeouts
- ✅ **Performance Tests**: Caching behavior
### 🔧 Executar Testes
```bash
# Todos os testes
cd server
rails test
# Testes específicos
rails test test/services/hacker_news_service_test.rb
# Com cobertura
rails test:coverage
```
## 🔧 Tecnologias Utilizadas
### Backend
- **Ruby on Rails 8.0** - Framework web
- **Action Cable** - WebSocket real-time
- **Puma** - Application server
- **Net::HTTP** - HTTP client nativo
- **Rails Cache** - Sistema de cache
- **dotenv-rails** - Gerenciamento de variáveis de ambiente
### Frontend
- **Vue.js 3** - Framework reativo
- **Vite** - Build tool e dev server
- **Axios** - HTTP client
- **Action Cable JS** - WebSocket client
- **DOMPurify** - Sanitização XSS
## 📝 API Endpoints
```
GET /api/stories # Lista top stories
GET /api/stories/search # Busca stories por query
POST /api/stories/update # Force cache update
WS /cable # WebSocket connection
```
**Desenvolvido com 🎵 usando Ruby on Rails e Vue.js**