Fluxo Típico de Uso
📝
1. Onboarding & Cadastro
O usuário baixa o app ou abre o site. Ele precisa criar uma conta para salvar seus alertas.
POST /register
{ "name": "Leandro", "email": "leo@sky.com", "pass": "*****" }
🔍
2. Descoberta & Feed
Ao logar, ele vê o "Feed de Oportunidades". Voos que caíram de preço nas últimas horas aparecem no topo com destaque verde.
🎯
3. Intenção de Compra (Alerta)
O usuário quer ir para Lisboa, mas só se for barato. Ele cadastra uma intenção de monitoramento.
POST /alerts
{ "origin": "REC", "dest": "LIS", "target_price": 3000.00 }
⚙️
4. O "Motor" Trabalha (Invisible)
O backend (Márcio) roda 24/7. De repente, o algoritmo baixa o preço de REC-LIS para R$ 2.950,00. O sistema detecta que bateu com o alvo do usuário.
🔔
5. Notificação & Conversão
O App do Leandro vibra e o Site do Jefferson mostra um Toast: "Seu voo baixou!". O usuário clica e vê os detalhes da oferta.

Visual Targets (A Meta Visual)

Dashboard Web
ANÁLISE: REC-LIS
R$ 2.450
▼ Caindo rápido nas últimas 2h
App Mobile
Olá, Leandro 👋
OFERTAS QUENTES
REC ✈️ GRU▲ +5%
LatamR$ 1.200
GRU ✈️ MIA▼ -12%
AmericanR$ 3.100
REC ✈️ LIS▼ -2%
TAPR$ 4.800

Organização e Git Flow

Regras da Casa

  • Git Flow Simplificado:
    • main: Ninguém toca. É o código que funciona.
    • develop: Onde juntamos o código de todo mundo.
    • feat/nome-da-feature: Onde você trabalha. Ex: feat/login-leandro.
  • Commits Semânticos:
    • feat: Nova funcionalidade.
    • fix: Correção de bug.
    • docs: Mudança em documentação.
  • Rituais: Daily Assíncrona no WhatsApp ("O que fiz ontem, o que farei hoje").

Strato Design System

Copiem estes hexadecimais. Se usarem cores diferentes, o projeto vai parecer uma colcha de retalhos.

BG Body
#0f172a
BG Card
#1e293b
Primary
#6366f1
Green/Down
#10b981
Red/Up
#ef4444

Backend: Márcio GoLang

O cérebro da operação. Você não cria telas, você cria a inteligência.

🚀 Features Detalhadas para Desenvolver

1. Simulador Estocástico (Worker)
Criar uma Goroutine que roda infinitamente. A cada ciclo (ex: 5s), ela deve iterar sobre todos os voos no banco. Use a função rand para aplicar volatilidade (+/- 5%), mas implemente uma lógica de "Mean Reversion" para que o preço não suba para sempre, ele deve tender a voltar para o base_price.
2. API RESTful Padronizada
Não devolva apenas arrays soltos. Padronize as respostas JSON. Se der erro, devolva {"error": "message", "code": 400}. Se der sucesso, devolva {"data": [...], "meta": { "total": 10 }}. Implemente CORS para que o React e o Native consigam acessar.
3. Autenticação JWT (Middleware)
Crie um middleware no Gin. Antes de deixar acessar /alerts, verifique se o Header tem Authorization: Bearer xyz. Valide a assinatura do token. Se for inválido, retorne 401 Unauthorized imediatamente.
4. Sistema de Logs Estruturados
Em vez de usar println, use uma lib de log (ex: Zerolog ou Zap). O log deve sair em JSON: {"level": "info", "msg": "Price updated", "route": "REC-LIS"}. Isso é vital para debugging em produção.

Esquema do Banco de Dados (DER)

routes (As Rotas)
id UUID
origin CHAR(3)
destination CHAR(3)
current_price FLOAT
price_history (O Gráfico)
id INT (AI)
route_id UUID
price FLOAT
timestamp DATETIME

Arquitetura & Código Core

sky-backend/
cmd/
main.go
internal/
models/
flight.go
simulator/
worker.go

Code Snippet: O Simulador (worker.go)

package simulator

import (
    "math/rand"
    "time"
    "gorm.io/gorm"
    "sky-backend/internal/models"
)

// StartMarket roda em uma Goroutine separada (Background)
func StartMarket(db *gorm.DB) {
    go func() {
        for {
            time.Sleep(5 * time.Second) // O pulso do mercado

            var routes []models.Route
            db.Find(&routes)

            for _, r := range routes {
                // Variação percentual (-5% a +5%)
                variation := (rand.Float64() * 0.10) - 0.05
                newPrice := r.CurrentPrice * (1 + variation)
                
                // Trava de segurança (preço mínimo)
                if newPrice < 50 { newPrice = 50 }

                // Atualiza e Salva Histórico
                r.CurrentPrice = newPrice
                db.Save(&r)
                
                db.Create(&models.PriceHistory{
                    RouteID: r.ID,
                    Price: newPrice,
                    Timestamp: time.Now(),
                })
            }
            println("♻️ Market Updated")
        }
    }()
}

Web: Jefferson React

O Analista. Foco em Dashboards densos e performance de renderização.

🚀 Features Detalhadas para Desenvolver

1. Polling Inteligente (SWR/React Query)
Não use setInterval puro. Use bibliotecas como SWR. Configure-a para parar de fazer requisições se o usuário trocar de aba (foco perdido) e retomar quando voltar. Isso economiza bateria e dados. O intervalo deve ser de ~5 segundos.
2. Gráficos de Alta Performance
Use Recharts. O desafio aqui é pegar o array de histórico (que pode ter 1000 itens) e formatar a data no Eixo X para ficar legível (ex: apenas Hora:Minuto). Implemente Tooltips customizados que mostram o preço exato ao passar o mouse.
3. Protected Routes (Auth Wrapper)
Crie um componente RequireAuth que envolve as rotas do Dashboard. Se o usuário não tiver o token no LocalStorage, ele deve ser "kickado" automaticamente para a tela de Login.
4. Feedback Visual (Toasts)
Implemente uma biblioteca de Toasts (ex: React Hot Toast). Quando o usuário salvar uma configuração ou fizer login, mostre um feedback visual no canto superior direito. Não use alert() nativo do navegador.

Arquitetura & Código Core

sky-web/
src/
hooks/
useFlightData.js
components/
FlightChart.jsx
App.jsx

Code Snippet: Custom Hook (useFlightData.js)

import { useState, useEffect } from 'react';

export function useFlightData() {
    const [data, setData] = useState([]);
    
    const update = async () => {
        try {
            const res = await fetch('http://localhost:8080/flights');
            const json = await res.json();
            setData(json);
        } catch (err) {
            console.error("API Error", err);
        }
    };

    useEffect(() => {
        update();
        // Polling a cada 3s
        const interval = setInterval(update, 3000);
        return () => clearInterval(interval);
    }, []);

    return data;
}

Mobile: Leandro React Native

O Viajante. Foco em UX fluida, animações e funcionamento offline.

🚀 Features Detalhadas para Desenvolver

1. Lista Virtualizada (FlatList Optimization)
Como a lista de voos pode crescer, nunca use ScrollView com map. Use FlatList. Implemente as propriedades initialNumToRender e windowSize para garantir que o scroll fique em 60fps mesmo com muitos dados.
2. Animações de Preço (Reanimated)
Quando o preço mudar, não mude o texto "seco". Faça a cor piscar ou o número deslizar. Use useEffect dentro do Card para detectar mudança na prop price e disparar uma animação de cor (Verde para queda, Vermelho para subida).
3. Cache Offline (AsyncStorage)
Implemente a estratégia "Stale-While-Revalidate". Ao abrir o app, carregue imediatamente o JSON salvo no AsyncStorage para a tela não ficar branca. Só depois tente buscar na API e atualizar a tela. O usuário deve ver dados em 100ms.
4. Pull to Refresh & Haptics
Adicione a propriedade onRefresh na FlatList. Quando o usuário puxar e soltar, dispare o fetch novamente. Ao concluir, use Haptics.notificationAsync para dar um "tique" de vibração na mão do usuário, confirmando a atualização.

Arquitetura & Código Core

sky-mobile/
src/
components/
FlightCard.js
screens/
Home.js
App.js

Code Snippet: Lógica de Cor (FlightCard.js)

import { View, Text, StyleSheet } from 'react-native';

export default function FlightCard({ item }) {
    // Lógica visual simples
    const isCheap = item.trend === 'down';
    const color = isCheap ? '#10b981' : '#ef4444';

    return (
        <View style={styles.card}>
            <View>
                <Text style={styles.route}>{item.origin} ✈ {item.dest}</Text>
                <Text style={styles.sub}>Voo Direto</Text>
            </View>
            <View>
                <Text style={[styles.price, { color }]}>
                    R$ {item.price.toFixed(0)}
                </Text>
            </View>
        </View>
    );
}