diff --git a/projects/backend/beginner/06-cli-user-manager/README.md b/projects/backend/beginner/06-cli-user-manager/README.md index 24b34c4..94c0193 100644 --- a/projects/backend/beginner/06-cli-user-manager/README.md +++ b/projects/backend/beginner/06-cli-user-manager/README.md @@ -46,7 +46,7 @@ By the end, you should be able to: ```text Storage: users.json -> [ { id, name, email, role, createdAt } ] -tool add --name "Ada" --email ada@x.com [--role user] +tool add --name "Ada" --email ada@example.com [--role user] tool list [--role admin] [--sort name] tool update --id u_01 --name "Ada L." tool delete --id u_01 diff --git a/projects/backend/beginner/06-cli-user-manager/README.pt-BR.md b/projects/backend/beginner/06-cli-user-manager/README.pt-BR.md index a7f69ca..3f62554 100644 --- a/projects/backend/beginner/06-cli-user-manager/README.pt-BR.md +++ b/projects/backend/beginner/06-cli-user-manager/README.pt-BR.md @@ -46,7 +46,7 @@ Ao final, você deve ser capaz de: ```text Armazenamento: users.json -> [ { id, name, email, role, createdAt } ] -tool add --name "Ada" --email ada@x.com [--role user] +tool add --name "Ada" --email ada@example.com [--role user] tool list [--role admin] [--sort name] tool update --id u_01 --name "Ada L." tool delete --id u_01 diff --git a/projects/data-engineering/advanced/01-real-time-platform/README.md b/projects/data-engineering/advanced/01-real-time-platform/README.md index bc719df..37962aa 100644 --- a/projects/data-engineering/advanced/01-real-time-platform/README.md +++ b/projects/data-engineering/advanced/01-real-time-platform/README.md @@ -1,34 +1,87 @@ # Real-time Data Platform -## Idea -Build a complete real-time data platform supporting streaming ingestion and analytics. Learn about modern data stack architecture. +> 🌐 **English** · [Português](./README.pt-BR.md) + +**Domain:** Data Engineering · **Level:** Advanced · **Estimated time:** 1–2 weeks + +## Overview + +Build an end-to-end real-time data platform: raw events flow in through a durable log, a stream processor turns them into rolling aggregates, and a low-latency serving layer answers dashboard and API queries within seconds of an event landing. Think of the "live metrics" view behind a payments dashboard or a ride-hailing ops screen — the value is entirely in freshness, so a pipeline that is correct but ten minutes stale has failed. This project forces you to reason about the whole path at once: ingestion durability, processing semantics, state, and read-side latency. You will pick where to accept approximation (windowed counts) and where you cannot (money totals), and you will design for the failure modes that only appear when data never stops arriving. + +## Prerequisites + +- Comfort with a stream processor's core model (Flink, Spark Structured Streaming, or Kafka Streams) +- Experience running a partitioned log like Kafka or Pulsar, including consumer groups and offsets +- A grounding in batch pipelines ([distributed ETL](../02-distributed-etl/) is a useful warm-up) +- Familiarity with windowing, watermarks, and event-time vs processing-time ## Learning Objectives -- Implement streaming infrastructure -- Real-time aggregations -- Build serving layer -- Handle scalability -- Implement monitoring - -## Implementation Tips -- Create streaming infrastructure (Kafka, Pulsar) -- Implement stream processing (Flink, Spark) -- Create real-time aggregations -- Build serving layer (Redis, Elasticsearch) -- Implement real-time dashboards -- Add API layer -- Create data quality monitoring -- Implement alerting -- Add latency monitoring -- Create capacity planning -- Implement auto-scaling -- Add disaster recovery -- Build compliance layer -- Create cost optimization - -## Key Challenges -- End-to-end latency -- Consistency at scale -- State management -- Infrastructure complexity -- Cost management + +By the end, you should be able to: + +- Design an ingestion → processing → serving topology with explicit delivery guarantees at each hop +- Choose event-time windowing and watermark strategy for out-of-order and late data +- Manage large keyed state and reason about checkpoint/restore cost +- Separate a hot serving store from the processing layer and justify the split +- Define and measure end-to-end latency and freshness SLOs + +## Functional Requirements + +1. The platform must ingest events into a partitioned, replayable log and survive a broker restart without data loss. +2. A stream job must compute time-windowed aggregations keyed by a business dimension (e.g. per-merchant, per-region). +3. Late events arriving within a bounded allowed-lateness must still update their window; events beyond it must be routed to a side output, not silently dropped. +4. Results must be written to a serving store that answers point and range queries in single-digit milliseconds. +5. The system must expose end-to-end latency (event timestamp → queryable) as a metric. +6. On job restart from checkpoint, aggregates must not double-count already-processed events. + +## Suggested Milestones + +1. **Milestone 1 — Ingest & replay:** Stand up the log, produce synthetic events with embedded event-time, and prove you can replay from an offset. +2. **Milestone 2 — Windowed processing:** Implement keyed event-time windows with watermarks, checkpointing, and a late-data side output. +3. **Milestone 3 — Serve & observe:** Sink aggregates to the hot store, add a query API, and instrument freshness and latency SLOs. + +## Data & Interface Sketch + +```text +producers ─▶ [log: topic "events", N partitions, RF=3] + │ event: {id, merchantId, amountCents, eventTime} + ▼ + [stream job] keyBy(merchantId) + tumbling 1-min windows, watermark = maxEventTime - 30s + allowedLateness = 5min ─▶ side output "late" + checkpoint every 30s ─▶ durable state backend + │ agg: {merchantId, windowStart, count, sumCents} + ▼ + [hot store: Redis / key-value] key = merchantId:windowStart + ▼ +GET /metrics/{merchantId}?from=..&to=.. -> [{windowStart, count, sumCents}] +GET /health/freshness -> { lagSeconds } +``` + +## Stretch Goals + +- Add a second, slower "correction" path (batch reprocessing) and reconcile it against the streaming result — a lambda/kappa comparison. +- Support exactly-once end-to-end by using a transactional sink and idempotent keys. +- Add auto-scaling of processing parallelism driven by consumer lag. + +## Definition of Done + +- [ ] Events survive a broker or job restart with no loss and no double-counting. +- [ ] Late-but-within-bound events update their window; beyond-bound events land in the side output. +- [ ] The serving API returns windowed aggregates for a key within the target latency. +- [ ] End-to-end freshness lag is exported as a metric and stays under the stated SLO under load. +- [ ] A documented benchmark records throughput, p99 latency, and lag at your target event rate. + +## Common Pitfalls + +- Mixing processing-time and event-time semantics, so results shift depending on when the job runs. +- Setting watermarks too aggressively and dropping legitimately late data, or too loosely and never closing windows. +- Ignoring state size until checkpoints time out — unbounded keys quietly grow forever. +- Treating the processing store as the serving store, coupling read latency to job restarts. + +## Resources + +- [Apache Flink: Event Time & Watermarks](https://nightlies.apache.org/flink/flink-docs-stable/docs/concepts/time/) — the canonical model for time in streams. +- [Kafka Documentation: Design](https://kafka.apache.org/documentation/#design) — how the log gives you durability and replay. +- [The Dataflow Model (paper)](https://research.google/pubs/pub43864/) — windowing, watermarks, and triggers, from first principles. +- [Spark Structured Streaming Programming Guide](https://spark.apache.org/docs/latest/structured-streaming-programming-guide.html) — an alternative processing model to compare against. diff --git a/projects/data-engineering/advanced/01-real-time-platform/README.pt-BR.md b/projects/data-engineering/advanced/01-real-time-platform/README.pt-BR.md new file mode 100644 index 0000000..9f1661b --- /dev/null +++ b/projects/data-engineering/advanced/01-real-time-platform/README.pt-BR.md @@ -0,0 +1,87 @@ +# Plataforma de Dados em Tempo Real + +> 🌐 [English](./README.md) · **Português** + +**Domínio:** Data Engineering · **Nível:** Avançado · **Tempo estimado:** 1–2 semanas + +## Visão Geral + +Construa uma plataforma de dados em tempo real de ponta a ponta: eventos brutos chegam por um log durável, um processador de stream os transforma em agregações contínuas, e uma camada de serving de baixa latência responde consultas de dashboards e APIs segundos após o evento chegar. Pense na visão de "métricas ao vivo" por trás de um dashboard de pagamentos ou de uma tela de operações de mobilidade — o valor está inteiramente na atualidade, então um pipeline correto mas dez minutos atrasado falhou. Este projeto força você a raciocinar sobre todo o caminho de uma vez: durabilidade da ingestão, semântica de processamento, estado e latência de leitura. Você escolherá onde aceitar aproximação (contagens em janela) e onde não pode (totais de dinheiro), e projetará para os modos de falha que só aparecem quando os dados nunca param de chegar. + +## Pré-requisitos + +- Conforto com o modelo central de um processador de stream (Flink, Spark Structured Streaming ou Kafka Streams) +- Experiência operando um log particionado como Kafka ou Pulsar, incluindo grupos de consumidores e offsets +- Uma base em pipelines batch ([ETL distribuído](../02-distributed-etl/) é um bom aquecimento) +- Familiaridade com janelamento, watermarks e event-time vs processing-time + +## Objetivos de Aprendizado + +Ao final, você deve ser capaz de: + +- Projetar uma topologia ingestão → processamento → serving com garantias de entrega explícitas em cada salto +- Escolher janelamento por event-time e estratégia de watermark para dados fora de ordem e atrasados +- Gerenciar estado grande por chave e raciocinar sobre o custo de checkpoint/restore +- Separar um store de serving quente da camada de processamento e justificar a divisão +- Definir e medir SLOs de latência e atualidade de ponta a ponta + +## Requisitos Funcionais + +1. A plataforma deve ingerir eventos em um log particionado e reproduzível e sobreviver ao reinício de um broker sem perda de dados. +2. Um job de stream deve calcular agregações por janela de tempo, chaveadas por uma dimensão de negócio (ex.: por comerciante, por região). +3. Eventos atrasados que chegarem dentro de uma tolerância de atraso limitada ainda devem atualizar sua janela; eventos além dela devem ser roteados para uma saída lateral, não descartados silenciosamente. +4. Os resultados devem ser gravados em um store de serving que responda consultas pontuais e por intervalo em milissegundos de um dígito. +5. O sistema deve expor a latência de ponta a ponta (timestamp do evento → consultável) como métrica. +6. Ao reiniciar o job a partir de um checkpoint, as agregações não devem contar em dobro eventos já processados. + +## Marcos Sugeridos + +1. **Marco 1 — Ingerir e reproduzir:** Suba o log, produza eventos sintéticos com event-time embutido e prove que consegue reproduzir a partir de um offset. +2. **Marco 2 — Processamento em janela:** Implemente janelas por event-time chaveadas, com watermarks, checkpointing e uma saída lateral para dados atrasados. +3. **Marco 3 — Servir e observar:** Envie as agregações ao store quente, adicione uma API de consulta e instrumente SLOs de atualidade e latência. + +## Esboço de Dados e Interface + +```text +produtores ─▶ [log: tópico "events", N partições, RF=3] + │ evento: {id, merchantId, amountCents, eventTime} + ▼ + [job de stream] keyBy(merchantId) + janelas tumbling de 1min, watermark = maxEventTime - 30s + allowedLateness = 5min ─▶ saída lateral "late" + checkpoint a cada 30s ─▶ backend de estado durável + │ agg: {merchantId, windowStart, count, sumCents} + ▼ + [store quente: Redis / chave-valor] chave = merchantId:windowStart + ▼ +GET /metrics/{merchantId}?from=..&to=.. -> [{windowStart, count, sumCents}] +GET /health/freshness -> { lagSeconds } +``` + +## Desafios Extras + +- Adicione um segundo caminho de "correção" mais lento (reprocessamento batch) e reconcilie-o com o resultado do streaming — uma comparação lambda/kappa. +- Suporte exactly-once de ponta a ponta usando um sink transacional e chaves idempotentes. +- Adicione auto-scaling do paralelismo de processamento guiado pelo lag do consumidor. + +## Definição de Pronto + +- [ ] Eventos sobrevivem ao reinício de um broker ou job sem perda e sem contagem dupla. +- [ ] Eventos atrasados dentro do limite atualizam sua janela; além do limite caem na saída lateral. +- [ ] A API de serving retorna agregações em janela para uma chave dentro da latência alvo. +- [ ] O lag de atualidade de ponta a ponta é exportado como métrica e permanece abaixo do SLO declarado sob carga. +- [ ] Um benchmark documentado registra throughput, latência p99 e lag na sua taxa de eventos alvo. + +## Armadilhas Comuns + +- Misturar semânticas de processing-time e event-time, fazendo os resultados mudarem conforme o momento em que o job roda. +- Definir watermarks agressivos demais e descartar dados legitimamente atrasados, ou frouxos demais e nunca fechar janelas. +- Ignorar o tamanho do estado até que os checkpoints estourem o tempo — chaves ilimitadas crescem para sempre em silêncio. +- Tratar o store de processamento como store de serving, acoplando a latência de leitura aos reinícios do job. + +## Recursos + +- [Apache Flink: Event Time e Watermarks](https://nightlies.apache.org/flink/flink-docs-stable/docs/concepts/time/) — o modelo canônico de tempo em streams. +- [Documentação do Kafka: Design](https://kafka.apache.org/documentation/#design) — como o log te dá durabilidade e replay. +- [The Dataflow Model (artigo)](https://research.google/pubs/pub43864/) — janelamento, watermarks e triggers a partir dos princípios. +- [Guia de Programação do Spark Structured Streaming](https://spark.apache.org/docs/latest/structured-streaming-programming-guide.html) — um modelo de processamento alternativo para comparar. diff --git a/projects/data-engineering/advanced/02-distributed-etl/README.md b/projects/data-engineering/advanced/02-distributed-etl/README.md index 5b8cb3e..9fb9db9 100644 --- a/projects/data-engineering/advanced/02-distributed-etl/README.md +++ b/projects/data-engineering/advanced/02-distributed-etl/README.md @@ -1,34 +1,91 @@ # Distributed ETL System -## Idea -Design a distributed ETL system that scales across multiple nodes. Learn about distributed computing and fault tolerance. +> 🌐 **English** · [Português](./README.pt-BR.md) + +**Domain:** Data Engineering · **Level:** Advanced · **Estimated time:** 1–2 weeks + +## Overview + +Design a distributed ETL job that reads a large dataset, transforms it across many worker nodes, and writes a partitioned result — while staying correct and cheap when a worker dies mid-run. The interesting problems here are not the transformations themselves but everything around them: how data is partitioned, why one hot key can stall a whole stage (data skew), how a shuffle moves gigabytes across the network, and how checkpointing lets you recover without redoing everything. You will treat the cluster as an unreliable machine — nodes vanish, disks fill, one partition is 100× the others — and build a job whose runtime and cost stay predictable anyway. The deliverable is a design and a working distributed job on a framework like Spark, plus a documented plan for skew, retries, and recovery. + +## Prerequisites + +- Working knowledge of a distributed framework (Apache Spark or Hadoop MapReduce) +- Understanding of partitioning, shuffles, and the map/reduce mental model +- Comfort reasoning about network and disk I/O as the dominant cost +- Familiarity with a columnar format (Parquet/ORC) and object storage ## Learning Objectives -- Implement distributed processing -- Handle distributed state -- Implement fault tolerance -- Optimize resource usage -- Monitor distributed system - -## Implementation Tips -- Use distributed framework (Spark, Hadoop) -- Implement distributed tasks -- Handle data distribution -- Create shuffling strategy -- Implement fault tolerance -- Add checkpointing -- Create recovery mechanisms -- Implement monitoring -- Add performance optimization -- Handle skew -- Create resource management -- Implement auto-scaling -- Build operational dashboards -- Create debugging tools - -## Key Challenges -- Network I/O optimization -- Data skew handling -- Fault recovery complexity -- Cost optimization -- Debugging distributed issues + +By the end, you should be able to: + +- Partition input and control parallelism to match cluster resources +- Diagnose and mitigate data skew (salting, broadcast joins, repartitioning) +- Explain what a shuffle does and how to minimize its cost +- Use checkpointing and idempotent writes so a failed run resumes safely +- Instrument a distributed job and read its stage/task metrics to find bottlenecks + +## Functional Requirements + +1. The job must process a dataset far larger than any single node's memory, in bounded parallelism. +2. Transformations must be deterministic and idempotent so a retried task produces identical output. +3. The job must detect and mitigate skew on at least one join or group-by key. +4. On worker failure, only the lost tasks must re-execute — not the entire job. +5. Output must be written partitioned (e.g. by date) to object storage, with atomic commit so partial writes are never read as complete. +6. The job must emit metrics for records in/out, shuffle bytes, and per-stage duration. + +## Suggested Milestones + +1. **Milestone 1 — Baseline job:** Read → transform → write partitioned output on a small cluster; confirm correctness on a known sample. +2. **Milestone 2 — Scale & skew:** Run against a large, skewed dataset; measure the straggler, then apply salting or a broadcast join and re-measure. +3. **Milestone 3 — Resilience:** Add checkpointing and atomic/idempotent writes; kill a worker mid-run and verify clean recovery. + +## Data & Interface Sketch + +```text +[source: object store] raw/events/*.parquet (billions of rows) + │ read, partitions = f(input size, cores) + ▼ +[map stage] parse, filter, derive columns (no shuffle) + │ + ▼ +[shuffle] repartition by joinKey ── skew? salt hot keys: key -> key#rand(0..N) + │ + ▼ +[reduce stage] join / aggregate (checkpoint here) + │ + ▼ +[sink] write partitioned by dt=YYYY-MM-DD, atomic commit (_SUCCESS marker) + out/agg/dt=2026-07-24/part-*.parquet + +Non-functional targets: runtime < T for dataset size S, cost < $C, +recovery re-runs only failed tasks. +``` + +## Stretch Goals + +- Add adaptive query execution (or manual equivalent) that re-partitions based on observed shuffle sizes. +- Support incremental runs that process only new partitions instead of the full dataset. +- Add a spot/preemptible instance pool and prove the job still completes when nodes are reclaimed. + +## Definition of Done + +- [ ] The job completes on a dataset larger than any node's RAM without OOM. +- [ ] A documented skew mitigation measurably shrinks the slowest task. +- [ ] Killing a worker mid-run reruns only lost tasks and yields identical output. +- [ ] Output is partitioned and only visible after atomic commit; a crashed write leaves no readable partial data. +- [ ] A benchmark records runtime, shuffle bytes, and cost at your target dataset size. + +## Common Pitfalls + +- Letting the framework pick a default partition count that is far too low or too high for your data. +- Fixing skew by adding memory instead of rebalancing keys — it postpones the failure, it doesn't remove it. +- Non-idempotent writes, so a retried task appends duplicates. +- Reading output before the atomic commit marker exists and treating a partial write as complete. + +## Resources + +- [Spark: Tuning & Performance](https://spark.apache.org/docs/latest/tuning.html) — memory, serialization, and partitioning guidance. +- [Spark SQL Performance Tuning](https://spark.apache.org/docs/latest/sql-performance-tuning.html) — broadcast joins and adaptive execution for skew. +- [MapReduce (paper)](https://research.google/pubs/pub62/) — the original model for fault-tolerant distributed processing. +- [Apache Parquet documentation](https://parquet.apache.org/docs/) — the columnar format and its partitioning story. diff --git a/projects/data-engineering/advanced/02-distributed-etl/README.pt-BR.md b/projects/data-engineering/advanced/02-distributed-etl/README.pt-BR.md new file mode 100644 index 0000000..a1e015f --- /dev/null +++ b/projects/data-engineering/advanced/02-distributed-etl/README.pt-BR.md @@ -0,0 +1,91 @@ +# Sistema de ETL Distribuído + +> 🌐 [English](./README.md) · **Português** + +**Domínio:** Data Engineering · **Nível:** Avançado · **Tempo estimado:** 1–2 semanas + +## Visão Geral + +Projete um job de ETL distribuído que lê um dataset grande, o transforma em muitos nós de trabalho e grava um resultado particionado — mantendo-se correto e barato quando um worker morre no meio da execução. Os problemas interessantes aqui não são as transformações em si, mas tudo ao redor: como os dados são particionados, por que uma única chave quente pode travar um estágio inteiro (data skew), como um shuffle move gigabytes pela rede e como o checkpointing permite recuperar sem refazer tudo. Você tratará o cluster como uma máquina não confiável — nós somem, discos enchem, uma partição é 100× as outras — e construirá um job cujo tempo de execução e custo permaneçam previsíveis mesmo assim. A entrega é um design e um job distribuído funcional em um framework como o Spark, mais um plano documentado para skew, retries e recuperação. + +## Pré-requisitos + +- Conhecimento prático de um framework distribuído (Apache Spark ou Hadoop MapReduce) +- Entendimento de particionamento, shuffles e o modelo mental map/reduce +- Conforto para raciocinar sobre I/O de rede e disco como o custo dominante +- Familiaridade com um formato colunar (Parquet/ORC) e armazenamento de objetos + +## Objetivos de Aprendizado + +Ao final, você deve ser capaz de: + +- Particionar a entrada e controlar o paralelismo para casar com os recursos do cluster +- Diagnosticar e mitigar data skew (salting, broadcast joins, reparticionamento) +- Explicar o que um shuffle faz e como minimizar seu custo +- Usar checkpointing e escritas idempotentes para que uma execução falha retome com segurança +- Instrumentar um job distribuído e ler suas métricas de estágio/task para achar gargalos + +## Requisitos Funcionais + +1. O job deve processar um dataset muito maior que a memória de qualquer nó único, com paralelismo limitado. +2. As transformações devem ser determinísticas e idempotentes para que uma task repetida produza saída idêntica. +3. O job deve detectar e mitigar skew em ao menos uma chave de join ou group-by. +4. Em caso de falha de worker, apenas as tasks perdidas devem ser reexecutadas — não o job inteiro. +5. A saída deve ser gravada particionada (ex.: por data) no armazenamento de objetos, com commit atômico para que escritas parciais nunca sejam lidas como completas. +6. O job deve emitir métricas de registros de entrada/saída, bytes de shuffle e duração por estágio. + +## Marcos Sugeridos + +1. **Marco 1 — Job base:** Ler → transformar → gravar saída particionada em um cluster pequeno; confirme a correção em uma amostra conhecida. +2. **Marco 2 — Escala e skew:** Rode contra um dataset grande e enviesado; meça o straggler, então aplique salting ou um broadcast join e meça de novo. +3. **Marco 3 — Resiliência:** Adicione checkpointing e escritas atômicas/idempotentes; mate um worker no meio e verifique a recuperação limpa. + +## Esboço de Dados e Interface + +```text +[origem: object store] raw/events/*.parquet (bilhões de linhas) + │ ler, partições = f(tamanho da entrada, cores) + ▼ +[estágio map] parse, filtro, colunas derivadas (sem shuffle) + │ + ▼ +[shuffle] reparticiona por joinKey ── skew? salgar chaves quentes: key -> key#rand(0..N) + │ + ▼ +[estágio reduce] join / agregação (checkpoint aqui) + │ + ▼ +[sink] grava particionado por dt=YYYY-MM-DD, commit atômico (marcador _SUCCESS) + out/agg/dt=2026-07-24/part-*.parquet + +Alvos não funcionais: runtime < T para tamanho S, custo < $C, +recuperação reexecuta apenas tasks falhas. +``` + +## Desafios Extras + +- Adicione execução adaptativa de consultas (ou equivalente manual) que reparticiona com base nos tamanhos de shuffle observados. +- Suporte execuções incrementais que processam apenas partições novas em vez do dataset completo. +- Adicione um pool de instâncias spot/preemptíveis e prove que o job ainda conclui quando nós são recuperados. + +## Definição de Pronto + +- [ ] O job conclui em um dataset maior que a RAM de qualquer nó sem OOM. +- [ ] Uma mitigação de skew documentada encolhe mensuravelmente a task mais lenta. +- [ ] Matar um worker no meio reexecuta apenas as tasks perdidas e gera saída idêntica. +- [ ] A saída é particionada e só fica visível após o commit atômico; uma escrita interrompida não deixa dados parciais legíveis. +- [ ] Um benchmark registra runtime, bytes de shuffle e custo no tamanho de dataset alvo. + +## Armadilhas Comuns + +- Deixar o framework escolher uma contagem de partições padrão baixa ou alta demais para seus dados. +- Corrigir skew adicionando memória em vez de rebalancear chaves — isso adia a falha, não a remove. +- Escritas não idempotentes, fazendo uma task repetida anexar duplicatas. +- Ler a saída antes de o marcador de commit atômico existir e tratar uma escrita parcial como completa. + +## Recursos + +- [Spark: Tuning e Performance](https://spark.apache.org/docs/latest/tuning.html) — orientação de memória, serialização e particionamento. +- [Tuning de Performance do Spark SQL](https://spark.apache.org/docs/latest/sql-performance-tuning.html) — broadcast joins e execução adaptativa para skew. +- [MapReduce (artigo)](https://research.google/pubs/pub62/) — o modelo original de processamento distribuído tolerante a falhas. +- [Documentação do Apache Parquet](https://parquet.apache.org/docs/) — o formato colunar e sua história de particionamento. diff --git a/projects/data-engineering/advanced/03-data-mesh/README.md b/projects/data-engineering/advanced/03-data-mesh/README.md index 38bc820..cb68fee 100644 --- a/projects/data-engineering/advanced/03-data-mesh/README.md +++ b/projects/data-engineering/advanced/03-data-mesh/README.md @@ -1,34 +1,92 @@ # Data Mesh Simulation -## Idea -Simulate a data mesh architecture with decentralized data ownership. Learn about modern data organization patterns. +> 🌐 **English** · [Português](./README.pt-BR.md) + +**Domain:** Data Engineering · **Level:** Advanced · **Estimated time:** 1–2 weeks + +## Overview + +Simulate a data mesh: instead of one central team owning a monolithic warehouse, several independent domains each publish their data as a **data product** with an owner, a versioned contract, quality SLOs, and a discoverable entry in a catalog. You will model two or three domains (say, Orders, Payments, and Customers), give each a published output port, and enforce a **data contract** so that a breaking schema change is caught before it reaches consumers. The hard part is organizational made technical: how do you keep domains autonomous while still guaranteeing a consumer can join across them? You will design federated governance — global rules everyone follows, local freedom in everything else — and prove it with a cross-domain query that only works because contracts held. + +## Prerequisites + +- Experience building data pipelines and thinking about producers vs consumers +- Familiarity with schema formats and evolution (Avro, Protobuf, or JSON Schema) +- Understanding of a data catalog / metadata store concept +- Comfort with the tradeoffs of decentralized ownership (this is an architecture exercise as much as a coding one) ## Learning Objectives -- Design data mesh structure -- Implement data domains -- Create data products -- Build federated governance -- Ensure data quality - -## Implementation Tips -- Define data domains -- Create domain APIs -- Implement data contracts -- Build metadata catalog -- Create governance policies -- Implement access control -- Add data versioning -- Create quality standards -- Build federated monitoring -- Implement SLAs -- Create discoverability -- Add data lineage tracking -- Implement federated platforms -- Build community collaboration - -## Key Challenges -- Organizational alignment -- Contract enforcement -- Cross-domain consistency -- Governance scalability -- Quality standardization + +By the end, you should be able to: + +- Model a domain as a self-contained data product with a clear output port +- Define and version a data contract, and detect breaking vs compatible changes +- Design federated governance: which rules are global, which are local +- Make data products discoverable through a catalog with ownership and SLOs +- Reason about cross-domain consistency without a single owning team + +## Functional Requirements + +1. Each domain must expose at least one data product with a documented schema, owner, and freshness/quality SLO. +2. Every data product must be registered in a shared catalog that a consumer can search by domain, owner, or field. +3. A published contract must be validated on every new dataset version; a backward-incompatible change must be rejected or flagged before publish. +4. A consumer must be able to run a query that joins two domains' products using only their public contracts. +5. Global governance rules (e.g. every product carries a `data_owner` and a PII classification) must be enforced uniformly. +6. Contract violations and SLO breaches must surface to the owning domain, not to a central team. + +## Suggested Milestones + +1. **Milestone 1 — Domains & products:** Model 2–3 domains, each publishing a data product with schema, owner, and SLO metadata. +2. **Milestone 2 — Contracts & catalog:** Add contract validation on publish and register everything in a searchable catalog. +3. **Milestone 3 — Federated governance:** Enforce global rules, wire SLO/contract alerts to domain owners, and demo a cross-domain join. + +## Data & Interface Sketch + +```text +Domain "orders" Domain "payments" + data product: orders_daily data product: settlements_daily + owner: orders-team@example.com owner: payments-team@example.com + contract v2 { orderId, amount, contract v1 { orderId, settledAt, + currency, dt } slo: freshness<2h status } slo: completeness>99.9% + │ publish (validate contract) │ + └──────────────┬───────────────────────┘ + ▼ + [catalog / metadata] + registry[product] = { schema, owner, slo, piiClass, version } + search(field="orderId") -> [orders_daily, settlements_daily] + │ + ▼ + consumer query: JOIN orders_daily ON settlements_daily USING(orderId) + (works only because both contracts expose orderId compatibly) + +Global rules (federated): every product MUST have data_owner + piiClass. +Local freedom: storage, transform tooling, internal model per domain. +``` + +## Stretch Goals + +- Add automated contract-diffing in CI that blocks a merge introducing a breaking change. +- Implement a "consumer registration" so producers know who depends on them before they change a schema. +- Add per-product data-quality tests (null rates, referential integrity) that feed the SLO status. + +## Definition of Done + +- [ ] Each domain publishes an independently owned data product with schema, owner, and SLO. +- [ ] The catalog is searchable and returns ownership and SLO for any product. +- [ ] A backward-incompatible schema change is caught at publish time, not by a broken consumer. +- [ ] A cross-domain join runs using only public contracts. +- [ ] Global governance fields are enforced on every product; a missing one blocks publish. + +## Common Pitfalls + +- Rebuilding a central warehouse with extra steps — domains that can't publish without a central team aren't autonomous. +- Treating "contract" as documentation instead of an enforced, versioned check. +- No breaking-change policy, so every schema edit silently risks downstream jobs. +- A catalog nobody updates — discoverability decays the moment registration is manual and optional. + +## Resources + +- [Data Mesh Principles (Zhamak Dehghani)](https://martinfowler.com/articles/data-mesh-principles.html) — the four founding principles. +- [Data Mesh: Logical Architecture](https://martinfowler.com/articles/data-monolith-to-mesh.html) — domains and products explained. +- [Confluent Schema Registry: Compatibility](https://docs.confluent.io/platform/current/schema-registry/fundamentals/avro.html) — how compatibility modes formalize contracts. +- [OpenLineage](https://openlineage.io/docs/) — a standard for describing datasets and their producers/consumers. diff --git a/projects/data-engineering/advanced/03-data-mesh/README.pt-BR.md b/projects/data-engineering/advanced/03-data-mesh/README.pt-BR.md new file mode 100644 index 0000000..ddffe5a --- /dev/null +++ b/projects/data-engineering/advanced/03-data-mesh/README.pt-BR.md @@ -0,0 +1,92 @@ +# Simulação de Data Mesh + +> 🌐 [English](./README.md) · **Português** + +**Domínio:** Data Engineering · **Nível:** Avançado · **Tempo estimado:** 1–2 semanas + +## Visão Geral + +Simule um data mesh: em vez de um time central dono de um data warehouse monolítico, vários domínios independentes publicam cada um seus dados como um **data product** com dono, contrato versionado, SLOs de qualidade e uma entrada descobrível em um catálogo. Você modelará dois ou três domínios (digamos, Pedidos, Pagamentos e Clientes), dará a cada um uma porta de saída publicada e imporá um **contrato de dados** para que uma mudança de schema quebradora seja capturada antes de chegar aos consumidores. A parte difícil é o organizacional transformado em técnico: como manter domínios autônomos e ainda garantir que um consumidor consiga fazer join entre eles? Você projetará governança federada — regras globais que todos seguem, liberdade local em tudo o mais — e a provará com uma consulta entre domínios que só funciona porque os contratos se mantiveram. + +## Pré-requisitos + +- Experiência construindo pipelines de dados e pensando em produtores vs consumidores +- Familiaridade com formatos de schema e evolução (Avro, Protobuf ou JSON Schema) +- Entendimento do conceito de catálogo de dados / store de metadados +- Conforto com os tradeoffs da posse descentralizada (este é tanto um exercício de arquitetura quanto de código) + +## Objetivos de Aprendizado + +Ao final, você deve ser capaz de: + +- Modelar um domínio como um data product autocontido com uma porta de saída clara +- Definir e versionar um contrato de dados e detectar mudanças quebradoras vs compatíveis +- Projetar governança federada: quais regras são globais, quais são locais +- Tornar data products descobríveis por um catálogo com posse e SLOs +- Raciocinar sobre consistência entre domínios sem um único time dono + +## Requisitos Funcionais + +1. Cada domínio deve expor ao menos um data product com schema documentado, dono e SLO de atualidade/qualidade. +2. Todo data product deve ser registrado em um catálogo compartilhado que um consumidor possa buscar por domínio, dono ou campo. +3. Um contrato publicado deve ser validado a cada nova versão do dataset; uma mudança incompatível para trás deve ser rejeitada ou sinalizada antes da publicação. +4. Um consumidor deve conseguir rodar uma consulta que faz join dos produtos de dois domínios usando apenas seus contratos públicos. +5. Regras globais de governança (ex.: todo produto carrega um `data_owner` e uma classificação de PII) devem ser impostas uniformemente. +6. Violações de contrato e quebras de SLO devem aparecer para o domínio dono, não para um time central. + +## Marcos Sugeridos + +1. **Marco 1 — Domínios e produtos:** Modele 2–3 domínios, cada um publicando um data product com schema, dono e metadados de SLO. +2. **Marco 2 — Contratos e catálogo:** Adicione validação de contrato na publicação e registre tudo em um catálogo pesquisável. +3. **Marco 3 — Governança federada:** Imponha regras globais, conecte alertas de SLO/contrato aos donos de domínio e demonstre um join entre domínios. + +## Esboço de Dados e Interface + +```text +Domínio "orders" Domínio "payments" + data product: orders_daily data product: settlements_daily + dono: orders-team@example.com dono: payments-team@example.com + contrato v2 { orderId, amount, contrato v1 { orderId, settledAt, + currency, dt } slo: freshness<2h status } slo: completeness>99.9% + │ publicar (validar contrato) │ + └──────────────┬───────────────────────┘ + ▼ + [catálogo / metadados] + registry[product] = { schema, dono, slo, piiClass, versão } + search(field="orderId") -> [orders_daily, settlements_daily] + │ + ▼ + consulta do consumidor: JOIN orders_daily ON settlements_daily USING(orderId) + (funciona só porque ambos os contratos expõem orderId de forma compatível) + +Regras globais (federadas): todo produto DEVE ter data_owner + piiClass. +Liberdade local: storage, ferramentas de transformação, modelo interno por domínio. +``` + +## Desafios Extras + +- Adicione diffing automático de contratos no CI que bloqueia um merge introduzindo uma mudança quebradora. +- Implemente um "registro de consumidor" para que produtores saibam quem depende deles antes de mudar um schema. +- Adicione testes de qualidade de dados por produto (taxas de nulos, integridade referencial) que alimentam o status do SLO. + +## Definição de Pronto + +- [ ] Cada domínio publica um data product de posse independente com schema, dono e SLO. +- [ ] O catálogo é pesquisável e retorna posse e SLO para qualquer produto. +- [ ] Uma mudança de schema incompatível para trás é capturada no momento da publicação, não por um consumidor quebrado. +- [ ] Um join entre domínios roda usando apenas contratos públicos. +- [ ] Campos globais de governança são impostos em todo produto; a ausência de um bloqueia a publicação. + +## Armadilhas Comuns + +- Reconstruir um warehouse central com passos extras — domínios que não conseguem publicar sem um time central não são autônomos. +- Tratar "contrato" como documentação em vez de uma verificação imposta e versionada. +- Nenhuma política de mudança quebradora, então toda edição de schema arrisca silenciosamente os jobs a jusante. +- Um catálogo que ninguém atualiza — a descoberta decai no momento em que o registro é manual e opcional. + +## Recursos + +- [Princípios do Data Mesh (Zhamak Dehghani)](https://martinfowler.com/articles/data-mesh-principles.html) — os quatro princípios fundadores. +- [Data Mesh: Arquitetura Lógica](https://martinfowler.com/articles/data-monolith-to-mesh.html) — domínios e produtos explicados. +- [Confluent Schema Registry: Compatibilidade](https://docs.confluent.io/platform/current/schema-registry/fundamentals/avro.html) — como os modos de compatibilidade formalizam contratos. +- [OpenLineage](https://openlineage.io/docs/) — um padrão para descrever datasets e seus produtores/consumidores. diff --git a/projects/data-engineering/advanced/04-data-lake-architecture/README.md b/projects/data-engineering/advanced/04-data-lake-architecture/README.md index c8b693e..653ea1d 100644 --- a/projects/data-engineering/advanced/04-data-lake-architecture/README.md +++ b/projects/data-engineering/advanced/04-data-lake-architecture/README.md @@ -1,34 +1,89 @@ # Scalable Data Lake Architecture -## Idea -Design a data lake architecture supporting massive scale with optimization. Learn about big data architecture patterns. +> 🌐 **English** · [Português](./README.pt-BR.md) + +**Domain:** Data Engineering · **Level:** Advanced · **Estimated time:** 1–2 weeks + +## Overview + +Design a scalable data lake that behaves like a warehouse where it matters — a **lakehouse**. Raw files in object storage are cheap and infinite but query slowly and can't do atomic updates; a table format (Apache Iceberg, Delta Lake, or Apache Hudi) sits on top and adds ACID commits, schema evolution, time travel, and file compaction. You will design the storage layout (hot/warm/cold tiering, partitioning, file sizing), pick a table format and justify it, and prove that a well-organized lake answers analytical queries fast while a naive dump of small files does not. The theme running through it is that layout *is* performance: partition pruning, file compaction, and metadata pruning are what separate a query that scans a terabyte from one that scans a gigabyte. + +## Prerequisites + +- Comfort with object storage (S3/GCS/Azure Blob) and a columnar format (Parquet/ORC) +- A query engine you can point at files (Spark, Trino, DuckDB, or Athena) +- Understanding of partitioning and predicate pushdown +- Familiarity with the "small files problem" and why it hurts ## Learning Objectives -- Design scalable structure -- Implement tiering -- Optimize costs -- Ensure performance -- Maintain governance - -## Implementation Tips -- Create multi-tier storage (hot, warm, cold) -- Implement data organization -- Add compression and encoding -- Implement partitioning -- Create indexing strategies -- Add caching layer -- Implement data compression -- Create retention policies -- Build governance policies -- Implement access control -- Add encryption -- Create disaster recovery -- Build cost optimization -- Implement performance monitoring - -## Key Challenges -- Storage cost optimization -- Query performance at scale -- Data discovery scalability -- Governance enforcement -- Multi-tenant isolation + +By the end, you should be able to: + +- Choose a table format (Iceberg / Delta / Hudi) and justify it against your workload +- Design partitioning and file sizing so queries prune instead of full-scan +- Implement tiering (hot/warm/cold) with lifecycle rules and reason about cost/latency tradeoffs +- Use ACID table operations: atomic append, schema evolution, and time travel +- Measure query cost (bytes scanned, latency) and tie it back to layout decisions + +## Functional Requirements + +1. The lake must store data in a table format providing atomic commits and schema evolution. +2. Data must be partitioned so a filtered query prunes partitions rather than scanning everything. +3. A compaction process must consolidate small files into target-sized files without downtime for readers. +4. The design must define tiering with a documented lifecycle policy (e.g. cold data → cheaper storage class after N days). +5. The table must support time travel: a query must be able to read a previous snapshot. +6. Query cost (bytes scanned, latency) must be measurable and reported before and after optimization. + +## Suggested Milestones + +1. **Milestone 1 — Table format on object storage:** Land data in an Iceberg/Delta/Hudi table with a partition scheme; run a baseline query. +2. **Milestone 2 — Optimize layout:** Add compaction and right-size files; measure the drop in bytes scanned and latency. +3. **Milestone 3 — Tiering & time travel:** Add lifecycle tiering and demonstrate reading a prior snapshot after a schema change. + +## Data & Interface Sketch + +```text +[ingest] ─▶ object store bucket + warehouse/db/events/ + metadata/ <- table format: snapshots, schema, manifest list + data/dt=2026-07-24/ part-0001.parquet (target ~128-512MB each) + dt=2026-07-23/ ... + +query: SELECT ... WHERE dt = '2026-07-24' AND region = 'us' + -> partition prune (dt) -> file prune via column stats (region) + -> scans a few files, not the table + +compaction job: many small files -> fewer right-sized files (atomic rewrite) +time travel: SELECT ... FOR SYSTEM_VERSION AS OF + +Tiering: hot (last 7d, standard) | warm (30d, infrequent) | cold (>90d, archive) +Non-functional: query p95 < T, storage cost/TB < $C, no reader downtime on compaction. +``` + +## Stretch Goals + +- Add hidden/transform partitioning (e.g. Iceberg's `days(ts)`) and compare pruning against manual partition columns. +- Implement a Z-order or clustering step and measure its effect on multi-column filters. +- Add a metadata/statistics-driven query cost estimate and validate it against actual bytes scanned. + +## Definition of Done + +- [ ] Data is stored in a table format with atomic commits and evolvable schema. +- [ ] A filtered query demonstrably prunes partitions/files instead of full-scanning. +- [ ] Compaction reduces file count and improves query latency without breaking concurrent reads. +- [ ] Time travel returns a correct earlier snapshot after a schema change. +- [ ] A before/after benchmark documents bytes scanned, latency, and storage cost across tiers. + +## Common Pitfalls + +- The small files problem: streaming or over-partitioning produces thousands of tiny files that murder query planning. +- Partitioning on a high-cardinality column, creating millions of partitions and slow metadata. +- Treating the lake as a filesystem and losing atomicity — half-written data read as complete. +- Ignoring metadata growth in the table format; unbounded snapshots need expiration too. + +## Resources + +- [Apache Iceberg documentation](https://iceberg.apache.org/docs/latest/) — table spec, partitioning, and snapshots. +- [Delta Lake documentation](https://docs.delta.io/latest/index.html) — ACID transactions and time travel on the lake. +- [Apache Hudi documentation](https://hudi.apache.org/docs/overview) — copy-on-write vs merge-on-read tradeoffs. +- [Trino: Object storage & pruning](https://trino.io/docs/current/connector/hive.html) — how a query engine prunes lake data. diff --git a/projects/data-engineering/advanced/04-data-lake-architecture/README.pt-BR.md b/projects/data-engineering/advanced/04-data-lake-architecture/README.pt-BR.md new file mode 100644 index 0000000..f443ddc --- /dev/null +++ b/projects/data-engineering/advanced/04-data-lake-architecture/README.pt-BR.md @@ -0,0 +1,89 @@ +# Arquitetura de Data Lake Escalável + +> 🌐 [English](./README.md) · **Português** + +**Domínio:** Data Engineering · **Nível:** Avançado · **Tempo estimado:** 1–2 semanas + +## Visão Geral + +Projete um data lake escalável que se comporta como um warehouse onde importa — um **lakehouse**. Arquivos brutos no armazenamento de objetos são baratos e infinitos, mas consultam devagar e não fazem updates atômicos; um formato de tabela (Apache Iceberg, Delta Lake ou Apache Hudi) fica por cima e adiciona commits ACID, evolução de schema, time travel e compactação de arquivos. Você projetará o layout de armazenamento (tiering quente/morno/frio, particionamento, tamanho de arquivo), escolherá um formato de tabela e o justificará, e provará que um lake bem organizado responde consultas analíticas rápido enquanto um despejo ingênuo de arquivos pequenos não. O tema que atravessa tudo é que layout *é* performance: partition pruning, compactação de arquivos e pruning de metadados são o que separa uma consulta que varre um terabyte de uma que varre um gigabyte. + +## Pré-requisitos + +- Conforto com armazenamento de objetos (S3/GCS/Azure Blob) e um formato colunar (Parquet/ORC) +- Um motor de consulta que você possa apontar para arquivos (Spark, Trino, DuckDB ou Athena) +- Entendimento de particionamento e predicate pushdown +- Familiaridade com o "problema dos arquivos pequenos" e por que ele prejudica + +## Objetivos de Aprendizado + +Ao final, você deve ser capaz de: + +- Escolher um formato de tabela (Iceberg / Delta / Hudi) e justificá-lo contra sua carga de trabalho +- Projetar particionamento e tamanho de arquivo para que consultas façam pruning em vez de full-scan +- Implementar tiering (quente/morno/frio) com regras de ciclo de vida e raciocinar sobre tradeoffs de custo/latência +- Usar operações ACID de tabela: append atômico, evolução de schema e time travel +- Medir custo de consulta (bytes varridos, latência) e ligá-lo às decisões de layout + +## Requisitos Funcionais + +1. O lake deve armazenar dados em um formato de tabela que forneça commits atômicos e evolução de schema. +2. Os dados devem ser particionados para que uma consulta filtrada faça pruning de partições em vez de varrer tudo. +3. Um processo de compactação deve consolidar arquivos pequenos em arquivos de tamanho alvo sem downtime para leitores. +4. O design deve definir tiering com uma política de ciclo de vida documentada (ex.: dados frios → classe de armazenamento mais barata após N dias). +5. A tabela deve suportar time travel: uma consulta deve conseguir ler um snapshot anterior. +6. O custo de consulta (bytes varridos, latência) deve ser mensurável e reportado antes e depois da otimização. + +## Marcos Sugeridos + +1. **Marco 1 — Formato de tabela no object storage:** Deposite dados em uma tabela Iceberg/Delta/Hudi com um esquema de partição; rode uma consulta base. +2. **Marco 2 — Otimizar layout:** Adicione compactação e dimensione bem os arquivos; meça a queda em bytes varridos e latência. +3. **Marco 3 — Tiering e time travel:** Adicione tiering por ciclo de vida e demonstre ler um snapshot anterior após uma mudança de schema. + +## Esboço de Dados e Interface + +```text +[ingestão] ─▶ bucket do object store + warehouse/db/events/ + metadata/ <- formato de tabela: snapshots, schema, lista de manifests + data/dt=2026-07-24/ part-0001.parquet (alvo ~128-512MB cada) + dt=2026-07-23/ ... + +consulta: SELECT ... WHERE dt = '2026-07-24' AND region = 'us' + -> prune de partição (dt) -> prune de arquivo via estatísticas de coluna (region) + -> varre poucos arquivos, não a tabela + +job de compactação: muitos arquivos pequenos -> poucos arquivos dimensionados (reescrita atômica) +time travel: SELECT ... FOR SYSTEM_VERSION AS OF + +Tiering: quente (últimos 7d, standard) | morno (30d, infrequente) | frio (>90d, archive) +Não funcional: consulta p95 < T, custo de storage/TB < $C, sem downtime de leitor na compactação. +``` + +## Desafios Extras + +- Adicione particionamento oculto/por transformação (ex.: `days(ts)` do Iceberg) e compare o pruning contra colunas de partição manuais. +- Implemente um passo de Z-order ou clustering e meça seu efeito em filtros de múltiplas colunas. +- Adicione uma estimativa de custo de consulta guiada por metadados/estatísticas e valide-a contra os bytes realmente varridos. + +## Definição de Pronto + +- [ ] Os dados estão em um formato de tabela com commits atômicos e schema evoluível. +- [ ] Uma consulta filtrada comprovadamente faz pruning de partições/arquivos em vez de full-scan. +- [ ] A compactação reduz a contagem de arquivos e melhora a latência sem quebrar leituras concorrentes. +- [ ] O time travel retorna um snapshot anterior correto após uma mudança de schema. +- [ ] Um benchmark antes/depois documenta bytes varridos, latência e custo de armazenamento entre tiers. + +## Armadilhas Comuns + +- O problema dos arquivos pequenos: streaming ou particionamento excessivo produz milhares de arquivos minúsculos que matam o planejamento da consulta. +- Particionar em uma coluna de alta cardinalidade, criando milhões de partições e metadados lentos. +- Tratar o lake como um filesystem e perder atomicidade — dados semi-escritos lidos como completos. +- Ignorar o crescimento de metadados no formato de tabela; snapshots ilimitados também precisam de expiração. + +## Recursos + +- [Documentação do Apache Iceberg](https://iceberg.apache.org/docs/latest/) — spec da tabela, particionamento e snapshots. +- [Documentação do Delta Lake](https://docs.delta.io/latest/index.html) — transações ACID e time travel no lake. +- [Documentação do Apache Hudi](https://hudi.apache.org/docs/overview) — tradeoffs de copy-on-write vs merge-on-read. +- [Trino: Object storage e pruning](https://trino.io/docs/current/connector/hive.html) — como um motor de consulta faz pruning de dados do lake. diff --git a/projects/data-engineering/advanced/05-cdc-pipeline/README.md b/projects/data-engineering/advanced/05-cdc-pipeline/README.md index 7e225c7..0c55385 100644 --- a/projects/data-engineering/advanced/05-cdc-pipeline/README.md +++ b/projects/data-engineering/advanced/05-cdc-pipeline/README.md @@ -1,34 +1,90 @@ # CDC Pipeline (Change Data Capture) -## Idea -Implement a Change Data Capture system to track data modifications. Learn about CDC patterns and real-time replication. +> 🌐 **English** · [Português](./README.pt-BR.md) + +**Domain:** Data Engineering · **Level:** Advanced · **Estimated time:** 1–2 weeks + +## Overview + +Build a Change Data Capture pipeline that streams every insert, update, and delete from an operational database into a downstream store — keeping a replica or a data lake continuously in sync without hammering the source with polling queries. The right approach reads the database's write-ahead log (log-based CDC via Debezium), which captures changes in commit order and at low overhead. The genuinely hard parts are ordering (changes to the same row must apply in sequence), the initial snapshot-then-stream handoff (load existing data, then switch to the log without a gap or a duplicate), schema changes mid-stream, and idempotency so a replay after a crash converges to the same state. You will pick delivery semantics — at-least-once with idempotent upserts is usually the pragmatic target — and prove convergence. + +## Prerequisites + +- A database with logical replication / WAL access (PostgreSQL, MySQL, or MongoDB) +- Familiarity with Kafka or another log for transporting change events +- Understanding of primary keys, upserts, and idempotency +- Comfort with the tradeoffs of exactly-once vs at-least-once delivery ## Learning Objectives -- Capture data changes -- Implement CDC logic -- Replicate changes -- Handle order guarantees -- Build consistency - -## Implementation Tips -- Choose CDC method (log-based, query-based, trigger-based) -- Implement change detection -- Create change streaming -- Implement ordering guarantees -- Handle schema changes -- Create replication logic -- Add conflict resolution -- Implement idempotency -- Create monitoring -- Add performance optimization -- Implement retry logic -- Build error handling -- Create recovery mechanisms -- Build compliance layer - -## Key Challenges -- Change ordering -- Schema change handling -- Performance impact -- Consistency guarantees -- Scalability at high volume + +By the end, you should be able to: + +- Explain log-based vs query-based vs trigger-based CDC and choose one +- Perform a consistent initial snapshot and hand off to streaming without gaps or duplicates +- Preserve per-key ordering through partitioning +- Handle source schema changes (added/dropped/renamed columns) without breaking consumers +- Design idempotent apply logic so replays converge to identical state + +## Functional Requirements + +1. The pipeline must capture inserts, updates, and deletes from the source in commit order. +2. An initial snapshot must load existing rows, then transition to streaming with no missed or duplicated changes at the boundary. +3. Changes to the same primary key must be applied in their original order downstream. +4. Applying the change stream must be idempotent: replaying from an earlier offset converges to the same final state. +5. A source schema change must be detected and propagated (or safely rejected), not silently corrupt the target. +6. Replication lag (source commit → applied downstream) must be exposed as a metric. + +## Suggested Milestones + +1. **Milestone 1 — Capture:** Connect a log-based connector to the source and stream change events into a topic; inspect insert/update/delete envelopes. +2. **Milestone 2 — Snapshot + apply:** Do a consistent snapshot, hand off to streaming, and apply changes as idempotent upserts/deletes into the target. +3. **Milestone 3 — Ordering, schema & lag:** Partition by key for ordering, handle a schema change, and instrument replication lag. + +## Data & Interface Sketch + +```text +[source DB] WAL / binlog + │ log-based capture (Debezium) + ▼ +change event (per row): + { op: c|u|d, key: {id}, before: {...}, after: {...}, ts_ms, lsn } + │ produce to topic "cdc.public.orders", partition = hash(key.id) + ▼ +[log] ordering preserved *within* a partition (same key -> same partition) + ▼ +[sink apply] op=c/u -> UPSERT by key ; op=d -> DELETE by key (idempotent) + target row: { id (pk), ..., _lsn, _updated_at } + apply rule: ignore event if event.lsn <= stored _lsn (dedupe on replay) + +Snapshot->stream handoff: snapshot at LSN X, then stream from X (no gap). +Delivery: at-least-once transport + idempotent upsert => effectively-once state. +Metric: lag = now - source_commit_ts of last applied event. +``` + +## Stretch Goals + +- Add tombstone handling and compaction so deletes propagate and the topic stays bounded. +- Support a schema-registry-backed contract and evolve a column without downstream breakage. +- Add a reconciliation job that periodically diffs source vs target row counts/checksums. + +## Definition of Done + +- [ ] Inserts, updates, and deletes all propagate correctly to the target. +- [ ] Snapshot-to-stream handoff produces no gap and no duplicate at the boundary. +- [ ] Same-key changes apply in order; a shuffled-partition test would break, and yours doesn't. +- [ ] Replaying from an old offset converges to identical target state (idempotency proven). +- [ ] Replication lag is exported and stays within the stated bound under a write burst. + +## Common Pitfalls + +- Query-based CDC (`WHERE updated_at > ?`) that misses deletes and hard-deletes entirely. +- Losing ordering by partitioning on the wrong key, so an update lands before its insert. +- A snapshot that isn't consistent with the log offset, leaving a gap or overlap at handoff. +- Non-idempotent apply, so a crash-replay double-applies and corrupts counts. + +## Resources + +- [Debezium documentation](https://debezium.io/documentation/reference/stable/index.html) — the reference log-based CDC platform. +- [Debezium: Change event structure](https://debezium.io/documentation/reference/stable/connectors/postgresql.html) — the before/after/op envelope. +- [Kafka Connect](https://kafka.apache.org/documentation/#connect) — how connectors move CDC events into a log. +- [PostgreSQL: Logical Decoding](https://www.postgresql.org/docs/current/logicaldecoding.html) — the WAL mechanism log-based CDC relies on. diff --git a/projects/data-engineering/advanced/05-cdc-pipeline/README.pt-BR.md b/projects/data-engineering/advanced/05-cdc-pipeline/README.pt-BR.md new file mode 100644 index 0000000..cc98126 --- /dev/null +++ b/projects/data-engineering/advanced/05-cdc-pipeline/README.pt-BR.md @@ -0,0 +1,90 @@ +# Pipeline de CDC (Change Data Capture) + +> 🌐 [English](./README.md) · **Português** + +**Domínio:** Data Engineering · **Nível:** Avançado · **Tempo estimado:** 1–2 semanas + +## Visão Geral + +Construa um pipeline de Change Data Capture que transmite cada insert, update e delete de um banco operacional para um store a jusante — mantendo uma réplica ou um data lake continuamente sincronizados sem martelar a origem com consultas de polling. A abordagem correta lê o write-ahead log do banco (CDC baseado em log via Debezium), que captura mudanças na ordem de commit e com baixo overhead. As partes genuinamente difíceis são a ordenação (mudanças na mesma linha devem aplicar em sequência), o handoff snapshot-depois-stream (carregar dados existentes e então trocar para o log sem lacuna nem duplicata), mudanças de schema no meio do stream, e idempotência para que um replay após um crash convirja ao mesmo estado. Você escolherá semânticas de entrega — at-least-once com upserts idempotentes costuma ser o alvo pragmático — e provará a convergência. + +## Pré-requisitos + +- Um banco com replicação lógica / acesso ao WAL (PostgreSQL, MySQL ou MongoDB) +- Familiaridade com Kafka ou outro log para transportar eventos de mudança +- Entendimento de chaves primárias, upserts e idempotência +- Conforto com os tradeoffs de entrega exactly-once vs at-least-once + +## Objetivos de Aprendizado + +Ao final, você deve ser capaz de: + +- Explicar CDC baseado em log vs baseado em consulta vs baseado em trigger e escolher um +- Fazer um snapshot inicial consistente e passar para streaming sem lacunas ou duplicatas +- Preservar a ordenação por chave através do particionamento +- Tratar mudanças de schema na origem (colunas adicionadas/removidas/renomeadas) sem quebrar consumidores +- Projetar lógica de aplicação idempotente para que replays convirjam ao estado idêntico + +## Requisitos Funcionais + +1. O pipeline deve capturar inserts, updates e deletes da origem na ordem de commit. +2. Um snapshot inicial deve carregar as linhas existentes e então transicionar para streaming sem mudanças perdidas ou duplicadas na fronteira. +3. Mudanças na mesma chave primária devem ser aplicadas na sua ordem original a jusante. +4. Aplicar o stream de mudanças deve ser idempotente: reproduzir a partir de um offset anterior converge ao mesmo estado final. +5. Uma mudança de schema na origem deve ser detectada e propagada (ou rejeitada com segurança), não corromper silenciosamente o destino. +6. O lag de replicação (commit na origem → aplicado a jusante) deve ser exposto como métrica. + +## Marcos Sugeridos + +1. **Marco 1 — Captura:** Conecte um conector baseado em log à origem e transmita eventos de mudança a um tópico; inspecione os envelopes de insert/update/delete. +2. **Marco 2 — Snapshot + aplicação:** Faça um snapshot consistente, passe para streaming e aplique mudanças como upserts/deletes idempotentes no destino. +3. **Marco 3 — Ordenação, schema e lag:** Particione por chave para ordenação, trate uma mudança de schema e instrumente o lag de replicação. + +## Esboço de Dados e Interface + +```text +[banco de origem] WAL / binlog + │ captura baseada em log (Debezium) + ▼ +evento de mudança (por linha): + { op: c|u|d, key: {id}, before: {...}, after: {...}, ts_ms, lsn } + │ produzir ao tópico "cdc.public.orders", partição = hash(key.id) + ▼ +[log] ordenação preservada *dentro* de uma partição (mesma chave -> mesma partição) + ▼ +[aplicação no sink] op=c/u -> UPSERT por chave ; op=d -> DELETE por chave (idempotente) + linha destino: { id (pk), ..., _lsn, _updated_at } + regra de aplicação: ignore o evento se event.lsn <= _lsn armazenado (dedupe no replay) + +Handoff snapshot->stream: snapshot no LSN X, depois stream a partir de X (sem lacuna). +Entrega: transporte at-least-once + upsert idempotente => estado effectively-once. +Métrica: lag = agora - ts_commit_origem do último evento aplicado. +``` + +## Desafios Extras + +- Adicione tratamento de tombstones e compactação para que deletes propaguem e o tópico fique limitado. +- Suporte um contrato apoiado em schema registry e evolua uma coluna sem quebra a jusante. +- Adicione um job de reconciliação que periodicamente compara contagens/checksums de linhas origem vs destino. + +## Definição de Pronto + +- [ ] Inserts, updates e deletes propagam corretamente ao destino. +- [ ] O handoff snapshot-para-stream não produz lacuna nem duplicata na fronteira. +- [ ] Mudanças de mesma chave aplicam em ordem; um teste de partição embaralhada quebraria, e o seu não. +- [ ] Reproduzir de um offset antigo converge ao estado idêntico do destino (idempotência provada). +- [ ] O lag de replicação é exportado e permanece dentro do limite declarado sob uma rajada de escritas. + +## Armadilhas Comuns + +- CDC baseado em consulta (`WHERE updated_at > ?`) que perde deletes e hard-deletes por completo. +- Perder a ordenação particionando pela chave errada, fazendo um update chegar antes do seu insert. +- Um snapshot que não é consistente com o offset do log, deixando uma lacuna ou sobreposição no handoff. +- Aplicação não idempotente, fazendo um replay pós-crash aplicar em dobro e corromper contagens. + +## Recursos + +- [Documentação do Debezium](https://debezium.io/documentation/reference/stable/index.html) — a plataforma de referência de CDC baseado em log. +- [Debezium: Estrutura do evento de mudança](https://debezium.io/documentation/reference/stable/connectors/postgresql.html) — o envelope before/after/op. +- [Kafka Connect](https://kafka.apache.org/documentation/#connect) — como conectores movem eventos de CDC para um log. +- [PostgreSQL: Logical Decoding](https://www.postgresql.org/docs/current/logicaldecoding.html) — o mecanismo de WAL em que o CDC baseado em log se apoia. diff --git a/projects/data-engineering/advanced/06-data-lineage/README.md b/projects/data-engineering/advanced/06-data-lineage/README.md index 5040434..9ffba45 100644 --- a/projects/data-engineering/advanced/06-data-lineage/README.md +++ b/projects/data-engineering/advanced/06-data-lineage/README.md @@ -1,34 +1,92 @@ # Data Lineage System -## Idea -Build a system that tracks data lineage across pipelines. Learn about data provenance and governance. +> 🌐 **English** · [Português](./README.pt-BR.md) + +**Domain:** Data Engineering · **Level:** Advanced · **Estimated time:** 1–2 weeks + +## Overview + +Build a system that tracks data lineage — which datasets a given table was derived from, through which jobs, and (ideally) at the column level. When a downstream dashboard shows wrong numbers, lineage answers "what feeds this?" in seconds instead of a day of archaeology; when a source column changes, lineage answers "what breaks?" before you ship. You will capture lineage automatically from running jobs (emitting run/dataset/job events, ideally in the OpenLineage format), store it as a directed acyclic graph, and expose queries for upstream/downstream traversal and impact analysis. The core challenges are *completeness* (a job you don't instrument is a blind spot), keeping graph queries fast as the graph grows, and capturing lineage without asking engineers to hand-maintain it. + +## Prerequisites + +- Familiarity with pipelines/DAGs and an orchestrator (Airflow, Dagster, or similar) +- Comfort with graph modeling and a graph or relational store +- Understanding of jobs producing/consuming datasets +- Basic knowledge of a lineage standard like OpenLineage (helpful, not required) ## Learning Objectives -- Track data origins -- Map transformations -- Build lineage graphs -- Support queries -- Ensure compliance - -## Implementation Tips -- Capture source information -- Track transformations -- Create lineage graphs -- Implement lineage query API -- Add visualization -- Track schema changes -- Create impact analysis -- Add compliance tracking -- Implement audit logs -- Build discovery interface -- Add performance optimization -- Create automated lineage capture -- Implement lineage validation -- Build reporting - -## Key Challenges -- Lineage completeness -- Query performance at scale -- Real-time tracking -- Schema change complexity -- Multi-system integration + +By the end, you should be able to: + +- Model lineage as a DAG of datasets, jobs, and runs +- Capture lineage automatically from job execution rather than manual annotation +- Support upstream ("what feeds X") and downstream ("what depends on X") traversal +- Run impact analysis: given a changed/broken source, list everything affected +- Reason about completeness gaps and how partial lineage misleads + +## Functional Requirements + +1. Every job run must emit a lineage event recording its input datasets, output datasets, and run status. +2. The system must store lineage as a queryable DAG with nodes for datasets and jobs. +3. A query must return the full upstream chain of any dataset (transitive sources). +4. A query must return the full downstream chain (transitive consumers) for impact analysis. +5. Column-level lineage must be supported for at least one transformation (which input columns produced an output column). +6. The system must record schema/version changes on datasets over time. + +## Suggested Milestones + +1. **Milestone 1 — Capture:** Emit run/job/dataset events from a couple of pipeline steps and persist them. +2. **Milestone 2 — Graph & traversal:** Build the DAG and expose upstream/downstream queries with cycle protection. +3. **Milestone 3 — Impact & columns:** Add column-level lineage for one transform and an impact-analysis query, plus a lineage visualization. + +## Data & Interface Sketch + +```text +lineage event (per run): + { runId, job: "etl.orders_daily", state: complete, + inputs: [orders_raw, fx_rates], + outputs: [orders_daily], + columnLineage: { "orders_daily.amount_usd": + ["orders_raw.amount", "fx_rates.rate"] } } + +graph: + orders_raw ─▶ [etl.orders_daily] ─▶ orders_daily ─▶ [bi.revenue] ─▶ revenue_dash + fx_rates ─┘ + +queries: + upstream(revenue_dash) -> {orders_daily, orders_raw, fx_rates} + downstream(orders_raw) -> {orders_daily, revenue_dash} (impact analysis) + columnsFor(orders_daily.amount_usd) -> [orders_raw.amount, fx_rates.rate] + +Non-functional: traversal p95 < T on N nodes; capture adds < X% job overhead; +completeness = instrumented jobs / total jobs (track it). +``` + +## Stretch Goals + +- Integrate OpenLineage so lineage is emitted by real connectors, not just your own hooks. +- Add "freshness propagation": mark all downstream datasets stale when an upstream run fails. +- Detect and alert on orphaned datasets (no producing job) and dead-end sources. + +## Definition of Done + +- [ ] Job runs emit lineage events automatically; no manual graph editing required. +- [ ] Upstream and downstream traversals return correct transitive sets, cycle-safe. +- [ ] Column-level lineage is correct for at least one non-trivial transformation. +- [ ] Impact analysis lists everything affected by a changed source. +- [ ] A visualization renders the DAG and traversal p95 stays within target as the graph grows. + +## Common Pitfalls + +- Manual lineage that drifts the moment a job changes — automatic capture is the whole point. +- Silent completeness gaps: an uninstrumented job breaks the chain and nobody notices. +- Storing lineage without run/time versioning, so you can't answer "what did this look like last Tuesday". +- Unbounded traversals with no cycle detection, hanging on a diamond-shaped graph. + +## Resources + +- [OpenLineage documentation](https://openlineage.io/docs/) — the open standard for lineage events. +- [OpenLineage: Column-level lineage](https://openlineage.io/docs/spec/facets/dataset-facets/column_lineage_facet/) — the facet that models column derivation. +- [Marquez](https://marquezproject.github.io/marquez/) — a reference lineage metadata service built on OpenLineage. +- [Apache Atlas](https://atlas.apache.org/#/) — an enterprise metadata and lineage governance system to compare against. diff --git a/projects/data-engineering/advanced/06-data-lineage/README.pt-BR.md b/projects/data-engineering/advanced/06-data-lineage/README.pt-BR.md new file mode 100644 index 0000000..4ea0cbc --- /dev/null +++ b/projects/data-engineering/advanced/06-data-lineage/README.pt-BR.md @@ -0,0 +1,92 @@ +# Sistema de Linhagem de Dados + +> 🌐 [English](./README.md) · **Português** + +**Domínio:** Data Engineering · **Nível:** Avançado · **Tempo estimado:** 1–2 semanas + +## Visão Geral + +Construa um sistema que rastreia a linhagem de dados — de quais datasets uma dada tabela foi derivada, por quais jobs e (idealmente) no nível de coluna. Quando um dashboard a jusante mostra números errados, a linhagem responde "o que alimenta isto?" em segundos em vez de um dia de arqueologia; quando uma coluna de origem muda, a linhagem responde "o que quebra?" antes de você subir. Você capturará linhagem automaticamente de jobs em execução (emitindo eventos de run/dataset/job, idealmente no formato OpenLineage), a armazenará como um grafo acíclico direcionado, e exporá consultas para travessia a montante/jusante e análise de impacto. Os desafios centrais são *completude* (um job que você não instrumenta é um ponto cego), manter as consultas de grafo rápidas conforme o grafo cresce, e capturar linhagem sem pedir aos engenheiros que a mantenham à mão. + +## Pré-requisitos + +- Familiaridade com pipelines/DAGs e um orquestrador (Airflow, Dagster ou similar) +- Conforto com modelagem de grafos e um store de grafo ou relacional +- Entendimento de jobs produzindo/consumindo datasets +- Conhecimento básico de um padrão de linhagem como OpenLineage (útil, não obrigatório) + +## Objetivos de Aprendizado + +Ao final, você deve ser capaz de: + +- Modelar linhagem como um DAG de datasets, jobs e runs +- Capturar linhagem automaticamente da execução dos jobs em vez de anotação manual +- Suportar travessia a montante ("o que alimenta X") e a jusante ("o que depende de X") +- Rodar análise de impacto: dada uma origem alterada/quebrada, listar tudo que é afetado +- Raciocinar sobre lacunas de completude e como a linhagem parcial engana + +## Requisitos Funcionais + +1. Todo run de job deve emitir um evento de linhagem registrando seus datasets de entrada, de saída e o status do run. +2. O sistema deve armazenar linhagem como um DAG consultável com nós para datasets e jobs. +3. Uma consulta deve retornar toda a cadeia a montante de qualquer dataset (fontes transitivas). +4. Uma consulta deve retornar toda a cadeia a jusante (consumidores transitivos) para análise de impacto. +5. A linhagem no nível de coluna deve ser suportada para ao menos uma transformação (quais colunas de entrada produziram uma coluna de saída). +6. O sistema deve registrar mudanças de schema/versão nos datasets ao longo do tempo. + +## Marcos Sugeridos + +1. **Marco 1 — Captura:** Emita eventos de run/job/dataset de alguns passos do pipeline e persista-os. +2. **Marco 2 — Grafo e travessia:** Construa o DAG e exponha consultas a montante/jusante com proteção contra ciclos. +3. **Marco 3 — Impacto e colunas:** Adicione linhagem no nível de coluna para uma transformação e uma consulta de análise de impacto, mais uma visualização de linhagem. + +## Esboço de Dados e Interface + +```text +evento de linhagem (por run): + { runId, job: "etl.orders_daily", state: complete, + inputs: [orders_raw, fx_rates], + outputs: [orders_daily], + columnLineage: { "orders_daily.amount_usd": + ["orders_raw.amount", "fx_rates.rate"] } } + +grafo: + orders_raw ─▶ [etl.orders_daily] ─▶ orders_daily ─▶ [bi.revenue] ─▶ revenue_dash + fx_rates ─┘ + +consultas: + upstream(revenue_dash) -> {orders_daily, orders_raw, fx_rates} + downstream(orders_raw) -> {orders_daily, revenue_dash} (análise de impacto) + columnsFor(orders_daily.amount_usd) -> [orders_raw.amount, fx_rates.rate] + +Não funcional: travessia p95 < T em N nós; captura adiciona < X% de overhead ao job; +completude = jobs instrumentados / jobs totais (acompanhe isso). +``` + +## Desafios Extras + +- Integre o OpenLineage para que a linhagem seja emitida por conectores reais, não apenas pelos seus hooks. +- Adicione "propagação de atualidade": marque todos os datasets a jusante como obsoletos quando um run a montante falhar. +- Detecte e alerte sobre datasets órfãos (sem job produtor) e fontes sem saída. + +## Definição de Pronto + +- [ ] Runs de jobs emitem eventos de linhagem automaticamente; nenhuma edição manual de grafo é necessária. +- [ ] Travessias a montante e a jusante retornam conjuntos transitivos corretos, seguras contra ciclos. +- [ ] A linhagem no nível de coluna está correta para ao menos uma transformação não trivial. +- [ ] A análise de impacto lista tudo afetado por uma origem alterada. +- [ ] Uma visualização renderiza o DAG e a travessia p95 permanece dentro do alvo conforme o grafo cresce. + +## Armadilhas Comuns + +- Linhagem manual que se descola no momento em que um job muda — a captura automática é o ponto central. +- Lacunas de completude silenciosas: um job não instrumentado quebra a cadeia e ninguém percebe. +- Armazenar linhagem sem versionamento por run/tempo, então você não consegue responder "como isto estava terça passada". +- Travessias ilimitadas sem detecção de ciclos, travando em um grafo em forma de diamante. + +## Recursos + +- [Documentação do OpenLineage](https://openlineage.io/docs/) — o padrão aberto para eventos de linhagem. +- [OpenLineage: Linhagem no nível de coluna](https://openlineage.io/docs/spec/facets/dataset-facets/column_lineage_facet/) — o facet que modela a derivação de colunas. +- [Marquez](https://marquezproject.github.io/marquez/) — um serviço de metadados de linhagem de referência construído sobre OpenLineage. +- [Apache Atlas](https://atlas.apache.org/#/) — um sistema corporativo de metadados e governança de linhagem para comparar. diff --git a/projects/data-engineering/advanced/07-high-throughput-streaming/README.md b/projects/data-engineering/advanced/07-high-throughput-streaming/README.md index 9548aba..099d93d 100644 --- a/projects/data-engineering/advanced/07-high-throughput-streaming/README.md +++ b/projects/data-engineering/advanced/07-high-throughput-streaming/README.md @@ -1,34 +1,92 @@ # High-Throughput Streaming System -## Idea -Build a streaming system optimized for high throughput. Learn about performance tuning and scalability. +> 🌐 **English** · [Português](./README.pt-BR.md) + +**Domain:** Data Engineering · **Level:** Advanced · **Estimated time:** 1–2 weeks + +## Overview + +Build and tune a streaming system to move millions of events per second, then measure it honestly. This is a performance-engineering project: the goal is not a new feature but a documented, reproducible benchmark and a set of tuning decisions that provably move the numbers. You will push against the fundamental tension between throughput and latency — bigger batches and compression raise throughput but add latency; smaller batches cut latency but waste per-message overhead — and you will find where your system falls over. Along the way you will handle backpressure (what happens when consumers can't keep up), pick a serialization format, tune partitioning and parallelism, and separate genuine bottlenecks from noise. The deliverable is a system plus a benchmark report showing throughput, p50/p99 latency, and the effect of each tuning knob. + +## Prerequisites + +- Experience with a streaming platform (Kafka, Pulsar, Redpanda) and its producer/consumer tuning knobs +- Comfort profiling and reading latency percentiles, not just averages +- Understanding of batching, compression, and serialization tradeoffs +- Familiarity with backpressure and flow control concepts ## Learning Objectives -- Optimize throughput -- Minimize latency -- Scale horizontally -- Handle backpressure -- Monitor performance - -## Implementation Tips -- Implement batch processing -- Add buffer optimization -- Create parallelization strategy -- Implement compression -- Optimize serialization -- Add network optimization -- Implement connection pooling -- Create resource management -- Add performance monitoring -- Implement auto-scaling -- Add tuning parameters -- Create bottleneck analysis -- Build benchmarking -- Implement optimization strategies - -## Key Challenges -- Throughput optimization -- Latency-throughput tradeoff -- Resource efficiency -- GC pause handling -- Network optimization + +By the end, you should be able to: + +- Design a repeatable throughput/latency benchmark with a controlled load generator +- Tune batching, compression, and partition count and quantify each effect +- Handle backpressure so an overwhelmed consumer degrades gracefully instead of collapsing +- Choose a serialization format (Avro/Protobuf vs JSON) based on measured cost +- Identify the real bottleneck (CPU, network, GC, disk) instead of guessing + +## Functional Requirements + +1. A load generator must produce a controllable, sustained event rate for benchmarking. +2. The system must report throughput (events/s and bytes/s) and end-to-end latency percentiles (p50/p99). +3. Backpressure must be handled: when consumers lag, the system must throttle or buffer within bounds, never lose data silently or OOM. +4. At least three tuning knobs (e.g. batch size, compression, partition count) must be varied and their effects measured. +5. The benchmark must be reproducible: same config, same result within tolerance. +6. The system must sustain a target rate for a sustained window without unbounded lag growth. + +## Suggested Milestones + +1. **Milestone 1 — Baseline & harness:** Build the load generator and metrics collection; record an untuned baseline (throughput, p99). +2. **Milestone 2 — Tune:** Sweep batching, compression, serialization, and partition count; chart each knob's throughput/latency effect. +3. **Milestone 3 — Backpressure & limits:** Add flow control, then push past capacity to find and document the breaking point. + +## Data & Interface Sketch + +```text +[load gen] --rate R--> [producer] + knobs: batch.size, linger.ms, compression{none|lz4|zstd}, serialization{json|proto} + │ + ▼ + [log: P partitions] throughput scales ~ with P (up to a point) + │ + ▼ + [consumers, C instances] consumer lag = latest offset - committed offset + │ + ▼ + [sink] + +backpressure: if lag > threshold -> throttle producer / grow buffer to bound B + never: drop silently, or buffer unbounded -> OOM + +report (per config): + throughput_eps | throughput_MBps | p50_ms | p99_ms | max_lag | cpu% | gc_ms +tradeoff seen: larger batch => higher throughput, higher p99 latency +``` + +## Stretch Goals + +- Add auto-scaling of consumers driven by lag and show it holds latency under a spike. +- Compare zero-copy / no-compression vs zstd and quantify the CPU/network tradeoff. +- Profile and eliminate a GC-pause-driven p99 spike (tune heap or switch to off-heap buffers). + +## Definition of Done + +- [ ] The benchmark is reproducible and reports throughput plus p50/p99 latency. +- [ ] At least three tuning knobs are swept with charted, explained effects. +- [ ] Backpressure keeps the system bounded under overload — no silent loss, no OOM. +- [ ] The documented breaking point identifies the actual bottleneck (CPU/network/GC/disk). +- [ ] The throughput/latency tradeoff is demonstrated with data, not asserted. + +## Common Pitfalls + +- Reporting average latency, hiding the p99 tail where the real pain lives. +- Benchmarking with a load generator too weak to saturate the system — you measure the generator, not the pipeline. +- Adding partitions past the point of diminishing returns and paying coordination overhead for nothing. +- "Fixing" backpressure with an unbounded in-memory queue that just moves the crash later. + +## Resources + +- [Kafka: Producer & consumer configs](https://kafka.apache.org/documentation/#producerconfigs) — batching, linger, and compression knobs. +- [Confluent: Optimizing Kafka throughput vs latency](https://docs.confluent.io/cloud/current/client-apps/optimizing/throughput.html) — the core tradeoff, with concrete settings. +- [Flink: Back Pressure](https://nightlies.apache.org/flink/flink-docs-stable/docs/ops/monitoring/back_pressure/) — how a processor surfaces and handles overload. +- [Brendan Gregg: Latency percentiles & USE method](https://www.brendangregg.com/usemethod.html) — a rigorous approach to finding bottlenecks. diff --git a/projects/data-engineering/advanced/07-high-throughput-streaming/README.pt-BR.md b/projects/data-engineering/advanced/07-high-throughput-streaming/README.pt-BR.md new file mode 100644 index 0000000..2570b7e --- /dev/null +++ b/projects/data-engineering/advanced/07-high-throughput-streaming/README.pt-BR.md @@ -0,0 +1,92 @@ +# Sistema de Streaming de Alta Vazão + +> 🌐 [English](./README.md) · **Português** + +**Domínio:** Data Engineering · **Nível:** Avançado · **Tempo estimado:** 1–2 semanas + +## Visão Geral + +Construa e ajuste um sistema de streaming para mover milhões de eventos por segundo, e então meça-o honestamente. Este é um projeto de engenharia de performance: o objetivo não é uma nova funcionalidade, mas um benchmark documentado e reproduzível, e um conjunto de decisões de tuning que comprovadamente movem os números. Você empurrará contra a tensão fundamental entre vazão e latência — lotes maiores e compressão elevam a vazão mas adicionam latência; lotes menores cortam latência mas desperdiçam overhead por mensagem — e descobrirá onde seu sistema cai. Pelo caminho você tratará backpressure (o que acontece quando os consumidores não acompanham), escolherá um formato de serialização, ajustará particionamento e paralelismo, e separará gargalos genuínos do ruído. A entrega é um sistema mais um relatório de benchmark mostrando vazão, latência p50/p99 e o efeito de cada botão de tuning. + +## Pré-requisitos + +- Experiência com uma plataforma de streaming (Kafka, Pulsar, Redpanda) e seus botões de tuning de produtor/consumidor +- Conforto para perfilar e ler percentis de latência, não só médias +- Entendimento de tradeoffs de batching, compressão e serialização +- Familiaridade com conceitos de backpressure e controle de fluxo + +## Objetivos de Aprendizado + +Ao final, você deve ser capaz de: + +- Projetar um benchmark de vazão/latência repetível com um gerador de carga controlado +- Ajustar batching, compressão e contagem de partições e quantificar cada efeito +- Tratar backpressure para que um consumidor sobrecarregado degrade graciosamente em vez de colapsar +- Escolher um formato de serialização (Avro/Protobuf vs JSON) com base em custo medido +- Identificar o gargalo real (CPU, rede, GC, disco) em vez de adivinhar + +## Requisitos Funcionais + +1. Um gerador de carga deve produzir uma taxa de eventos sustentada e controlável para o benchmark. +2. O sistema deve reportar vazão (eventos/s e bytes/s) e percentis de latência de ponta a ponta (p50/p99). +3. O backpressure deve ser tratado: quando os consumidores atrasam, o sistema deve throttle ou bufferizar dentro de limites, nunca perder dados silenciosamente nem dar OOM. +4. Ao menos três botões de tuning (ex.: tamanho de lote, compressão, contagem de partições) devem ser variados e seus efeitos medidos. +5. O benchmark deve ser reproduzível: mesma config, mesmo resultado dentro da tolerância. +6. O sistema deve sustentar uma taxa alvo por uma janela sustentada sem crescimento ilimitado de lag. + +## Marcos Sugeridos + +1. **Marco 1 — Base e harness:** Construa o gerador de carga e a coleta de métricas; registre uma base sem tuning (vazão, p99). +2. **Marco 2 — Ajustar:** Varra batching, compressão, serialização e contagem de partições; plote o efeito de vazão/latência de cada botão. +3. **Marco 3 — Backpressure e limites:** Adicione controle de fluxo, então empurre além da capacidade para achar e documentar o ponto de ruptura. + +## Esboço de Dados e Interface + +```text +[gerador de carga] --taxa R--> [produtor] + botões: batch.size, linger.ms, compression{none|lz4|zstd}, serialization{json|proto} + │ + ▼ + [log: P partições] vazão escala ~ com P (até certo ponto) + │ + ▼ + [consumidores, C instâncias] lag do consumidor = offset mais recente - offset commitado + │ + ▼ + [sink] + +backpressure: se lag > limite -> throttle produtor / crescer buffer até limite B + nunca: descartar silenciosamente, ou bufferizar ilimitadamente -> OOM + +relatório (por config): + vazao_eps | vazao_MBps | p50_ms | p99_ms | lag_max | cpu% | gc_ms +tradeoff observado: lote maior => maior vazão, maior latência p99 +``` + +## Desafios Extras + +- Adicione auto-scaling de consumidores guiado por lag e mostre que ele segura a latência sob um pico. +- Compare zero-copy / sem-compressão vs zstd e quantifique o tradeoff de CPU/rede. +- Perfile e elimine um pico de p99 causado por pausa de GC (ajuste o heap ou mude para buffers off-heap). + +## Definição de Pronto + +- [ ] O benchmark é reproduzível e reporta vazão mais latência p50/p99. +- [ ] Ao menos três botões de tuning são varridos com efeitos plotados e explicados. +- [ ] O backpressure mantém o sistema limitado sob sobrecarga — sem perda silenciosa, sem OOM. +- [ ] O ponto de ruptura documentado identifica o gargalo real (CPU/rede/GC/disco). +- [ ] O tradeoff vazão/latência é demonstrado com dados, não afirmado. + +## Armadilhas Comuns + +- Reportar latência média, escondendo a cauda p99 onde mora a dor real. +- Fazer benchmark com um gerador de carga fraco demais para saturar o sistema — você mede o gerador, não o pipeline. +- Adicionar partições além do ponto de retornos decrescentes e pagar overhead de coordenação à toa. +- "Consertar" backpressure com uma fila em memória ilimitada que só adia o crash. + +## Recursos + +- [Kafka: Configs de produtor e consumidor](https://kafka.apache.org/documentation/#producerconfigs) — botões de batching, linger e compressão. +- [Confluent: Otimizando vazão vs latência no Kafka](https://docs.confluent.io/cloud/current/client-apps/optimizing/throughput.html) — o tradeoff central, com configurações concretas. +- [Flink: Back Pressure](https://nightlies.apache.org/flink/flink-docs-stable/docs/ops/monitoring/back_pressure/) — como um processador expõe e trata sobrecarga. +- [Brendan Gregg: Percentis de latência e método USE](https://www.brendangregg.com/usemethod.html) — uma abordagem rigorosa para achar gargalos. diff --git a/projects/data-engineering/advanced/08-cost-optimized-pipeline/README.md b/projects/data-engineering/advanced/08-cost-optimized-pipeline/README.md index 798f947..3ccc7dd 100644 --- a/projects/data-engineering/advanced/08-cost-optimized-pipeline/README.md +++ b/projects/data-engineering/advanced/08-cost-optimized-pipeline/README.md @@ -1,34 +1,89 @@ # Cost-Optimized Data Pipeline -## Idea -Design a data pipeline optimized for cost efficiency. Learn about cloud optimization and resource management. +> 🌐 **English** · [Português](./README.pt-BR.md) + +**Domain:** Data Engineering · **Level:** Advanced · **Estimated time:** 1–2 weeks + +## Overview + +Take a working but wasteful data pipeline and cut its cloud bill without breaking its SLAs. This is an optimization project where the objective function is dollars, and the discipline is measuring cost per run *before* you touch anything. You will attribute spend across compute, storage, and data transfer, then attack the biggest line item: spot/preemptible instances for fault-tolerant batch work, storage tiering and compression, avoiding cross-region egress, right-sizing over-provisioned clusters, and scheduling non-urgent jobs into cheaper windows. The constant tension is cost vs performance and cost vs reliability — a spot instance is cheap until it's reclaimed mid-job. The deliverable is a before/after cost analysis with each optimization's savings and its risk trade-off documented. + +## Prerequisites + +- A cloud data stack you can measure (managed Spark, a warehouse, or object storage + query engine) +- Understanding of cloud pricing dimensions: compute-hours, storage class, egress, requests +- Familiarity with spot/preemptible instances and their reclamation behavior +- Comfort reading a cost/billing breakdown and attributing it to workloads ## Learning Objectives -- Optimize resource usage -- Reduce cloud costs -- Implement tiering -- Schedule workloads -- Monitor spending - -## Implementation Tips -- Implement compute optimization -- Add storage tiering -- Optimize data transfer -- Implement workload scheduling -- Add spot instance usage -- Create compression -- Implement caching strategies -- Add batch scheduling -- Create resource pooling -- Implement cost monitoring -- Add cost allocation -- Create budget alerts -- Build optimization recommendations -- Implement automatic cost optimization - -## Key Challenges -- Cost vs performance tradeoff -- Cloud pricing complexity -- Workload variability -- Commitment discounts -- Multi-cloud optimization + +By the end, you should be able to: + +- Instrument and attribute pipeline cost across compute, storage, and transfer +- Use spot/preemptible capacity for fault-tolerant work without risking data loss +- Apply storage tiering, compression, and file layout to cut storage and scan costs +- Eliminate avoidable data-transfer/egress charges +- Weigh each optimization's savings against its performance and reliability risk + +## Functional Requirements + +1. The pipeline's cost per run must be measured and attributed to compute, storage, and transfer before optimization. +2. At least one fault-tolerant stage must run on spot/preemptible capacity with safe handling of reclamation (checkpoint/retry). +3. Storage cost must be reduced via tiering and/or compression, with data still queryable within SLA. +4. A documented change must eliminate or reduce cross-region/egress transfer cost. +5. Every optimization must preserve the pipeline's correctness and its latency/freshness SLA. +6. A budget/cost alert must fire when spend exceeds a defined threshold. + +## Suggested Milestones + +1. **Milestone 1 — Measure & attribute:** Instrument cost per run and break it down by resource; identify the top 2–3 line items. +2. **Milestone 2 — Optimize compute & storage:** Move a stage to spot with checkpointing; apply tiering/compression; re-measure. +3. **Milestone 3 — Transfer & guardrails:** Cut egress, add scheduling into cheap windows, and wire a budget alert. + +## Data & Interface Sketch + +```text +cost attribution (per run, before): + compute $X (cluster hours x instance price) <- usually the big one + storage $Y (GB-month x storage class) + transfer $Z (cross-region egress GB x rate) + total $T --> target: reduce to $T' at same SLA + +optimizations & risk: + on-demand -> spot (batch) save ~60-90% risk: reclamation -> need checkpoint+retry + standard -> tiered storage save on cold risk: retrieval latency on archive + cross-region -> same-region save egress risk: reduced geo-redundancy + right-size cluster save idle risk: less burst headroom + schedule off-peak save (spot mkt) risk: later completion + +guardrail: if month_to_date_spend > BUDGET -> alert (do not silently overrun) +invariant: correctness + SLA unchanged after every change. +``` + +## Stretch Goals + +- Add a cost-vs-latency Pareto chart so a stakeholder can pick a point, not just "cheapest". +- Implement automatic right-sizing that scales the cluster to observed load per run. +- Model committed-use / reserved discounts and compute the break-even utilization. + +## Definition of Done + +- [ ] Cost per run is measured and attributed before and after, with total savings quantified. +- [ ] A spot-backed stage survives reclamation via checkpoint/retry with no data loss. +- [ ] Storage and/or scan cost drops measurably while data stays queryable within SLA. +- [ ] An egress/transfer optimization is documented with its savings. +- [ ] A budget alert fires on threshold breach; each optimization's risk is written down. + +## Common Pitfalls + +- Optimizing cost you can't see — no attribution means you cut the wrong thing. +- Putting a stateful, non-recoverable stage on spot and losing work when it's reclaimed. +- Compressing/tiering so aggressively that a query blows its latency SLA fetching cold data. +- Ignoring egress until the transfer line dominates the bill — cross-region reads are silent money. + +## Resources + +- [AWS Well-Architected: Cost Optimization Pillar](https://docs.aws.amazon.com/wellarchitected/latest/cost-optimization-pillar/welcome.html) — a structured framework for cost decisions. +- [AWS: Spot Instances best practices](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/spot-best-practices.html) — using interruptible capacity safely. +- [Google Cloud: Storage classes](https://cloud.google.com/storage/docs/storage-classes) — tiering economics and retrieval tradeoffs. +- [Spark: Tuning](https://spark.apache.org/docs/latest/tuning.html) — right-sizing resources to avoid paying for idle. diff --git a/projects/data-engineering/advanced/08-cost-optimized-pipeline/README.pt-BR.md b/projects/data-engineering/advanced/08-cost-optimized-pipeline/README.pt-BR.md new file mode 100644 index 0000000..43ae79d --- /dev/null +++ b/projects/data-engineering/advanced/08-cost-optimized-pipeline/README.pt-BR.md @@ -0,0 +1,89 @@ +# Pipeline de Dados Otimizado para Custo + +> 🌐 [English](./README.md) · **Português** + +**Domínio:** Data Engineering · **Nível:** Avançado · **Tempo estimado:** 1–2 semanas + +## Visão Geral + +Pegue um pipeline de dados funcional mas perdulário e corte sua conta de nuvem sem quebrar seus SLAs. Este é um projeto de otimização em que a função objetivo é dólares, e a disciplina é medir o custo por execução *antes* de tocar em qualquer coisa. Você atribuirá o gasto entre compute, armazenamento e transferência de dados, e então atacará o maior item: instâncias spot/preemptíveis para trabalho batch tolerante a falhas, tiering de armazenamento e compressão, evitar egress entre regiões, right-sizing de clusters superdimensionados, e agendar jobs não urgentes em janelas mais baratas. A tensão constante é custo vs performance e custo vs confiabilidade — uma instância spot é barata até ser recuperada no meio do job. A entrega é uma análise de custo antes/depois com a economia de cada otimização e seu trade-off de risco documentados. + +## Pré-requisitos + +- Um stack de dados em nuvem que você possa medir (Spark gerenciado, um warehouse, ou object storage + motor de consulta) +- Entendimento das dimensões de preço de nuvem: horas de compute, classe de armazenamento, egress, requisições +- Familiaridade com instâncias spot/preemptíveis e seu comportamento de recuperação +- Conforto para ler um detalhamento de custo/faturamento e atribuí-lo a cargas de trabalho + +## Objetivos de Aprendizado + +Ao final, você deve ser capaz de: + +- Instrumentar e atribuir o custo do pipeline entre compute, armazenamento e transferência +- Usar capacidade spot/preemptível para trabalho tolerante a falhas sem arriscar perda de dados +- Aplicar tiering de armazenamento, compressão e layout de arquivos para cortar custos de armazenamento e varredura +- Eliminar cobranças evitáveis de transferência/egress de dados +- Pesar a economia de cada otimização contra seu risco de performance e confiabilidade + +## Requisitos Funcionais + +1. O custo por execução do pipeline deve ser medido e atribuído a compute, armazenamento e transferência antes da otimização. +2. Ao menos um estágio tolerante a falhas deve rodar em capacidade spot/preemptível com tratamento seguro da recuperação (checkpoint/retry). +3. O custo de armazenamento deve ser reduzido via tiering e/ou compressão, com os dados ainda consultáveis dentro do SLA. +4. Uma mudança documentada deve eliminar ou reduzir o custo de transferência entre regiões/egress. +5. Toda otimização deve preservar a correção do pipeline e seu SLA de latência/atualidade. +6. Um alerta de orçamento/custo deve disparar quando o gasto exceder um limite definido. + +## Marcos Sugeridos + +1. **Marco 1 — Medir e atribuir:** Instrumente o custo por execução e decomponha-o por recurso; identifique os 2–3 maiores itens. +2. **Marco 2 — Otimizar compute e armazenamento:** Mova um estágio para spot com checkpointing; aplique tiering/compressão; meça de novo. +3. **Marco 3 — Transferência e guardrails:** Corte egress, adicione agendamento em janelas baratas e conecte um alerta de orçamento. + +## Esboço de Dados e Interface + +```text +atribuição de custo (por execução, antes): + compute $X (horas de cluster x preço da instância) <- geralmente o maior + storage $Y (GB-mês x classe de armazenamento) + transfer $Z (egress entre regiões GB x taxa) + total $T --> alvo: reduzir para $T' no mesmo SLA + +otimizações e risco: + on-demand -> spot (batch) economiza ~60-90% risco: recuperação -> precisa checkpoint+retry + standard -> storage tiered economiza no frio risco: latência de recuperação no archive + entre regiões -> mesma região economiza egress risco: menos geo-redundância + right-size do cluster economiza ocioso risco: menos folga para burst + agendar fora de pico economiza (mkt spot) risco: conclusão mais tarde + +guardrail: se gasto_no_mês > ORÇAMENTO -> alerta (não estourar silenciosamente) +invariante: correção + SLA inalterados após cada mudança. +``` + +## Desafios Extras + +- Adicione um gráfico de Pareto custo-vs-latência para que um stakeholder possa escolher um ponto, não só "o mais barato". +- Implemente right-sizing automático que escala o cluster à carga observada por execução. +- Modele descontos de uso comprometido / reservado e calcule a utilização de break-even. + +## Definição de Pronto + +- [ ] O custo por execução é medido e atribuído antes e depois, com a economia total quantificada. +- [ ] Um estágio apoiado em spot sobrevive à recuperação via checkpoint/retry sem perda de dados. +- [ ] O custo de armazenamento e/ou varredura cai mensuravelmente enquanto os dados seguem consultáveis dentro do SLA. +- [ ] Uma otimização de egress/transferência é documentada com sua economia. +- [ ] Um alerta de orçamento dispara na quebra do limite; o risco de cada otimização é anotado. + +## Armadilhas Comuns + +- Otimizar um custo que você não consegue ver — sem atribuição, você corta a coisa errada. +- Colocar um estágio com estado e não recuperável em spot e perder trabalho quando ele é recuperado. +- Comprimir/tierar tão agressivamente que uma consulta estoura seu SLA de latência buscando dados frios. +- Ignorar o egress até que a linha de transferência domine a conta — leituras entre regiões são dinheiro silencioso. + +## Recursos + +- [AWS Well-Architected: Pilar de Otimização de Custo](https://docs.aws.amazon.com/wellarchitected/latest/cost-optimization-pillar/welcome.html) — um framework estruturado para decisões de custo. +- [AWS: Boas práticas de Spot Instances](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/spot-best-practices.html) — usar capacidade interruptível com segurança. +- [Google Cloud: Classes de armazenamento](https://cloud.google.com/storage/docs/storage-classes) — economia de tiering e tradeoffs de recuperação. +- [Spark: Tuning](https://spark.apache.org/docs/latest/tuning.html) — right-sizing de recursos para não pagar por ociosidade. diff --git a/projects/data-engineering/advanced/09-multi-region-replication/README.md b/projects/data-engineering/advanced/09-multi-region-replication/README.md index 698fe66..4f6b30f 100644 --- a/projects/data-engineering/advanced/09-multi-region-replication/README.md +++ b/projects/data-engineering/advanced/09-multi-region-replication/README.md @@ -1,34 +1,91 @@ # Multi-Region Data Replication -## Idea -Implement a system for replicating data across multiple regions. Learn about geographic distribution and consistency. +> 🌐 **English** · [Português](./README.pt-BR.md) + +**Domain:** Data Engineering · **Level:** Advanced · **Estimated time:** 1–2 weeks + +## Overview + +Design and build a system that replicates data across geographic regions so it survives a whole-region outage and serves reads close to users — while confronting the fact that you cannot have strong consistency, low latency, and partition tolerance all at once. This is where CAP and PACELC stop being trivia and start dictating your design. You will pick a consistency model (synchronous strong replication vs asynchronous eventual, or something in between), define your failure story (RPO — how much data you can lose; RTO — how fast you recover), and handle the messy reality of concurrent writes in two regions producing conflicts. Data residency rules add a constraint that pure engineering can't wave away. The deliverable is a replication design plus a working prototype demonstrating failover and a documented conflict-resolution strategy. + +## Prerequisites + +- A datastore with cross-region replication features (a distributed DB, Kafka MirrorMaker, or object-store cross-region replication) +- Solid grasp of consistency models (strong, eventual, causal) and the CAP/PACELC theorems +- Understanding of RPO/RTO and failover concepts +- Familiarity with conflict resolution (last-write-wins, vector clocks, CRDTs) ## Learning Objectives -- Replicate across regions -- Handle consistency -- Manage conflicts -- Optimize network -- Ensure compliance - -## Implementation Tips -- Implement replication strategy -- Choose consistency model -- Implement conflict resolution -- Add compression for transfer -- Create optimization -- Handle network failures -- Implement monitoring -- Add alerting -- Create compliance policies -- Implement data residency -- Add latency optimization -- Create disaster recovery -- Implement rollback -- Build testing - -## Key Challenges -- Consistency model selection -- Conflict resolution -- Network optimization -- Compliance requirements -- Disaster recovery + +By the end, you should be able to: + +- Choose a consistency model and justify it against latency and availability needs +- Define and measure RPO and RTO for a region-loss scenario +- Design and execute a failover (and failback) without data loss beyond your RPO +- Resolve concurrent cross-region write conflicts with a documented strategy +- Account for data-residency constraints in the replication topology + +## Functional Requirements + +1. Data written in one region must replicate to at least one other region within a bounded lag. +2. The system must define an explicit consistency model and enforce it consistently for reads. +3. A simulated region outage must trigger failover to another region with data loss within the stated RPO. +4. Concurrent writes to the same key in two regions must be reconciled by a documented conflict-resolution rule. +5. Replication lag and per-region health must be observable as metrics. +6. The topology must respect a data-residency rule (e.g. EU-origin data does not leave EU regions). + +## Suggested Milestones + +1. **Milestone 1 — Replicate:** Stand up two regions and asynchronous replication; measure baseline replication lag. +2. **Milestone 2 — Failover & RPO/RTO:** Simulate a region outage, fail over, measure actual RPO/RTO, then fail back. +3. **Milestone 3 — Conflicts & residency:** Force concurrent conflicting writes, apply a resolution strategy, and enforce a residency constraint. + +## Data & Interface Sketch + +```text + region A (primary) region B (replica/active) + [write] ──async replicate──▶ replication lag = L + │ │ + reads (strong here) reads (eventual here, unless promoted) + +consistency choice (PACELC): + if Partition -> pick A (availability) or C (consistency) + Else (normal ops) -> pick L (latency) or C (consistency) + +failover: A down -> promote B ; RPO = data written to A not yet replicated + RTO = time until B serves writes +conflict (same key, both regions write): + strategy A: last-write-wins by timestamp (simple, can lose a write) + strategy B: version vectors / CRDT (merges, more complex) + +residency: tag data{region_of_origin}; replicate EU-origin only to EU regions. +metrics: replication_lag_ms, region_health, conflict_count. +``` + +## Stretch Goals + +- Implement active-active writes in both regions with CRDT-based merge and prove convergence. +- Add automatic failover with a health-check-driven promotion instead of manual intervention. +- Model quorum-based replication (write to W of N regions) and analyze its RPO/latency profile. + +## Definition of Done + +- [ ] Writes replicate cross-region within a measured, bounded lag. +- [ ] A region-outage simulation fails over with data loss within the declared RPO and recovery within RTO. +- [ ] Concurrent conflicting writes are reconciled by a documented, tested rule. +- [ ] Replication lag and region health are exported as metrics. +- [ ] A residency constraint is enforced and demonstrated (restricted data never leaves its allowed regions). + +## Common Pitfalls + +- Claiming "strongly consistent and highly available across regions" — the CAP theorem says pick two under partition. +- Never actually testing failover, so RTO is a guess and the runbook is fiction. +- Last-write-wins with unsynchronized clocks, silently dropping the "losing" write. +- Ignoring residency until an auditor finds EU data replicated to us-east-1. + +## Resources + +- [Consistency models & CAP (Jepsen)](https://jepsen.io/consistency) — a precise map of consistency guarantees. +- [PACELC theorem](https://en.wikipedia.org/wiki/PACELC_theorem) — the latency-vs-consistency tradeoff even without partitions. +- [Kafka: Geo-replication (MirrorMaker 2)](https://kafka.apache.org/documentation/#georeplication) — cross-cluster/region replication in practice. +- [Amazon: Dynamo (paper)](https://www.allthingsdistributed.com/files/amazon-dynamo-sosp2007.pdf) — eventual consistency and conflict resolution at scale. diff --git a/projects/data-engineering/advanced/09-multi-region-replication/README.pt-BR.md b/projects/data-engineering/advanced/09-multi-region-replication/README.pt-BR.md new file mode 100644 index 0000000..24001e2 --- /dev/null +++ b/projects/data-engineering/advanced/09-multi-region-replication/README.pt-BR.md @@ -0,0 +1,91 @@ +# Replicação de Dados Multi-Região + +> 🌐 [English](./README.md) · **Português** + +**Domínio:** Data Engineering · **Nível:** Avançado · **Tempo estimado:** 1–2 semanas + +## Visão Geral + +Projete e construa um sistema que replica dados entre regiões geográficas para que sobrevivam a uma queda de região inteira e sirvam leituras perto dos usuários — enfrentando o fato de que você não pode ter consistência forte, baixa latência e tolerância a partições ao mesmo tempo. É aqui que CAP e PACELC deixam de ser curiosidade e passam a ditar seu design. Você escolherá um modelo de consistência (replicação forte síncrona vs eventual assíncrona, ou algo no meio), definirá sua história de falha (RPO — quanto dado você pode perder; RTO — quão rápido você recupera), e tratará a realidade bagunçada de escritas concorrentes em duas regiões produzindo conflitos. Regras de residência de dados adicionam uma restrição que engenharia pura não descarta. A entrega é um design de replicação mais um protótipo funcional demonstrando failover e uma estratégia de resolução de conflitos documentada. + +## Pré-requisitos + +- Um datastore com recursos de replicação entre regiões (um DB distribuído, Kafka MirrorMaker ou replicação entre regiões de object store) +- Domínio sólido de modelos de consistência (forte, eventual, causal) e dos teoremas CAP/PACELC +- Entendimento dos conceitos de RPO/RTO e failover +- Familiaridade com resolução de conflitos (last-write-wins, vector clocks, CRDTs) + +## Objetivos de Aprendizado + +Ao final, você deve ser capaz de: + +- Escolher um modelo de consistência e justificá-lo contra necessidades de latência e disponibilidade +- Definir e medir RPO e RTO para um cenário de perda de região +- Projetar e executar um failover (e failback) sem perda de dados além do seu RPO +- Resolver conflitos de escrita concorrente entre regiões com uma estratégia documentada +- Considerar restrições de residência de dados na topologia de replicação + +## Requisitos Funcionais + +1. Dados escritos em uma região devem replicar para ao menos outra região dentro de um lag limitado. +2. O sistema deve definir um modelo de consistência explícito e impô-lo consistentemente nas leituras. +3. Uma queda de região simulada deve disparar failover para outra região com perda de dados dentro do RPO declarado. +4. Escritas concorrentes na mesma chave em duas regiões devem ser reconciliadas por uma regra de resolução de conflitos documentada. +5. O lag de replicação e a saúde por região devem ser observáveis como métricas. +6. A topologia deve respeitar uma regra de residência de dados (ex.: dados de origem UE não saem de regiões da UE). + +## Marcos Sugeridos + +1. **Marco 1 — Replicar:** Suba duas regiões e replicação assíncrona; meça o lag de replicação base. +2. **Marco 2 — Failover e RPO/RTO:** Simule uma queda de região, faça failover, meça o RPO/RTO real, e então faça failback. +3. **Marco 3 — Conflitos e residência:** Force escritas conflitantes concorrentes, aplique uma estratégia de resolução e imponha uma restrição de residência. + +## Esboço de Dados e Interface + +```text + região A (primária) região B (réplica/ativa) + [escrita] ──replica async──▶ lag de replicação = L + │ │ + leituras (fortes aqui) leituras (eventuais aqui, salvo se promovida) + +escolha de consistência (PACELC): + se Partição -> escolha A (disponibilidade) ou C (consistência) + Senão (operação normal) -> escolha L (latência) ou C (consistência) + +failover: A caiu -> promover B ; RPO = dados escritos em A ainda não replicados + RTO = tempo até B servir escritas +conflito (mesma chave, ambas regiões escrevem): + estratégia A: last-write-wins por timestamp (simples, pode perder escrita) + estratégia B: version vectors / CRDT (mescla, mais complexa) + +residência: marque data{região_de_origem}; replique origem-UE só para regiões UE. +métricas: replication_lag_ms, saúde_da_região, contagem_de_conflitos. +``` + +## Desafios Extras + +- Implemente escritas ativo-ativo em ambas as regiões com mescla baseada em CRDT e prove a convergência. +- Adicione failover automático com promoção guiada por health-check em vez de intervenção manual. +- Modele replicação baseada em quorum (escrever em W de N regiões) e analise seu perfil de RPO/latência. + +## Definição de Pronto + +- [ ] Escritas replicam entre regiões dentro de um lag medido e limitado. +- [ ] Uma simulação de queda de região faz failover com perda de dados dentro do RPO declarado e recuperação dentro do RTO. +- [ ] Escritas conflitantes concorrentes são reconciliadas por uma regra documentada e testada. +- [ ] O lag de replicação e a saúde da região são exportados como métricas. +- [ ] Uma restrição de residência é imposta e demonstrada (dados restritos nunca deixam suas regiões permitidas). + +## Armadilhas Comuns + +- Alegar "fortemente consistente e altamente disponível entre regiões" — o teorema CAP diz para escolher dois sob partição. +- Nunca testar failover de verdade, então o RTO é um chute e o runbook é ficção. +- Last-write-wins com relógios não sincronizados, descartando silenciosamente a escrita "perdedora". +- Ignorar residência até que um auditor encontre dados da UE replicados para us-east-1. + +## Recursos + +- [Modelos de consistência e CAP (Jepsen)](https://jepsen.io/consistency) — um mapa preciso das garantias de consistência. +- [Teorema PACELC](https://en.wikipedia.org/wiki/PACELC_theorem) — o tradeoff latência-vs-consistência mesmo sem partições. +- [Kafka: Geo-replicação (MirrorMaker 2)](https://kafka.apache.org/documentation/#georeplication) — replicação entre clusters/regiões na prática. +- [Amazon: Dynamo (artigo)](https://www.allthingsdistributed.com/files/amazon-dynamo-sosp2007.pdf) — consistência eventual e resolução de conflitos em escala. diff --git a/projects/data-engineering/advanced/10-self-healing-pipelines/README.md b/projects/data-engineering/advanced/10-self-healing-pipelines/README.md index 8c70cdb..a237d89 100644 --- a/projects/data-engineering/advanced/10-self-healing-pipelines/README.md +++ b/projects/data-engineering/advanced/10-self-healing-pipelines/README.md @@ -1,34 +1,91 @@ # Self-Healing Pipelines -## Idea -Build pipelines that can automatically detect and recover from failures. Learn about resilience and automation. +> 🌐 **English** · [Português](./README.pt-BR.md) + +**Domain:** Data Engineering · **Level:** Advanced · **Estimated time:** 1–2 weeks + +## Overview + +Build data pipelines that detect their own failures and recover automatically — retrying transient errors, quarantining poison records, rerouting around a dead dependency, and rolling back a bad run — so a human is paged for genuine novelty, not for the same flaky failure at 3am. The design challenge is doing this *safely*: an over-eager auto-remediation can amplify an incident (retry storms hammering a struggling downstream, a rollback that deletes good data). You will classify failures (transient vs permanent), pick the right response per class (retry with backoff, circuit-break, quarantine, compensate/rollback), and add health checks and anomaly detection to trigger them. The theme is graceful degradation with guardrails. The deliverable is a pipeline that survives injected failures with documented recovery behavior and blast-radius limits. + +## Prerequisites + +- Experience building pipelines and an orchestrator (Airflow, Dagster, Temporal, or similar) +- Understanding of retry strategies, idempotency, and exponential backoff +- Familiarity with circuit breakers, dead-letter queues, and health checks +- Comfort reasoning about failure modes and blast radius ## Learning Objectives -- Detect failures -- Implement recovery -- Learn from failures -- Automate remediation -- Prevent cascading failures - -## Implementation Tips -- Implement health checks -- Create anomaly detection -- Implement automatic recovery -- Add compensation logic -- Create rollback mechanisms -- Implement retry strategies -- Add circuit breakers -- Create quarantine mechanisms -- Build failure analysis -- Implement learning system -- Add pattern recognition -- Create preventive measures -- Implement auto-healing -- Build diagnostics - -## Key Challenges -- Failure detection accuracy -- Recovery safety -- Learning effectiveness -- Overly aggressive healing -- Complex failure modes + +By the end, you should be able to: + +- Classify failures as transient vs permanent and respond appropriately to each +- Implement safe retries with exponential backoff and jitter, bounded by idempotency +- Use circuit breakers and dead-letter/quarantine to contain a failing dependency or bad records +- Design compensation/rollback so a partial failure leaves consistent state +- Detect anomalies (volume, latency, error rate) that trigger remediation before a hard failure + +## Functional Requirements + +1. The pipeline must distinguish transient failures (retryable) from permanent ones (not) and act differently on each. +2. Transient failures must retry with exponential backoff and jitter, capped, and only where operations are idempotent. +3. Records that repeatedly fail must be quarantined to a dead-letter store, not block the whole pipeline. +4. A failing downstream dependency must trip a circuit breaker that stops hammering it and recovers when it heals. +5. A failed run must roll back or compensate so no partial, inconsistent output is published. +6. Health checks and at least one anomaly signal must be able to trigger automated remediation, with every action logged. + +## Suggested Milestones + +1. **Milestone 1 — Retry & classify:** Add failure classification and idempotent retry-with-backoff; inject transient errors and watch recovery. +2. **Milestone 2 — Contain:** Add a dead-letter/quarantine path and a circuit breaker for a flaky dependency. +3. **Milestone 3 — Rollback & detect:** Add compensation/rollback for a bad run and an anomaly detector that triggers remediation, all audited. + +## Data & Interface Sketch + +```text + ┌─────────── failure classifier ───────────┐ + [stage] ──err─▶ transient? ──yes──▶ retry(backoff, jitter, maxN) (idempotent only) + └ permanent? ──yes──▶ quarantine record ─▶ [dead-letter store] + (pipeline keeps flowing) + +dependency call ─▶ [circuit breaker] closed -> allow | open -> fail fast + skip + trips at error_rate > threshold; half-open probes to recover + +run outcome: + success -> atomic publish + failure -> compensate/rollback -> no partial output visible + +anomaly detector: watch {input_volume, latency, error_rate} + deviation > k*stddev -> trigger remediation + PAGE if unrecognized + +guardrails: max retries, breaker cooldown, remediation rate-limit +audit log: every automated action { time, trigger, action, result } +``` + +## Stretch Goals + +- Add a "learning" layer that tracks recurring failure signatures and suggests (or applies) a known fix. +- Implement automatic backfill of a quarantined batch once the root cause clears. +- Add chaos testing that randomly injects failures in CI to prove the healing actually works. + +## Definition of Done + +- [ ] Transient and permanent failures are classified and handled differently. +- [ ] Idempotent retries with capped backoff+jitter recover from injected transient errors. +- [ ] Poison records land in a dead-letter store without stalling the pipeline. +- [ ] A circuit breaker protects a flaky dependency and recovers automatically. +- [ ] A failed run leaves no partial output; every automated remediation is logged and rate-limited. + +## Common Pitfalls + +- Retry storms: unbounded or un-jittered retries turn a blip into a self-inflicted outage. +- Retrying non-idempotent operations and double-applying side effects. +- Auto-healing so aggressively it masks a real bug — nobody ever learns the pipeline is broken. +- Rollback that deletes or corrupts good data because compensation wasn't scoped to the failed run. + +## Resources + +- [Google SRE Book: Handling Overload & Cascading Failures](https://sre.google/sre-book/handling-overload/) — retry budgets and load shedding done right. +- [AWS: Timeouts, retries, and backoff with jitter](https://aws.amazon.com/builders-library/timeouts-retries-and-backoff-with-jitter/) — the canonical safe-retry guidance. +- [Martin Fowler: Circuit Breaker](https://martinfowler.com/bliki/CircuitBreaker.html) — the pattern for containing a failing dependency. +- [Airflow: Retries & callbacks](https://airflow.apache.org/docs/apache-airflow/stable/core-concepts/tasks.html) — orchestrator-level retry and failure hooks. diff --git a/projects/data-engineering/advanced/10-self-healing-pipelines/README.pt-BR.md b/projects/data-engineering/advanced/10-self-healing-pipelines/README.pt-BR.md new file mode 100644 index 0000000..dadc1d6 --- /dev/null +++ b/projects/data-engineering/advanced/10-self-healing-pipelines/README.pt-BR.md @@ -0,0 +1,91 @@ +# Pipelines Autorrecuperáveis + +> 🌐 [English](./README.md) · **Português** + +**Domínio:** Data Engineering · **Nível:** Avançado · **Tempo estimado:** 1–2 semanas + +## Visão Geral + +Construa pipelines de dados que detectam suas próprias falhas e se recuperam automaticamente — retentando erros transitórios, colocando registros venenosos em quarentena, redirecionando ao redor de uma dependência morta e revertendo uma execução ruim — para que um humano seja acionado por novidade genuína, não pela mesma falha instável às 3 da manhã. O desafio de design é fazer isso *com segurança*: uma auto-remediação afoita demais pode amplificar um incidente (tempestades de retry martelando um downstream em dificuldade, um rollback que apaga dados bons). Você classificará falhas (transitória vs permanente), escolherá a resposta certa por classe (retry com backoff, circuit-break, quarentena, compensar/reverter), e adicionará health checks e detecção de anomalias para dispará-las. O tema é degradação graciosa com guardrails. A entrega é um pipeline que sobrevive a falhas injetadas com comportamento de recuperação documentado e limites de raio de impacto. + +## Pré-requisitos + +- Experiência construindo pipelines e um orquestrador (Airflow, Dagster, Temporal ou similar) +- Entendimento de estratégias de retry, idempotência e backoff exponencial +- Familiaridade com circuit breakers, dead-letter queues e health checks +- Conforto para raciocinar sobre modos de falha e raio de impacto + +## Objetivos de Aprendizado + +Ao final, você deve ser capaz de: + +- Classificar falhas como transitórias vs permanentes e responder apropriadamente a cada uma +- Implementar retries seguros com backoff exponencial e jitter, limitados por idempotência +- Usar circuit breakers e dead-letter/quarentena para conter uma dependência falha ou registros ruins +- Projetar compensação/rollback para que uma falha parcial deixe estado consistente +- Detectar anomalias (volume, latência, taxa de erro) que disparam remediação antes de uma falha dura + +## Requisitos Funcionais + +1. O pipeline deve distinguir falhas transitórias (retentáveis) das permanentes (não) e agir diferente em cada uma. +2. Falhas transitórias devem retentar com backoff exponencial e jitter, com teto, e apenas onde as operações são idempotentes. +3. Registros que falham repetidamente devem ir para quarentena em um dead-letter store, não bloquear o pipeline inteiro. +4. Uma dependência a jusante falha deve acionar um circuit breaker que para de martelá-la e recupera quando ela se cura. +5. Uma execução falha deve reverter ou compensar para que nenhuma saída parcial e inconsistente seja publicada. +6. Health checks e ao menos um sinal de anomalia devem conseguir disparar remediação automática, com toda ação registrada. + +## Marcos Sugeridos + +1. **Marco 1 — Retry e classificar:** Adicione classificação de falhas e retry-com-backoff idempotente; injete erros transitórios e observe a recuperação. +2. **Marco 2 — Conter:** Adicione um caminho de dead-letter/quarentena e um circuit breaker para uma dependência instável. +3. **Marco 3 — Rollback e detectar:** Adicione compensação/rollback para uma execução ruim e um detector de anomalias que dispara remediação, tudo auditado. + +## Esboço de Dados e Interface + +```text + ┌─────────── classificador de falhas ───────────┐ + [estágio] ─err─▶ transitória? ──sim──▶ retry(backoff, jitter, maxN) (só idempotente) + └ permanente? ──sim──▶ quarentena do registro ─▶ [dead-letter store] + (o pipeline segue fluindo) + +chamada a dependência ─▶ [circuit breaker] fechado -> permite | aberto -> falha rápido + pula + aciona em taxa_erro > limite; meio-aberto sonda para recuperar + +resultado da execução: + sucesso -> publicação atômica + falha -> compensar/reverter -> nenhuma saída parcial visível + +detector de anomalia: observa {volume_entrada, latência, taxa_erro} + desvio > k*desvio_padrão -> dispara remediação + ACIONA se não reconhecido + +guardrails: máximo de retries, cooldown do breaker, rate-limit de remediação +log de auditoria: toda ação automática { tempo, gatilho, ação, resultado } +``` + +## Desafios Extras + +- Adicione uma camada de "aprendizado" que rastreia assinaturas de falha recorrentes e sugere (ou aplica) uma correção conhecida. +- Implemente backfill automático de um lote em quarentena assim que a causa raiz for resolvida. +- Adicione teste de caos que injeta falhas aleatoriamente no CI para provar que a recuperação de fato funciona. + +## Definição de Pronto + +- [ ] Falhas transitórias e permanentes são classificadas e tratadas de forma diferente. +- [ ] Retries idempotentes com backoff+jitter limitados recuperam de erros transitórios injetados. +- [ ] Registros venenosos caem em um dead-letter store sem travar o pipeline. +- [ ] Um circuit breaker protege uma dependência instável e recupera automaticamente. +- [ ] Uma execução falha não deixa saída parcial; toda remediação automática é registrada e limitada por taxa. + +## Armadilhas Comuns + +- Tempestades de retry: retries ilimitados ou sem jitter transformam um soluço em uma queda autoinfligida. +- Retentar operações não idempotentes e aplicar efeitos colaterais em dobro. +- Auto-recuperar tão agressivamente que mascara um bug real — ninguém nunca descobre que o pipeline está quebrado. +- Rollback que apaga ou corrompe dados bons porque a compensação não foi escopada à execução falha. + +## Recursos + +- [Livro SRE do Google: Lidando com Sobrecarga e Falhas em Cascata](https://sre.google/sre-book/handling-overload/) — orçamentos de retry e load shedding bem feitos. +- [AWS: Timeouts, retries e backoff com jitter](https://aws.amazon.com/builders-library/timeouts-retries-and-backoff-with-jitter/) — a orientação canônica de retry seguro. +- [Martin Fowler: Circuit Breaker](https://martinfowler.com/bliki/CircuitBreaker.html) — o padrão para conter uma dependência falha. +- [Airflow: Retries e callbacks](https://airflow.apache.org/docs/apache-airflow/stable/core-concepts/tasks.html) — retry e hooks de falha no nível do orquestrador. diff --git a/projects/data-engineering/beginner/01-csv-to-database/README.md b/projects/data-engineering/beginner/01-csv-to-database/README.md index 320f4d8..bf1630d 100644 --- a/projects/data-engineering/beginner/01-csv-to-database/README.md +++ b/projects/data-engineering/beginner/01-csv-to-database/README.md @@ -1,34 +1,92 @@ # CSV to Database Loader -## Idea -Build a tool that reads CSV files and loads them into a database. Learn about data ingestion, validation, and database operations. +> 🌐 **English** · [Português](./README.pt-BR.md) + +**Domain:** Data Engineering · **Level:** Beginner · **Estimated time:** 3–6 hours + +## Overview + +Take a raw CSV file — the kind exported from a spreadsheet or a legacy system — and load it cleanly into a relational database table. Along the way you will confront the questions every ingestion job eventually asks: what type is each column, what do I do with the row that has a letter where a number belongs, and how do I re-run this tomorrow without doubling every record? This project keeps the scope small (one file, one table) so you can focus on doing the load *correctly* rather than *fast*, and it gives you a reusable mental model for the CSV-to-warehouse pattern that shows up everywhere in data work. + +## Prerequisites + +- Basic Python (or a language with a CSV library and a DB driver) +- A relational database you can run locally (SQLite needs no setup; Postgres is a good next step) +- Comfort writing simple `CREATE TABLE` and `INSERT` statements +- Understanding of what a primary key is and why it matters ## Learning Objectives -- Read CSV files programmatically -- Validate data before loading -- Create database schema -- Perform bulk inserts -- Handle errors and logging - -## Implementation Tips -- Create CSV parser -- Implement data validation -- Generate database schema -- Handle data type inference -- Implement bulk insert operations -- Add error handling and recovery -- Create progress tracking -- Add duplicate detection -- Implement transaction support -- Create detailed logging -- Add data quality checks -- Implement retry logic -- Create performance monitoring -- Build command-line interface - -## Key Challenges -- Large file handling -- Schema inference accuracy -- Data type mismatches -- Duplicate detection -- Performance optimization + +By the end, you should be able to: + +- Stream a CSV file row by row instead of loading it all into memory +- Infer or declare a column type and coerce string values into it +- Design a table schema that matches your source data +- Perform inserts in batches inside a transaction +- Skip or quarantine malformed rows without aborting the whole load +- Make the loader idempotent so a re-run does not create duplicates + +## Functional Requirements + +1. The tool must read a CSV with a header row and map each column to a table field by name, not position. +2. The tool must create the target table if it does not already exist. +3. Each value must be coerced to its declared type; a row that fails coercion must be rejected, logged with its line number, and skipped — never silently dropped. +4. Rows must be inserted inside a transaction so a mid-load failure leaves no partial batch behind. +5. Re-running the loader on the same file must not create duplicate rows (use a natural or primary key). +6. On completion, the tool must report counts: rows read, inserted, and rejected. + +## Suggested Milestones + +1. **Milestone 1 — Parse & print:** Read the CSV and print typed rows to the console; no database yet. +2. **Milestone 2 — Load:** Create the table and insert rows in batched transactions. +3. **Milestone 3 — Robustness:** Add type coercion with a rejects log, idempotent re-runs, and a summary report. + +## Data & Interface Sketch + +```text +source: users.csv + id,name,signup_date,score + 1,Ana,2024-01-05,88 + +transform: + id -> INTEGER (reject if not parseable) + name -> TEXT (trim whitespace) + signup_date -> DATE (parse ISO-8601) + score -> REAL (NULL if blank) + +target table: users (id PRIMARY KEY, name, signup_date, score) + +rejects.log: line 42: score="N/A" not a number -> skipped + +CLI: loader --file users.csv --table users --batch 500 +summary: read=1000 inserted=987 rejected=13 +``` + +## Stretch Goals + +- Infer column types automatically by sampling the first N rows. +- Support "upsert" so existing keys are updated instead of skipped. +- Add a `--dry-run` flag that validates without writing. +- Stream a gzipped CSV without fully decompressing to disk. + +## Definition of Done + +- [ ] A well-formed CSV loads fully into the table with correct types. +- [ ] Malformed rows are logged with line numbers and skipped. +- [ ] Running the loader twice yields the same row count as once. +- [ ] A failure mid-load rolls back the current transaction cleanly. +- [ ] The final summary reports read, inserted, and rejected counts. + +## Common Pitfalls + +- Reading the whole file into memory — use a streaming reader so large files do not exhaust RAM. +- Inserting one row per statement, which is slow; batch inside a transaction instead. +- Treating empty strings as valid numbers or dates; decide on NULL handling explicitly. +- Assuming column positions never change instead of mapping by header name. + +## Resources + +- [Python `csv` module](https://docs.python.org/3/library/csv.html) — the standard streaming CSV reader. +- [SQLite documentation](https://www.sqlite.org/docs.html) — zero-setup database ideal for this project. +- [PostgreSQL `COPY`](https://www.postgresql.org/docs/current/sql-copy.html) — the fast bulk-load path once you outgrow row inserts. +- [pandas `read_csv`](https://pandas.pydata.org/docs/reference/api/pandas.read_csv.html) — a higher-level option worth comparing against manual parsing. diff --git a/projects/data-engineering/beginner/01-csv-to-database/README.pt-BR.md b/projects/data-engineering/beginner/01-csv-to-database/README.pt-BR.md new file mode 100644 index 0000000..1882bf7 --- /dev/null +++ b/projects/data-engineering/beginner/01-csv-to-database/README.pt-BR.md @@ -0,0 +1,92 @@ +# Carregador de CSV para Banco de Dados + +> 🌐 [English](./README.md) · **Português** + +**Domínio:** Data Engineering · **Nível:** Iniciante · **Tempo estimado:** 3–6 horas + +## Visão Geral + +Pegue um arquivo CSV bruto — do tipo exportado de uma planilha ou de um sistema legado — e carregue-o de forma limpa em uma tabela de banco de dados relacional. No caminho você vai encarar as perguntas que todo job de ingestão acaba fazendo: qual é o tipo de cada coluna, o que faço com a linha que tem uma letra onde deveria haver um número, e como re-executo isso amanhã sem duplicar todos os registros? Este projeto mantém o escopo pequeno (um arquivo, uma tabela) para você focar em fazer a carga *corretamente* em vez de *rápido*, e te dá um modelo mental reutilizável para o padrão CSV-para-warehouse que aparece em toda parte no trabalho com dados. + +## Pré-requisitos + +- Python básico (ou uma linguagem com biblioteca de CSV e driver de banco) +- Um banco relacional que você consiga rodar localmente (SQLite não exige configuração; Postgres é um bom próximo passo) +- Conforto para escrever comandos simples de `CREATE TABLE` e `INSERT` +- Entender o que é uma chave primária e por que ela importa + +## Objetivos de Aprendizado + +Ao final, você deve ser capaz de: + +- Ler um arquivo CSV linha a linha em vez de carregá-lo todo na memória +- Inferir ou declarar o tipo de uma coluna e converter valores de texto para ele +- Projetar um esquema de tabela que corresponda aos seus dados de origem +- Realizar inserções em lotes dentro de uma transação +- Pular ou colocar em quarentena linhas malformadas sem abortar toda a carga +- Tornar o carregador idempotente para que uma re-execução não crie duplicatas + +## Requisitos Funcionais + +1. A ferramenta deve ler um CSV com linha de cabeçalho e mapear cada coluna para um campo da tabela por nome, não por posição. +2. A ferramenta deve criar a tabela de destino caso ela ainda não exista. +3. Cada valor deve ser convertido para o tipo declarado; uma linha que falhar na conversão deve ser rejeitada, registrada com seu número de linha e pulada — nunca descartada silenciosamente. +4. As linhas devem ser inseridas dentro de uma transação para que uma falha no meio da carga não deixe um lote parcial. +5. Re-executar o carregador no mesmo arquivo não deve criar linhas duplicadas (use uma chave natural ou primária). +6. Ao concluir, a ferramenta deve reportar contagens: linhas lidas, inseridas e rejeitadas. + +## Marcos Sugeridos + +1. **Marco 1 — Analisar e imprimir:** Leia o CSV e imprima as linhas tipadas no console; ainda sem banco de dados. +2. **Marco 2 — Carregar:** Crie a tabela e insira as linhas em transações em lote. +3. **Marco 3 — Robustez:** Adicione conversão de tipos com um log de rejeições, re-execuções idempotentes e um relatório de resumo. + +## Esboço de Dados e Interface + +```text +origem: users.csv + id,name,signup_date,score + 1,Ana,2024-01-05,88 + +transformação: + id -> INTEGER (rejeita se não for parseável) + name -> TEXT (remove espaços) + signup_date -> DATE (parse ISO-8601) + score -> REAL (NULL se vazio) + +tabela de destino: users (id PRIMARY KEY, name, signup_date, score) + +rejects.log: linha 42: score="N/A" não é número -> pulada + +CLI: loader --file users.csv --table users --batch 500 +resumo: lidas=1000 inseridas=987 rejeitadas=13 +``` + +## Desafios Extras + +- Inferir os tipos das colunas automaticamente amostrando as primeiras N linhas. +- Suportar "upsert" para que chaves existentes sejam atualizadas em vez de puladas. +- Adicionar uma flag `--dry-run` que valida sem escrever. +- Ler um CSV compactado com gzip sem descomprimi-lo totalmente em disco. + +## Definição de Pronto + +- [ ] Um CSV bem-formado carrega totalmente na tabela com os tipos corretos. +- [ ] Linhas malformadas são registradas com números de linha e puladas. +- [ ] Rodar o carregador duas vezes resulta na mesma contagem de linhas que uma vez. +- [ ] Uma falha no meio da carga faz rollback da transação atual de forma limpa. +- [ ] O resumo final reporta contagens de lidas, inseridas e rejeitadas. + +## Armadilhas Comuns + +- Ler o arquivo inteiro na memória — use um leitor em streaming para que arquivos grandes não esgotem a RAM. +- Inserir uma linha por comando, o que é lento; agrupe em lotes dentro de uma transação. +- Tratar strings vazias como números ou datas válidos; decida o tratamento de NULL explicitamente. +- Assumir que as posições das colunas nunca mudam em vez de mapear pelo nome do cabeçalho. + +## Recursos + +- [Módulo `csv` do Python](https://docs.python.org/3/library/csv.html) — o leitor de CSV em streaming padrão. +- [Documentação do SQLite](https://www.sqlite.org/docs.html) — banco sem configuração, ideal para este projeto. +- [PostgreSQL `COPY`](https://www.postgresql.org/docs/current/sql-copy.html) — o caminho rápido de carga em massa quando você superar as inserções linha a linha. +- [pandas `read_csv`](https://pandas.pydata.org/docs/reference/api/pandas.read_csv.html) — uma opção de mais alto nível que vale comparar com o parsing manual. diff --git a/projects/data-engineering/beginner/02-simple-etl/README.md b/projects/data-engineering/beginner/02-simple-etl/README.md index f33ce1c..195918f 100644 --- a/projects/data-engineering/beginner/02-simple-etl/README.md +++ b/projects/data-engineering/beginner/02-simple-etl/README.md @@ -1,34 +1,93 @@ # Simple ETL Pipeline -## Idea -Create a simple Extract-Transform-Load pipeline that moves data from source to destination. Learn about data workflows and transformations. +> 🌐 **English** · [Português](./README.pt-BR.md) + +**Domain:** Data Engineering · **Level:** Beginner · **Estimated time:** 3–6 hours + +## Overview + +Build a small Extract-Transform-Load pipeline that reads records from one place, reshapes them, and writes them somewhere else. The classic beginner version: pull rows from a source file or table, clean and enrich them, and land them in a destination table. The value here is not any single step but the *shape* of the whole — three clearly separated stages joined by a well-defined record format. Once you can see extract, transform, and load as independent, testable functions, you have the backbone that every data pipeline, no matter how large, is built on. + +## Prerequisites + +- Comfort reading and writing files or a simple database (see [CSV to Database Loader](../01-csv-to-database/) first if that is new) +- Basic functions and data structures in your language of choice +- Understanding of what a record/row looks like as a dictionary or object +- Familiarity with running a script from the command line ## Learning Objectives -- Implement data extraction -- Apply transformations -- Load into destination -- Handle errors -- Monitor pipeline execution - -## Implementation Tips -- Create data source connectors -- Implement transformation logic -- Create load strategies -- Add error handling -- Implement logging and monitoring -- Create data validation -- Add transformation reusability -- Implement incremental loads -- Create scheduling -- Add recovery mechanisms -- Implement data lineage tracking -- Create performance metrics -- Add alerting -- Build pipeline orchestration - -## Key Challenges -- Data quality assurance -- Transformation complexity -- Error handling and recovery -- Performance optimization -- Data consistency + +By the end, you should be able to: + +- Separate a pipeline into distinct extract, transform, and load stages +- Model an in-flight record as a plain data structure passed between stages +- Apply field-level transformations: renaming, deriving, and type-casting +- Route bad records to a rejects sink instead of crashing the run +- Emit run metadata (counts, duration) so a pipeline is observable +- Design the transform stage to be pure and unit-testable + +## Functional Requirements + +1. The pipeline must have three separable stages, each callable independently for testing. +2. Extract must read from a defined source and yield records one at a time. +3. Transform must apply at least three operations: a rename, a derived field, and a type cast. +4. A record that fails transformation must be sent to a rejects sink with the reason, not halt the pipeline. +5. Load must write valid records to the destination and be safe to re-run. +6. The pipeline must print a summary: records extracted, loaded, and rejected, plus elapsed time. + +## Suggested Milestones + +1. **Milestone 1 — Extract & pass through:** Read the source and load unchanged records to the destination. +2. **Milestone 2 — Transform:** Insert the transform stage with renames, derived fields, and casts. +3. **Milestone 3 — Resilience & reporting:** Add the rejects sink and a run summary with counts and timing. + +## Data & Interface Sketch + +```text +extract (source: sales.csv) + {"order":"A1","amount":"19.90","ts":"2024-03-01T10:00Z"} + +transform + order -> order_id (rename) + amount -> amount_cents (float * 100 -> int; reject if not numeric) + ts -> order_date (derive date from timestamp) + +load (target: orders table) + order_id | amount_cents | order_date + +rejects sink -> rejects.jsonl + {"record": {...}, "reason": "amount not numeric"} + +flow: extract -> transform -> [ok] load + \-> [bad] rejects +summary: extracted=500 loaded=492 rejected=8 elapsed=1.4s +``` + +## Stretch Goals + +- Add incremental extraction using a high-water mark (only new rows since last run). +- Make the transform config-driven so mappings live in a file, not code. +- Support multiple destinations (a table plus a Parquet file) from one run. +- Add a `--limit` flag to process a sample for quick iteration. + +## Definition of Done + +- [ ] Each stage can be called and tested in isolation. +- [ ] A valid source runs end-to-end and lands correct records. +- [ ] Bad records land in the rejects sink with a reason and do not stop the run. +- [ ] Re-running the pipeline does not duplicate loaded records. +- [ ] The summary reports extracted, loaded, and rejected counts plus timing. + +## Common Pitfalls + +- Fusing all three stages into one function, making anything untestable. +- Letting one bad record throw and kill the whole batch. +- Mutating source records in place instead of producing new transformed ones. +- Forgetting timezone or format normalization when deriving dates. + +## Resources + +- [Python Functional Programming HOWTO](https://docs.python.org/3/howto/functional.html) — generators and pure functions for pipeline stages. +- [Wikipedia: Extract, transform, load](https://en.wikipedia.org/wiki/Extract,_transform,_load) — the pattern and its vocabulary. +- [Apache Airflow concepts](https://airflow.apache.org/docs/apache-airflow/stable/core-concepts/overview.html) — how the industry orchestrates real ETL, worth reading for context. +- [petl documentation](https://petl.readthedocs.io/en/stable/) — a lightweight Python ETL library to compare your hand-rolled version against. diff --git a/projects/data-engineering/beginner/02-simple-etl/README.pt-BR.md b/projects/data-engineering/beginner/02-simple-etl/README.pt-BR.md new file mode 100644 index 0000000..9b2e9c1 --- /dev/null +++ b/projects/data-engineering/beginner/02-simple-etl/README.pt-BR.md @@ -0,0 +1,93 @@ +# Pipeline ETL Simples + +> 🌐 [English](./README.md) · **Português** + +**Domínio:** Data Engineering · **Nível:** Iniciante · **Tempo estimado:** 3–6 horas + +## Visão Geral + +Construa um pequeno pipeline de Extract-Transform-Load (Extrair-Transformar-Carregar) que lê registros de um lugar, os remodela e os grava em outro. A versão clássica para iniciantes: puxe linhas de um arquivo ou tabela de origem, limpe e enriqueça-as, e as deposite em uma tabela de destino. O valor aqui não está em nenhuma etapa isolada, mas no *formato* do todo — três estágios claramente separados unidos por um formato de registro bem definido. Quando você conseguir enxergar extração, transformação e carga como funções independentes e testáveis, você terá a espinha dorsal sobre a qual todo pipeline de dados, por maior que seja, é construído. + +## Pré-requisitos + +- Conforto para ler e escrever arquivos ou um banco de dados simples (veja [Carregador de CSV para Banco de Dados](../01-csv-to-database/) primeiro, se isso for novo) +- Funções e estruturas de dados básicas na linguagem de sua escolha +- Entender como um registro/linha se parece como um dicionário ou objeto +- Familiaridade com a execução de um script pela linha de comando + +## Objetivos de Aprendizado + +Ao final, você deve ser capaz de: + +- Separar um pipeline em estágios distintos de extração, transformação e carga +- Modelar um registro em trânsito como uma estrutura de dados simples passada entre os estágios +- Aplicar transformações no nível de campo: renomear, derivar e converter tipos +- Rotear registros ruins para um destino de rejeições em vez de travar a execução +- Emitir metadados da execução (contagens, duração) para que o pipeline seja observável +- Projetar o estágio de transformação para ser puro e testável por testes unitários + +## Requisitos Funcionais + +1. O pipeline deve ter três estágios separáveis, cada um chamável de forma independente para testes. +2. A extração deve ler de uma origem definida e produzir registros um a um. +3. A transformação deve aplicar ao menos três operações: uma renomeação, um campo derivado e uma conversão de tipo. +4. Um registro que falhar na transformação deve ser enviado a um destino de rejeições com o motivo, sem parar o pipeline. +5. A carga deve gravar registros válidos no destino e ser segura para re-execução. +6. O pipeline deve imprimir um resumo: registros extraídos, carregados e rejeitados, além do tempo decorrido. + +## Marcos Sugeridos + +1. **Marco 1 — Extrair e repassar:** Leia a origem e carregue registros inalterados no destino. +2. **Marco 2 — Transformar:** Insira o estágio de transformação com renomeações, campos derivados e conversões. +3. **Marco 3 — Resiliência e relatório:** Adicione o destino de rejeições e um resumo da execução com contagens e tempo. + +## Esboço de Dados e Interface + +```text +extração (origem: sales.csv) + {"order":"A1","amount":"19.90","ts":"2024-03-01T10:00Z"} + +transformação + order -> order_id (renomeia) + amount -> amount_cents (float * 100 -> int; rejeita se não numérico) + ts -> order_date (deriva a data do timestamp) + +carga (destino: tabela orders) + order_id | amount_cents | order_date + +destino de rejeições -> rejects.jsonl + {"record": {...}, "reason": "amount não numérico"} + +fluxo: extração -> transformação -> [ok] carga + \-> [ruim] rejeições +resumo: extraídos=500 carregados=492 rejeitados=8 tempo=1.4s +``` + +## Desafios Extras + +- Adicionar extração incremental usando uma marca d'água (só linhas novas desde a última execução). +- Tornar a transformação orientada por configuração para que os mapeamentos morem em um arquivo, não no código. +- Suportar múltiplos destinos (uma tabela mais um arquivo Parquet) em uma única execução. +- Adicionar uma flag `--limit` para processar uma amostra para iteração rápida. + +## Definição de Pronto + +- [ ] Cada estágio pode ser chamado e testado isoladamente. +- [ ] Uma origem válida roda de ponta a ponta e deposita registros corretos. +- [ ] Registros ruins caem no destino de rejeições com um motivo e não param a execução. +- [ ] Re-executar o pipeline não duplica registros carregados. +- [ ] O resumo reporta contagens de extraídos, carregados e rejeitados, além do tempo. + +## Armadilhas Comuns + +- Fundir os três estágios em uma única função, tornando tudo não testável. +- Deixar um registro ruim lançar exceção e matar o lote inteiro. +- Mutar registros de origem no lugar em vez de produzir novos transformados. +- Esquecer da normalização de fuso horário ou de formato ao derivar datas. + +## Recursos + +- [Python Functional Programming HOWTO](https://docs.python.org/3/howto/functional.html) — geradores e funções puras para estágios de pipeline. +- [Wikipedia: Extract, transform, load](https://en.wikipedia.org/wiki/Extract,_transform,_load) — o padrão e seu vocabulário. +- [Conceitos do Apache Airflow](https://airflow.apache.org/docs/apache-airflow/stable/core-concepts/overview.html) — como a indústria orquestra ETL real, vale ler para contexto. +- [Documentação do petl](https://petl.readthedocs.io/en/stable/) — uma biblioteca leve de ETL em Python para comparar com sua versão feita à mão. diff --git a/projects/data-engineering/beginner/03-data-validation/README.md b/projects/data-engineering/beginner/03-data-validation/README.md index 5d50cb6..9a106fa 100644 --- a/projects/data-engineering/beginner/03-data-validation/README.md +++ b/projects/data-engineering/beginner/03-data-validation/README.md @@ -1,34 +1,94 @@ # Data Validation Script -## Idea -Create a script to validate data quality and enforce data constraints. Learn about data quality patterns and validation rules. +> 🌐 **English** · [Português](./README.pt-BR.md) + +**Domain:** Data Engineering · **Level:** Beginner · **Estimated time:** 3–6 hours + +## Overview + +Before data can be trusted, it has to be checked. Build a script that takes a dataset and a set of rules — "this column is required," "this must be a positive number," "emails must look like emails" — and produces a report of exactly which rows broke which rule. This is the guardrail that sits at the front door of every serious pipeline: it turns "the data looks weird" into a precise, line-by-line diagnosis. The interesting design work is not the checks themselves but how you express rules cleanly and how you report failures so a human can actually act on them. + +## Prerequisites + +- Ability to read a CSV or JSON dataset (see [CSV to Database Loader](../01-csv-to-database/) if new) +- Comfort with conditionals, loops, and basic string handling +- Familiarity with regular expressions at a beginner level +- Understanding of data types: string, number, date, boolean ## Learning Objectives -- Define validation rules -- Check data constraints -- Generate validation reports -- Handle invalid data -- Create quality metrics - -## Implementation Tips -- Define schema validation -- Implement constraint checks (NOT NULL, UNIQUE, FOREIGN KEY) -- Add format validation -- Create range checks -- Implement completeness checks -- Add referential integrity checks -- Create data profiling -- Generate quality reports -- Implement rule engine -- Add custom validation rules -- Create anomaly detection -- Implement statistical validation -- Add logging of violations -- Create corrective actions - -## Key Challenges -- Rule complexity -- Performance at scale -- False positive rates -- Handling edge cases -- Real-time validation + +By the end, you should be able to: + +- Express validation rules as data or small functions rather than tangled `if` blocks +- Distinguish structural checks (type, required) from semantic checks (range, format) +- Collect *all* violations for a row instead of stopping at the first +- Produce a human-readable report and a machine-readable one +- Compute quality metrics like completeness and validity rates per column +- Exit with a status code that a scheduler or CI job can react to + +## Functional Requirements + +1. The script must accept a dataset and a rule set describing per-column constraints. +2. It must support at least: required/NOT NULL, type check, numeric range, and regex format. +3. Every row must be checked against all applicable rules, collecting every failure, not just the first. +4. The output must include a summary (rows checked, rows with errors, error count per rule) and per-row detail. +5. A machine-readable report (JSON or CSV of violations) must be written for downstream use. +6. The process must exit non-zero when any rule fails, so automation can gate on it. + +## Suggested Milestones + +1. **Milestone 1 — One rule:** Check a single required-column rule and print failing row numbers. +2. **Milestone 2 — Rule set:** Support multiple rule types read from a config and collect all violations per row. +3. **Milestone 3 — Reporting:** Emit a summary, a violations file, quality metrics, and a proper exit code. + +## Data & Interface Sketch + +```text +rule set (config) + age -> {required: true, type: int, min: 0, max: 120} + email -> {required: true, regex: "^[^@]+@[^@]+\\.[^@]+$"} + status -> {allowed: ["active","churned","trial"]} + +input row (line 7) + {"age": "-3", "email": "bob@", "status": "active"} + +violations collected + line 7 age -> below min (0) + line 7 email -> fails regex + +report summary + rows=1000 clean=944 with_errors=56 + by_rule: age.min=12 email.regex=31 status.allowed=13 + metrics: email.validity=96.9% age.completeness=99.1% + +exit code: 1 (violations present) +``` + +## Stretch Goals + +- Add cross-field rules (e.g. `end_date` must be after `start_date`). +- Support uniqueness checks across the whole dataset (detect duplicate keys). +- Add simple statistical anomaly flags (values beyond N standard deviations). +- Make rule severity configurable (error vs warning) and only fail on errors. + +## Definition of Done + +- [ ] Rules are defined as configuration, not hard-coded per dataset. +- [ ] Every failing row lists all of its violations, not just one. +- [ ] Both a human summary and a machine-readable violations file are produced. +- [ ] Quality metrics per column are reported. +- [ ] The script exits non-zero exactly when violations exist. + +## Common Pitfalls + +- Stopping at the first error in a row, hiding the other problems from the user. +- Treating an empty string, `null`, and a missing key as the same without deciding intentionally. +- Regexes that are too strict (rejecting valid emails) or too loose (accepting junk). +- Reporting only counts without line numbers, so nobody can find the bad rows. + +## Resources + +- [Great Expectations docs](https://docs.greatexpectations.io/docs/home/) — the reference vocabulary for data validation "expectations". +- [Pandera documentation](https://pandera.readthedocs.io/en/stable/) — schema and statistical validation for dataframes. +- [MDN: Regular expressions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_expressions) — a solid, practical regex primer. +- [JSON Schema](https://json-schema.org/learn/getting-started-step-by-step) — a standard way to express structural validation rules. diff --git a/projects/data-engineering/beginner/03-data-validation/README.pt-BR.md b/projects/data-engineering/beginner/03-data-validation/README.pt-BR.md new file mode 100644 index 0000000..676595d --- /dev/null +++ b/projects/data-engineering/beginner/03-data-validation/README.pt-BR.md @@ -0,0 +1,94 @@ +# Script de Validação de Dados + +> 🌐 [English](./README.md) · **Português** + +**Domínio:** Data Engineering · **Nível:** Iniciante · **Tempo estimado:** 3–6 horas + +## Visão Geral + +Antes que os dados possam ser confiados, eles precisam ser verificados. Construa um script que recebe um conjunto de dados e um conjunto de regras — "esta coluna é obrigatória", "isto deve ser um número positivo", "e-mails devem parecer e-mails" — e produz um relatório de exatamente quais linhas quebraram quais regras. Este é o guarda-corpo que fica na porta de entrada de todo pipeline sério: transforma "os dados parecem estranhos" em um diagnóstico preciso, linha a linha. O trabalho de design interessante não são as verificações em si, mas como você expressa regras de forma limpa e como reporta falhas para que um humano consiga de fato agir sobre elas. + +## Pré-requisitos + +- Capacidade de ler um conjunto de dados CSV ou JSON (veja [Carregador de CSV para Banco de Dados](../01-csv-to-database/) se for novo) +- Conforto com condicionais, laços e manipulação básica de strings +- Familiaridade com expressões regulares em nível iniciante +- Entender tipos de dados: string, número, data, booleano + +## Objetivos de Aprendizado + +Ao final, você deve ser capaz de: + +- Expressar regras de validação como dados ou pequenas funções em vez de blocos `if` emaranhados +- Distinguir verificações estruturais (tipo, obrigatório) de verificações semânticas (faixa, formato) +- Coletar *todas* as violações de uma linha em vez de parar na primeira +- Produzir um relatório legível por humanos e outro legível por máquinas +- Calcular métricas de qualidade como taxas de completude e validade por coluna +- Sair com um código de status ao qual um agendador ou job de CI possa reagir + +## Requisitos Funcionais + +1. O script deve aceitar um conjunto de dados e um conjunto de regras descrevendo restrições por coluna. +2. Deve suportar ao menos: obrigatório/NOT NULL, verificação de tipo, faixa numérica e formato via regex. +3. Cada linha deve ser verificada contra todas as regras aplicáveis, coletando toda falha, não apenas a primeira. +4. A saída deve incluir um resumo (linhas verificadas, linhas com erros, contagem de erros por regra) e detalhe por linha. +5. Um relatório legível por máquina (JSON ou CSV de violações) deve ser gravado para uso downstream. +6. O processo deve sair com código diferente de zero quando qualquer regra falhar, para que a automação possa barrar a execução. + +## Marcos Sugeridos + +1. **Marco 1 — Uma regra:** Verifique uma única regra de coluna obrigatória e imprima os números das linhas que falharem. +2. **Marco 2 — Conjunto de regras:** Suporte múltiplos tipos de regra lidos de uma configuração e colete todas as violações por linha. +3. **Marco 3 — Relatório:** Emita um resumo, um arquivo de violações, métricas de qualidade e um código de saída adequado. + +## Esboço de Dados e Interface + +```text +conjunto de regras (config) + age -> {required: true, type: int, min: 0, max: 120} + email -> {required: true, regex: "^[^@]+@[^@]+\\.[^@]+$"} + status -> {allowed: ["active","churned","trial"]} + +linha de entrada (linha 7) + {"age": "-3", "email": "bob@", "status": "active"} + +violações coletadas + linha 7 age -> abaixo do min (0) + linha 7 email -> falha no regex + +resumo do relatório + linhas=1000 limpas=944 com_erros=56 + por_regra: age.min=12 email.regex=31 status.allowed=13 + métricas: email.validade=96.9% age.completude=99.1% + +código de saída: 1 (há violações) +``` + +## Desafios Extras + +- Adicionar regras entre campos (ex.: `end_date` deve ser posterior a `start_date`). +- Suportar verificações de unicidade em todo o conjunto de dados (detectar chaves duplicadas). +- Adicionar sinalizadores simples de anomalia estatística (valores além de N desvios-padrão). +- Tornar a severidade das regras configurável (erro vs aviso) e falhar apenas em erros. + +## Definição de Pronto + +- [ ] As regras são definidas como configuração, não codificadas por conjunto de dados. +- [ ] Cada linha com falha lista todas as suas violações, não apenas uma. +- [ ] Tanto um resumo humano quanto um arquivo de violações legível por máquina são produzidos. +- [ ] Métricas de qualidade por coluna são reportadas. +- [ ] O script sai com código diferente de zero exatamente quando há violações. + +## Armadilhas Comuns + +- Parar no primeiro erro de uma linha, escondendo os outros problemas do usuário. +- Tratar uma string vazia, `null` e uma chave ausente como a mesma coisa sem decidir intencionalmente. +- Regexes rígidas demais (rejeitando e-mails válidos) ou frouxas demais (aceitando lixo). +- Reportar apenas contagens sem números de linha, de modo que ninguém consegue achar as linhas ruins. + +## Recursos + +- [Documentação do Great Expectations](https://docs.greatexpectations.io/docs/home/) — o vocabulário de referência para "expectativas" de validação de dados. +- [Documentação do Pandera](https://pandera.readthedocs.io/en/stable/) — validação de esquema e estatística para dataframes. +- [MDN: Expressões regulares](https://developer.mozilla.org/pt-BR/docs/Web/JavaScript/Guide/Regular_expressions) — uma introdução prática e sólida a regex. +- [JSON Schema](https://json-schema.org/learn/getting-started-step-by-step) — uma forma padrão de expressar regras de validação estrutural. diff --git a/projects/data-engineering/beginner/04-log-parser/README.md b/projects/data-engineering/beginner/04-log-parser/README.md index eeb1ad0..09e1f02 100644 --- a/projects/data-engineering/beginner/04-log-parser/README.md +++ b/projects/data-engineering/beginner/04-log-parser/README.md @@ -1,34 +1,94 @@ # Log Parser -## Idea -Build a tool that parses log files and extracts structured information. Learn about text parsing and data extraction. +> 🌐 **English** · [Português](./README.pt-BR.md) + +**Domain:** Data Engineering · **Level:** Beginner · **Estimated time:** 3–6 hours + +## Overview + +Server logs arrive as walls of text, but hidden inside each line is a structured record: a timestamp, a level, a source, a message. Build a tool that reads a log file, extracts those fields into clean records, and lets you filter and summarize them — how many errors in the last hour, which endpoint is slowest, what the top messages are. This is the foundational skill behind every observability pipeline: turning free-form text into queryable data. The heart of the project is a robust parser that handles the lines that *almost* match the format without falling over. + +## Prerequisites + +- Comfort reading files line by line +- Beginner-level regular expressions or knowledge of a structured log format (JSON lines) +- Basic understanding of timestamps and time ranges +- Familiarity with dictionaries/maps for grouping and counting ## Learning Objectives -- Parse unstructured logs -- Extract relevant information -- Create structured records -- Filter and query logs -- Generate summaries - -## Implementation Tips -- Define log format patterns (regex, structured parsers) -- Implement parsing engine -- Extract key fields (timestamp, level, message) -- Create filtering capabilities -- Add aggregation functions -- Create statistics generation -- Implement search functionality -- Add export formats -- Create visualization -- Handle different log formats -- Implement performance optimization -- Add streaming support -- Create error detection -- Build user interface - -## Key Challenges -- Variable log formats -- Large log file processing -- Regex complexity -- Performance at scale -- Storage optimization + +By the end, you should be able to: + +- Define a log line format and parse it into named fields +- Handle both a fixed text format (via regex) and structured JSON lines +- Deal gracefully with lines that do not match — count them, don't crash +- Filter records by level, time window, or field value +- Aggregate: counts by level, top-N messages, requests per minute +- Stream a large file without loading it entirely into memory + +## Functional Requirements + +1. The tool must parse each line into a record with at least timestamp, level, and message. +2. It must support a configurable line format (regex pattern or JSON) rather than hard-coding one. +3. Lines that fail to parse must be counted and optionally written to an "unparsed" file, never dropped silently. +4. The tool must filter records by level and by a time range given on the command line. +5. It must produce aggregations: count per level and the top-N most frequent messages. +6. It must process files line by line so arbitrarily large logs are handled. + +## Suggested Milestones + +1. **Milestone 1 — Parse:** Turn each matching line into a structured record and print it. +2. **Milestone 2 — Filter:** Add level and time-range filtering over the parsed records. +3. **Milestone 3 — Aggregate & report:** Add counts per level, top-N messages, and unparsed-line handling. + +## Data & Interface Sketch + +```text +source line (Apache-ish) + 2024-05-01T10:15:03Z ERROR api order-service "db timeout" 503 + +parse pattern (regex, named groups) + (?P\S+) (?P\w+) (?P\S+) (?P\S+) "(?P[^"]*)" (?P\d+) + +structured record + { ts, level, component, service, message, status } + +unparsed lines -> unparsed.log (with line number) + +query flow + read -> parse -> [ok] filter(level>=WARN, ts in window) -> aggregate + \-> [no match] count + unparsed sink + +report + by_level: INFO=8210 WARN=145 ERROR=37 + top_messages: "db timeout" x22, "retry" x15 +``` + +## Stretch Goals + +- Auto-detect the format (JSON vs text) by sniffing the first lines. +- Add a `--follow` mode that tails the file and parses new lines as they arrive. +- Compute latency percentiles if a duration field is present. +- Support gzip-compressed log files transparently. + +## Definition of Done + +- [ ] Well-formed lines parse into records with all expected fields. +- [ ] Unmatched lines are counted and preserved, not silently discarded. +- [ ] Level and time-range filters return the correct subset. +- [ ] Counts per level and top-N messages are accurate. +- [ ] A multi-hundred-MB file processes without exhausting memory. + +## Common Pitfalls + +- A brittle regex that breaks on quoted fields, extra spaces, or multiline messages. +- Parsing timestamps without handling timezones, so time-range filters are off. +- Loading the whole file into a list before processing large logs. +- Silently skipping unparsed lines and hiding a format drift you should know about. + +## Resources + +- [Python `re` module](https://docs.python.org/3/library/re.html) — named groups make log patterns readable. +- [regex101](https://regex101.com/) — build and test log patterns interactively. +- [The Twelve-Factor App: Logs](https://12factor.net/logs) — why treating logs as event streams matters. +- [Elastic: Grok processor](https://www.elastic.co/guide/en/elasticsearch/reference/current/grok-processor.html) — how a production system names log-field patterns. diff --git a/projects/data-engineering/beginner/04-log-parser/README.pt-BR.md b/projects/data-engineering/beginner/04-log-parser/README.pt-BR.md new file mode 100644 index 0000000..6c9546c --- /dev/null +++ b/projects/data-engineering/beginner/04-log-parser/README.pt-BR.md @@ -0,0 +1,94 @@ +# Analisador de Logs + +> 🌐 [English](./README.md) · **Português** + +**Domínio:** Data Engineering · **Nível:** Iniciante · **Tempo estimado:** 3–6 horas + +## Visão Geral + +Logs de servidor chegam como paredes de texto, mas escondido dentro de cada linha há um registro estruturado: um timestamp, um nível, uma origem, uma mensagem. Construa uma ferramenta que lê um arquivo de log, extrai esses campos em registros limpos e permite filtrá-los e resumi-los — quantos erros na última hora, qual endpoint está mais lento, quais são as mensagens mais frequentes. Esta é a habilidade fundamental por trás de todo pipeline de observabilidade: transformar texto livre em dados consultáveis. O coração do projeto é um analisador robusto que lida com as linhas que *quase* correspondem ao formato sem quebrar. + +## Pré-requisitos + +- Conforto para ler arquivos linha a linha +- Expressões regulares em nível iniciante ou conhecimento de um formato de log estruturado (JSON lines) +- Entendimento básico de timestamps e intervalos de tempo +- Familiaridade com dicionários/mapas para agrupar e contar + +## Objetivos de Aprendizado + +Ao final, você deve ser capaz de: + +- Definir um formato de linha de log e analisá-lo em campos nomeados +- Lidar tanto com um formato de texto fixo (via regex) quanto com JSON lines estruturado +- Tratar com elegância as linhas que não correspondem — conte-as, não trave +- Filtrar registros por nível, janela de tempo ou valor de campo +- Agregar: contagens por nível, top-N mensagens, requisições por minuto +- Ler um arquivo grande em streaming sem carregá-lo inteiro na memória + +## Requisitos Funcionais + +1. A ferramenta deve analisar cada linha em um registro com ao menos timestamp, nível e mensagem. +2. Deve suportar um formato de linha configurável (padrão regex ou JSON) em vez de codificar um fixo. +3. Linhas que falharem na análise devem ser contadas e opcionalmente gravadas em um arquivo de "não analisadas", nunca descartadas silenciosamente. +4. A ferramenta deve filtrar registros por nível e por um intervalo de tempo informado na linha de comando. +5. Deve produzir agregações: contagem por nível e as top-N mensagens mais frequentes. +6. Deve processar arquivos linha a linha para que logs arbitrariamente grandes sejam suportados. + +## Marcos Sugeridos + +1. **Marco 1 — Analisar:** Transforme cada linha correspondente em um registro estruturado e imprima-o. +2. **Marco 2 — Filtrar:** Adicione filtragem por nível e por intervalo de tempo sobre os registros analisados. +3. **Marco 3 — Agregar e reportar:** Adicione contagens por nível, top-N mensagens e o tratamento de linhas não analisadas. + +## Esboço de Dados e Interface + +```text +linha de origem (estilo Apache) + 2024-05-01T10:15:03Z ERROR api order-service "db timeout" 503 + +padrão de análise (regex, grupos nomeados) + (?P\S+) (?P\w+) (?P\S+) (?P\S+) "(?P[^"]*)" (?P\d+) + +registro estruturado + { ts, level, component, service, message, status } + +linhas não analisadas -> unparsed.log (com número da linha) + +fluxo de consulta + ler -> analisar -> [ok] filtrar(level>=WARN, ts na janela) -> agregar + \-> [sem match] contar + destino de não analisadas + +relatório + por_nível: INFO=8210 WARN=145 ERROR=37 + top_mensagens: "db timeout" x22, "retry" x15 +``` + +## Desafios Extras + +- Detectar o formato automaticamente (JSON vs texto) farejando as primeiras linhas. +- Adicionar um modo `--follow` que acompanha o arquivo e analisa novas linhas conforme chegam. +- Calcular percentis de latência se houver um campo de duração. +- Suportar arquivos de log compactados com gzip de forma transparente. + +## Definição de Pronto + +- [ ] Linhas bem-formadas são analisadas em registros com todos os campos esperados. +- [ ] Linhas sem correspondência são contadas e preservadas, não descartadas silenciosamente. +- [ ] Os filtros de nível e de intervalo de tempo retornam o subconjunto correto. +- [ ] As contagens por nível e as top-N mensagens estão corretas. +- [ ] Um arquivo de centenas de MB é processado sem esgotar a memória. + +## Armadilhas Comuns + +- Uma regex frágil que quebra em campos entre aspas, espaços extras ou mensagens multilinha. +- Analisar timestamps sem tratar fusos horários, deixando os filtros de intervalo de tempo errados. +- Carregar o arquivo inteiro em uma lista antes de processar logs grandes. +- Pular silenciosamente linhas não analisadas e esconder uma mudança de formato que você deveria conhecer. + +## Recursos + +- [Módulo `re` do Python](https://docs.python.org/3/library/re.html) — grupos nomeados tornam os padrões de log legíveis. +- [regex101](https://regex101.com/) — construa e teste padrões de log de forma interativa. +- [The Twelve-Factor App: Logs](https://12factor.net/logs) — por que tratar logs como fluxos de eventos importa. +- [Elastic: processador Grok](https://www.elastic.co/guide/en/elasticsearch/reference/current/grok-processor.html) — como um sistema de produção nomeia padrões de campos de log. diff --git a/projects/data-engineering/beginner/05-api-to-csv/README.md b/projects/data-engineering/beginner/05-api-to-csv/README.md index 9fce867..e1d5e58 100644 --- a/projects/data-engineering/beginner/05-api-to-csv/README.md +++ b/projects/data-engineering/beginner/05-api-to-csv/README.md @@ -1,34 +1,97 @@ # API to CSV Exporter -## Idea -Create a tool that fetches data from an API and exports it to CSV format. Learn about API integration and data export. +> 🌐 **English** · [Português](./README.pt-BR.md) + +**Domain:** Data Engineering · **Level:** Beginner · **Estimated time:** 3–6 hours + +## Overview + +A huge amount of data lives behind HTTP APIs, one page at a time. Build a tool that calls a paginated REST API, walks through every page, flattens each JSON record into a flat row, and writes the whole result to a clean CSV. The real lessons hide in the corners: following pagination correctly so you get *all* the data and no duplicates, backing off when the API rate-limits you, and retrying a flaky request without corrupting your output. It is the first project where your program depends on a system you do not control, so handling its failures gracefully is the whole point. + +## Prerequisites + +- Ability to make an HTTP GET request in your language of choice +- Understanding of JSON structure (objects, arrays, nesting) +- Comfort writing a CSV file (see [CSV to Database Loader](../01-csv-to-database/) for CSV basics) +- Awareness of HTTP status codes, especially 429 and 5xx ## Learning Objectives -- Call REST APIs -- Handle pagination -- Transform API responses -- Export to CSV -- Handle errors - -## Implementation Tips -- Implement API client -- Handle pagination -- Add rate limiting -- Implement retry logic -- Transform API data to CSV schema -- Create field mapping -- Add data validation -- Implement scheduling -- Handle API errors gracefully -- Create progress tracking -- Add logging -- Implement incremental exports -- Create deduplication -- Build configuration management - -## Key Challenges -- API rate limiting -- Pagination handling -- Data transformation complexity -- Error recovery -- Large dataset handling + +By the end, you should be able to: + +- Consume a paginated API using cursor- or offset-based pagination +- Respect rate limits and back off on `429 Too Many Requests` +- Retry transient failures with exponential backoff and a cap +- Flatten nested JSON into columns for a tabular CSV +- Map API fields to CSV headers via configuration, not hard-coding +- Deduplicate records by a stable key across pages + +## Functional Requirements + +1. The tool must fetch all pages of a paginated endpoint until there are no more. +2. It must handle `429` and `5xx` responses by retrying with backoff, up to a configurable limit. +3. It must transform each JSON record into a flat row using a defined field mapping. +4. Nested fields must be flattened or extracted; arrays must have a documented handling (join, first, or count). +5. Duplicate records (same key appearing across pages) must be written only once. +6. The output must be a valid CSV with a header row and a run summary of pages fetched and rows written. + +## Suggested Milestones + +1. **Milestone 1 — Fetch one page:** Call the endpoint once and print the parsed records. +2. **Milestone 2 — Paginate:** Follow pagination to the end, accumulating records with retry/backoff. +3. **Milestone 3 — Transform & export:** Flatten records, deduplicate, and write the CSV with a summary. + +## Data & Interface Sketch + +```text +GET /api/v1/users?page=1 -> { "data": [ ... ], "next": "?page=2" } + +api record (nested) + { "id": 7, "name": "Ana", + "address": { "city": "Recife" }, + "tags": ["vip","beta"] } + +field mapping (config) + id -> id + name -> name + address.city -> city (flatten nested) + tags -> tags (join with ";") + +csv row + id,name,city,tags + 7,Ana,Recife,vip;beta + +retry policy + 429/5xx -> wait (2^attempt * base), max 5 attempts, honor Retry-After + +summary: pages=12 rows=1180 duplicates_skipped=4 retries=3 +``` + +## Stretch Goals + +- Support incremental export using an `updated_since` parameter and a saved high-water mark. +- Stream rows to the CSV as pages arrive instead of buffering everything in memory. +- Add a config-driven authentication header (API key or bearer token) read from the environment. +- Emit both CSV and newline-delimited JSON from the same run. + +## Definition of Done + +- [ ] Every page is fetched; the final row count matches the API's reported total. +- [ ] Rate-limit and server errors trigger backoff and eventual success or a clear failure. +- [ ] Nested fields are flattened correctly and arrays handled per the documented rule. +- [ ] No duplicate keys appear in the output CSV. +- [ ] A summary reports pages fetched, rows written, and retries. + +## Common Pitfalls + +- Assuming a fixed number of pages instead of following the API's "next" signal. +- Hammering the API and getting throttled because you ignore `429` and `Retry-After`. +- Losing nested data by writing a Python dict or JSON blob straight into a CSV cell. +- Buffering all records in memory for a large dataset instead of streaming to disk. + +## Resources + +- [MDN: HTTP response status codes](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status) — what 429, 500, and 503 mean for retry logic. +- [Google Cloud: Retry with exponential backoff](https://cloud.google.com/storage/docs/retry-strategy) — a clear, standard backoff strategy. +- [Python `requests`](https://requests.readthedocs.io/en/latest/) — the ergonomic HTTP client for the fetch layer. +- [REST API pagination patterns](https://developer.mozilla.org/en-US/docs/Web/HTTP/Link) — how APIs signal the next page via headers. diff --git a/projects/data-engineering/beginner/05-api-to-csv/README.pt-BR.md b/projects/data-engineering/beginner/05-api-to-csv/README.pt-BR.md new file mode 100644 index 0000000..db6ddd9 --- /dev/null +++ b/projects/data-engineering/beginner/05-api-to-csv/README.pt-BR.md @@ -0,0 +1,97 @@ +# Exportador de API para CSV + +> 🌐 [English](./README.md) · **Português** + +**Domínio:** Data Engineering · **Nível:** Iniciante · **Tempo estimado:** 3–6 horas + +## Visão Geral + +Uma enorme quantidade de dados vive atrás de APIs HTTP, uma página por vez. Construa uma ferramenta que chama uma API REST paginada, percorre todas as páginas, achata cada registro JSON em uma linha plana e escreve o resultado inteiro em um CSV limpo. As lições reais se escondem nos cantos: seguir a paginação corretamente para obter *todos* os dados e nenhuma duplicata, recuar quando a API te limita por taxa, e repetir uma requisição instável sem corromper sua saída. É o primeiro projeto em que seu programa depende de um sistema que você não controla, então lidar com as falhas dele com elegância é todo o objetivo. + +## Pré-requisitos + +- Capacidade de fazer uma requisição HTTP GET na linguagem de sua escolha +- Entender a estrutura JSON (objetos, arrays, aninhamento) +- Conforto para escrever um arquivo CSV (veja [Carregador de CSV para Banco de Dados](../01-csv-to-database/) para o básico de CSV) +- Consciência dos códigos de status HTTP, especialmente 429 e 5xx + +## Objetivos de Aprendizado + +Ao final, você deve ser capaz de: + +- Consumir uma API paginada usando paginação por cursor ou por offset +- Respeitar limites de taxa e recuar em `429 Too Many Requests` +- Repetir falhas transitórias com backoff exponencial e um teto +- Achatar JSON aninhado em colunas para um CSV tabular +- Mapear campos da API para cabeçalhos de CSV via configuração, não codificação fixa +- Deduplicar registros por uma chave estável entre páginas + +## Requisitos Funcionais + +1. A ferramenta deve buscar todas as páginas de um endpoint paginado até não haver mais. +2. Deve tratar respostas `429` e `5xx` repetindo com backoff, até um limite configurável. +3. Deve transformar cada registro JSON em uma linha plana usando um mapeamento de campos definido. +4. Campos aninhados devem ser achatados ou extraídos; arrays devem ter um tratamento documentado (juntar, primeiro ou contar). +5. Registros duplicados (a mesma chave aparecendo em páginas diferentes) devem ser escritos apenas uma vez. +6. A saída deve ser um CSV válido com linha de cabeçalho e um resumo da execução com páginas buscadas e linhas escritas. + +## Marcos Sugeridos + +1. **Marco 1 — Buscar uma página:** Chame o endpoint uma vez e imprima os registros analisados. +2. **Marco 2 — Paginar:** Siga a paginação até o fim, acumulando registros com retry/backoff. +3. **Marco 3 — Transformar e exportar:** Achate os registros, deduplique e escreva o CSV com um resumo. + +## Esboço de Dados e Interface + +```text +GET /api/v1/users?page=1 -> { "data": [ ... ], "next": "?page=2" } + +registro da api (aninhado) + { "id": 7, "name": "Ana", + "address": { "city": "Recife" }, + "tags": ["vip","beta"] } + +mapeamento de campos (config) + id -> id + name -> name + address.city -> city (achata aninhado) + tags -> tags (junta com ";") + +linha csv + id,name,city,tags + 7,Ana,Recife,vip;beta + +política de retry + 429/5xx -> espera (2^tentativa * base), máx 5 tentativas, honra Retry-After + +resumo: páginas=12 linhas=1180 duplicatas_puladas=4 retries=3 +``` + +## Desafios Extras + +- Suportar exportação incremental usando um parâmetro `updated_since` e uma marca d'água salva. +- Transmitir linhas para o CSV conforme as páginas chegam em vez de armazenar tudo em memória. +- Adicionar um cabeçalho de autenticação orientado por configuração (chave de API ou bearer token) lido do ambiente. +- Emitir tanto CSV quanto JSON delimitado por linhas na mesma execução. + +## Definição de Pronto + +- [ ] Toda página é buscada; a contagem final de linhas bate com o total reportado pela API. +- [ ] Erros de limite de taxa e de servidor disparam backoff e resultam em sucesso eventual ou falha clara. +- [ ] Campos aninhados são achatados corretamente e arrays tratados conforme a regra documentada. +- [ ] Nenhuma chave duplicada aparece no CSV de saída. +- [ ] Um resumo reporta páginas buscadas, linhas escritas e retries. + +## Armadilhas Comuns + +- Assumir um número fixo de páginas em vez de seguir o sinal "next" da API. +- Martelar a API e ser limitado porque você ignora `429` e `Retry-After`. +- Perder dados aninhados escrevendo um dicionário ou blob JSON direto em uma célula do CSV. +- Armazenar todos os registros em memória para um conjunto grande em vez de transmitir para o disco. + +## Recursos + +- [MDN: códigos de status de resposta HTTP](https://developer.mozilla.org/pt-BR/docs/Web/HTTP/Status) — o que 429, 500 e 503 significam para a lógica de retry. +- [Google Cloud: Retry com backoff exponencial](https://cloud.google.com/storage/docs/retry-strategy) — uma estratégia de backoff clara e padrão. +- [Python `requests`](https://requests.readthedocs.io/en/latest/) — o cliente HTTP ergonômico para a camada de busca. +- [Padrões de paginação de API REST](https://developer.mozilla.org/en-US/docs/Web/HTTP/Link) — como as APIs sinalizam a próxima página via cabeçalhos. diff --git a/projects/data-engineering/beginner/06-batch-processing/README.md b/projects/data-engineering/beginner/06-batch-processing/README.md index f4fef08..726823d 100644 --- a/projects/data-engineering/beginner/06-batch-processing/README.md +++ b/projects/data-engineering/beginner/06-batch-processing/README.md @@ -1,34 +1,94 @@ # Batch Processing Script -## Idea -Build a script that processes data in batches. Learn about batch processing patterns and scheduling. +> 🌐 **English** · [Português](./README.pt-BR.md) + +**Domain:** Data Engineering · **Level:** Beginner · **Estimated time:** 3–6 hours + +## Overview + +Processing a million records one at a time is slow and fragile; processing them all at once blows up your memory. The answer is batching: chunk the input into fixed-size groups, process each group as a unit, and commit it before moving on. Build a script that reads a large input, works through it in batches, handles the failure of a single batch without losing the ones already done, and can resume from where it stopped. This is the workhorse pattern of data engineering — the one you reach for whenever "just loop over everything" stops working. + +## Prerequisites + +- Comfort reading a large input file or query result iteratively +- Understanding of transactions (a batch either fully commits or rolls back) +- Basic error handling (try/except or equivalent) +- Familiarity with reading and writing a small state/checkpoint file ## Learning Objectives -- Implement batch processing logic -- Handle batch optimization -- Create scheduling -- Implement monitoring -- Handle failures gracefully - -## Implementation Tips -- Define batch size strategies -- Implement batch accumulation -- Create batch processing functions -- Add transaction support -- Implement error handling per batch -- Create progress tracking -- Add logging and monitoring -- Implement recovery mechanisms -- Create performance metrics -- Add batching optimization -- Implement parallel processing -- Create scheduling -- Add retry logic -- Build status reporting - -## Key Challenges -- Batch size optimization -- Memory management -- Error handling per batch -- Transaction rollback -- Performance tuning + +By the end, you should be able to: + +- Split a stream of records into fixed-size batches without loading everything +- Process each batch as an atomic unit that commits or rolls back cleanly +- Isolate a failing batch so earlier successful batches are not lost +- Checkpoint progress so an interrupted run can resume, not restart +- Report per-batch and overall progress with counts and timing +- Reason about the trade-off between batch size, memory, and throughput + +## Functional Requirements + +1. The script must read input and group records into batches of a configurable size. +2. Each batch must be processed transactionally: on error, that batch rolls back but the run continues. +3. A failed batch must be recorded (its identifier and reason) for later inspection or retry. +4. The script must write a checkpoint after each successful batch so it can resume from the last committed point. +5. On restart, it must skip already-processed batches and continue from the checkpoint. +6. It must report progress: batches done, records processed, failures, and total time. + +## Suggested Milestones + +1. **Milestone 1 — Batch & process:** Chunk the input and process each batch, printing progress. +2. **Milestone 2 — Fault isolation:** Wrap each batch in a transaction and record failures without aborting. +3. **Milestone 3 — Resume:** Add checkpointing and skip-completed logic so an interrupted run continues. + +## Data & Interface Sketch + +```text +input: 1,000,000 records (stream) +batch size: 500 -> 2,000 batches + +per-batch flow + accumulate 500 records + begin transaction + process + write batch + commit -> checkpoint {last_batch: N, records: N*500} + on error -> rollback, log {batch: N, reason}, continue + +checkpoint file (checkpoint.json) + { "last_completed_batch": 1450, "records_done": 725000 } + +restart + read checkpoint -> resume at batch 1451 + +CLI: process --input data.jsonl --batch-size 500 --resume +report: batches=2000 ok=1996 failed=4 records=998000 elapsed=42s +``` + +## Stretch Goals + +- Add a `--retry-failed` mode that reprocesses only the batches recorded as failed. +- Process independent batches in parallel with a bounded worker pool. +- Make batch size adaptive, shrinking after a failure and growing when stable. +- Emit a metrics line per batch (throughput in records/sec) for tuning. + +## Definition of Done + +- [ ] Input is processed in configurable-size batches without loading it all. +- [ ] A single failing batch is isolated and logged; other batches still complete. +- [ ] A checkpoint is written after every successful batch. +- [ ] Killing and restarting the script resumes from the checkpoint, not the start. +- [ ] The final report shows batches, records, failures, and elapsed time. + +## Common Pitfalls + +- Committing per record (too slow) or per whole run (loses everything on one failure). +- Letting one bad batch throw an unhandled exception and kill the entire job. +- Checkpointing before the batch actually commits, so a crash loses committed work or double-processes. +- Choosing a batch size blindly instead of measuring memory and throughput. + +## Resources + +- [PostgreSQL: Transactions](https://www.postgresql.org/docs/current/tutorial-transactions.html) — the atomicity guarantee a batch relies on. +- [Python `itertools` recipes](https://docs.python.org/3/library/itertools.html#itertools-recipes) — a clean `batched()` for chunking iterables. +- [Idempotency and checkpointing](https://aws.amazon.com/builders-library/making-retries-safe-with-idempotent-APIs/) — why safe resumes need idempotence. +- [Designing Data-Intensive Applications (concepts)](https://dataintensive.net/) — batch processing fundamentals in chapter 10. diff --git a/projects/data-engineering/beginner/06-batch-processing/README.pt-BR.md b/projects/data-engineering/beginner/06-batch-processing/README.pt-BR.md new file mode 100644 index 0000000..b4bbee9 --- /dev/null +++ b/projects/data-engineering/beginner/06-batch-processing/README.pt-BR.md @@ -0,0 +1,94 @@ +# Script de Processamento em Lote + +> 🌐 [English](./README.md) · **Português** + +**Domínio:** Data Engineering · **Nível:** Iniciante · **Tempo estimado:** 3–6 horas + +## Visão Geral + +Processar um milhão de registros um a um é lento e frágil; processá-los todos de uma vez estoura sua memória. A resposta é o lote (batch): divida a entrada em grupos de tamanho fixo, processe cada grupo como uma unidade e faça o commit antes de seguir. Construa um script que lê uma entrada grande, a percorre em lotes, trata a falha de um único lote sem perder os já concluídos, e consegue retomar de onde parou. Este é o padrão cavalo de batalha da engenharia de dados — aquele ao qual você recorre sempre que "só percorra tudo" para de funcionar. + +## Pré-requisitos + +- Conforto para ler um arquivo de entrada grande ou resultado de consulta iterativamente +- Entender transações (um lote ou faz commit completo ou rollback) +- Tratamento básico de erros (try/except ou equivalente) +- Familiaridade com ler e escrever um pequeno arquivo de estado/checkpoint + +## Objetivos de Aprendizado + +Ao final, você deve ser capaz de: + +- Dividir um fluxo de registros em lotes de tamanho fixo sem carregar tudo +- Processar cada lote como uma unidade atômica que faz commit ou rollback de forma limpa +- Isolar um lote com falha para que lotes bem-sucedidos anteriores não sejam perdidos +- Registrar checkpoints do progresso para que uma execução interrompida retome, e não recomece +- Reportar progresso por lote e geral com contagens e tempo +- Raciocinar sobre o trade-off entre tamanho do lote, memória e throughput + +## Requisitos Funcionais + +1. O script deve ler a entrada e agrupar registros em lotes de um tamanho configurável. +2. Cada lote deve ser processado transacionalmente: em caso de erro, esse lote faz rollback mas a execução continua. +3. Um lote com falha deve ser registrado (seu identificador e motivo) para inspeção ou retry posterior. +4. O script deve escrever um checkpoint após cada lote bem-sucedido para poder retomar do último ponto confirmado. +5. Ao reiniciar, deve pular os lotes já processados e continuar a partir do checkpoint. +6. Deve reportar progresso: lotes concluídos, registros processados, falhas e tempo total. + +## Marcos Sugeridos + +1. **Marco 1 — Lote e processamento:** Divida a entrada e processe cada lote, imprimindo o progresso. +2. **Marco 2 — Isolamento de falhas:** Envolva cada lote em uma transação e registre falhas sem abortar. +3. **Marco 3 — Retomada:** Adicione checkpoints e lógica de pular-concluídos para que uma execução interrompida continue. + +## Esboço de Dados e Interface + +```text +entrada: 1.000.000 registros (stream) +tamanho do lote: 500 -> 2.000 lotes + +fluxo por lote + acumula 500 registros + inicia transação + processa + grava o lote + commit -> checkpoint {last_batch: N, records: N*500} + em erro -> rollback, log {batch: N, reason}, continua + +arquivo de checkpoint (checkpoint.json) + { "last_completed_batch": 1450, "records_done": 725000 } + +reinício + lê o checkpoint -> retoma no lote 1451 + +CLI: process --input data.jsonl --batch-size 500 --resume +relatório: lotes=2000 ok=1996 falhos=4 registros=998000 tempo=42s +``` + +## Desafios Extras + +- Adicionar um modo `--retry-failed` que reprocessa apenas os lotes registrados como falhos. +- Processar lotes independentes em paralelo com um pool limitado de workers. +- Tornar o tamanho do lote adaptativo, encolhendo após uma falha e crescendo quando estável. +- Emitir uma linha de métricas por lote (throughput em registros/seg) para tuning. + +## Definição de Pronto + +- [ ] A entrada é processada em lotes de tamanho configurável sem carregá-la toda. +- [ ] Um único lote com falha é isolado e registrado; os outros lotes ainda concluem. +- [ ] Um checkpoint é escrito após cada lote bem-sucedido. +- [ ] Matar e reiniciar o script retoma a partir do checkpoint, não do início. +- [ ] O relatório final mostra lotes, registros, falhas e tempo decorrido. + +## Armadilhas Comuns + +- Fazer commit por registro (lento demais) ou por execução inteira (perde tudo em uma falha). +- Deixar um lote ruim lançar uma exceção não tratada e matar o job inteiro. +- Fazer checkpoint antes do lote de fato dar commit, de modo que um crash perde trabalho confirmado ou processa em dobro. +- Escolher um tamanho de lote às cegas em vez de medir memória e throughput. + +## Recursos + +- [PostgreSQL: Transações](https://www.postgresql.org/docs/current/tutorial-transactions.html) — a garantia de atomicidade da qual um lote depende. +- [Receitas do `itertools` do Python](https://docs.python.org/3/library/itertools.html#itertools-recipes) — um `batched()` limpo para dividir iteráveis. +- [Idempotência e checkpointing](https://aws.amazon.com/builders-library/making-retries-safe-with-idempotent-APIs/) — por que retomadas seguras precisam de idempotência. +- [Designing Data-Intensive Applications (conceitos)](https://dataintensive.net/) — fundamentos de processamento em lote no capítulo 10. diff --git a/projects/data-engineering/beginner/07-file-ingestion/README.md b/projects/data-engineering/beginner/07-file-ingestion/README.md index 4d9f83a..374640d 100644 --- a/projects/data-engineering/beginner/07-file-ingestion/README.md +++ b/projects/data-engineering/beginner/07-file-ingestion/README.md @@ -1,34 +1,93 @@ # File Ingestion System -## Idea -Create a system that monitors directories and ingests files. Learn about file system monitoring and processing. +> 🌐 **English** · [Português](./README.pt-BR.md) + +**Domain:** Data Engineering · **Level:** Beginner · **Estimated time:** 3–6 hours + +## Overview + +Many pipelines start with a "drop folder": another team, a partner, or an export job leaves files in a directory, and your system must notice them, process them, and move them out of the way. Build a service that watches an incoming directory, picks up each new file, validates and processes it, and then moves it to a "done" or "failed" folder so it is never processed twice. The subtle challenges — a file that is still being written when you grab it, two runs racing over the same file, a corrupt file that must not block the queue — are exactly what makes ingestion a real engineering problem. + +## Prerequisites + +- Comfort listing directories and moving/renaming files +- Understanding of file paths and basic filesystem operations +- Beginner error handling and logging +- Awareness that a file can be partially written (not yet complete) ## Learning Objectives -- Monitor file system -- Detect new files -- Process files -- Move processed files -- Handle errors - -## Implementation Tips -- Implement file system watcher -- Detect file arrivals -- Create file type validation -- Implement file processing -- Create archival mechanism -- Add error handling -- Implement retry logic -- Create logging -- Add performance monitoring -- Implement cleanup -- Add notification system -- Create configuration -- Implement parallel processing -- Build status dashboard - -## Key Challenges -- File system monitoring reliability -- Concurrent file processing -- Error recovery -- File locking issues -- Performance at scale + +By the end, you should be able to: + +- Detect new files in a watched directory reliably +- Avoid grabbing a file that is still being written (stability check) +- Process each file exactly once and move it to a terminal folder +- Route failed files to a quarantine folder instead of retrying forever +- Make the pickup safe against a second run racing on the same file +- Log every ingestion event so the pipeline is auditable + +## Functional Requirements + +1. The system must scan an `incoming/` directory and detect files that have not yet been processed. +2. It must confirm a file is complete before processing (e.g. size stable across two checks, or an atomic rename convention). +3. Each file must be validated (type/extension and basic structure) before it is processed. +4. On success, the file must move to `processed/`; on failure, to `failed/` with an error record. +5. A file must never be processed twice, even across restarts or overlapping runs. +6. Every action (detected, processed, failed) must be logged with a timestamp and the filename. + +## Suggested Milestones + +1. **Milestone 1 — Detect & move:** Scan `incoming/`, process each file, and move it to `processed/`. +2. **Milestone 2 — Safety:** Add the completeness check and a claim mechanism so the same file is not double-processed. +3. **Milestone 3 — Failure handling:** Validate files, quarantine bad ones in `failed/`, and log every event. + +## Data & Interface Sketch + +```text +directory layout + incoming/ <- files arrive here + processing/ <- claimed files (in-flight) + processed/ <- success + failed/ <- quarantine + .error.txt + +per-file flow + detect incoming/orders_2024-05-01.csv + completeness check (size stable? or .ready marker?) + claim: atomic rename -> processing/ (wins the race) + validate (extension=csv, header present) + process -> [ok] move to processed/ + \-> [bad] move to failed/ + write reason + +ingest.log + 2024-05-01T09:00 detected orders_...csv + 2024-05-01T09:00 processed orders_...csv rows=812 +``` + +## Stretch Goals + +- Add a continuous watch loop (polling interval or OS filesystem events) instead of a one-shot scan. +- Support multiple file types with a handler chosen by extension. +- Add a retry policy with a maximum attempt count before quarantine. +- Emit a daily summary of files ingested, rows processed, and failures. + +## Definition of Done + +- [ ] New files in `incoming/` are detected and processed. +- [ ] A file still being written is not picked up until complete. +- [ ] Successful files land in `processed/`, failures in `failed/` with a reason. +- [ ] No file is processed twice, even with two runs overlapping. +- [ ] Every ingestion event is logged with timestamp and filename. + +## Common Pitfalls + +- Grabbing a file mid-write and processing a truncated, corrupt copy. +- Two runs both claiming the same file because the claim is not atomic. +- Leaving failed files in `incoming/`, so they are retried forever and block the queue. +- Relying on modification time alone to detect "new" files, which is fragile across clocks. + +## Resources + +- [Python `pathlib`](https://docs.python.org/3/library/pathlib.html) — clean, cross-platform filesystem operations. +- [watchdog library](https://python-watchdog.readthedocs.io/en/stable/) — OS-level filesystem event notifications. +- [POSIX `rename` atomicity](https://pubs.opengroup.org/onlinepubs/9699919799/functions/rename.html) — why an atomic rename is the safe claim primitive. +- [The Log: What every engineer should know](https://engineering.linkedin.com/distributed-systems/log-what-every-software-engineer-should-know-about-real-time-datas-unifying) — ingestion as the front of a data system. diff --git a/projects/data-engineering/beginner/07-file-ingestion/README.pt-BR.md b/projects/data-engineering/beginner/07-file-ingestion/README.pt-BR.md new file mode 100644 index 0000000..311f380 --- /dev/null +++ b/projects/data-engineering/beginner/07-file-ingestion/README.pt-BR.md @@ -0,0 +1,93 @@ +# Sistema de Ingestão de Arquivos + +> 🌐 [English](./README.md) · **Português** + +**Domínio:** Data Engineering · **Nível:** Iniciante · **Tempo estimado:** 3–6 horas + +## Visão Geral + +Muitos pipelines começam com uma "pasta de entrega": outra equipe, um parceiro ou um job de exportação deixa arquivos em um diretório, e seu sistema precisa notá-los, processá-los e tirá-los do caminho. Construa um serviço que observa um diretório de entrada, pega cada arquivo novo, valida e processa, e depois o move para uma pasta de "concluídos" ou "falhos" para que nunca seja processado duas vezes. Os desafios sutis — um arquivo que ainda está sendo escrito quando você o pega, duas execuções disputando o mesmo arquivo, um arquivo corrompido que não pode bloquear a fila — são exatamente o que torna a ingestão um problema de engenharia de verdade. + +## Pré-requisitos + +- Conforto para listar diretórios e mover/renomear arquivos +- Entender caminhos de arquivo e operações básicas de sistema de arquivos +- Tratamento de erros e logging em nível iniciante +- Consciência de que um arquivo pode estar parcialmente escrito (ainda não completo) + +## Objetivos de Aprendizado + +Ao final, você deve ser capaz de: + +- Detectar novos arquivos em um diretório observado de forma confiável +- Evitar pegar um arquivo que ainda está sendo escrito (verificação de estabilidade) +- Processar cada arquivo exatamente uma vez e movê-lo para uma pasta terminal +- Rotear arquivos com falha para uma pasta de quarentena em vez de repetir para sempre +- Tornar a captura segura contra uma segunda execução disputando o mesmo arquivo +- Registrar em log todo evento de ingestão para que o pipeline seja auditável + +## Requisitos Funcionais + +1. O sistema deve varrer um diretório `incoming/` e detectar arquivos que ainda não foram processados. +2. Deve confirmar que um arquivo está completo antes de processar (ex.: tamanho estável entre duas verificações, ou uma convenção de renomeação atômica). +3. Cada arquivo deve ser validado (tipo/extensão e estrutura básica) antes de ser processado. +4. Em sucesso, o arquivo deve mover para `processed/`; em falha, para `failed/` com um registro de erro. +5. Um arquivo nunca deve ser processado duas vezes, mesmo entre reinícios ou execuções sobrepostas. +6. Toda ação (detectado, processado, falho) deve ser registrada com um timestamp e o nome do arquivo. + +## Marcos Sugeridos + +1. **Marco 1 — Detectar e mover:** Varra `incoming/`, processe cada arquivo e mova-o para `processed/`. +2. **Marco 2 — Segurança:** Adicione a verificação de completude e um mecanismo de reivindicação para que o mesmo arquivo não seja processado em dobro. +3. **Marco 3 — Tratamento de falhas:** Valide arquivos, coloque os ruins em quarentena em `failed/` e registre cada evento. + +## Esboço de Dados e Interface + +```text +layout de diretórios + incoming/ <- arquivos chegam aqui + processing/ <- arquivos reivindicados (em andamento) + processed/ <- sucesso + failed/ <- quarentena + .error.txt + +fluxo por arquivo + detecta incoming/orders_2024-05-01.csv + verificação de completude (tamanho estável? ou marcador .ready?) + reivindica: rename atômico -> processing/ (vence a disputa) + valida (extensão=csv, cabeçalho presente) + processa -> [ok] move para processed/ + \-> [ruim] move para failed/ + escreve motivo + +ingest.log + 2024-05-01T09:00 detectado orders_...csv + 2024-05-01T09:00 processado orders_...csv linhas=812 +``` + +## Desafios Extras + +- Adicionar um laço de observação contínua (intervalo de polling ou eventos de sistema de arquivos do SO) em vez de uma varredura única. +- Suportar múltiplos tipos de arquivo com um handler escolhido pela extensão. +- Adicionar uma política de retry com um número máximo de tentativas antes da quarentena. +- Emitir um resumo diário de arquivos ingeridos, linhas processadas e falhas. + +## Definição de Pronto + +- [ ] Novos arquivos em `incoming/` são detectados e processados. +- [ ] Um arquivo ainda sendo escrito não é pego até estar completo. +- [ ] Arquivos bem-sucedidos caem em `processed/`, falhas em `failed/` com um motivo. +- [ ] Nenhum arquivo é processado duas vezes, mesmo com duas execuções sobrepostas. +- [ ] Todo evento de ingestão é registrado com timestamp e nome do arquivo. + +## Armadilhas Comuns + +- Pegar um arquivo no meio da escrita e processar uma cópia truncada e corrompida. +- Duas execuções reivindicando o mesmo arquivo porque a reivindicação não é atômica. +- Deixar arquivos com falha em `incoming/`, de modo que são repetidos para sempre e bloqueiam a fila. +- Confiar apenas na hora de modificação para detectar arquivos "novos", o que é frágil entre relógios. + +## Recursos + +- [Python `pathlib`](https://docs.python.org/3/library/pathlib.html) — operações de sistema de arquivos limpas e multiplataforma. +- [Biblioteca watchdog](https://python-watchdog.readthedocs.io/en/stable/) — notificações de eventos de sistema de arquivos em nível de SO. +- [Atomicidade do `rename` POSIX](https://pubs.opengroup.org/onlinepubs/9699919799/functions/rename.html) — por que um rename atômico é a primitiva de reivindicação segura. +- [The Log: What every engineer should know](https://engineering.linkedin.com/distributed-systems/log-what-every-software-engineer-should-know-about-real-time-datas-unifying) — ingestão como a frente de um sistema de dados. diff --git a/projects/data-engineering/beginner/08-data-cleaning/README.md b/projects/data-engineering/beginner/08-data-cleaning/README.md index 0adb166..14ac77d 100644 --- a/projects/data-engineering/beginner/08-data-cleaning/README.md +++ b/projects/data-engineering/beginner/08-data-cleaning/README.md @@ -1,34 +1,96 @@ # Data Cleaning Pipeline -## Idea -Build a pipeline that cleans and normalizes data. Learn about data transformation and quality improvement. +> 🌐 **English** · [Português](./README.pt-BR.md) + +**Domain:** Data Engineering · **Level:** Beginner · **Estimated time:** 3–6 hours + +## Overview + +Real-world data is messy: the same customer spelled three ways, dates in five formats, phone numbers with and without country codes, blank cells that mean different things. Build a pipeline that takes a dirty dataset and produces a clean, normalized one — deduplicating records, filling or flagging missing values, and standardizing formats. The discipline here is to make every cleaning decision *explicit and reversible*: you keep an audit trail of what changed and why, so a downstream analyst can trust the output and trace any value back to its raw form. + +## Prerequisites + +- Ability to read and write a CSV or JSON dataset +- Comfort with string manipulation and basic data types +- Understanding of what "duplicate" and "missing" mean for your data +- Familiarity with dictionaries/maps for grouping records ## Learning Objectives -- Remove duplicates -- Handle missing values -- Normalize data -- Validate constraints -- Generate quality metrics - -## Implementation Tips -- Implement duplicate detection -- Add missing value handling strategies -- Create data normalization -- Implement validation rules -- Add outlier detection -- Create data profiling -- Generate quality reports -- Implement transformations -- Add error logging -- Create recovery mechanisms -- Implement performance optimization -- Add monitoring -- Create audit trails -- Build user interface - -## Key Challenges -- Missing value strategy selection -- Outlier handling -- Data normalization consistency -- Performance at scale -- Quality metric calculation + +By the end, you should be able to: + +- Detect duplicate records by an exact key and by a normalized/fuzzy key +- Choose and apply a missing-value strategy (drop, default, or flag) per column +- Normalize formats: trim, case, dates, and numeric units to a canonical form +- Keep an audit trail recording every transformation applied to each record +- Produce before/after quality metrics so cleaning is measurable +- Separate "cleaned" from "unfixable" records rather than forcing every row through + +## Functional Requirements + +1. The pipeline must remove exact-duplicate rows and detect near-duplicates by a normalized key. +2. It must apply a configurable missing-value strategy per column, never guessing silently. +3. It must normalize at least: whitespace, letter case, date formats, and one numeric/unit field. +4. Every change must be recorded in an audit trail tying the cleaned value to its original. +5. Records that cannot be cleaned to meet the rules must be routed to a rejects output, not forced through. +6. The pipeline must report quality metrics before and after: completeness, duplicate rate, and rows rejected. + +## Suggested Milestones + +1. **Milestone 1 — Normalize:** Apply whitespace, case, and format normalization to each field. +2. **Milestone 2 — Dedup & missing:** Remove duplicates and apply per-column missing-value strategies. +3. **Milestone 3 — Audit & metrics:** Add the audit trail, rejects routing, and before/after quality metrics. + +## Data & Interface Sketch + +```text +source row (dirty) + { "name": " ANA souza ", "email": "ANA@example.com", + "phone": "(81) 9999-1111", "signup": "01/05/2024" } + +cleaning steps + name -> trim + title-case -> "Ana Souza" + email -> trim + lower-case -> "ana@example.com" + phone -> strip non-digits + E.164 -> "+558199991111" + signup -> parse dd/mm/yyyy -> ISO -> "2024-05-01" + +dedup key: lower(email) -> collapse duplicates, keep newest + +audit trail (per record) + { id: 7, changes: ["name:trim+case", "signup:reformatted"] } + +rejects -> unfixable.jsonl (e.g. phone has no digits) + +metrics + before: rows=1000 completeness=82% duplicate_rate=6% + after: rows=940 completeness=99% duplicate_rate=0% rejected=12 +``` + +## Stretch Goals + +- Add fuzzy matching (edit distance) to catch near-duplicate names, not just exact keys. +- Make cleaning rules config-driven so the same engine handles different datasets. +- Support "soft" vs "hard" cleaning modes (flag-only vs modify-in-place). +- Emit a diff report showing sample before/after values for spot-checking. + +## Definition of Done + +- [ ] Exact and near-duplicate records are collapsed by the chosen key. +- [ ] Each column's missing-value strategy is applied explicitly, not by accident. +- [ ] Whitespace, case, dates, and the numeric field are normalized consistently. +- [ ] Every changed value is traceable to its original via the audit trail. +- [ ] Before/after quality metrics and a rejects count are reported. + +## Common Pitfalls + +- Filling missing values with a default that pollutes analysis (e.g. `0` where NULL means "unknown"). +- Deduplicating on the raw key so "Ana" and "ANA " survive as two records. +- Applying an irreversible transform with no record of the original value. +- Forcing unfixable rows through instead of quarantining them, corrupting the clean set. + +## Resources + +- [pandas: Working with missing data](https://pandas.pydata.org/docs/user_guide/missing_data.html) — strategies for nulls done well. +- [E.164 phone number format](https://en.wikipedia.org/wiki/E.164) — the canonical international phone standard. +- [Unicode normalization forms](https://unicode.org/reports/tr15/) — why text needs canonicalizing before comparison. +- [Tidy Data (Hadley Wickham)](https://vita.had.co.nz/papers/tidy-data.pdf) — the paper defining what "clean" tabular data means. diff --git a/projects/data-engineering/beginner/08-data-cleaning/README.pt-BR.md b/projects/data-engineering/beginner/08-data-cleaning/README.pt-BR.md new file mode 100644 index 0000000..61e02ac --- /dev/null +++ b/projects/data-engineering/beginner/08-data-cleaning/README.pt-BR.md @@ -0,0 +1,96 @@ +# Pipeline de Limpeza de Dados + +> 🌐 [English](./README.md) · **Português** + +**Domínio:** Data Engineering · **Nível:** Iniciante · **Tempo estimado:** 3–6 horas + +## Visão Geral + +Dados do mundo real são bagunçados: o mesmo cliente escrito de três formas, datas em cinco formatos, números de telefone com e sem código de país, células em branco que significam coisas diferentes. Construa um pipeline que pega um conjunto de dados sujo e produz um limpo e normalizado — deduplicando registros, preenchendo ou sinalizando valores ausentes e padronizando formatos. A disciplina aqui é tornar cada decisão de limpeza *explícita e reversível*: você mantém uma trilha de auditoria do que mudou e por quê, para que um analista downstream possa confiar na saída e rastrear qualquer valor de volta à sua forma bruta. + +## Pré-requisitos + +- Capacidade de ler e escrever um conjunto de dados CSV ou JSON +- Conforto com manipulação de strings e tipos de dados básicos +- Entender o que "duplicata" e "ausente" significam para seus dados +- Familiaridade com dicionários/mapas para agrupar registros + +## Objetivos de Aprendizado + +Ao final, você deve ser capaz de: + +- Detectar registros duplicados por uma chave exata e por uma chave normalizada/fuzzy +- Escolher e aplicar uma estratégia de valores ausentes (descartar, padrão ou sinalizar) por coluna +- Normalizar formatos: espaços, caixa, datas e unidades numéricas para uma forma canônica +- Manter uma trilha de auditoria registrando cada transformação aplicada a cada registro +- Produzir métricas de qualidade antes/depois para que a limpeza seja mensurável +- Separar registros "limpos" dos "não corrigíveis" em vez de forçar toda linha a passar + +## Requisitos Funcionais + +1. O pipeline deve remover linhas duplicadas exatas e detectar quase-duplicatas por uma chave normalizada. +2. Deve aplicar uma estratégia configurável de valores ausentes por coluna, nunca adivinhando silenciosamente. +3. Deve normalizar ao menos: espaços em branco, caixa das letras, formatos de data e um campo numérico/de unidade. +4. Toda mudança deve ser registrada em uma trilha de auditoria ligando o valor limpo ao seu original. +5. Registros que não podem ser limpos para atender às regras devem ser roteados para uma saída de rejeições, não forçados. +6. O pipeline deve reportar métricas de qualidade antes e depois: completude, taxa de duplicatas e linhas rejeitadas. + +## Marcos Sugeridos + +1. **Marco 1 — Normalizar:** Aplique normalização de espaços, caixa e formato a cada campo. +2. **Marco 2 — Deduplicar e ausentes:** Remova duplicatas e aplique estratégias de valores ausentes por coluna. +3. **Marco 3 — Auditoria e métricas:** Adicione a trilha de auditoria, o roteamento de rejeições e as métricas de qualidade antes/depois. + +## Esboço de Dados e Interface + +```text +linha de origem (suja) + { "name": " ANA souza ", "email": "ANA@example.com", + "phone": "(81) 9999-1111", "signup": "01/05/2024" } + +etapas de limpeza + name -> trim + title-case -> "Ana Souza" + email -> trim + minúsculas -> "ana@example.com" + phone -> remove não-dígitos + E.164 -> "+558199991111" + signup -> parse dd/mm/yyyy -> ISO -> "2024-05-01" + +chave de dedup: lower(email) -> colapsa duplicatas, mantém a mais nova + +trilha de auditoria (por registro) + { id: 7, changes: ["name:trim+case", "signup:reformatado"] } + +rejeições -> unfixable.jsonl (ex.: phone sem dígitos) + +métricas + antes: linhas=1000 completude=82% taxa_duplicatas=6% + depois: linhas=940 completude=99% taxa_duplicatas=0% rejeitadas=12 +``` + +## Desafios Extras + +- Adicionar correspondência fuzzy (distância de edição) para pegar nomes quase-duplicados, não só chaves exatas. +- Tornar as regras de limpeza orientadas por configuração para que o mesmo motor trate diferentes conjuntos de dados. +- Suportar modos de limpeza "suave" vs "forte" (só sinalizar vs modificar no lugar). +- Emitir um relatório de diff mostrando valores de amostra antes/depois para conferência. + +## Definição de Pronto + +- [ ] Registros duplicados exatos e quase-duplicados são colapsados pela chave escolhida. +- [ ] A estratégia de valores ausentes de cada coluna é aplicada explicitamente, não por acidente. +- [ ] Espaços, caixa, datas e o campo numérico são normalizados de forma consistente. +- [ ] Todo valor alterado é rastreável até seu original pela trilha de auditoria. +- [ ] Métricas de qualidade antes/depois e uma contagem de rejeições são reportadas. + +## Armadilhas Comuns + +- Preencher valores ausentes com um padrão que polui a análise (ex.: `0` onde NULL significa "desconhecido"). +- Deduplicar pela chave bruta, deixando "Ana" e "ANA " sobreviverem como dois registros. +- Aplicar uma transformação irreversível sem registro do valor original. +- Forçar linhas não corrigíveis a passar em vez de colocá-las em quarentena, corrompendo o conjunto limpo. + +## Recursos + +- [pandas: Trabalhando com dados ausentes](https://pandas.pydata.org/docs/user_guide/missing_data.html) — estratégias para nulos bem feitas. +- [Formato de número de telefone E.164](https://en.wikipedia.org/wiki/E.164) — o padrão internacional canônico de telefone. +- [Formas de normalização Unicode](https://unicode.org/reports/tr15/) — por que texto precisa ser canonizado antes da comparação. +- [Tidy Data (Hadley Wickham)](https://vita.had.co.nz/papers/tidy-data.pdf) — o artigo que define o que dados tabulares "limpos" significam. diff --git a/projects/data-engineering/beginner/09-json-transformer/README.md b/projects/data-engineering/beginner/09-json-transformer/README.md index 7d6789e..3f88bb5 100644 --- a/projects/data-engineering/beginner/09-json-transformer/README.md +++ b/projects/data-engineering/beginner/09-json-transformer/README.md @@ -1,34 +1,94 @@ # JSON Transformer -## Idea -Create a tool that transforms JSON data between formats. Learn about JSON processing and schema transformations. +> 🌐 **English** · [Português](./README.pt-BR.md) + +**Domain:** Data Engineering · **Level:** Beginner · **Estimated time:** 3–6 hours + +## Overview + +Two systems rarely agree on the shape of their JSON. One nests an address deep inside a customer object; the other wants a flat row with `customer_city`. Build a tool that reshapes JSON from a source structure to a target structure using a declarative mapping — flattening nested objects, renaming keys, picking fields out of arrays, and casting types. The goal is a small transformation *engine* driven by configuration rather than one-off code, so the same tool can adapt document A into document B without you rewriting logic each time the schema changes. + +## Prerequisites + +- Solid understanding of JSON (objects, arrays, nesting, null) +- Comfort navigating nested data structures in code +- Familiarity with recursion or iterative traversal of trees +- Beginner error handling for missing or unexpected fields ## Learning Objectives -- Parse JSON -- Transform structure -- Validate schemas -- Handle nested data -- Export transformed data - -## Implementation Tips -- Implement JSON parser -- Create transformation rules -- Add schema validation -- Implement flattening/nesting -- Create field mapping -- Add conditional transformations -- Implement aggregations -- Create filtering -- Add validation -- Implement performance optimization -- Create error handling -- Build rule engine -- Add batch processing -- Create testing framework - -## Key Challenges -- Nested structure transformation -- Schema evolution -- Performance with large JSONs -- Complex transformation logic -- Error handling + +By the end, you should be able to: + +- Traverse arbitrarily nested JSON safely, handling missing paths +- Express a transformation as a source-path → target-path mapping +- Flatten nested objects into dotted or underscored keys and back (nest) +- Handle arrays: pick an element, map over all, or aggregate (count, join) +- Cast values to a target type and default or reject on mismatch +- Validate output against an expected shape before emitting it + +## Functional Requirements + +1. The tool must read JSON input (a single document or newline-delimited records) and a mapping spec. +2. It must resolve nested source paths (e.g. `address.city`) and place values at target paths, missing paths handled explicitly. +3. It must support flattening (nested → flat) and nesting (flat → nested) driven by the mapping. +4. It must handle arrays with a declared rule: index, map-over, or aggregate. +5. Values must be cast to declared target types; a failed cast must default or route the record to rejects per config. +6. Transformed output must be validated against a target shape and written; a summary reports transformed and rejected counts. + +## Suggested Milestones + +1. **Milestone 1 — Rename & pick:** Map top-level fields and copy selected keys to the target. +2. **Milestone 2 — Nested & arrays:** Resolve nested paths, flatten/nest, and apply an array rule. +3. **Milestone 3 — Types & validation:** Add type casting, defaults/rejects, output validation, and a summary. + +## Data & Interface Sketch + +```text +source document + { "id": 7, + "customer": { "name": "Ana", "address": { "city": "Recife" } }, + "items": [ {"sku":"A","qty":2}, {"sku":"B","qty":1} ] } + +mapping spec + id -> order_id (cast: int) + customer.name -> customer_name + customer.address.city -> customer_city (default: "unknown") + items[*].qty -> total_qty (aggregate: sum) + items[0].sku -> first_sku + +target document (flat) + { "order_id": 7, "customer_name": "Ana", + "customer_city": "Recife", "total_qty": 3, "first_sku": "A" } + +on missing path -> use default OR reject (per field config) +summary: transformed=980 rejected=20 +``` + +## Stretch Goals + +- Support a small expression syntax for derived fields (concatenation, arithmetic). +- Add reverse mapping so a transform can be inverted (target → source). +- Validate against a JSON Schema instead of an ad-hoc shape. +- Stream newline-delimited JSON so huge files transform without buffering. + +## Definition of Done + +- [ ] Nested source paths resolve correctly, with missing paths handled per config. +- [ ] Flatten and nest both work, driven only by the mapping spec. +- [ ] Array rules (index, map, aggregate) produce correct target values. +- [ ] Type casts succeed or trigger the configured default/reject behavior. +- [ ] Output is validated against the target shape and a summary is reported. + +## Common Pitfalls + +- Crashing on a missing nested key instead of applying a default or rejecting cleanly. +- Hard-coding the transformation so a schema change means editing code, not config. +- Losing array data by grabbing `[0]` when you meant to aggregate over all elements. +- Emitting invalid output because you skip validating the transformed shape. + +## Resources + +- [JSON specification (ECMA-404)](https://www.json.org/json-en.html) — the precise data model you are traversing. +- [JMESPath](https://jmespath.org/) — a query language for extracting and reshaping JSON, great inspiration for path syntax. +- [jq manual](https://jqlang.github.io/jq/manual/) — the canonical JSON transformation tool to compare against. +- [JSON Schema validation](https://json-schema.org/understanding-json-schema/) — how to validate your target output rigorously. diff --git a/projects/data-engineering/beginner/09-json-transformer/README.pt-BR.md b/projects/data-engineering/beginner/09-json-transformer/README.pt-BR.md new file mode 100644 index 0000000..3dd523d --- /dev/null +++ b/projects/data-engineering/beginner/09-json-transformer/README.pt-BR.md @@ -0,0 +1,94 @@ +# Transformador de JSON + +> 🌐 [English](./README.md) · **Português** + +**Domínio:** Data Engineering · **Nível:** Iniciante · **Tempo estimado:** 3–6 horas + +## Visão Geral + +Dois sistemas raramente concordam sobre o formato de seu JSON. Um aninha um endereço fundo dentro de um objeto de cliente; o outro quer uma linha plana com `customer_city`. Construa uma ferramenta que remodela JSON de uma estrutura de origem para uma estrutura de destino usando um mapeamento declarativo — achatando objetos aninhados, renomeando chaves, escolhendo campos dentro de arrays e convertendo tipos. O objetivo é um pequeno *motor* de transformação orientado por configuração em vez de código pontual, para que a mesma ferramenta possa adaptar o documento A no documento B sem você reescrever lógica toda vez que o esquema muda. + +## Pré-requisitos + +- Entendimento sólido de JSON (objetos, arrays, aninhamento, null) +- Conforto para navegar em estruturas de dados aninhadas no código +- Familiaridade com recursão ou travessia iterativa de árvores +- Tratamento de erros em nível iniciante para campos ausentes ou inesperados + +## Objetivos de Aprendizado + +Ao final, você deve ser capaz de: + +- Percorrer JSON arbitrariamente aninhado com segurança, tratando caminhos ausentes +- Expressar uma transformação como um mapeamento caminho-de-origem → caminho-de-destino +- Achatar objetos aninhados em chaves com ponto ou sublinhado e o inverso (aninhar) +- Tratar arrays: escolher um elemento, mapear sobre todos ou agregar (contar, juntar) +- Converter valores para um tipo de destino e usar padrão ou rejeitar em caso de incompatibilidade +- Validar a saída contra um formato esperado antes de emiti-la + +## Requisitos Funcionais + +1. A ferramenta deve ler entrada JSON (um único documento ou registros delimitados por linha) e uma especificação de mapeamento. +2. Deve resolver caminhos de origem aninhados (ex.: `address.city`) e colocar valores em caminhos de destino, com caminhos ausentes tratados explicitamente. +3. Deve suportar achatamento (aninhado → plano) e aninhamento (plano → aninhado) orientados pelo mapeamento. +4. Deve tratar arrays com uma regra declarada: índice, mapear-sobre ou agregar. +5. Valores devem ser convertidos para os tipos de destino declarados; uma conversão falha deve usar padrão ou rotear o registro para rejeições conforme a config. +6. A saída transformada deve ser validada contra um formato de destino e escrita; um resumo reporta contagens de transformados e rejeitados. + +## Marcos Sugeridos + +1. **Marco 1 — Renomear e escolher:** Mapeie campos de nível superior e copie chaves selecionadas para o destino. +2. **Marco 2 — Aninhados e arrays:** Resolva caminhos aninhados, achate/aninhe e aplique uma regra de array. +3. **Marco 3 — Tipos e validação:** Adicione conversão de tipos, padrões/rejeições, validação de saída e um resumo. + +## Esboço de Dados e Interface + +```text +documento de origem + { "id": 7, + "customer": { "name": "Ana", "address": { "city": "Recife" } }, + "items": [ {"sku":"A","qty":2}, {"sku":"B","qty":1} ] } + +especificação de mapeamento + id -> order_id (cast: int) + customer.name -> customer_name + customer.address.city -> customer_city (default: "unknown") + items[*].qty -> total_qty (aggregate: sum) + items[0].sku -> first_sku + +documento de destino (plano) + { "order_id": 7, "customer_name": "Ana", + "customer_city": "Recife", "total_qty": 3, "first_sku": "A" } + +em caminho ausente -> usa default OU rejeita (por config de campo) +resumo: transformados=980 rejeitados=20 +``` + +## Desafios Extras + +- Suportar uma pequena sintaxe de expressão para campos derivados (concatenação, aritmética). +- Adicionar mapeamento reverso para que uma transformação possa ser invertida (destino → origem). +- Validar contra um JSON Schema em vez de um formato ad-hoc. +- Transmitir JSON delimitado por linha para que arquivos enormes se transformem sem armazenamento em memória. + +## Definição de Pronto + +- [ ] Caminhos de origem aninhados resolvem corretamente, com caminhos ausentes tratados conforme a config. +- [ ] Achatar e aninhar funcionam, orientados apenas pela especificação de mapeamento. +- [ ] Regras de array (índice, mapear, agregar) produzem valores de destino corretos. +- [ ] Conversões de tipo têm sucesso ou disparam o comportamento configurado de padrão/rejeição. +- [ ] A saída é validada contra o formato de destino e um resumo é reportado. + +## Armadilhas Comuns + +- Travar em uma chave aninhada ausente em vez de aplicar um padrão ou rejeitar de forma limpa. +- Codificar a transformação de forma fixa, de modo que uma mudança de esquema significa editar código, não config. +- Perder dados de array pegando `[0]` quando você queria agregar sobre todos os elementos. +- Emitir saída inválida por pular a validação do formato transformado. + +## Recursos + +- [Especificação JSON (ECMA-404)](https://www.json.org/json-en.html) — o modelo de dados preciso que você está percorrendo. +- [JMESPath](https://jmespath.org/) — uma linguagem de consulta para extrair e remodelar JSON, ótima inspiração para sintaxe de caminhos. +- [Manual do jq](https://jqlang.github.io/jq/manual/) — a ferramenta canônica de transformação de JSON para comparar. +- [Validação com JSON Schema](https://json-schema.org/understanding-json-schema/) — como validar sua saída de destino com rigor. diff --git a/projects/data-engineering/beginner/10-basic-scheduler/README.md b/projects/data-engineering/beginner/10-basic-scheduler/README.md index 6a062b4..bc7ca59 100644 --- a/projects/data-engineering/beginner/10-basic-scheduler/README.md +++ b/projects/data-engineering/beginner/10-basic-scheduler/README.md @@ -1,34 +1,97 @@ # Basic Scheduler (cron-like) -## Idea -Build a basic task scheduler similar to cron. Learn about scheduling and task automation. +> 🌐 **English** · [Português](./README.pt-BR.md) + +**Domain:** Data Engineering · **Level:** Beginner · **Estimated time:** 3–6 hours + +## Overview + +Data pipelines rarely run on demand — they run *on a schedule*. Build a small cron-like scheduler that reads a list of jobs, each with a time expression, and runs each one when its time comes. You will parse cron-style expressions, compute the next run time, execute the due jobs, and keep a history of what ran and whether it succeeded. The deceptively hard parts are the ones every real scheduler wrestles with: not running a job twice for the same tick, deciding what to do about a missed run, and making sure a slow job does not silently overlap itself. + +## Prerequisites + +- Comfort working with dates, times, and the concept of "now" +- Basic parsing of a structured string (a cron expression) +- Ability to execute a function or shell command from code +- Beginner file I/O for reading job definitions and writing history ## Learning Objectives -- Implement scheduling logic -- Handle time expressions -- Execute tasks -- Handle failures -- Monitor execution - -## Implementation Tips -- Create schedule parser (cron expressions) -- Implement scheduling engine -- Add task execution -- Create logging -- Add error handling -- Implement retry logic -- Create monitoring -- Add notification system -- Implement task history -- Create dashboard -- Add configuration management -- Implement parallel execution -- Add resource limits -- Build web interface - -## Key Challenges -- Cron expression parsing -- Time zone handling -- Concurrent task execution -- Failure recovery -- Resource management + +By the end, you should be able to: + +- Parse a cron-style expression into a schedule (minute, hour, day, month, weekday) +- Compute the next scheduled run time from a given moment +- Run a main loop that fires due jobs without busy-waiting +- Guarantee a job runs once per scheduled tick, not zero or twice +- Record execution history with status, start, and duration +- Prevent a long-running job from overlapping its next invocation + +## Functional Requirements + +1. The scheduler must load a list of jobs, each with a cron-style expression and a command/function to run. +2. It must correctly parse the expression and compute each job's next run time. +3. The main loop must execute a job exactly once when its scheduled time arrives. +4. It must never double-fire a job for the same tick, even if the loop is slightly delayed. +5. If a run is still in progress when the next is due, the scheduler must skip or queue it per a defined policy (no silent overlap). +6. It must persist a run history: job name, scheduled time, start, end, and success/failure. + +## Suggested Milestones + +1. **Milestone 1 — Parse & compute:** Parse a cron expression and print the next N run times. +2. **Milestone 2 — Run loop:** Add a loop that fires jobs at their due time and logs each run. +3. **Milestone 3 — Correctness:** Add once-per-tick guarantees, overlap prevention, and persisted history. + +## Data & Interface Sketch + +```text +job definitions (jobs file) + daily_export `0 2 * * *` -> run export.job + every_15m "*/15 * * * *"-> run sync.job + weekday_report "30 8 * * 1-5"-> run report.job + +cron field order + minute hour day-of-month month day-of-week + +scheduler loop + now = current time (truncated to the minute) + for job in jobs: + if job.next_run <= now and job.last_tick != now: + run(job); record(status, start, duration) + job.last_tick = now + job.next_run = compute_next(job.expr, now) + if job still running and due again -> skip (policy) + sleep until next minute boundary + +history.log + daily_export 2024-05-01T02:00 ok duration=41s + sync 2024-05-01T02:15 fail duration=3s "timeout" +``` + +## Stretch Goals + +- Add catch-up policy: on startup, decide whether to run jobs that were missed while down. +- Support time zones so `0 2 * * *` means 2 AM in a configured zone. +- Add per-job retry with a max attempt count on failure. +- Expose a small status command listing each job's last and next run. + +## Definition of Done + +- [ ] Cron expressions parse and next-run computation matches hand-checked cases. +- [ ] A due job runs exactly once at its scheduled tick. +- [ ] The loop never double-fires a job for the same minute. +- [ ] An overlapping run is skipped or queued per the documented policy. +- [ ] Run history records status, timing, and failures for every execution. + +## Common Pitfalls + +- Busy-waiting in a tight loop instead of sleeping until the next boundary, burning CPU. +- Double-firing because the loop checks the same minute twice — track the last tick per job. +- Ignoring timezones and DST, so schedules drift or fire twice on clock changes. +- Letting a slow job overlap its next run, so two copies mutate the same data at once. + +## Resources + +- [crontab.guru](https://crontab.guru/) — interactively decode and verify cron expressions. +- [Wikipedia: Cron](https://en.wikipedia.org/wiki/Cron) — the field format and its history. +- [Python `datetime`](https://docs.python.org/3/library/datetime.html) — computing next-run times and durations correctly. +- [croniter library](https://github.com/kiorky/croniter) — a reference implementation of next-run computation to compare against. diff --git a/projects/data-engineering/beginner/10-basic-scheduler/README.pt-BR.md b/projects/data-engineering/beginner/10-basic-scheduler/README.pt-BR.md new file mode 100644 index 0000000..8e6ab17 --- /dev/null +++ b/projects/data-engineering/beginner/10-basic-scheduler/README.pt-BR.md @@ -0,0 +1,97 @@ +# Agendador Básico (tipo cron) + +> 🌐 [English](./README.md) · **Português** + +**Domínio:** Data Engineering · **Nível:** Iniciante · **Tempo estimado:** 3–6 horas + +## Visão Geral + +Pipelines de dados raramente rodam sob demanda — eles rodam *em uma agenda*. Construa um pequeno agendador tipo cron que lê uma lista de jobs, cada um com uma expressão de tempo, e roda cada um quando sua hora chega. Você vai analisar expressões estilo cron, calcular o próximo horário de execução, executar os jobs devidos e manter um histórico do que rodou e se teve sucesso. As partes enganosamente difíceis são as com que todo agendador real se debate: não rodar um job duas vezes no mesmo tick, decidir o que fazer com uma execução perdida, e garantir que um job lento não se sobreponha silenciosamente a si mesmo. + +## Pré-requisitos + +- Conforto para trabalhar com datas, horas e o conceito de "agora" +- Parsing básico de uma string estruturada (uma expressão cron) +- Capacidade de executar uma função ou comando de shell a partir do código +- I/O de arquivo em nível iniciante para ler definições de jobs e escrever histórico + +## Objetivos de Aprendizado + +Ao final, você deve ser capaz de: + +- Analisar uma expressão estilo cron em uma agenda (minuto, hora, dia, mês, dia da semana) +- Calcular o próximo horário de execução agendado a partir de um dado momento +- Rodar um laço principal que dispara jobs devidos sem busy-waiting +- Garantir que um job rode uma vez por tick agendado, nem zero nem duas vezes +- Registrar o histórico de execução com status, início e duração +- Impedir que um job de longa duração se sobreponha à sua próxima invocação + +## Requisitos Funcionais + +1. O agendador deve carregar uma lista de jobs, cada um com uma expressão estilo cron e um comando/função a rodar. +2. Deve analisar corretamente a expressão e calcular o próximo horário de execução de cada job. +3. O laço principal deve executar um job exatamente uma vez quando seu horário agendado chega. +4. Nunca deve disparar em dobro um job no mesmo tick, mesmo que o laço esteja levemente atrasado. +5. Se uma execução ainda está em andamento quando a próxima é devida, o agendador deve pulá-la ou enfileirá-la conforme uma política definida (sem sobreposição silenciosa). +6. Deve persistir um histórico de execução: nome do job, horário agendado, início, fim e sucesso/falha. + +## Marcos Sugeridos + +1. **Marco 1 — Analisar e calcular:** Analise uma expressão cron e imprima os próximos N horários de execução. +2. **Marco 2 — Laço de execução:** Adicione um laço que dispara jobs no horário devido e registra cada execução. +3. **Marco 3 — Correção:** Adicione garantias de uma-vez-por-tick, prevenção de sobreposição e histórico persistido. + +## Esboço de Dados e Interface + +```text +definições de jobs (arquivo de jobs) + daily_export `0 2 * * *` -> roda export.job + every_15m "*/15 * * * *"-> roda sync.job + weekday_report "30 8 * * 1-5"-> roda report.job + +ordem dos campos cron + minuto hora dia-do-mês mês dia-da-semana + +laço do agendador + now = horário atual (truncado ao minuto) + para job em jobs: + se job.next_run <= now e job.last_tick != now: + roda(job); registra(status, início, duração) + job.last_tick = now + job.next_run = calcula_próximo(job.expr, now) + se job ainda rodando e devido de novo -> pula (política) + dorme até o próximo limite de minuto + +history.log + daily_export 2024-05-01T02:00 ok duração=41s + sync 2024-05-01T02:15 fail duração=3s "timeout" +``` + +## Desafios Extras + +- Adicionar política de recuperação: na inicialização, decidir se roda jobs que foram perdidos enquanto estava fora do ar. +- Suportar fusos horários para que `0 2 * * *` signifique 2h em um fuso configurado. +- Adicionar retry por job com um número máximo de tentativas em caso de falha. +- Expor um pequeno comando de status listando a última e a próxima execução de cada job. + +## Definição de Pronto + +- [ ] Expressões cron são analisadas e o cálculo do próximo horário bate com casos verificados à mão. +- [ ] Um job devido roda exatamente uma vez em seu tick agendado. +- [ ] O laço nunca dispara em dobro um job no mesmo minuto. +- [ ] Uma execução sobreposta é pulada ou enfileirada conforme a política documentada. +- [ ] O histórico de execução registra status, tempo e falhas para toda execução. + +## Armadilhas Comuns + +- Fazer busy-waiting em um laço apertado em vez de dormir até o próximo limite, queimando CPU. +- Disparar em dobro porque o laço verifica o mesmo minuto duas vezes — rastreie o último tick por job. +- Ignorar fusos horários e horário de verão, fazendo as agendas derivarem ou dispararem duas vezes em mudanças de relógio. +- Deixar um job lento se sobrepor à sua próxima execução, fazendo duas cópias mutarem os mesmos dados ao mesmo tempo. + +## Recursos + +- [crontab.guru](https://crontab.guru/) — decodifique e verifique expressões cron de forma interativa. +- [Wikipedia: Cron](https://en.wikipedia.org/wiki/Cron) — o formato dos campos e sua história. +- [Python `datetime`](https://docs.python.org/3/library/datetime.html) — calcular próximos horários e durações corretamente. +- [Biblioteca croniter](https://github.com/kiorky/croniter) — uma implementação de referência do cálculo de próxima execução para comparar. diff --git a/projects/data-engineering/intermediate/01-airflow-etl/README.md b/projects/data-engineering/intermediate/01-airflow-etl/README.md index dfbbf92..9d6259d 100644 --- a/projects/data-engineering/intermediate/01-airflow-etl/README.md +++ b/projects/data-engineering/intermediate/01-airflow-etl/README.md @@ -1,34 +1,92 @@ # ETL Pipeline with Airflow -## Idea -Build an enterprise-grade ETL pipeline using Apache Airflow. Learn about workflow orchestration and scheduling. +> 🌐 **English** · [Português](./README.pt-BR.md) + +**Domain:** Data Engineering · **Level:** Intermediate · **Estimated time:** 1–2 days + +## Overview + +Build a scheduled ETL pipeline that extracts from a source (an API or an operational database), transforms the data, and loads it into a warehouse or analytics table — all orchestrated by Apache Airflow. The interesting part is not the transform itself but the orchestration around it: expressing dependencies as a DAG, scheduling daily runs, and making each run *idempotent* so a re-run for a given date produces the same result instead of duplicating rows. You will add a sensor that waits for upstream data to land before the DAG proceeds, wire up retries and alerting so a transient failure heals itself, and support a backfill that reprocesses a range of historical dates. By the end you will understand why data teams reach for a scheduler instead of a cron job and a pile of shell scripts. + +## Prerequisites + +- Comfort writing Python and reasoning about functions with side effects +- Basic SQL and an understanding of what a batch job is +- Familiarity with cron-style scheduling concepts +- A local Airflow environment (Docker Compose or `airflow standalone`) — do not install into a shared cluster ## Learning Objectives -- Design DAGs (Directed Acyclic Graphs) -- Implement complex workflows -- Handle dependencies -- Monitor pipelines -- Implement error handling - -## Implementation Tips -- Create Airflow DAGs -- Define task dependencies -- Implement sensors for data readiness -- Add data quality checks -- Create branching logic -- Implement error handling -- Add retry mechanisms -- Create monitoring -- Implement alerting -- Add logging and tracking -- Create backfill functionality -- Implement dynamic DAGs -- Add testing framework -- Build Airflow UI exploration - -## Key Challenges -- Complex DAG design -- Dependency management -- Scalability -- Monitoring and debugging -- Resource optimization + +By the end, you should be able to: + +- Model a data workflow as a DAG with explicit task dependencies +- Parameterize tasks by the logical execution date so runs are isolated and reproducible +- Make a load idempotent so re-running a date never duplicates data +- Use a sensor to wait for an upstream dependency before proceeding +- Backfill a historical date range and reason about task retries and alerting + +## Functional Requirements + +1. The pipeline must be defined as an Airflow DAG with a daily schedule and clear task dependencies. +2. Each task must derive its input and output partition from the run's logical (execution) date, not `now()`. +3. A load for a given date must be idempotent — re-running it replaces that date's rows rather than appending duplicates. +4. A sensor or equivalent must block the DAG until the required source data for that date is available. +5. Failed tasks must retry with backoff a bounded number of times, and exhausted retries must trigger an alert. +6. The DAG must support a backfill over an arbitrary date range without manual editing per date. +7. The pipeline must record run metadata (rows processed, duration) for later inspection. + +## Suggested Milestones + +1. **Milestone 1 — Linear DAG:** Extract → transform → load as three ordered tasks running on a daily schedule. +2. **Milestone 2 — Idempotent load & sensor:** Make the load overwrite-by-date, and gate it behind a readiness sensor. +3. **Milestone 3 — Reliability & backfill:** Add retries with backoff, failure alerting, run metrics, then backfill a week. + +## Data & Interface Sketch + +```text +DAG: daily_sales_etl schedule=@daily start_date=2024-01-01 + + wait_for_source (sensor: is source/{{ ds }} present?) + | + extract --> raw/date={{ ds }}/data.parquet + | + transform --> staging table (partition = ds) + | + load --> DELETE WHERE dt = {{ ds }}; INSERT ... (idempotent) + | + record_metrics --> runs(dag_id, ds, rows, seconds) + +{{ ds }} = Airflow logical execution date (YYYY-MM-DD), NOT "today" +Task config: retries=3, retry_delay=5m, sla=2h, on_failure_callback=notify +Backfill: airflow dags backfill -s 2024-01-01 -e 2024-01-07 daily_sales_etl +``` + +## Stretch Goals + +- Add a branching task that skips the load when the extract yields zero rows. +- Generate the DAG dynamically from a config file listing multiple source tables. +- Use dynamic task mapping to fan out over partitions in parallel. +- Add an SLA so a run that misses its deadline raises a distinct alert. + +## Definition of Done + +- [ ] The DAG renders in the Airflow UI with correct dependencies and no import errors. +- [ ] Re-running any single date produces identical output — verified by row counts before and after. +- [ ] The load never starts until the readiness sensor confirms source data exists. +- [ ] A backfill over several days completes and populates one correct partition per date. +- [ ] A forced task failure retries per config and fires the configured alert. + +## Common Pitfalls + +- Using `datetime.now()` inside tasks instead of the execution date, which breaks backfills and reproducibility. +- Appending on load so re-runs silently double the data — always make the write idempotent. +- Doing heavy computation in the DAG file's top-level scope, which runs on every scheduler parse. +- Setting `retries` without `retry_delay`, so a flapping dependency hammers the source. +- Treating retries as a substitute for idempotency; a retry of a non-idempotent task corrupts data. + +## Resources + +- [Apache Airflow: Core Concepts](https://airflow.apache.org/docs/apache-airflow/stable/core-concepts/index.html) — DAGs, tasks, operators, and the scheduler. +- [Airflow: Best Practices](https://airflow.apache.org/docs/apache-airflow/stable/best-practices.html) — idempotency, top-level code, and testing. +- [Astronomer: Airflow DAG best practices](https://www.astronomer.io/docs/learn/dag-best-practices) — practical patterns for reliable pipelines. +- [The Data Engineer roadmap](https://roadmap.sh/data-engineer) — where orchestration fits in the wider picture. diff --git a/projects/data-engineering/intermediate/01-airflow-etl/README.pt-BR.md b/projects/data-engineering/intermediate/01-airflow-etl/README.pt-BR.md new file mode 100644 index 0000000..ac1b745 --- /dev/null +++ b/projects/data-engineering/intermediate/01-airflow-etl/README.pt-BR.md @@ -0,0 +1,92 @@ +# Pipeline ETL com Airflow + +> 🌐 [English](./README.md) · **Português** + +**Domínio:** Data Engineering · **Nível:** Intermediário · **Tempo estimado:** 1–2 dias + +## Visão Geral + +Construa um pipeline ETL agendado que extrai de uma fonte (uma API ou um banco operacional), transforma os dados e os carrega em um warehouse ou tabela analítica — tudo orquestrado pelo Apache Airflow. A parte interessante não é a transformação em si, mas a orquestração ao redor dela: expressar dependências como um DAG, agendar execuções diárias e tornar cada execução *idempotente*, para que reprocessar uma data produza o mesmo resultado em vez de duplicar linhas. Você adicionará um sensor que espera os dados de origem chegarem antes de o DAG prosseguir, configurará retries e alertas para que uma falha transitória se cure sozinha, e suportará um backfill que reprocessa um intervalo de datas históricas. Ao final, você entenderá por que times de dados recorrem a um agendador em vez de um cron e uma pilha de scripts shell. + +## Pré-requisitos + +- Conforto para escrever Python e raciocinar sobre funções com efeitos colaterais +- SQL básico e o entendimento do que é um job em lote +- Familiaridade com conceitos de agendamento estilo cron +- Um ambiente Airflow local (Docker Compose ou `airflow standalone`) — não instale em um cluster compartilhado + +## Objetivos de Aprendizado + +Ao final, você deve ser capaz de: + +- Modelar um fluxo de dados como um DAG com dependências explícitas entre tarefas +- Parametrizar tarefas pela data lógica de execução para que as execuções sejam isoladas e reproduzíveis +- Tornar uma carga idempotente para que reprocessar uma data nunca duplique dados +- Usar um sensor para esperar uma dependência upstream antes de prosseguir +- Fazer o backfill de um intervalo de datas históricas e raciocinar sobre retries e alertas + +## Requisitos Funcionais + +1. O pipeline deve ser definido como um DAG do Airflow com agendamento diário e dependências claras entre tarefas. +2. Cada tarefa deve derivar sua partição de entrada e saída da data lógica (de execução) do run, não de `now()`. +3. A carga de uma dada data deve ser idempotente — reprocessá-la substitui as linhas daquela data em vez de anexar duplicatas. +4. Um sensor ou equivalente deve bloquear o DAG até que os dados de origem daquela data estejam disponíveis. +5. Tarefas que falham devem repetir com backoff um número limitado de vezes, e retries esgotados devem disparar um alerta. +6. O DAG deve suportar um backfill de um intervalo arbitrário de datas sem edição manual por data. +7. O pipeline deve registrar metadados do run (linhas processadas, duração) para inspeção posterior. + +## Marcos Sugeridos + +1. **Marco 1 — DAG linear:** Extrair → transformar → carregar como três tarefas ordenadas em agendamento diário. +2. **Marco 2 — Carga idempotente e sensor:** Faça a carga sobrescrever por data e a proteja atrás de um sensor de prontidão. +3. **Marco 3 — Confiabilidade e backfill:** Adicione retries com backoff, alertas de falha, métricas de run e faça o backfill de uma semana. + +## Esboço de Dados e Interface + +```text +DAG: daily_sales_etl schedule=@daily start_date=2024-01-01 + + wait_for_source (sensor: source/{{ ds }} existe?) + | + extract --> raw/date={{ ds }}/data.parquet + | + transform --> tabela de staging (partição = ds) + | + load --> DELETE WHERE dt = {{ ds }}; INSERT ... (idempotente) + | + record_metrics --> runs(dag_id, ds, linhas, segundos) + +{{ ds }} = data lógica de execução do Airflow (YYYY-MM-DD), NÃO "hoje" +Config da tarefa: retries=3, retry_delay=5m, sla=2h, on_failure_callback=notify +Backfill: airflow dags backfill -s 2024-01-01 -e 2024-01-07 daily_sales_etl +``` + +## Desafios Extras + +- Adicione uma tarefa de branching que pula a carga quando a extração retorna zero linhas. +- Gere o DAG dinamicamente a partir de um arquivo de config listando múltiplas tabelas de origem. +- Use mapeamento dinâmico de tarefas para paralelizar sobre partições. +- Adicione uma SLA para que um run que perde o prazo dispare um alerta distinto. + +## Definição de Pronto + +- [ ] O DAG renderiza na UI do Airflow com dependências corretas e sem erros de import. +- [ ] Reprocessar qualquer data produz saída idêntica — verificado por contagens de linhas antes e depois. +- [ ] A carga nunca inicia até o sensor de prontidão confirmar que os dados de origem existem. +- [ ] Um backfill de vários dias completa e popula uma partição correta por data. +- [ ] Uma falha forçada de tarefa repete conforme a config e dispara o alerta configurado. + +## Armadilhas Comuns + +- Usar `datetime.now()` dentro das tarefas em vez da data de execução, o que quebra backfills e a reprodutibilidade. +- Anexar na carga, fazendo reprocessamentos duplicarem os dados silenciosamente — sempre torne a escrita idempotente. +- Fazer computação pesada no escopo de topo do arquivo do DAG, que roda a cada parse do scheduler. +- Definir `retries` sem `retry_delay`, fazendo uma dependência instável martelar a fonte. +- Tratar retries como substituto de idempotência; um retry de uma tarefa não idempotente corrompe os dados. + +## Recursos + +- [Apache Airflow: Conceitos Centrais](https://airflow.apache.org/docs/apache-airflow/stable/core-concepts/index.html) — DAGs, tarefas, operadores e o scheduler. +- [Airflow: Boas Práticas](https://airflow.apache.org/docs/apache-airflow/stable/best-practices.html) — idempotência, código de topo e testes. +- [Astronomer: boas práticas de DAG no Airflow](https://www.astronomer.io/docs/learn/dag-best-practices) — padrões práticos para pipelines confiáveis. +- [O roadmap de Data Engineer](https://roadmap.sh/data-engineer) — onde a orquestração se encaixa no quadro maior. diff --git a/projects/data-engineering/intermediate/02-data-warehouse-loader/README.md b/projects/data-engineering/intermediate/02-data-warehouse-loader/README.md index adc08cf..6897d27 100644 --- a/projects/data-engineering/intermediate/02-data-warehouse-loader/README.md +++ b/projects/data-engineering/intermediate/02-data-warehouse-loader/README.md @@ -1,34 +1,95 @@ # Data Warehouse Loader -## Idea -Build a system to load data into a data warehouse with optimizations for analytics. Learn about warehouse design and optimizations. +> 🌐 **English** · [Português](./README.pt-BR.md) + +**Domain:** Data Engineering · **Level:** Intermediate · **Estimated time:** 1–2 days + +## Overview + +Build the loading layer that turns raw operational records into a query-friendly dimensional model in a warehouse. You will land source data into a staging area, then load it into fact and dimension tables shaped as a star schema. The centerpiece is handling *slowly changing dimensions* (SCD Type 2): when a customer changes their city, you keep the old row, close it out, and open a new versioned row — so historical facts still join to the address that was true at the time. You will also make the load incremental and idempotent, so re-running a batch corrects itself instead of doubling revenue, and support a backfill that rebuilds a range of past batches. This is the difference between a warehouse people trust and a spreadsheet with extra steps. + +## Prerequisites + +- Solid SQL: joins, `GROUP BY`, window functions, and `MERGE`/upsert semantics +- Understanding of primary/foreign keys and referential integrity +- Familiarity with a warehouse or database (Postgres, DuckDB, BigQuery, or Snowflake) +- Basic grasp of the ETL/ELT distinction +- The [Airflow ETL project](../01-airflow-etl/) is a useful warm-up for the load orchestration ## Learning Objectives -- Design warehouse schema -- Implement efficient loading -- Create dimension/fact tables -- Implement slowly changing dimensions -- Optimize queries - -## Implementation Tips -- Design star or snowflake schema -- Create staging tables -- Implement dimension loading -- Create fact table loading -- Implement slowly changing dimensions (SCD) -- Add incremental loading -- Implement data validation -- Create deduplication -- Optimize warehouse structure -- Implement partitioning -- Create indexing strategy -- Add compression -- Implement materialized views -- Build performance monitoring - -## Key Challenges -- Schema design decisions -- SCD implementation -- Performance optimization -- Data consistency -- Incremental load complexity + +By the end, you should be able to: + +- Design a star schema with fact and dimension tables and surrogate keys +- Implement SCD Type 2 so dimension history is preserved and queryable as-of a date +- Load incrementally using a high-water mark rather than reprocessing everything +- Make loads idempotent via upsert/merge so re-runs never double-count +- Backfill a range of batches and verify referential integrity afterward + +## Functional Requirements + +1. Source data must first land in a staging table before any transformation into the model. +2. The warehouse must expose at least one fact table and two dimensions in a star schema, keyed by surrogate keys. +3. A tracked dimension must implement SCD Type 2 with `valid_from`, `valid_to`, and a current-row flag. +4. Loads must be incremental, selecting only rows changed since the last successful high-water mark. +5. Re-running a batch must be idempotent — an upsert/merge, not a blind insert. +6. Fact rows must reference the dimension version that was current at the event's timestamp. +7. A backfill must be able to rebuild a specified range of batches without duplicating rows. + +## Suggested Milestones + +1. **Milestone 1 — Stage & load dims:** Land source into staging and populate dimensions with surrogate keys. +2. **Milestone 2 — SCD Type 2 & facts:** Version a changing dimension and load facts that join to the correct version. +3. **Milestone 3 — Incremental & idempotent:** Add a high-water mark, make the merge idempotent, and test a backfill. + +## Data & Interface Sketch + +```text +staging_customer(raw cols..., loaded_at) + +dim_customer fact_orders + customer_sk PK (surrogate) order_sk PK + customer_id (natural/business key) customer_sk FK -> dim_customer + city order_date_sk FK -> dim_date + valid_from timestamp amount + valid_to timestamp (or NULL) ... + is_current boolean + +SCD2 on change of city: + UPDATE dim_customer SET valid_to = now(), is_current = false + WHERE customer_id = ? AND is_current; + INSERT new row with new city, valid_from = now(), is_current = true; + +Incremental: WHERE source.updated_at > last_high_water_mark +Idempotent load: MERGE ... ON natural_key WHEN MATCHED ... WHEN NOT MATCHED ... +``` + +## Stretch Goals + +- Add SCD Type 1 for an attribute where history is not worth keeping, and contrast the two. +- Build an as-of query that reconstructs the dimension state on an arbitrary past date. +- Add a late-arriving-fact handler that back-dates to the correct dimension version. +- Track load metrics (rows inserted/updated/rejected) per batch for monitoring. + +## Definition of Done + +- [ ] Facts join to dimensions with zero orphan surrogate keys (referential integrity holds). +- [ ] Changing a tracked attribute closes the old dimension row and opens a new current one. +- [ ] Re-running the same batch leaves row counts unchanged (idempotent merge verified). +- [ ] An incremental run touches only rows changed since the last high-water mark. +- [ ] A backfill over several batches reproduces the same result as loading them in order. + +## Common Pitfalls + +- Using the natural business key as the fact foreign key, which breaks the moment SCD2 creates a second version. +- Forgetting to close the previous row's `valid_to`, leaving two "current" rows for one entity. +- Blind `INSERT` loads that double data on re-run instead of `MERGE`/upsert. +- Advancing the high-water mark before the load commits, so a mid-load crash skips rows forever. +- Overlapping `valid_from`/`valid_to` ranges that make as-of joins return duplicates. + +## Resources + +- [Kimball Group: Dimensional Modeling Techniques](https://www.kimballgroup.com/data-warehouse-business-intelligence-resources/kimball-techniques/dimensional-modeling-techniques/) — the canonical reference for star schemas and SCDs. +- [Wikipedia: Slowly Changing Dimension](https://en.wikipedia.org/wiki/Slowly_changing_dimension) — a concise tour of SCD types 1–6. +- [dbt: SCD / snapshots](https://docs.getdbt.com/docs/build/snapshots) — how a modern tool models Type 2 history. +- [Star schema (Wikipedia)](https://en.wikipedia.org/wiki/Star_schema) — facts, dimensions, and surrogate keys. diff --git a/projects/data-engineering/intermediate/02-data-warehouse-loader/README.pt-BR.md b/projects/data-engineering/intermediate/02-data-warehouse-loader/README.pt-BR.md new file mode 100644 index 0000000..b3144fa --- /dev/null +++ b/projects/data-engineering/intermediate/02-data-warehouse-loader/README.pt-BR.md @@ -0,0 +1,95 @@ +# Carregador de Data Warehouse + +> 🌐 [English](./README.md) · **Português** + +**Domínio:** Data Engineering · **Nível:** Intermediário · **Tempo estimado:** 1–2 dias + +## Visão Geral + +Construa a camada de carga que transforma registros operacionais brutos em um modelo dimensional amigável para consultas em um warehouse. Você vai aterrissar os dados de origem em uma área de staging e depois carregá-los em tabelas fato e dimensão modeladas como um star schema. A peça central é lidar com *dimensões que mudam lentamente* (SCD Tipo 2): quando um cliente muda de cidade, você mantém a linha antiga, a encerra e abre uma nova linha versionada — para que fatos históricos ainda façam join com o endereço que era verdadeiro na época. Você também tornará a carga incremental e idempotente, para que reprocessar um lote se corrija em vez de dobrar a receita, e suportará um backfill que reconstrói um intervalo de lotes passados. Essa é a diferença entre um warehouse em que as pessoas confiam e uma planilha com passos extras. + +## Pré-requisitos + +- SQL sólido: joins, `GROUP BY`, funções de janela e semântica de `MERGE`/upsert +- Entendimento de chaves primárias/estrangeiras e integridade referencial +- Familiaridade com um warehouse ou banco (Postgres, DuckDB, BigQuery ou Snowflake) +- Noção básica da distinção ETL/ELT +- O [projeto de ETL com Airflow](../01-airflow-etl/) é um bom aquecimento para a orquestração da carga + +## Objetivos de Aprendizado + +Ao final, você deve ser capaz de: + +- Projetar um star schema com tabelas fato e dimensão e chaves substitutas +- Implementar SCD Tipo 2 para que o histórico da dimensão seja preservado e consultável em uma data +- Carregar incrementalmente usando uma marca d'água em vez de reprocessar tudo +- Tornar cargas idempotentes via upsert/merge para que reprocessamentos nunca dupliquem contagens +- Fazer backfill de um intervalo de lotes e verificar a integridade referencial depois + +## Requisitos Funcionais + +1. Os dados de origem devem primeiro aterrissar em uma tabela de staging antes de qualquer transformação no modelo. +2. O warehouse deve expor ao menos uma tabela fato e duas dimensões em star schema, chaveadas por chaves substitutas. +3. Uma dimensão rastreada deve implementar SCD Tipo 2 com `valid_from`, `valid_to` e um flag de linha atual. +4. As cargas devem ser incrementais, selecionando apenas linhas alteradas desde a última marca d'água bem-sucedida. +5. Reprocessar um lote deve ser idempotente — um upsert/merge, não um insert cego. +6. Linhas de fato devem referenciar a versão da dimensão que era atual no timestamp do evento. +7. Um backfill deve conseguir reconstruir um intervalo especificado de lotes sem duplicar linhas. + +## Marcos Sugeridos + +1. **Marco 1 — Staging e carga de dimensões:** Aterrisse a origem em staging e popule as dimensões com chaves substitutas. +2. **Marco 2 — SCD Tipo 2 e fatos:** Versione uma dimensão que muda e carregue fatos que fazem join com a versão correta. +3. **Marco 3 — Incremental e idempotente:** Adicione uma marca d'água, torne o merge idempotente e teste um backfill. + +## Esboço de Dados e Interface + +```text +staging_customer(cols brutas..., loaded_at) + +dim_customer fact_orders + customer_sk PK (substituta) order_sk PK + customer_id (chave natural/negócio) customer_sk FK -> dim_customer + city order_date_sk FK -> dim_date + valid_from timestamp amount + valid_to timestamp (ou NULL) ... + is_current boolean + +SCD2 na mudança de city: + UPDATE dim_customer SET valid_to = now(), is_current = false + WHERE customer_id = ? AND is_current; + INSERT nova linha com nova city, valid_from = now(), is_current = true; + +Incremental: WHERE source.updated_at > ultima_marca_dagua +Carga idempotente: MERGE ... ON chave_natural WHEN MATCHED ... WHEN NOT MATCHED ... +``` + +## Desafios Extras + +- Adicione SCD Tipo 1 para um atributo cujo histórico não vale a pena manter, e contraste os dois. +- Construa uma consulta "as-of" que reconstrói o estado da dimensão em uma data passada arbitrária. +- Adicione um tratador de fato tardio que retroage à versão correta da dimensão. +- Rastreie métricas de carga (linhas inseridas/atualizadas/rejeitadas) por lote para monitoramento. + +## Definição de Pronto + +- [ ] Fatos fazem join com dimensões sem nenhuma chave substituta órfã (a integridade referencial se mantém). +- [ ] Mudar um atributo rastreado encerra a linha antiga da dimensão e abre uma nova atual. +- [ ] Reprocessar o mesmo lote mantém as contagens de linhas inalteradas (merge idempotente verificado). +- [ ] Um run incremental toca apenas linhas alteradas desde a última marca d'água. +- [ ] Um backfill de vários lotes reproduz o mesmo resultado de carregá-los em ordem. + +## Armadilhas Comuns + +- Usar a chave de negócio natural como FK do fato, o que quebra no momento em que o SCD2 cria uma segunda versão. +- Esquecer de encerrar o `valid_to` da linha anterior, deixando duas linhas "atuais" para uma entidade. +- Cargas com `INSERT` cego que duplicam dados no reprocessamento em vez de `MERGE`/upsert. +- Avançar a marca d'água antes de a carga confirmar, fazendo um crash no meio pular linhas para sempre. +- Intervalos `valid_from`/`valid_to` sobrepostos que fazem joins "as-of" retornarem duplicatas. + +## Recursos + +- [Kimball Group: Técnicas de Modelagem Dimensional](https://www.kimballgroup.com/data-warehouse-business-intelligence-resources/kimball-techniques/dimensional-modeling-techniques/) — a referência canônica de star schemas e SCDs. +- [Wikipedia: Slowly Changing Dimension](https://en.wikipedia.org/wiki/Slowly_changing_dimension) — um tour conciso pelos tipos 1–6 de SCD. +- [dbt: snapshots / SCD](https://docs.getdbt.com/docs/build/snapshots) — como uma ferramenta moderna modela histórico Tipo 2. +- [Star schema (Wikipedia)](https://en.wikipedia.org/wiki/Star_schema) — fatos, dimensões e chaves substitutas. diff --git a/projects/data-engineering/intermediate/03-streaming-kafka/README.md b/projects/data-engineering/intermediate/03-streaming-kafka/README.md index d486774..4ebd582 100644 --- a/projects/data-engineering/intermediate/03-streaming-kafka/README.md +++ b/projects/data-engineering/intermediate/03-streaming-kafka/README.md @@ -1,34 +1,93 @@ # Streaming Pipeline (Kafka) -## Idea -Create a real-time streaming pipeline using Kafka. Learn about event streaming and real-time processing. +> 🌐 **English** · [Português](./README.pt-BR.md) + +**Domain:** Data Engineering · **Level:** Intermediate · **Estimated time:** 1–2 days + +## Overview + +Build a real-time streaming pipeline on Apache Kafka: a producer that emits events to a topic, and a consumer that reads them, maintains state, and writes results to a sink. The shift from batch to streaming forces you to confront questions batch never asks — what happens when the consumer crashes mid-message, how do you avoid processing the same event twice, and how do you compute an aggregate over an unbounded stream. You will manage consumer offsets deliberately, design for at-least-once delivery, and make your processing idempotent so duplicates are harmless. You will also add monitoring for consumer lag so you can see when the pipeline falls behind. This project is where "the data is just sitting in a table" stops being true and you start thinking in terms of continuously arriving events. + +## Prerequisites + +- Comfort with a language that has a Kafka client (Python, Java, or Go) +- Understanding of publish/subscribe messaging and queues +- Familiarity with JSON or another serialization format +- A local Kafka (Docker Compose with Kafka + optionally a schema registry) ## Learning Objectives -- Produce to Kafka topics -- Consume from Kafka -- Process streams -- Handle backpressure -- Ensure exactly-once semantics - -## Implementation Tips -- Create Kafka producers -- Implement consumers -- Add message serialization -- Create stream processing logic -- Implement stateful operations -- Add windowing operations -- Create aggregations -- Implement joins -- Add error handling -- Create consumer groups -- Implement offset management -- Add monitoring -- Create schema registry integration -- Build performance tuning - -## Key Challenges -- Exactly-once processing -- Backpressure handling -- State management -- Stream joins complexity -- Performance at scale + +By the end, you should be able to: + +- Produce and consume events on a partitioned Kafka topic +- Reason about delivery semantics: at-most-once, at-least-once, exactly-once +- Commit offsets deliberately so a crash resumes without losing or replaying data incorrectly +- Make consumer processing idempotent so at-least-once duplicates are harmless +- Compute a windowed aggregate over an unbounded stream and monitor consumer lag + +## Functional Requirements + +1. A producer must publish structured events to a Kafka topic with a partitioning key. +2. A consumer must read events and write derived results to a sink (database, file, or another topic). +3. The consumer must commit offsets only after a message is successfully processed (at-least-once). +4. Processing must be idempotent so a redelivered message does not corrupt the sink. +5. On restart, the consumer must resume from its last committed offset — no gaps, no full replay. +6. The pipeline must maintain a running aggregate (e.g. per-key count or sum) over a time window. +7. Consumer lag must be observable so falling behind is detectable. + +## Suggested Milestones + +1. **Milestone 1 — Produce & consume:** Emit events to a topic and log them from a consumer group. +2. **Milestone 2 — Offsets & idempotency:** Commit after processing, then prove a mid-batch crash resumes cleanly. +3. **Milestone 3 — Windowed aggregate & lag:** Maintain a windowed aggregate to the sink and expose consumer lag. + +## Data & Interface Sketch + +```text +topic: page_views partitions: 3 key: user_id + +event = { + "event_id": "uuid", # dedup key for idempotency + "user_id": "u-123", + "url": "/pricing", + "ts": "2024-01-01T10:00:00Z" +} + +Producer --> [ p0 | p1 | p2 ] --> Consumer group "aggregator" + | + upsert into sink: (user_id, window) -> count + commit offset AFTER upsert succeeds + +Delivery: at-least-once + idempotent upsert on event_id => effectively once +Monitoring: lag = log-end-offset - committed-offset (per partition) +``` + +## Stretch Goals + +- Add a second consumer instance and watch Kafka rebalance partitions across the group. +- Route un-processable messages to a dead-letter topic instead of blocking the stream. +- Implement tumbling vs sliding windows and compare their output. +- Add a schema registry with Avro and evolve the event schema without breaking consumers. + +## Definition of Done + +- [ ] Killing the consumer mid-stream and restarting it resumes from the last committed offset. +- [ ] A deliberately redelivered event does not change the aggregate (idempotency verified). +- [ ] The windowed aggregate in the sink matches a hand-computed expected value. +- [ ] Consumer lag is queryable and rises then recovers when the consumer is paused. +- [ ] Two consumers in one group split the partitions without processing the same message twice. + +## Common Pitfalls + +- Committing offsets before processing, turning a crash into silent data loss (at-most-once by accident). +- Auto-commit on a timer while processing is slow, so offsets advance past unprocessed messages. +- Assuming ordering across partitions — Kafka only orders within a single partition. +- Non-idempotent sink writes, so every rebalance or retry inflates the aggregate. +- Using one partition "for simplicity," then being unable to scale consumers past one. + +## Resources + +- [Apache Kafka documentation](https://kafka.apache.org/documentation/) — brokers, topics, partitions, and consumer groups. +- [Kafka: Consumer offsets & delivery semantics](https://kafka.apache.org/documentation/#semantics) — at-least-once vs exactly-once. +- [Confluent: Kafka consumers](https://developer.confluent.io/courses/apache-kafka/consumers/) — offset management and rebalancing explained. +- [Confluent: Schema Registry & Avro](https://docs.confluent.io/platform/current/schema-registry/index.html) — evolving event schemas safely. diff --git a/projects/data-engineering/intermediate/03-streaming-kafka/README.pt-BR.md b/projects/data-engineering/intermediate/03-streaming-kafka/README.pt-BR.md new file mode 100644 index 0000000..0951e0f --- /dev/null +++ b/projects/data-engineering/intermediate/03-streaming-kafka/README.pt-BR.md @@ -0,0 +1,93 @@ +# Pipeline de Streaming (Kafka) + +> 🌐 [English](./README.md) · **Português** + +**Domínio:** Data Engineering · **Nível:** Intermediário · **Tempo estimado:** 1–2 dias + +## Visão Geral + +Construa um pipeline de streaming em tempo real no Apache Kafka: um produtor que emite eventos para um tópico e um consumidor que os lê, mantém estado e escreve resultados em um sink. A mudança de lote para streaming força você a encarar perguntas que o lote nunca faz — o que acontece quando o consumidor cai no meio de uma mensagem, como evitar processar o mesmo evento duas vezes e como computar um agregado sobre um fluxo ilimitado. Você gerenciará os offsets do consumidor deliberadamente, projetará para entrega ao-menos-uma-vez e tornará seu processamento idempotente para que duplicatas sejam inofensivas. Você também adicionará monitoramento de lag do consumidor para enxergar quando o pipeline fica para trás. Este projeto é onde "os dados estão só parados numa tabela" deixa de ser verdade e você começa a pensar em termos de eventos que chegam continuamente. + +## Pré-requisitos + +- Conforto com uma linguagem que tenha um cliente Kafka (Python, Java ou Go) +- Entendimento de mensageria publish/subscribe e filas +- Familiaridade com JSON ou outro formato de serialização +- Um Kafka local (Docker Compose com Kafka + opcionalmente um schema registry) + +## Objetivos de Aprendizado + +Ao final, você deve ser capaz de: + +- Produzir e consumir eventos em um tópico Kafka particionado +- Raciocinar sobre semânticas de entrega: no-máximo-uma-vez, ao-menos-uma-vez, exatamente-uma-vez +- Confirmar offsets deliberadamente para que um crash retome sem perder ou reprocessar dados incorretamente +- Tornar o processamento do consumidor idempotente para que duplicatas ao-menos-uma-vez sejam inofensivas +- Computar um agregado com janela sobre um fluxo ilimitado e monitorar o lag do consumidor + +## Requisitos Funcionais + +1. Um produtor deve publicar eventos estruturados em um tópico Kafka com uma chave de particionamento. +2. Um consumidor deve ler eventos e escrever resultados derivados em um sink (banco, arquivo ou outro tópico). +3. O consumidor deve confirmar offsets apenas após uma mensagem ser processada com sucesso (ao-menos-uma-vez). +4. O processamento deve ser idempotente para que uma mensagem reentregue não corrompa o sink. +5. Ao reiniciar, o consumidor deve retomar do último offset confirmado — sem lacunas, sem replay completo. +6. O pipeline deve manter um agregado corrente (ex.: contagem ou soma por chave) sobre uma janela de tempo. +7. O lag do consumidor deve ser observável para que ficar para trás seja detectável. + +## Marcos Sugeridos + +1. **Marco 1 — Produzir e consumir:** Emita eventos para um tópico e os registre a partir de um grupo consumidor. +2. **Marco 2 — Offsets e idempotência:** Confirme após processar e prove que um crash no meio do lote retoma limpo. +3. **Marco 3 — Agregado com janela e lag:** Mantenha um agregado com janela no sink e exponha o lag do consumidor. + +## Esboço de Dados e Interface + +```text +tópico: page_views partições: 3 key: user_id + +event = { + "event_id": "uuid", # chave de dedup para idempotência + "user_id": "u-123", + "url": "/pricing", + "ts": "2024-01-01T10:00:00Z" +} + +Producer --> [ p0 | p1 | p2 ] --> Grupo consumidor "aggregator" + | + upsert no sink: (user_id, janela) -> count + confirma offset DEPOIS que o upsert tem sucesso + +Entrega: ao-menos-uma-vez + upsert idempotente por event_id => efetivamente uma vez +Monitoramento: lag = log-end-offset - offset-confirmado (por partição) +``` + +## Desafios Extras + +- Adicione uma segunda instância de consumidor e observe o Kafka rebalancear as partições no grupo. +- Roteie mensagens não processáveis para um tópico de dead-letter em vez de bloquear o fluxo. +- Implemente janelas tumbling vs sliding e compare a saída. +- Adicione um schema registry com Avro e evolua o schema do evento sem quebrar consumidores. + +## Definição de Pronto + +- [ ] Matar o consumidor no meio do fluxo e reiniciá-lo retoma do último offset confirmado. +- [ ] Um evento deliberadamente reentregue não altera o agregado (idempotência verificada). +- [ ] O agregado com janela no sink corresponde a um valor esperado calculado à mão. +- [ ] O lag do consumidor é consultável e sobe e depois se recupera quando o consumidor é pausado. +- [ ] Dois consumidores em um grupo dividem as partições sem processar a mesma mensagem duas vezes. + +## Armadilhas Comuns + +- Confirmar offsets antes de processar, transformando um crash em perda silenciosa de dados (no-máximo-uma-vez por acidente). +- Auto-commit em um timer enquanto o processamento é lento, fazendo os offsets avançarem além de mensagens não processadas. +- Assumir ordenação entre partições — o Kafka só ordena dentro de uma única partição. +- Escritas não idempotentes no sink, fazendo cada rebalance ou retry inflar o agregado. +- Usar uma única partição "por simplicidade" e depois não conseguir escalar consumidores além de um. + +## Recursos + +- [Documentação do Apache Kafka](https://kafka.apache.org/documentation/) — brokers, tópicos, partições e grupos consumidores. +- [Kafka: Offsets e semânticas de entrega](https://kafka.apache.org/documentation/#semantics) — ao-menos-uma-vez vs exatamente-uma-vez. +- [Confluent: Consumidores Kafka](https://developer.confluent.io/courses/apache-kafka/consumers/) — gestão de offsets e rebalanceamento explicados. +- [Confluent: Schema Registry e Avro](https://docs.confluent.io/platform/current/schema-registry/index.html) — evoluindo schemas de eventos com segurança. diff --git a/projects/data-engineering/intermediate/04-data-lake-ingestion/README.md b/projects/data-engineering/intermediate/04-data-lake-ingestion/README.md index 25a4378..0f24dbc 100644 --- a/projects/data-engineering/intermediate/04-data-lake-ingestion/README.md +++ b/projects/data-engineering/intermediate/04-data-lake-ingestion/README.md @@ -1,34 +1,93 @@ # Data Lake Ingestion System -## Idea -Build an ingestion system for a data lake supporting multiple data formats. Learn about data lake architecture and ingestion patterns. +> 🌐 **English** · [Português](./README.pt-BR.md) + +**Domain:** Data Engineering · **Level:** Intermediate · **Estimated time:** 1–2 days + +## Overview + +Build an ingestion system that lands raw data from several formats into a data lake and registers it in a catalog so it can actually be found and queried. The lake itself is just object storage (local filesystem, MinIO, or S3), but a lake without organization is a swamp. Your job is the layer that gives it structure: a zoned layout (raw → cleaned), consistent partitioning, extracted metadata, and a catalog that records what landed, when, and in what schema. You will ingest CSV, JSON, and Parquet, normalize them into a columnar format, and make ingestion idempotent so re-running a source drop replaces rather than duplicates. The payoff is understanding why "just dump the files in S3" is where data engineering begins, not ends. + +## Prerequisites + +- Comfort reading and writing files in a language like Python +- Familiarity with columnar formats (Parquet) and row formats (CSV/JSON) +- Basic understanding of object storage and key/prefix layouts +- Access to local object storage (filesystem, MinIO, or a cloud bucket) ## Learning Objectives -- Support multiple data sources -- Handle various formats -- Implement metadata management -- Create data cataloging -- Manage data organization - -## Implementation Tips -- Create multi-source connectors -- Support various formats (Parquet, JSON, CSV, Avro) -- Implement metadata extraction -- Create data cataloging system -- Implement data discovery -- Add versioning -- Create data lineage tracking -- Implement quality metrics -- Add governance policies -- Create partitioning strategy -- Implement compression -- Add replication -- Create backup strategy -- Build access control - -## Key Challenges -- Multi-format handling -- Metadata management scale -- Data discovery efficiency -- Governance enforcement -- Cost optimization + +By the end, you should be able to: + +- Design a zoned lake layout (raw vs cleaned) with a consistent partition scheme +- Ingest heterogeneous formats and normalize them to a single columnar format +- Extract and record metadata (schema, row count, source, ingest time) in a catalog +- Make ingestion idempotent so re-dropping a file does not duplicate data +- Support a backfill that re-ingests a range of historical source drops + +## Functional Requirements + +1. The system must ingest at least three formats (e.g. CSV, JSON, Parquet) through a common interface. +2. Raw files must land unchanged in a raw zone, then be normalized into a cleaned zone as Parquet. +3. Data must be partitioned by a stable key (e.g. source and ingest date) using a consistent path layout. +4. Each ingested dataset must be registered in a catalog with schema, row count, source, and timestamp. +5. Re-ingesting the same source drop must be idempotent — it replaces the partition, not appends to it. +6. The system must support backfilling a date range of source drops without manual per-file steps. +7. An ingestion failure must leave the target partition in its prior consistent state, never half-written. + +## Suggested Milestones + +1. **Milestone 1 — Land raw:** Ingest one format into a partitioned raw zone with correct paths. +2. **Milestone 2 — Normalize & catalog:** Convert to Parquet in the cleaned zone and register metadata in the catalog. +3. **Milestone 3 — Idempotency & backfill:** Make partition writes atomic/idempotent and re-ingest a historical range. + +## Data & Interface Sketch + +```text +lake/ + raw/ source=orders/ingest_date=2024-01-01/orders.csv + cleaned/ source=orders/ingest_date=2024-01-01/part-000.parquet + +catalog entry: + dataset: "orders" + path: "cleaned/source=orders/ingest_date=2024-01-01/" + format: "parquet" + schema: [ {name, type}, ... ] + row_count: 12045 + source_uri: "sftp://.../orders.csv" + ingested_at: "2024-01-01T02:15:00Z" + +ingest(source, ingest_date): + write to /... ; on success atomically swap into partition (idempotent) +Backfill: for d in date_range: ingest("orders", d) +``` + +## Stretch Goals + +- Add schema inference plus a check that fails ingestion when a file's schema drifts unexpectedly. +- Track simple lineage: which raw file produced which cleaned partition. +- Add an open table format (Delta Lake, Apache Iceberg, or Hudi) and compare it to plain Parquet + catalog. +- Compress and compact many small files into fewer right-sized ones. + +## Definition of Done + +- [ ] All three formats ingest through one interface and land as Parquet in the cleaned zone. +- [ ] Partitions follow a consistent, queryable path layout keyed by source and date. +- [ ] The catalog reflects every dataset's schema, row count, source, and ingest time. +- [ ] Re-ingesting the same drop leaves row counts unchanged (idempotent partition swap). +- [ ] A backfill over several dates populates each partition and its catalog entry. + +## Common Pitfalls + +- Writing directly into the final partition path, so a crash leaves a half-written, unreadable partition. +- Appending to a partition on re-ingest instead of replacing it, silently duplicating rows. +- Letting each source pick its own path convention, making the lake unqueryable as a whole. +- Producing thousands of tiny files, which cripples downstream query engines. +- Storing metadata only in file names instead of a real catalog, so discovery requires listing everything. + +## Resources + +- [AWS: What is a data lake?](https://aws.amazon.com/what-is/data-lake/) — zones, catalogs, and lake architecture. +- [Apache Parquet documentation](https://parquet.apache.org/docs/) — the columnar format and why it suits lakes. +- [Databricks: Medallion architecture](https://www.databricks.com/glossary/medallion-architecture) — raw/bronze → silver → gold zoning. +- [Apache Iceberg documentation](https://iceberg.apache.org/docs/latest/) — an open table format for lakes. diff --git a/projects/data-engineering/intermediate/04-data-lake-ingestion/README.pt-BR.md b/projects/data-engineering/intermediate/04-data-lake-ingestion/README.pt-BR.md new file mode 100644 index 0000000..459de82 --- /dev/null +++ b/projects/data-engineering/intermediate/04-data-lake-ingestion/README.pt-BR.md @@ -0,0 +1,93 @@ +# Sistema de Ingestão em Data Lake + +> 🌐 [English](./README.md) · **Português** + +**Domínio:** Data Engineering · **Nível:** Intermediário · **Tempo estimado:** 1–2 dias + +## Visão Geral + +Construa um sistema de ingestão que aterrissa dados brutos de vários formatos em um data lake e os registra em um catálogo para que possam de fato ser encontrados e consultados. O lake em si é apenas armazenamento de objetos (filesystem local, MinIO ou S3), mas um lake sem organização é um pântano. Seu trabalho é a camada que lhe dá estrutura: um layout em zonas (raw → cleaned), particionamento consistente, metadados extraídos e um catálogo que registra o que chegou, quando e em qual schema. Você ingerirá CSV, JSON e Parquet, os normalizará em um formato colunar e tornará a ingestão idempotente para que reprocessar uma entrega substitua em vez de duplicar. A recompensa é entender por que "só jogar os arquivos no S3" é onde a engenharia de dados começa, não termina. + +## Pré-requisitos + +- Conforto para ler e escrever arquivos em uma linguagem como Python +- Familiaridade com formatos colunares (Parquet) e de linha (CSV/JSON) +- Entendimento básico de armazenamento de objetos e layouts de chave/prefixo +- Acesso a armazenamento de objetos local (filesystem, MinIO ou um bucket na nuvem) + +## Objetivos de Aprendizado + +Ao final, você deve ser capaz de: + +- Projetar um layout de lake em zonas (raw vs cleaned) com um esquema de partição consistente +- Ingerir formatos heterogêneos e normalizá-los para um único formato colunar +- Extrair e registrar metadados (schema, contagem de linhas, origem, hora de ingestão) em um catálogo +- Tornar a ingestão idempotente para que reprocessar um arquivo não duplique dados +- Suportar um backfill que reingere um intervalo de entregas históricas + +## Requisitos Funcionais + +1. O sistema deve ingerir ao menos três formatos (ex.: CSV, JSON, Parquet) através de uma interface comum. +2. Arquivos brutos devem aterrissar inalterados em uma zona raw e depois ser normalizados na zona cleaned como Parquet. +3. Os dados devem ser particionados por uma chave estável (ex.: origem e data de ingestão) com um layout de caminho consistente. +4. Cada dataset ingerido deve ser registrado em um catálogo com schema, contagem de linhas, origem e timestamp. +5. Reingerir a mesma entrega deve ser idempotente — ela substitui a partição, não anexa a ela. +6. O sistema deve suportar backfill de um intervalo de datas de entregas sem passos manuais por arquivo. +7. Uma falha de ingestão deve deixar a partição alvo em seu estado consistente anterior, nunca meio escrita. + +## Marcos Sugeridos + +1. **Marco 1 — Aterrissar raw:** Ingira um formato em uma zona raw particionada com caminhos corretos. +2. **Marco 2 — Normalizar e catalogar:** Converta para Parquet na zona cleaned e registre metadados no catálogo. +3. **Marco 3 — Idempotência e backfill:** Torne a escrita de partição atômica/idempotente e reingira um intervalo histórico. + +## Esboço de Dados e Interface + +```text +lake/ + raw/ source=orders/ingest_date=2024-01-01/orders.csv + cleaned/ source=orders/ingest_date=2024-01-01/part-000.parquet + +entrada no catálogo: + dataset: "orders" + path: "cleaned/source=orders/ingest_date=2024-01-01/" + format: "parquet" + schema: [ {name, type}, ... ] + row_count: 12045 + source_uri: "sftp://.../orders.csv" + ingested_at: "2024-01-01T02:15:00Z" + +ingest(source, ingest_date): + escreve em /... ; ao ter sucesso troca atomicamente para a partição (idempotente) +Backfill: for d in intervalo_datas: ingest("orders", d) +``` + +## Desafios Extras + +- Adicione inferência de schema mais uma checagem que falha a ingestão quando o schema de um arquivo muda inesperadamente. +- Rastreie linhagem simples: qual arquivo raw produziu qual partição cleaned. +- Adicione um formato de tabela aberto (Delta Lake, Apache Iceberg ou Hudi) e o compare a Parquet puro + catálogo. +- Comprima e compacte muitos arquivos pequenos em menos arquivos de tamanho adequado. + +## Definição de Pronto + +- [ ] Todos os três formatos ingerem por uma interface e aterrissam como Parquet na zona cleaned. +- [ ] As partições seguem um layout de caminho consistente e consultável, chaveado por origem e data. +- [ ] O catálogo reflete o schema, contagem de linhas, origem e hora de ingestão de cada dataset. +- [ ] Reingerir a mesma entrega mantém as contagens de linhas inalteradas (troca de partição idempotente). +- [ ] Um backfill de várias datas popula cada partição e sua entrada no catálogo. + +## Armadilhas Comuns + +- Escrever diretamente no caminho final da partição, fazendo um crash deixar uma partição meio escrita e ilegível. +- Anexar a uma partição na reingestão em vez de substituí-la, duplicando linhas silenciosamente. +- Deixar cada origem escolher sua própria convenção de caminho, tornando o lake inconsultável como um todo. +- Produzir milhares de arquivos minúsculos, o que prejudica os motores de consulta downstream. +- Guardar metadados só nos nomes dos arquivos em vez de um catálogo real, exigindo listar tudo para descobrir. + +## Recursos + +- [AWS: O que é um data lake?](https://aws.amazon.com/what-is/data-lake/) — zonas, catálogos e arquitetura de lake. +- [Documentação do Apache Parquet](https://parquet.apache.org/docs/) — o formato colunar e por que ele serve a lakes. +- [Databricks: Arquitetura medallion](https://www.databricks.com/glossary/medallion-architecture) — zoneamento raw/bronze → silver → gold. +- [Documentação do Apache Iceberg](https://iceberg.apache.org/docs/latest/) — um formato de tabela aberto para lakes. diff --git a/projects/data-engineering/intermediate/05-schema-evolution/README.md b/projects/data-engineering/intermediate/05-schema-evolution/README.md index b6f8767..e446e2c 100644 --- a/projects/data-engineering/intermediate/05-schema-evolution/README.md +++ b/projects/data-engineering/intermediate/05-schema-evolution/README.md @@ -1,34 +1,92 @@ # Schema Evolution System -## Idea -Create a system that handles schema changes over time. Learn about versioning and backward compatibility. +> 🌐 **English** · [Português](./README.pt-BR.md) + +**Domain:** Data Engineering · **Level:** Intermediate · **Estimated time:** 1–2 days + +## Overview + +Build a system that lets a data schema change over time without breaking the producers and consumers that depend on it. Real pipelines never freeze their schema: fields get added, renamed, deprecated, and occasionally removed — and yet last year's data must still be readable and last week's consumer must not crash on today's records. You will implement a schema registry that versions schemas, classifies each proposed change as backward-, forward-, or fully-compatible, and rejects breaking changes before they ship. You will then write migrations that upgrade old records to the current schema on read. The lesson is that schema is a contract, and evolving a contract safely is a discipline, not an afterthought. + +## Prerequisites + +- Comfort modeling data with a serialization format (JSON Schema, Avro, or Protobuf) +- Understanding of producers and consumers sharing a data contract +- Familiarity with semantic versioning concepts +- The [Kafka streaming project](../03-streaming-kafka/) is useful context for why compatibility matters ## Learning Objectives -- Version schemas -- Handle schema changes -- Maintain compatibility -- Migrate data -- Track evolution - -## Implementation Tips -- Implement schema versioning -- Support backward compatibility -- Create schema registry -- Add schema validation -- Implement migration scripts -- Handle deprecated fields -- Create compatibility checking -- Implement data transformation -- Add rollback mechanisms -- Create audit trails -- Implement automated migrations -- Add testing framework -- Create documentation -- Build UI for schema management - -## Key Challenges -- Backward compatibility constraints -- Complex migration logic -- Data transformation at scale -- Rollback complexity -- Performance during migration + +By the end, you should be able to: + +- Version schemas and store them in a registry keyed by subject and version +- Distinguish backward, forward, and full compatibility and reason about who breaks when +- Detect a breaking change (e.g. removing a required field) before it is registered +- Migrate historical records to the current schema on read +- Manage field deprecation with defaults instead of hard removal + +## Functional Requirements + +1. The registry must store multiple versions of a schema under a stable subject name. +2. Registering a new version must run a compatibility check against the previous version(s). +3. A backward-incompatible change (e.g. dropping/renaming a required field) must be rejected with a clear reason. +4. Adding an optional field with a default must be accepted as a backward-compatible change. +5. A reader must be able to deserialize a record written with any registered version into the latest schema. +6. Deprecated fields must be supported via defaults so old and new records both read cleanly. +7. Every registered version must be retrievable by number so historical data stays decodable. + +## Suggested Milestones + +1. **Milestone 1 — Versioned registry:** Store and retrieve schemas by subject and version number. +2. **Milestone 2 — Compatibility checks:** Classify a proposed change and reject breaking ones automatically. +3. **Milestone 3 — Read-time migration:** Upgrade records from any old version to the latest on read. + +## Data & Interface Sketch + +```text +registry: + subject "user" + v1: { id: int, name: string } + v2: { id: int, name: string, email: string = "" } # +optional, default -> backward-compatible + v3: { id: int, full_name: string } # rename required -> REJECTED + +compatibility(new, old) -> BACKWARD | FORWARD | FULL | NONE + add optional w/ default -> BACKWARD ok + remove/rename required field -> NONE -> reject + add required field w/o default -> NONE -> reject + +read(record): + detect writer_version from record + apply migrations v_writer -> v_latest (fill defaults, map renames) + return record shaped as v_latest +``` + +## Stretch Goals + +- Support a compatibility *mode* per subject (backward / forward / full) and enforce accordingly. +- Add a dry-run "what would break" report for a proposed schema before registering it. +- Handle a controlled rename via an alias that reads both the old and new field name. +- Integrate with Avro or Protobuf and reuse its native resolution rules. + +## Definition of Done + +- [ ] Schemas are stored and retrievable by subject and version, with an immutable history. +- [ ] Adding an optional defaulted field is accepted; removing a required field is rejected with a reason. +- [ ] A record written under v1 deserializes correctly against the latest schema. +- [ ] Deprecated fields resolve via defaults with no reader errors. +- [ ] The compatibility classifier is covered by tests for each change type. + +## Common Pitfalls + +- Treating "add a field" as always safe — a new *required* field without a default breaks old producers. +- Mutating a registered version in place instead of creating a new one, corrupting history. +- Confusing backward and forward compatibility and enforcing the wrong direction for your rollout order. +- Renaming a field and calling it compatible; to readers it is a drop plus an add. +- Relying on field order or position instead of names, so any reorder silently misreads data. + +## Resources + +- [Confluent: Schema evolution and compatibility](https://docs.confluent.io/platform/current/schema-registry/fundamentals/schema-evolution.html) — the definitive compatibility taxonomy. +- [Apache Avro: Schema Resolution](https://avro.apache.org/docs/current/specification/#schema-resolution) — how readers and writers reconcile schemas. +- [JSON Schema documentation](https://json-schema.org/understanding-json-schema/) — modeling and validating evolving schemas. +- [Protocol Buffers: Updating a message type](https://protobuf.dev/programming-guides/proto3/#updating) — field-number rules for safe evolution. diff --git a/projects/data-engineering/intermediate/05-schema-evolution/README.pt-BR.md b/projects/data-engineering/intermediate/05-schema-evolution/README.pt-BR.md new file mode 100644 index 0000000..60224da --- /dev/null +++ b/projects/data-engineering/intermediate/05-schema-evolution/README.pt-BR.md @@ -0,0 +1,92 @@ +# Sistema de Evolução de Schema + +> 🌐 [English](./README.md) · **Português** + +**Domínio:** Data Engineering · **Nível:** Intermediário · **Tempo estimado:** 1–2 dias + +## Visão Geral + +Construa um sistema que permite a um schema de dados mudar ao longo do tempo sem quebrar os produtores e consumidores que dependem dele. Pipelines reais nunca congelam seu schema: campos são adicionados, renomeados, depreciados e ocasionalmente removidos — e ainda assim os dados do ano passado precisam continuar legíveis e o consumidor da semana passada não pode falhar com os registros de hoje. Você implementará um schema registry que versiona schemas, classifica cada mudança proposta como retrocompatível, compatível-adiante ou totalmente compatível, e rejeita mudanças quebradoras antes que entrem em produção. Depois você escreverá migrações que atualizam registros antigos para o schema atual na leitura. A lição é que schema é um contrato, e evoluir um contrato com segurança é uma disciplina, não um detalhe posterior. + +## Pré-requisitos + +- Conforto para modelar dados com um formato de serialização (JSON Schema, Avro ou Protobuf) +- Entendimento de produtores e consumidores compartilhando um contrato de dados +- Familiaridade com conceitos de versionamento semântico +- O [projeto de streaming Kafka](../03-streaming-kafka/) é um contexto útil de por que a compatibilidade importa + +## Objetivos de Aprendizado + +Ao final, você deve ser capaz de: + +- Versionar schemas e armazená-los em um registry chaveado por assunto (subject) e versão +- Distinguir compatibilidade retro, adiante e total e raciocinar sobre quem quebra quando +- Detectar uma mudança quebradora (ex.: remover um campo obrigatório) antes de ela ser registrada +- Migrar registros históricos para o schema atual na leitura +- Gerenciar a depreciação de campos com defaults em vez de remoção abrupta + +## Requisitos Funcionais + +1. O registry deve armazenar múltiplas versões de um schema sob um nome de assunto estável. +2. Registrar uma nova versão deve rodar uma checagem de compatibilidade contra a(s) versão(ões) anterior(es). +3. Uma mudança retro-incompatível (ex.: remover/renomear um campo obrigatório) deve ser rejeitada com um motivo claro. +4. Adicionar um campo opcional com default deve ser aceito como uma mudança retrocompatível. +5. Um leitor deve conseguir desserializar um registro escrito com qualquer versão registrada no schema mais recente. +6. Campos depreciados devem ser suportados via defaults para que registros antigos e novos leiam corretamente. +7. Toda versão registrada deve ser recuperável por número para que dados históricos permaneçam decodificáveis. + +## Marcos Sugeridos + +1. **Marco 1 — Registry versionado:** Armazene e recupere schemas por assunto e número de versão. +2. **Marco 2 — Checagens de compatibilidade:** Classifique uma mudança proposta e rejeite as quebradoras automaticamente. +3. **Marco 3 — Migração na leitura:** Atualize registros de qualquer versão antiga para a mais recente na leitura. + +## Esboço de Dados e Interface + +```text +registry: + subject "user" + v1: { id: int, name: string } + v2: { id: int, name: string, email: string = "" } # +opcional, default -> retrocompatível + v3: { id: int, full_name: string } # renomear obrigatório -> REJEITADO + +compatibility(nova, antiga) -> BACKWARD | FORWARD | FULL | NONE + adicionar opcional c/ default -> BACKWARD ok + remover/renomear campo obrigat. -> NONE -> rejeita + adicionar obrigatório sem default -> NONE -> rejeita + +read(record): + detecta writer_version do record + aplica migrações v_writer -> v_latest (preenche defaults, mapeia renomeações) + retorna record no formato v_latest +``` + +## Desafios Extras + +- Suporte um *modo* de compatibilidade por assunto (backward / forward / full) e aplique-o de acordo. +- Adicione um relatório dry-run "o que quebraria" para um schema proposto antes de registrá-lo. +- Trate uma renomeação controlada via um alias que lê tanto o nome antigo quanto o novo do campo. +- Integre com Avro ou Protobuf e reutilize suas regras nativas de resolução. + +## Definição de Pronto + +- [ ] Schemas são armazenados e recuperáveis por assunto e versão, com um histórico imutável. +- [ ] Adicionar um campo opcional com default é aceito; remover um campo obrigatório é rejeitado com motivo. +- [ ] Um registro escrito sob a v1 desserializa corretamente contra o schema mais recente. +- [ ] Campos depreciados resolvem via defaults sem erros de leitura. +- [ ] O classificador de compatibilidade é coberto por testes para cada tipo de mudança. + +## Armadilhas Comuns + +- Tratar "adicionar um campo" como sempre seguro — um novo campo *obrigatório* sem default quebra produtores antigos. +- Mutar uma versão registrada no lugar em vez de criar uma nova, corrompendo o histórico. +- Confundir compatibilidade retro e adiante e aplicar a direção errada para sua ordem de rollout. +- Renomear um campo e chamar isso de compatível; para os leitores é uma remoção mais uma adição. +- Confiar na ordem ou posição dos campos em vez de nomes, fazendo qualquer reordenação ler dados errados silenciosamente. + +## Recursos + +- [Confluent: Evolução e compatibilidade de schema](https://docs.confluent.io/platform/current/schema-registry/fundamentals/schema-evolution.html) — a taxonomia definitiva de compatibilidade. +- [Apache Avro: Resolução de Schema](https://avro.apache.org/docs/current/specification/#schema-resolution) — como leitores e escritores reconciliam schemas. +- [Documentação do JSON Schema](https://json-schema.org/understanding-json-schema/) — modelando e validando schemas em evolução. +- [Protocol Buffers: Atualizando um tipo de mensagem](https://protobuf.dev/programming-guides/proto3/#updating) — regras de número de campo para evolução segura. diff --git a/projects/data-engineering/intermediate/06-incremental-processing/README.md b/projects/data-engineering/intermediate/06-incremental-processing/README.md index 7b2f96b..d4194f5 100644 --- a/projects/data-engineering/intermediate/06-incremental-processing/README.md +++ b/projects/data-engineering/intermediate/06-incremental-processing/README.md @@ -1,34 +1,95 @@ # Incremental Data Processing -## Idea -Build a system that processes only new or changed data. Learn about incremental loading and state management. +> 🌐 **English** · [Português](./README.pt-BR.md) + +**Domain:** Data Engineering · **Level:** Intermediate · **Estimated time:** 1–2 days + +## Overview + +Build a batch job that processes only the records that are new or changed since its last successful run, instead of reprocessing the entire source every time. This is the workhorse pattern behind nightly warehouse loads and CDC pipelines: you track a high-water mark (a timestamp or monotonic id), read the delta above it, and advance the mark only after the write commits. The interesting part is not the SQL — it is the bookkeeping. What happens when the job crashes mid-write, when a row arrives late with an old timestamp, or when you need to rerun yesterday? Getting those cases right is the difference between a pipeline you trust and one you babysit. + +## Prerequisites + +- Comfort writing batch transformations over a tabular source (a warehouse table, files, or an API) +- Understanding of timestamps, watermarks, and monotonic identifiers +- Familiarity with idempotency — running the same operation twice yields the same result +- An engine of your choice (SQL + a scheduler, Spark, DuckDB, or a plain script) ## Learning Objectives -- Track data changes -- Identify new records -- Implement delta processing -- Manage state -- Optimize performance - -## Implementation Tips -- Implement change detection -- Create checkpoint management -- Track last processed timestamp -- Handle CDC (Change Data Capture) -- Implement full vs incremental logic -- Create state management -- Add rollback capability -- Implement recovery -- Create performance optimization -- Add monitoring -- Implement error handling -- Create replay capability -- Build testing framework -- Add documentation - -## Key Challenges -- Change detection accuracy -- State management complexity -- Recovery from failures -- Performance optimization -- Handling late arrivals + +By the end, you should be able to: + +- Detect new and changed rows using a watermark instead of a full scan +- Persist and advance processing state safely across runs +- Make writes idempotent so a retry never double-counts +- Distinguish full-refresh from incremental load and choose between them +- Handle late-arriving data and support backfilling a past window + +## Functional Requirements + +1. The job must read only records with a change key greater than the last committed watermark. +2. The job must persist the new watermark only after the corresponding write succeeds. +3. Rerunning the job with no new source data must produce no changes (idempotent). +4. The job must support a full-refresh mode that rebuilds the target from scratch. +5. The job must accept an explicit date/id range to backfill or reprocess a past window. +6. Upserts must key on the record's natural id so a changed row updates in place, not duplicates. +7. The job must record run metadata: rows read, rows written, watermark before/after, and status. + +## Suggested Milestones + +1. **Milestone 1 — Full load:** Read the whole source and write the target once, capturing the initial watermark. +2. **Milestone 2 — Delta load:** Read only rows above the watermark, upsert them, and advance the mark after commit. +3. **Milestone 3 — Recovery & backfill:** Make reruns idempotent, add a backfill range, and handle late arrivals with a lookback window. + +## Data & Interface Sketch + +```text +source.orders + id bigint (natural key) + updated_at timestamp (change key / watermark source) + ...payload + +pipeline_state + pipeline string (e.g. "orders_incremental") + watermark timestamp + updated_at timestamp + +run flow: + 1. read W = state.watermark + 2. rows = source where updated_at > W - lookback (lookback catches late data) + 3. upsert rows into target on id + 4. W' = max(updated_at) among rows + 5. commit target, then set state.watermark = W' + +modes: incremental (default) | full-refresh | backfill(from, to) +``` + +## Stretch Goals + +- Add hard-delete handling by consuming a change stream or comparing against a snapshot. +- Track per-run lineage so you can answer "which run produced this row?". +- Detect and alert when the watermark stops advancing (a stuck pipeline). +- Support parallel workers by partitioning the delta range and committing state atomically. + +## Definition of Done + +- [ ] A second run with no new data writes nothing and leaves the watermark unchanged. +- [ ] Killing the job after the write but before the state commit, then rerunning, produces no duplicates. +- [ ] A changed source row updates the existing target row rather than inserting a new one. +- [ ] Backfilling a past range reprocesses exactly that window without disturbing newer data. +- [ ] Run metadata is persisted and readable for every execution. + +## Common Pitfalls + +- Advancing the watermark before the write commits — a crash then silently skips rows forever. +- Using `>=` on the watermark and reprocessing the boundary row, or `>` and dropping it — pick one and stay consistent. +- Assuming `updated_at` is strictly increasing; clock skew and late writes mean you need a lookback buffer. +- Appending instead of upserting, so changed rows accumulate as duplicates. +- Making full-refresh truncate the target before the new load succeeds, leaving an empty table on failure. + +## Resources + +- [Airbyte: Incremental sync modes](https://docs.airbyte.com/using-airbyte/core-concepts/sync-modes/incremental-append) — how a real tool models incremental vs full loads. +- [dbt: Incremental models](https://docs.getdbt.com/docs/build/incremental-models) — watermark-based incremental builds in practice. +- [Martin Kleppmann: Designing Data-Intensive Applications](https://dataintensive.net/) — chapters on change capture and derived data. +- [Wikipedia: Change data capture](https://en.wikipedia.org/wiki/Change_data_capture) — the broader family of techniques. diff --git a/projects/data-engineering/intermediate/06-incremental-processing/README.pt-BR.md b/projects/data-engineering/intermediate/06-incremental-processing/README.pt-BR.md new file mode 100644 index 0000000..cb3b7d1 --- /dev/null +++ b/projects/data-engineering/intermediate/06-incremental-processing/README.pt-BR.md @@ -0,0 +1,95 @@ +# Processamento Incremental de Dados + +> 🌐 [English](./README.md) · **Português** + +**Domínio:** Data Engineering · **Nível:** Intermediário · **Tempo estimado:** 1–2 dias + +## Visão Geral + +Construa um job em lote que processa apenas os registros novos ou alterados desde sua última execução bem-sucedida, em vez de reprocessar toda a fonte a cada vez. Esse é o padrão que sustenta as cargas noturnas de data warehouse e os pipelines de CDC: você rastreia uma marca d'água (um timestamp ou id monotônico), lê o delta acima dela e avança a marca somente depois que a escrita é confirmada. A parte interessante não é o SQL — é a contabilidade. O que acontece quando o job falha no meio da escrita, quando uma linha chega atrasada com um timestamp antigo, ou quando você precisa reprocessar ontem? Acertar esses casos é a diferença entre um pipeline em que você confia e um que você precisa vigiar. + +## Pré-requisitos + +- Conforto para escrever transformações em lote sobre uma fonte tabular (uma tabela de warehouse, arquivos ou uma API) +- Entendimento de timestamps, marcas d'água e identificadores monotônicos +- Familiaridade com idempotência — executar a mesma operação duas vezes gera o mesmo resultado +- Um motor à sua escolha (SQL + um agendador, Spark, DuckDB ou um script simples) + +## Objetivos de Aprendizado + +Ao final, você deve ser capaz de: + +- Detectar linhas novas e alteradas usando uma marca d'água em vez de uma varredura completa +- Persistir e avançar o estado de processamento com segurança entre execuções +- Tornar as escritas idempotentes para que uma nova tentativa nunca conte em dobro +- Distinguir carga completa de carga incremental e escolher entre elas +- Tratar dados que chegam atrasados e suportar o reprocessamento de uma janela passada + +## Requisitos Funcionais + +1. O job deve ler apenas registros com uma chave de mudança maior que a última marca d'água confirmada. +2. O job deve persistir a nova marca d'água somente após a escrita correspondente ser bem-sucedida. +3. Reexecutar o job sem novos dados de origem não deve produzir alterações (idempotente). +4. O job deve suportar um modo de carga completa que reconstrói o destino do zero. +5. O job deve aceitar um intervalo explícito de data/id para reprocessar uma janela passada. +6. Os upserts devem usar a chave natural do registro para que uma linha alterada atualize no lugar, sem duplicar. +7. O job deve registrar metadados da execução: linhas lidas, linhas escritas, marca d'água antes/depois e status. + +## Marcos Sugeridos + +1. **Marco 1 — Carga completa:** Leia toda a fonte e escreva o destino uma vez, capturando a marca d'água inicial. +2. **Marco 2 — Carga delta:** Leia apenas as linhas acima da marca d'água, faça upsert e avance a marca após o commit. +3. **Marco 3 — Recuperação e reprocessamento:** Torne as reexecuções idempotentes, adicione um intervalo de backfill e trate chegadas atrasadas com uma janela de retrospecto. + +## Esboço de Dados e Interface + +```text +source.orders + id bigint (chave natural) + updated_at timestamp (chave de mudança / fonte da marca d'água) + ...payload + +pipeline_state + pipeline string (ex.: "orders_incremental") + watermark timestamp + updated_at timestamp + +fluxo da execução: + 1. leia W = state.watermark + 2. rows = source onde updated_at > W - lookback (lookback captura dados atrasados) + 3. upsert rows no destino por id + 4. W' = max(updated_at) entre as linhas + 5. faça commit do destino, então defina state.watermark = W' + +modos: incremental (padrão) | full-refresh | backfill(de, até) +``` + +## Desafios Extras + +- Adicione tratamento de exclusões físicas consumindo um change stream ou comparando com um snapshot. +- Rastreie a linhagem por execução para responder "qual execução produziu esta linha?". +- Detecte e alerte quando a marca d'água parar de avançar (um pipeline travado). +- Suporte workers paralelos particionando o intervalo do delta e confirmando o estado de forma atômica. + +## Definição de Pronto + +- [ ] Uma segunda execução sem novos dados não escreve nada e mantém a marca d'água inalterada. +- [ ] Matar o job após a escrita, mas antes do commit do estado, e reexecutar não produz duplicatas. +- [ ] Uma linha de origem alterada atualiza a linha existente no destino em vez de inserir uma nova. +- [ ] Reprocessar um intervalo passado reprocessa exatamente aquela janela sem perturbar dados mais novos. +- [ ] Os metadados da execução são persistidos e legíveis para cada execução. + +## Armadilhas Comuns + +- Avançar a marca d'água antes de o commit da escrita — uma falha então pula linhas silenciosamente para sempre. +- Usar `>=` na marca d'água e reprocessar a linha da borda, ou `>` e perdê-la — escolha uma e mantenha a consistência. +- Assumir que `updated_at` é estritamente crescente; desvio de relógio e escritas atrasadas exigem uma folga de lookback. +- Anexar em vez de fazer upsert, fazendo linhas alteradas se acumularem como duplicatas. +- Fazer a carga completa truncar o destino antes de a nova carga ter sucesso, deixando uma tabela vazia em caso de falha. + +## Recursos + +- [Airbyte: Modos de sincronização incremental](https://docs.airbyte.com/using-airbyte/core-concepts/sync-modes/incremental-append) — como uma ferramenta real modela cargas incrementais vs completas. +- [dbt: Modelos incrementais](https://docs.getdbt.com/docs/build/incremental-models) — builds incrementais baseados em marca d'água na prática. +- [Martin Kleppmann: Designing Data-Intensive Applications](https://dataintensive.net/) — capítulos sobre captura de mudanças e dados derivados. +- [Wikipedia: Change data capture](https://en.wikipedia.org/wiki/Change_data_capture) — a família mais ampla de técnicas. diff --git a/projects/data-engineering/intermediate/07-pipeline-monitoring/README.md b/projects/data-engineering/intermediate/07-pipeline-monitoring/README.md index a374aa6..bf699ea 100644 --- a/projects/data-engineering/intermediate/07-pipeline-monitoring/README.md +++ b/projects/data-engineering/intermediate/07-pipeline-monitoring/README.md @@ -1,34 +1,95 @@ # Pipeline Monitoring System -## Idea -Build a system to monitor data pipelines and alert on failures. Learn about observability and alerting. +> 🌐 **English** · [Português](./README.pt-BR.md) + +**Domain:** Data Engineering · **Level:** Intermediate · **Estimated time:** 1–2 days + +## Overview + +Build the observability layer that sits alongside your data pipelines and answers the question every data engineer dreads at 9am: "did last night's load actually work?" You will capture each pipeline run as a first-class record — start time, end time, status, row counts — evaluate it against SLA and freshness expectations, and fire an alert when something is late, empty, or broken. The goal is to catch a silent failure before a stakeholder does. The hard part is tuning: too sensitive and everyone mutes the channel, too lax and you find out about a broken table from a dashboard three days later. + +## Prerequisites + +- A pipeline or two whose runs you can instrument (even simple scripts on a schedule) +- Understanding of SLAs, data freshness, and the idea of an alerting threshold +- Familiarity with time-series thinking (a metric observed over successive runs) +- A store for run history (a table or document collection) and any notification channel ## Learning Objectives -- Track pipeline execution -- Monitor data quality -- Implement alerting -- Create dashboards -- Handle incidents - -## Implementation Tips -- Implement execution tracking -- Create SLA monitoring -- Add data quality checks -- Implement anomaly detection -- Create alert rules -- Build notification system -- Create dashboards -- Implement incident tracking -- Add root cause analysis -- Create performance metrics -- Implement logging -- Add tracing -- Create visualization -- Build remediation workflows - -## Key Challenges -- Real-time monitoring scale -- Alert threshold tuning -- False positive rates -- Root cause analysis complexity -- Dashboard design + +By the end, you should be able to: + +- Model a pipeline run as a structured, queryable event +- Define and evaluate SLA and freshness rules against run history +- Detect anomalies such as a sudden drop in row count or an overrun in duration +- Route alerts with enough context to act, and suppress duplicate noise +- Present pipeline health at a glance for someone who is not on call + +## Functional Requirements + +1. Every pipeline run must be recorded with start time, end time, status, and rows processed. +2. The system must flag a run that fails, exceeds its expected duration, or produces zero rows. +3. The system must evaluate data freshness — alert when a dataset has not updated within its SLA window. +4. The system must detect a row-count anomaly relative to a rolling baseline (e.g. drop > 50%). +5. An alert must include the pipeline name, what rule tripped, the observed value, and the expected value. +6. Repeated alerts for the same ongoing failure must be deduplicated, not resent every run. +7. The system must expose a health view listing each pipeline's last run, status, and freshness. + +## Suggested Milestones + +1. **Milestone 1 — Capture runs:** Instrument pipelines to emit a run record and store the history. +2. **Milestone 2 — Rules & alerts:** Add SLA, freshness, and row-count rules that produce alerts with context. +3. **Milestone 3 — Noise control & dashboard:** Deduplicate alerts and build a health view over the run history. + +## Data & Interface Sketch + +```text +pipeline_run + run_id uuid + pipeline string + started_at timestamp + ended_at timestamp + status enum(success | failed | running) + rows_out integer + +rule types: + sla_duration -> ended_at - started_at > threshold + freshness -> now - last_success.ended_at > window + volume_anomaly -> rows_out < baseline * (1 - drop_pct) + +alert + pipeline, rule, observed, expected, first_seen, still_open + -> notify to ; dedupe while still_open + +health view: pipeline | last_run | status | age | open_alerts +``` + +## Stretch Goals + +- Add root-cause hints by correlating a failure with the upstream pipeline that feeds it. +- Track a per-run trace so a slow stage inside a pipeline is visible, not just total duration. +- Support alert severities and escalation (warn in chat, page on repeated critical). +- Auto-resolve an alert and post a recovery notice when the next run succeeds. + +## Definition of Done + +- [ ] Every run appears in the history with correct status and row count. +- [ ] A failed or empty run produces exactly one alert, not one per retry. +- [ ] A dataset that goes stale past its SLA triggers a freshness alert without a run failing. +- [ ] A sudden row-count drop is flagged against the rolling baseline. +- [ ] The health view reflects the true last-run state for each pipeline. + +## Common Pitfalls + +- Alerting on every run so the channel becomes noise everyone ignores — deduplicate open incidents. +- Measuring freshness from run start instead of successful completion, hiding partial failures. +- Using a fixed row-count threshold that breaks on seasonal traffic; prefer a rolling baseline. +- Sending alerts with no context, forcing the reader to go dig for what actually broke. +- Treating a still-running long job as a failure because you only check for a completed record. + +## Resources + +- [Google SRE Book: Monitoring Distributed Systems](https://sre.google/sre-book/monitoring-distributed-systems/) — the four golden signals and alerting philosophy. +- [Prometheus: Alerting best practices](https://prometheus.io/docs/practices/alerting/) — how to write rules that stay actionable. +- [Airflow: SLAs and monitoring](https://airflow.apache.org/docs/apache-airflow/stable/core-concepts/tasks.html#slas) — SLA concepts in a real orchestrator. +- [Monte Carlo: What is data observability](https://www.montecarlodata.com/blog-what-is-data-observability/) — freshness, volume, and schema as observability pillars. diff --git a/projects/data-engineering/intermediate/07-pipeline-monitoring/README.pt-BR.md b/projects/data-engineering/intermediate/07-pipeline-monitoring/README.pt-BR.md new file mode 100644 index 0000000..6964517 --- /dev/null +++ b/projects/data-engineering/intermediate/07-pipeline-monitoring/README.pt-BR.md @@ -0,0 +1,95 @@ +# Sistema de Monitoramento de Pipelines + +> 🌐 [English](./README.md) · **Português** + +**Domínio:** Data Engineering · **Nível:** Intermediário · **Tempo estimado:** 1–2 dias + +## Visão Geral + +Construa a camada de observabilidade que fica ao lado dos seus pipelines de dados e responde à pergunta que todo engenheiro de dados teme às 9h: "a carga de ontem à noite realmente funcionou?". Você vai capturar cada execução de pipeline como um registro de primeira classe — horário de início, horário de fim, status, contagem de linhas —, avaliá-la contra expectativas de SLA e frescor, e disparar um alerta quando algo estiver atrasado, vazio ou quebrado. O objetivo é pegar uma falha silenciosa antes que um stakeholder pegue. A parte difícil é a calibragem: sensível demais e todos silenciam o canal; frouxo demais e você descobre uma tabela quebrada por um dashboard três dias depois. + +## Pré-requisitos + +- Um ou dois pipelines cujas execuções você possa instrumentar (mesmo scripts simples agendados) +- Entendimento de SLAs, frescor de dados e a ideia de um limiar de alerta +- Familiaridade com raciocínio de séries temporais (uma métrica observada ao longo de execuções sucessivas) +- Um armazenamento para o histórico de execuções (uma tabela ou coleção de documentos) e algum canal de notificação + +## Objetivos de Aprendizado + +Ao final, você deve ser capaz de: + +- Modelar uma execução de pipeline como um evento estruturado e consultável +- Definir e avaliar regras de SLA e frescor contra o histórico de execuções +- Detectar anomalias como uma queda súbita na contagem de linhas ou um estouro de duração +- Rotear alertas com contexto suficiente para agir e suprimir ruído duplicado +- Apresentar a saúde dos pipelines de relance para alguém que não está de plantão + +## Requisitos Funcionais + +1. Toda execução de pipeline deve ser registrada com horário de início, horário de fim, status e linhas processadas. +2. O sistema deve sinalizar uma execução que falha, excede sua duração esperada ou produz zero linhas. +3. O sistema deve avaliar o frescor dos dados — alertar quando um dataset não é atualizado dentro de sua janela de SLA. +4. O sistema deve detectar uma anomalia de contagem de linhas relativa a uma baseline móvel (ex.: queda > 50%). +5. Um alerta deve incluir o nome do pipeline, qual regra disparou, o valor observado e o valor esperado. +6. Alertas repetidos para a mesma falha em andamento devem ser deduplicados, não reenviados a cada execução. +7. O sistema deve expor uma visão de saúde listando a última execução, o status e o frescor de cada pipeline. + +## Marcos Sugeridos + +1. **Marco 1 — Capturar execuções:** Instrumente os pipelines para emitir um registro de execução e armazene o histórico. +2. **Marco 2 — Regras e alertas:** Adicione regras de SLA, frescor e contagem de linhas que produzam alertas com contexto. +3. **Marco 3 — Controle de ruído e dashboard:** Deduplique alertas e construa uma visão de saúde sobre o histórico de execuções. + +## Esboço de Dados e Interface + +```text +pipeline_run + run_id uuid + pipeline string + started_at timestamp + ended_at timestamp + status enum(success | failed | running) + rows_out integer + +tipos de regra: + sla_duration -> ended_at - started_at > limiar + freshness -> now - last_success.ended_at > janela + volume_anomaly -> rows_out < baseline * (1 - drop_pct) + +alert + pipeline, rule, observed, expected, first_seen, still_open + -> notificar em ; deduplicar enquanto still_open + +visão de saúde: pipeline | last_run | status | age | open_alerts +``` + +## Desafios Extras + +- Adicione pistas de causa raiz correlacionando uma falha com o pipeline upstream que o alimenta. +- Rastreie um trace por execução para que uma etapa lenta dentro de um pipeline fique visível, não apenas a duração total. +- Suporte severidades de alerta e escalonamento (avisar no chat, acionar plantão em crítico repetido). +- Resolva um alerta automaticamente e poste um aviso de recuperação quando a próxima execução for bem-sucedida. + +## Definição de Pronto + +- [ ] Toda execução aparece no histórico com status e contagem de linhas corretos. +- [ ] Uma execução com falha ou vazia produz exatamente um alerta, não um por nova tentativa. +- [ ] Um dataset que fica desatualizado além de seu SLA dispara um alerta de frescor sem que uma execução falhe. +- [ ] Uma queda súbita na contagem de linhas é sinalizada contra a baseline móvel. +- [ ] A visão de saúde reflete o verdadeiro estado da última execução de cada pipeline. + +## Armadilhas Comuns + +- Alertar a cada execução até o canal virar ruído que todos ignoram — deduplique incidentes abertos. +- Medir frescor a partir do início da execução em vez da conclusão bem-sucedida, escondendo falhas parciais. +- Usar um limiar fixo de contagem de linhas que quebra com tráfego sazonal; prefira uma baseline móvel. +- Enviar alertas sem contexto, forçando o leitor a investigar o que de fato quebrou. +- Tratar um job longo ainda em execução como uma falha porque você só verifica um registro concluído. + +## Recursos + +- [Google SRE Book: Monitoring Distributed Systems](https://sre.google/sre-book/monitoring-distributed-systems/) — os quatro sinais de ouro e a filosofia de alertas. +- [Prometheus: Boas práticas de alerta](https://prometheus.io/docs/practices/alerting/) — como escrever regras que permanecem acionáveis. +- [Airflow: SLAs e monitoramento](https://airflow.apache.org/docs/apache-airflow/stable/core-concepts/tasks.html#slas) — conceitos de SLA em um orquestrador real. +- [Monte Carlo: O que é observabilidade de dados](https://www.montecarlodata.com/blog-what-is-data-observability/) — frescor, volume e schema como pilares de observabilidade. diff --git a/projects/data-engineering/intermediate/08-data-quality/README.md b/projects/data-engineering/intermediate/08-data-quality/README.md index 13b685a..8daaee2 100644 --- a/projects/data-engineering/intermediate/08-data-quality/README.md +++ b/projects/data-engineering/intermediate/08-data-quality/README.md @@ -1,34 +1,93 @@ # Data Quality Checks Framework -## Idea -Create a comprehensive framework for data quality testing. Learn about quality metrics and validation patterns. +> 🌐 **English** · [Português](./README.pt-BR.md) + +**Domain:** Data Engineering · **Level:** Intermediate · **Estimated time:** 1–2 days + +## Overview + +Build a reusable framework that runs declarative quality checks against a dataset and reports where it falls short. Instead of scattering ad-hoc `assert` statements through every pipeline, you define rules once — "this column is never null", "order totals are non-negative", "customer_id is unique" — and let the framework evaluate them, score the dataset, and decide whether to warn or halt the pipeline. This is how teams stop shipping broken data downstream. The design challenge is making rules expressive enough to be useful, cheap enough to run on large tables, and structured enough that a failure tells you exactly which rows and which rule went wrong. + +## Prerequisites + +- Comfort querying or scanning a tabular dataset (SQL, a DataFrame API, or files) +- Understanding of common data quality dimensions: completeness, validity, uniqueness, consistency +- Familiarity with the idea of a declarative rule versus imperative code +- Any language and a dataset with realistic imperfections to test against ## Learning Objectives -- Define quality rules -- Implement validation -- Generate quality reports -- Track quality metrics -- Enforce standards - -## Implementation Tips -- Create rule engine -- Implement validation functions -- Add schema validation -- Create statistical checks -- Implement completeness checks -- Add accuracy checks -- Implement consistency checks -- Create outlier detection -- Add comparison with baseline -- Generate quality scorecards -- Create quality metrics -- Implement alerting -- Build quality dashboards -- Create remediation workflows - -## Key Challenges -- Rule complexity -- Performance at scale -- False positive rates -- Custom rule implementation -- Metric calculation accuracy + +By the end, you should be able to: + +- Express quality rules declaratively and evaluate them uniformly +- Cover the core quality dimensions — completeness, validity, uniqueness, consistency, freshness +- Produce a structured report that names the rule, the affected rows, and the failure count +- Compute a dataset quality score and gate a pipeline on it +- Separate blocking failures from warnings so bad data does not always stop the line + +## Functional Requirements + +1. The framework must accept a set of rules bound to a dataset and columns, defined as data/config, not hardcoded logic. +2. It must support not-null, uniqueness, range/domain, regex/format, and cross-column consistency checks. +3. Each check must report pass/fail, the number of violating rows, and a sample of offending values. +4. It must compute an overall quality score (e.g. weighted pass rate) for the dataset. +5. Rules must carry a severity so the framework can warn versus block the pipeline. +6. A referential check must verify that keys in one dataset exist in another. +7. Results must be persisted per run so quality can be tracked over time. + +## Suggested Milestones + +1. **Milestone 1 — Rule engine:** Define a rule format and evaluate single-column checks, producing pass/fail results. +2. **Milestone 2 — Coverage & reporting:** Add cross-column, referential, and statistical checks with a structured report and score. +3. **Milestone 3 — Gating & history:** Add severities that gate the pipeline and persist results to track quality trends. + +## Data & Interface Sketch + +```text +rule + id string + dataset string + column(s) list + type enum(not_null | unique | range | regex | consistency | referential) + params map (e.g. { min: 0 } or { pattern: "..." }) + severity enum(warn | block) + +check_result + rule_id, passed(bool), rows_total, rows_failed, sample_values[], run_id, ran_at + +report + dataset, score(0..100), results[], blocking_failures(int) + -> if blocking_failures > 0: fail the pipeline + +example rule: { column: "email", type: regex, params: { pattern: name@example.com form } } +``` + +## Stretch Goals + +- Add statistical checks: detect an outlier column mean or a distribution drift versus a baseline. +- Auto-suggest rules by profiling a clean sample (infer types, ranges, and null rates). +- Emit a per-run quality trend and alert when the score degrades between runs. +- Support quarantining failing rows to a side table instead of blocking the whole load. + +## Definition of Done + +- [ ] Rules are defined as configuration and run without touching framework code. +- [ ] A failing check reports the rule, the count, and a sample of the actual bad values. +- [ ] The quality score reflects the weighted outcome of all checks. +- [ ] A `block`-severity failure stops the pipeline; a `warn` failure lets it proceed. +- [ ] A referential check correctly catches an orphaned foreign key. + +## Common Pitfalls + +- Writing checks as one-off code so nothing is reusable across datasets — keep rules declarative. +- Reporting only pass/fail with no sample, forcing whoever triages to re-query the whole table. +- Running row-by-row in application code when a set-based query would be far cheaper at scale. +- Treating every failure as blocking, so a cosmetic issue halts a critical load. +- Checking uniqueness or nulls but never validating cross-column business rules where real bugs hide. + +## Resources + +- [Great Expectations: Core concepts](https://docs.greatexpectations.io/docs/core/introduction/) — a mature declarative data quality framework to study. +- [dbt: Tests](https://docs.getdbt.com/docs/build/data-tests) — how tests are declared and gated in a warehouse workflow. +- [Wikipedia: Data quality](https://en.wikipedia.org/wiki/Data_quality) — the standard quality dimensions. +- [Amazon Deequ paper](https://www.vldb.org/pvldb/vol11/p1781-schelter.pdf) — automating large-scale data quality verification. diff --git a/projects/data-engineering/intermediate/08-data-quality/README.pt-BR.md b/projects/data-engineering/intermediate/08-data-quality/README.pt-BR.md new file mode 100644 index 0000000..4f34854 --- /dev/null +++ b/projects/data-engineering/intermediate/08-data-quality/README.pt-BR.md @@ -0,0 +1,93 @@ +# Framework de Verificação de Qualidade de Dados + +> 🌐 [English](./README.md) · **Português** + +**Domínio:** Data Engineering · **Nível:** Intermediário · **Tempo estimado:** 1–2 dias + +## Visão Geral + +Construa um framework reutilizável que executa verificações de qualidade declarativas contra um dataset e reporta onde ele falha. Em vez de espalhar `assert` improvisados por todos os pipelines, você define regras uma vez — "esta coluna nunca é nula", "os totais dos pedidos são não-negativos", "customer_id é único" — e deixa o framework avaliá-las, pontuar o dataset e decidir se avisa ou interrompe o pipeline. É assim que as equipes param de enviar dados quebrados adiante. O desafio de design é tornar as regras expressivas o suficiente para serem úteis, baratas o suficiente para rodar em tabelas grandes e estruturadas o suficiente para que uma falha diga exatamente quais linhas e qual regra deram errado. + +## Pré-requisitos + +- Conforto para consultar ou varrer um dataset tabular (SQL, uma API de DataFrame ou arquivos) +- Entendimento das dimensões comuns de qualidade de dados: completude, validade, unicidade, consistência +- Familiaridade com a ideia de uma regra declarativa versus código imperativo +- Qualquer linguagem e um dataset com imperfeições realistas para testar + +## Objetivos de Aprendizado + +Ao final, você deve ser capaz de: + +- Expressar regras de qualidade de forma declarativa e avaliá-las uniformemente +- Cobrir as dimensões centrais de qualidade — completude, validade, unicidade, consistência, frescor +- Produzir um relatório estruturado que nomeia a regra, as linhas afetadas e a contagem de falhas +- Calcular uma pontuação de qualidade do dataset e usá-la como portão de um pipeline +- Separar falhas bloqueantes de avisos para que dados ruins nem sempre parem a linha + +## Requisitos Funcionais + +1. O framework deve aceitar um conjunto de regras vinculadas a um dataset e colunas, definidas como dados/config, não lógica hardcoded. +2. Deve suportar verificações de não-nulo, unicidade, faixa/domínio, regex/formato e consistência entre colunas. +3. Cada verificação deve reportar aprovado/reprovado, o número de linhas violadoras e uma amostra dos valores ofensores. +4. Deve calcular uma pontuação geral de qualidade (ex.: taxa de aprovação ponderada) para o dataset. +5. As regras devem carregar uma severidade para que o framework possa avisar versus bloquear o pipeline. +6. Uma verificação referencial deve confirmar que chaves em um dataset existem em outro. +7. Os resultados devem ser persistidos por execução para que a qualidade possa ser acompanhada ao longo do tempo. + +## Marcos Sugeridos + +1. **Marco 1 — Motor de regras:** Defina um formato de regra e avalie verificações de coluna única, produzindo resultados de aprovado/reprovado. +2. **Marco 2 — Cobertura e relatórios:** Adicione verificações entre colunas, referenciais e estatísticas com um relatório estruturado e uma pontuação. +3. **Marco 3 — Portão e histórico:** Adicione severidades que barram o pipeline e persista resultados para acompanhar tendências de qualidade. + +## Esboço de Dados e Interface + +```text +rule + id string + dataset string + column(s) list + type enum(not_null | unique | range | regex | consistency | referential) + params map (ex.: { min: 0 } ou { pattern: "..." }) + severity enum(warn | block) + +check_result + rule_id, passed(bool), rows_total, rows_failed, sample_values[], run_id, ran_at + +report + dataset, score(0..100), results[], blocking_failures(int) + -> se blocking_failures > 0: falhar o pipeline + +exemplo de regra: { column: "email", type: regex, params: { pattern: forma name@example.com } } +``` + +## Desafios Extras + +- Adicione verificações estatísticas: detecte uma média de coluna atípica ou um desvio de distribuição versus uma baseline. +- Sugira regras automaticamente perfilando uma amostra limpa (inferir tipos, faixas e taxas de nulos). +- Emita uma tendência de qualidade por execução e alerte quando a pontuação degradar entre execuções. +- Suporte colocar linhas com falha em quarentena numa tabela lateral em vez de bloquear toda a carga. + +## Definição de Pronto + +- [ ] As regras são definidas como configuração e rodam sem tocar no código do framework. +- [ ] Uma verificação reprovada reporta a regra, a contagem e uma amostra dos valores ruins reais. +- [ ] A pontuação de qualidade reflete o resultado ponderado de todas as verificações. +- [ ] Uma falha de severidade `block` para o pipeline; uma falha `warn` o deixa prosseguir. +- [ ] Uma verificação referencial captura corretamente uma chave estrangeira órfã. + +## Armadilhas Comuns + +- Escrever verificações como código pontual, de modo que nada seja reutilizável entre datasets — mantenha as regras declarativas. +- Reportar apenas aprovado/reprovado sem amostra, forçando quem faz a triagem a reconsultar a tabela inteira. +- Rodar linha a linha no código da aplicação quando uma consulta baseada em conjuntos seria muito mais barata em escala. +- Tratar toda falha como bloqueante, de modo que um problema cosmético interrompe uma carga crítica. +- Verificar unicidade ou nulos mas nunca validar regras de negócio entre colunas, onde os bugs reais se escondem. + +## Recursos + +- [Great Expectations: Conceitos centrais](https://docs.greatexpectations.io/docs/core/introduction/) — um framework declarativo maduro de qualidade de dados para estudar. +- [dbt: Testes](https://docs.getdbt.com/docs/build/data-tests) — como testes são declarados e barrados num fluxo de warehouse. +- [Wikipedia: Data quality](https://en.wikipedia.org/wiki/Data_quality) — as dimensões padrão de qualidade. +- [Artigo do Amazon Deequ](https://www.vldb.org/pvldb/vol11/p1781-schelter.pdf) — automatizando a verificação de qualidade de dados em larga escala. diff --git a/projects/data-engineering/intermediate/09-multi-source-ingestion/README.md b/projects/data-engineering/intermediate/09-multi-source-ingestion/README.md index df5213a..a2e712d 100644 --- a/projects/data-engineering/intermediate/09-multi-source-ingestion/README.md +++ b/projects/data-engineering/intermediate/09-multi-source-ingestion/README.md @@ -1,34 +1,95 @@ # Multi-Source Ingestion Pipeline -## Idea -Build a pipeline that ingests data from multiple diverse sources. Learn about source abstraction and scalable integration. +> 🌐 **English** · [Português](./README.pt-BR.md) + +**Domain:** Data Engineering · **Level:** Intermediate · **Estimated time:** 1–2 days + +## Overview + +Build a pipeline that pulls the same kind of entity — say, customers or products — from several very different sources and merges them into one clean, consistent dataset. One source is a REST API, another a CSV drop, another a database export; each names its fields differently, disagrees on formats, and sometimes describes the same real-world record. Your job is to hide that mess behind a common connector interface, map every source into a shared schema, and resolve conflicts when two sources disagree. This is the integration reality behind every "single view of the customer" project, and the lesson is that the hard part is never the fetching — it is reconciliation. + +## Prerequisites + +- Comfort calling an HTTP API and reading files (CSV/JSON) programmatically +- Understanding of schema mapping and normalization +- Familiarity with deduplication and the idea of a natural/business key +- Any language, plus two or three sources (real or mocked) describing overlapping records ## Learning Objectives -- Support multiple sources -- Create connectors -- Handle differences -- Merge data -- Maintain consistency - -## Implementation Tips -- Create connector framework -- Implement source adapters -- Handle different APIs -- Manage credentials -- Create deduplication across sources -- Implement conflict resolution -- Add schema mapping -- Create data enrichment -- Implement data validation -- Add error handling -- Create monitoring per source -- Implement retry logic -- Build configuration management -- Create testing framework - -## Key Challenges -- Connector complexity -- API diversity -- Deduplication across sources -- Conflict resolution -- Performance optimization + +By the end, you should be able to: + +- Design a connector interface that abstracts over heterogeneous sources +- Map each source's fields and formats into one shared target schema +- Deduplicate records that represent the same entity across sources +- Resolve conflicts with an explicit precedence or recency strategy +- Isolate failures so one broken source does not sink the whole run + +## Functional Requirements + +1. Each source must be accessed through a common connector interface (fetch → raw records). +2. Every source must map into a single shared schema with normalized types and formats. +3. The pipeline must deduplicate records across sources using a defined natural key. +4. When sources disagree on a field, a documented conflict-resolution rule must decide the winner. +5. A failure in one source must not abort ingestion of the others; it must be recorded and reported. +6. Each source's credentials/config must be externalized, not hardcoded. +7. The pipeline must emit per-source stats: fetched, mapped, rejected, deduplicated. + +## Suggested Milestones + +1. **Milestone 1 — Connectors:** Define the connector interface and implement two sources behind it. +2. **Milestone 2 — Normalize & merge:** Map each source to the shared schema and deduplicate on the natural key. +3. **Milestone 3 — Conflicts & resilience:** Add conflict resolution, per-source error isolation, and stats. + +## Data & Interface Sketch + +```text +Connector (interface) + name() -> string + fetch() -> iterable + map(raw_record) -> canonical_record | reject(reason) + +canonical_record (shared schema) + entity_id string (natural key, e.g. normalized email name@example.com) + full_name string + email string + updated_at timestamp + _source string + _fetched_at timestamp + +merge: + group by entity_id + on conflict -> pick by precedence [db > api > csv] OR most-recent updated_at + +source_stats: source | fetched | mapped | rejected | merged +``` + +## Stretch Goals + +- Add a fuzzy-match step so near-duplicate names/emails collapse to one entity. +- Make each connector independently retryable with backoff on transient API errors. +- Track field-level provenance so you can answer which source supplied each value. +- Support incremental fetch per source (only records changed since last run). + +## Definition of Done + +- [ ] Adding a new source requires only a new connector implementation, no pipeline changes. +- [ ] Two sources describing the same entity produce one merged record, not two. +- [ ] A field conflict resolves deterministically per the documented rule. +- [ ] One source returning an error still lets the others complete, with the failure reported. +- [ ] Per-source stats reconcile: fetched = mapped + rejected. + +## Common Pitfalls + +- Baking source-specific logic into the core pipeline instead of behind the connector interface. +- Deduplicating on a raw field (unnormalized email/case) so real duplicates slip through. +- Resolving conflicts implicitly by last-writer-wins iteration order — make the rule explicit. +- Letting one source's timeout or auth failure crash the entire run. +- Losing which source a value came from, making later debugging impossible. + +## Resources + +- [Airbyte: Connector development](https://docs.airbyte.com/connector-development/) — how a production system models pluggable sources. +- [Singer specification](https://github.com/singer-io/getting-started/blob/master/docs/SPEC.md) — an open standard for source/target connectors. +- [Wikipedia: Record linkage](https://en.wikipedia.org/wiki/Record_linkage) — the theory behind matching records across sources. +- [Martin Kleppmann: Designing Data-Intensive Applications](https://dataintensive.net/) — data integration and schema evolution chapters. diff --git a/projects/data-engineering/intermediate/09-multi-source-ingestion/README.pt-BR.md b/projects/data-engineering/intermediate/09-multi-source-ingestion/README.pt-BR.md new file mode 100644 index 0000000..4138624 --- /dev/null +++ b/projects/data-engineering/intermediate/09-multi-source-ingestion/README.pt-BR.md @@ -0,0 +1,95 @@ +# Pipeline de Ingestão de Múltiplas Fontes + +> 🌐 [English](./README.md) · **Português** + +**Domínio:** Data Engineering · **Nível:** Intermediário · **Tempo estimado:** 1–2 dias + +## Visão Geral + +Construa um pipeline que puxa o mesmo tipo de entidade — digamos, clientes ou produtos — de várias fontes muito diferentes e as mescla em um único dataset limpo e consistente. Uma fonte é uma API REST, outra é um envio de CSV, outra uma exportação de banco de dados; cada uma nomeia seus campos de forma diferente, discorda nos formatos e, às vezes, descreve o mesmo registro do mundo real. Seu trabalho é esconder essa bagunça atrás de uma interface de conector comum, mapear cada fonte para um schema compartilhado e resolver conflitos quando duas fontes divergem. Essa é a realidade de integração por trás de todo projeto de "visão única do cliente", e a lição é que a parte difícil nunca é a busca — é a reconciliação. + +## Pré-requisitos + +- Conforto para chamar uma API HTTP e ler arquivos (CSV/JSON) programaticamente +- Entendimento de mapeamento de schema e normalização +- Familiaridade com deduplicação e a ideia de uma chave natural/de negócio +- Qualquer linguagem, mais duas ou três fontes (reais ou simuladas) descrevendo registros sobrepostos + +## Objetivos de Aprendizado + +Ao final, você deve ser capaz de: + +- Projetar uma interface de conector que abstrai fontes heterogêneas +- Mapear os campos e formatos de cada fonte para um único schema alvo compartilhado +- Deduplicar registros que representam a mesma entidade entre fontes +- Resolver conflitos com uma estratégia explícita de precedência ou recência +- Isolar falhas para que uma fonte quebrada não afunde a execução inteira + +## Requisitos Funcionais + +1. Cada fonte deve ser acessada por meio de uma interface de conector comum (fetch → registros brutos). +2. Toda fonte deve mapear para um único schema compartilhado com tipos e formatos normalizados. +3. O pipeline deve deduplicar registros entre fontes usando uma chave natural definida. +4. Quando fontes divergem sobre um campo, uma regra documentada de resolução de conflito deve decidir o vencedor. +5. Uma falha em uma fonte não deve abortar a ingestão das outras; ela deve ser registrada e reportada. +6. As credenciais/config de cada fonte devem ser externalizadas, não hardcoded. +7. O pipeline deve emitir estatísticas por fonte: buscados, mapeados, rejeitados, deduplicados. + +## Marcos Sugeridos + +1. **Marco 1 — Conectores:** Defina a interface de conector e implemente duas fontes por trás dela. +2. **Marco 2 — Normalizar e mesclar:** Mapeie cada fonte para o schema compartilhado e deduplique pela chave natural. +3. **Marco 3 — Conflitos e resiliência:** Adicione resolução de conflitos, isolamento de erro por fonte e estatísticas. + +## Esboço de Dados e Interface + +```text +Connector (interface) + name() -> string + fetch() -> iterable + map(raw_record) -> canonical_record | reject(motivo) + +canonical_record (schema compartilhado) + entity_id string (chave natural, ex.: email normalizado name@example.com) + full_name string + email string + updated_at timestamp + _source string + _fetched_at timestamp + +merge: + agrupar por entity_id + em conflito -> escolher por precedência [db > api > csv] OU updated_at mais recente + +source_stats: source | fetched | mapped | rejected | merged +``` + +## Desafios Extras + +- Adicione uma etapa de correspondência fuzzy para que nomes/emails quase duplicados colapsem em uma entidade. +- Torne cada conector reexecutável de forma independente, com backoff em erros transitórios de API. +- Rastreie a proveniência em nível de campo para responder qual fonte forneceu cada valor. +- Suporte busca incremental por fonte (apenas registros alterados desde a última execução). + +## Definição de Pronto + +- [ ] Adicionar uma nova fonte exige apenas uma nova implementação de conector, sem mudanças no pipeline. +- [ ] Duas fontes descrevendo a mesma entidade produzem um registro mesclado, não dois. +- [ ] Um conflito de campo resolve de forma determinística conforme a regra documentada. +- [ ] Uma fonte retornando erro ainda deixa as outras concluírem, com a falha reportada. +- [ ] As estatísticas por fonte fecham: buscados = mapeados + rejeitados. + +## Armadilhas Comuns + +- Embutir lógica específica de fonte no núcleo do pipeline em vez de atrás da interface de conector. +- Deduplicar em um campo bruto (email sem normalização/caixa) de modo que duplicatas reais escapem. +- Resolver conflitos implicitamente pela ordem de iteração do último a escrever — torne a regra explícita. +- Deixar o timeout ou a falha de autenticação de uma fonte derrubar a execução inteira. +- Perder de qual fonte veio um valor, tornando a depuração posterior impossível. + +## Recursos + +- [Airbyte: Desenvolvimento de conectores](https://docs.airbyte.com/connector-development/) — como um sistema em produção modela fontes plugáveis. +- [Especificação Singer](https://github.com/singer-io/getting-started/blob/master/docs/SPEC.md) — um padrão aberto para conectores de fonte/destino. +- [Wikipedia: Record linkage](https://en.wikipedia.org/wiki/Record_linkage) — a teoria por trás de casar registros entre fontes. +- [Martin Kleppmann: Designing Data-Intensive Applications](https://dataintensive.net/) — capítulos sobre integração de dados e evolução de schema. diff --git a/projects/data-engineering/intermediate/10-partitioned-pipeline/README.md b/projects/data-engineering/intermediate/10-partitioned-pipeline/README.md index 411a324..2e84377 100644 --- a/projects/data-engineering/intermediate/10-partitioned-pipeline/README.md +++ b/projects/data-engineering/intermediate/10-partitioned-pipeline/README.md @@ -1,34 +1,94 @@ # Partitioned Data Pipeline -## Idea -Create a pipeline that partitions data for optimization. Learn about partitioning strategies and query optimization. +> 🌐 **English** · [Português](./README.pt-BR.md) + +**Domain:** Data Engineering · **Level:** Intermediate · **Estimated time:** 1–2 days + +## Overview + +Build a pipeline that writes its output split into partitions — typically by date — so that reads scan only the slices they need and reprocessing touches one partition instead of the whole table. This is the layout under every large data lake: `dt=2026-07-24/` folders, partition pruning at query time, and per-partition retention. You will choose a partition key, write data into the right partition, make each partition independently rebuildable, and prove that queries prune away the partitions they do not need. The payoff is concrete: a backfill or a bad-day fix becomes a one-partition operation instead of a full reload. + +## Prerequisites + +- Comfort writing a batch job that produces a dataset (files or warehouse tables) +- Understanding of how partition pruning speeds up queries +- Familiarity with idempotent writes and the incremental-load idea ([Incremental Data Processing](../06-incremental-processing/) is a good warm-up) +- A columnar format or partitioned table target (Parquet, Delta/Iceberg/Hive-style, or a partitioned SQL table) ## Learning Objectives -- Design partitioning scheme -- Implement partitioned loading -- Optimize queries -- Manage partition lifecycle -- Handle partition pruning - -## Implementation Tips -- Select partitioning key -- Implement date partitioning -- Add hash partitioning -- Create range partitioning -- Implement dynamic partitioning -- Add partition discovery -- Create partition management -- Implement partition pruning -- Optimize query performance -- Add garbage collection -- Create retention policies -- Implement partition migration -- Build monitoring -- Create testing framework - -## Key Challenges -- Partitioning key selection -- Skewed data handling -- Partition explosion -- Query performance optimization -- Partition lifecycle management + +By the end, you should be able to: + +- Choose a partition key by query pattern and cardinality, not by habit +- Write data into the correct partition and overwrite a single partition idempotently +- Verify that a filtered query prunes to only the relevant partitions +- Manage a partition lifecycle: retention, compaction, and cleanup +- Backfill or repair one partition without disturbing the rest + +## Functional Requirements + +1. The pipeline must write output partitioned by a chosen key (e.g. event date). +2. Re-running for a given partition must fully overwrite that partition, not append duplicates. +3. A query filtered on the partition key must read only matching partitions (prunable layout). +4. The pipeline must support backfilling an arbitrary set of past partitions. +5. A retention policy must drop partitions older than a configured horizon. +6. The layout must avoid tiny-file explosion — control the number of files per partition. +7. The pipeline must record which partitions were written or rebuilt in each run. + +## Suggested Milestones + +1. **Milestone 1 — Partitioned write:** Pick a key and write output into per-partition paths. +2. **Milestone 2 — Idempotent overwrite & pruning:** Overwrite a single partition on rerun and confirm queries prune. +3. **Milestone 3 — Lifecycle:** Add backfill, retention, and file-count control. + +## Data & Interface Sketch + +```text +partition layout (date-partitioned): + /warehouse/events/ + dt=2026-07-22/ part-000.parquet ... + dt=2026-07-23/ part-000.parquet ... + dt=2026-07-24/ part-000.parquet ... + +write contract: + write(partition=dt, rows) -> overwrite ONLY that dt's directory + backfill(dt_from, dt_to) -> rebuild each dt in range independently + +pruning check: + query WHERE dt = '2026-07-24' -> reads 1 partition, not the full table + +lifecycle: + retention: drop dt < today - N days + compaction: merge many small files -> few target-sized files + run_manifest: run_id | partitions_written[] | files | rows +``` + +## Stretch Goals + +- Handle skew: detect a hot partition and sub-partition it (e.g. by hash bucket) to balance load. +- Add multi-level partitioning (dt + region) and reason about the partition-explosion tradeoff. +- Track partition-level stats so a query planner can skip via min/max metadata, not just the key. +- Support late data by re-opening and rewriting an already-closed partition idempotently. + +## Definition of Done + +- [ ] Output lands in the correct partition path for its key. +- [ ] Reprocessing one date overwrites exactly that partition, leaving others untouched. +- [ ] A partition-filtered query demonstrably scans only the matching partitions. +- [ ] Backfilling a date range rebuilds each partition independently. +- [ ] Retention removes expired partitions and file counts stay bounded per partition. + +## Common Pitfalls + +- Choosing a high-cardinality partition key (e.g. user_id) and creating millions of tiny partitions. +- Appending on rerun so a reprocessed day silently doubles its rows. +- Partitioning on a column that queries never filter on, so pruning never kicks in. +- The small-files problem: thousands of KB-sized files per partition crushing read performance. +- Deleting a partition's files before the new write lands, leaving a gap on failure. + +## Resources + +- [Apache Hive: Partitioned tables](https://cwiki.apache.org/confluence/display/Hive/LanguageManual+DDL#LanguageManualDDL-PartitionedTables) — the original directory-partition convention. +- [Databricks: Partitioning best practices](https://docs.databricks.com/aws/en/tables/partitions) — when to partition and the small-files trap. +- [Apache Iceberg: Partitioning](https://iceberg.apache.org/docs/latest/partitioning/) — hidden partitioning and evolution done right. +- [Spark: Data sources — partition discovery](https://spark.apache.org/docs/latest/sql-data-sources-parquet.html#partition-discovery) — how pruning uses the layout. diff --git a/projects/data-engineering/intermediate/10-partitioned-pipeline/README.pt-BR.md b/projects/data-engineering/intermediate/10-partitioned-pipeline/README.pt-BR.md new file mode 100644 index 0000000..b3b04b3 --- /dev/null +++ b/projects/data-engineering/intermediate/10-partitioned-pipeline/README.pt-BR.md @@ -0,0 +1,94 @@ +# Pipeline de Dados Particionado + +> 🌐 [English](./README.md) · **Português** + +**Domínio:** Data Engineering · **Nível:** Intermediário · **Tempo estimado:** 1–2 dias + +## Visão Geral + +Construa um pipeline que escreve sua saída dividida em partições — tipicamente por data — para que as leituras varram apenas as fatias necessárias e o reprocessamento toque uma partição em vez da tabela inteira. Esse é o layout sob todo grande data lake: pastas `dt=2026-07-24/`, poda de partição no momento da consulta e retenção por partição. Você vai escolher uma chave de partição, escrever dados na partição certa, tornar cada partição reconstruível de forma independente e provar que as consultas podam as partições de que não precisam. O ganho é concreto: um backfill ou uma correção de um dia ruim vira uma operação de uma partição em vez de uma recarga completa. + +## Pré-requisitos + +- Conforto para escrever um job em lote que produz um dataset (arquivos ou tabelas de warehouse) +- Entendimento de como a poda de partição acelera consultas +- Familiaridade com escritas idempotentes e a ideia de carga incremental ([Processamento Incremental de Dados](../06-incremental-processing/) é um bom aquecimento) +- Um formato colunar ou destino de tabela particionada (Parquet, estilo Delta/Iceberg/Hive ou uma tabela SQL particionada) + +## Objetivos de Aprendizado + +Ao final, você deve ser capaz de: + +- Escolher uma chave de partição pelo padrão de consulta e cardinalidade, não por hábito +- Escrever dados na partição correta e sobrescrever uma única partição de forma idempotente +- Verificar que uma consulta filtrada poda apenas as partições relevantes +- Gerenciar o ciclo de vida de uma partição: retenção, compactação e limpeza +- Reprocessar ou reparar uma partição sem perturbar as demais + +## Requisitos Funcionais + +1. O pipeline deve escrever a saída particionada por uma chave escolhida (ex.: data do evento). +2. Reexecutar para uma dada partição deve sobrescrever totalmente aquela partição, não anexar duplicatas. +3. Uma consulta filtrada pela chave de partição deve ler apenas as partições correspondentes (layout podável). +4. O pipeline deve suportar o backfill de um conjunto arbitrário de partições passadas. +5. Uma política de retenção deve descartar partições mais antigas que um horizonte configurado. +6. O layout deve evitar a explosão de arquivos minúsculos — controle o número de arquivos por partição. +7. O pipeline deve registrar quais partições foram escritas ou reconstruídas em cada execução. + +## Marcos Sugeridos + +1. **Marco 1 — Escrita particionada:** Escolha uma chave e escreva a saída em caminhos por partição. +2. **Marco 2 — Sobrescrita idempotente e poda:** Sobrescreva uma única partição na reexecução e confirme que as consultas podam. +3. **Marco 3 — Ciclo de vida:** Adicione backfill, retenção e controle da contagem de arquivos. + +## Esboço de Dados e Interface + +```text +layout de partições (particionado por data): + /warehouse/events/ + dt=2026-07-22/ part-000.parquet ... + dt=2026-07-23/ part-000.parquet ... + dt=2026-07-24/ part-000.parquet ... + +contrato de escrita: + write(partition=dt, rows) -> sobrescrever APENAS o diretório daquele dt + backfill(dt_from, dt_to) -> reconstruir cada dt no intervalo de forma independente + +verificação de poda: + query WHERE dt = '2026-07-24' -> lê 1 partição, não a tabela inteira + +ciclo de vida: + retenção: descartar dt < hoje - N dias + compactação: mesclar muitos arquivos pequenos -> poucos arquivos do tamanho alvo + run_manifest: run_id | partitions_written[] | files | rows +``` + +## Desafios Extras + +- Trate o skew: detecte uma partição quente e a subparticione (ex.: por bucket de hash) para equilibrar a carga. +- Adicione particionamento multinível (dt + region) e raciocine sobre o tradeoff de explosão de partições. +- Rastreie estatísticas em nível de partição para que um planejador de consultas pule via metadados min/max, não só pela chave. +- Suporte dados atrasados reabrindo e reescrevendo uma partição já fechada de forma idempotente. + +## Definição de Pronto + +- [ ] A saída chega no caminho de partição correto para sua chave. +- [ ] Reprocessar uma data sobrescreve exatamente aquela partição, deixando as outras intactas. +- [ ] Uma consulta filtrada por partição comprovadamente varre apenas as partições correspondentes. +- [ ] Reprocessar um intervalo de datas reconstrói cada partição de forma independente. +- [ ] A retenção remove partições expiradas e a contagem de arquivos permanece limitada por partição. + +## Armadilhas Comuns + +- Escolher uma chave de partição de alta cardinalidade (ex.: user_id) e criar milhões de partições minúsculas. +- Anexar na reexecução, de modo que um dia reprocessado silenciosamente dobra suas linhas. +- Particionar por uma coluna pela qual as consultas nunca filtram, então a poda nunca acontece. +- O problema dos arquivos pequenos: milhares de arquivos de KB por partição destruindo o desempenho de leitura. +- Apagar os arquivos de uma partição antes de a nova escrita chegar, deixando uma lacuna em caso de falha. + +## Recursos + +- [Apache Hive: Tabelas particionadas](https://cwiki.apache.org/confluence/display/Hive/LanguageManual+DDL#LanguageManualDDL-PartitionedTables) — a convenção original de partição por diretório. +- [Databricks: Boas práticas de particionamento](https://docs.databricks.com/aws/en/tables/partitions) — quando particionar e a armadilha dos arquivos pequenos. +- [Apache Iceberg: Particionamento](https://iceberg.apache.org/docs/latest/partitioning/) — particionamento oculto e evolução feitos direito. +- [Spark: Fontes de dados — descoberta de partições](https://spark.apache.org/docs/latest/sql-data-sources-parquet.html#partition-discovery) — como a poda usa o layout. diff --git a/projects/data-science/advanced/01-end-to-end-ml-platform/README.md b/projects/data-science/advanced/01-end-to-end-ml-platform/README.md index b6d96b5..d5d9e44 100644 --- a/projects/data-science/advanced/01-end-to-end-ml-platform/README.md +++ b/projects/data-science/advanced/01-end-to-end-ml-platform/README.md @@ -1,34 +1,105 @@ # End-to-End ML Platform -## Idea -Build a complete machine learning platform for experimentation and deployment. Learn about MLOps and production ML systems. +> 🌐 **English** · [Português](./README.pt-BR.md) + +**Domain:** Data Science · **Level:** Advanced · **Estimated time:** 1–2 weeks + +## Overview + +Design and build a small internal ML platform that carries a model from raw data to a monitored production endpoint without any manual glue. The platform ties together four capabilities that are usually separate: versioned data, tracked experiments, a model registry with lifecycle stages, and an automated path from a registered model to a serving deployment. The point is not any single model — you might train something trivial — but the plumbing that makes the whole loop reproducible, auditable, and re-runnable months later by someone who did not build it. This is the MLOps backbone every production data team eventually needs. + +## Prerequisites + +- Comfort training and evaluating models with a mainstream framework (scikit-learn, PyTorch, or TensorFlow) +- Experience with containers and a CI runner (Docker plus GitHub Actions or similar) +- Familiarity with REST services and object storage (S3/GCS or a MinIO stand-in) +- Having built at least a couple of end-to-end pipelines before (e.g. an intermediate data-pipeline project) helps a lot ## Learning Objectives -- Implement data management -- Create experiment tracking -- Build model registry -- Implement deployment pipelines -- Monitor production models - -## Implementation Tips -- Create data versioning system -- Implement experiment tracking -- Build model registry with metadata -- Create model versioning -- Implement model comparison -- Build deployment automation -- Create monitoring systems -- Add alerting -- Implement feedback loops -- Create API for serving -- Add performance dashboards -- Implement retraining triggers -- Create documentation -- Build user interface - -## Key Challenges -- System complexity -- Data management scale -- Experiment reproducibility -- Model deployment reliability -- Production monitoring + +By the end, you should be able to: + +- Version datasets and tie each model artifact to the exact data and code that produced it +- Track experiments (params, metrics, artifacts) and compare runs objectively +- Operate a model registry with staged promotion (Staging → Production → Archived) +- Automate deployment so a promotion triggers a serving rollout +- Instrument the loop with monitoring and a retraining trigger + +## Functional Requirements + +1. The platform must version datasets so any model can be traced to the exact snapshot it trained on. +2. Every training run must log parameters, metrics, and artifacts to a queryable experiment tracker. +3. The model registry must store models with metadata and support stage transitions with an audit trail. +4. Promoting a model to Production must automatically trigger a serving deployment without manual file copying. +5. The serving endpoint must expose the current production model version and health via an API. +6. The system must record prediction inputs/outputs for later monitoring and drift analysis. +7. A retraining job must be triggerable both on a schedule and by a monitoring signal. + +## Non-Functional Requirements + +- **Reproducibility:** re-running a registered model's training must reproduce metrics within a documented tolerance. +- **Availability:** serving should tolerate a single-node failure; target 99.5% for the endpoint. +- **Latency/throughput:** serving p95 under a stated budget (e.g. 200 ms) at a defined request rate. +- **Auditability:** every promotion and deployment is attributable to a user, model version, and timestamp. + +## Suggested Milestones + +1. **Milestone 1 — Tracking & data versioning:** Stand up experiment tracking (MLflow) and dataset versioning (DVC or lakeFS); log a training run end to end. +2. **Milestone 2 — Registry & promotion:** Register models, implement staged transitions, and record the audit trail. +3. **Milestone 3 — Automated serving:** Wire a promotion event to a containerized deployment behind a stable API. +4. **Milestone 4 — Monitoring & retraining:** Log predictions, compute basic drift, and close the loop with a retraining trigger. + +## Data & Interface Sketch + +```text + +-------------+ +------------------+ + raw data ---> | Data Version | -> | Training Job | + | (DVC/lakeFS) | | logs -> Tracker | + +-------------+ +---------+--------+ + | + register model + v + +------------------+ + | Model Registry | + | Staging|Prod|Arch | + +---------+--------+ + promote(Prod) | event + v + +------------------+ +-----------+ + client --> POST /predict ------> | Serving (Prod ver)| --> | pred log | + GET /model/info +------------------+ +-----+-----+ + | + drift/perf signal ---+--> retrain + +Registered model + name, version, stage, run_id, data_version, metrics{}, created_by, created_at +``` + +## Stretch Goals + +- Add a feature store so training and serving share the same feature definitions. +- Support shadow/canary deployment: route a slice of traffic to a candidate version. +- Add lineage graphs linking data → run → model → deployment visually. +- Enforce approval gates (a second reviewer) before Production promotion. + +## Definition of Done + +- [ ] Any production model traces cleanly to its data version, code commit, and run. +- [ ] A promotion event deploys the model automatically with no manual artifact handling. +- [ ] The serving endpoint reports its live model version and passes health checks. +- [ ] Predictions are logged and a drift metric is computed on a schedule. +- [ ] A retraining run can be triggered by both schedule and monitoring signal. + +## Common Pitfalls + +- Treating experiment tracking as optional and losing the ability to reproduce a "best" model. +- Storing models as loose files instead of registry entries, so lifecycle state lives in someone's head. +- Coupling training and serving code so tightly that a serving change forces a retrain. +- Skipping prediction logging, then having nothing to compute drift against when quality drops. + +## Resources + +- [MLflow Documentation](https://mlflow.org/docs/latest/index.html) — tracking, registry, and model packaging. +- [Google Cloud: MLOps — Continuous delivery and automation pipelines in ML](https://cloud.google.com/architecture/mlops-continuous-delivery-and-automation-pipelines-in-machine-learning) — the canonical MLOps maturity reference. +- [DVC Documentation](https://dvc.org/doc) — data and pipeline versioning. +- [Hidden Technical Debt in Machine Learning Systems (Sculley et al., 2015)](https://papers.nips.cc/paper/2015/hash/86df7dcfd896fcaf2674f757a2463eba-Abstract.html) — why the glue matters more than the model. diff --git a/projects/data-science/advanced/01-end-to-end-ml-platform/README.pt-BR.md b/projects/data-science/advanced/01-end-to-end-ml-platform/README.pt-BR.md new file mode 100644 index 0000000..ff043df --- /dev/null +++ b/projects/data-science/advanced/01-end-to-end-ml-platform/README.pt-BR.md @@ -0,0 +1,105 @@ +# Plataforma de ML Ponta a Ponta + +> 🌐 [English](./README.md) · **Português** + +**Domínio:** Data Science · **Nível:** Avançado · **Tempo estimado:** 1–2 semanas + +## Visão Geral + +Projete e construa uma pequena plataforma interna de ML que leva um modelo dos dados brutos a um endpoint de produção monitorado sem nenhuma cola manual. A plataforma une quatro capacidades que normalmente ficam separadas: dados versionados, experimentos rastreados, um registro de modelos com estágios de ciclo de vida e um caminho automatizado de um modelo registrado até uma implantação de serving. O foco não é nenhum modelo específico — você pode treinar algo trivial — mas o encanamento que torna todo o ciclo reproduzível, auditável e re-executável meses depois por alguém que não o construiu. Esta é a espinha dorsal de MLOps que toda equipe de dados em produção eventualmente precisa. + +## Pré-requisitos + +- Conforto para treinar e avaliar modelos com um framework popular (scikit-learn, PyTorch ou TensorFlow) +- Experiência com containers e um runner de CI (Docker mais GitHub Actions ou similar) +- Familiaridade com serviços REST e armazenamento de objetos (S3/GCS ou um MinIO substituto) +- Ter construído ao menos alguns pipelines ponta a ponta antes (ex.: um projeto intermediário de pipeline de dados) ajuda bastante + +## Objetivos de Aprendizado + +Ao final, você deve ser capaz de: + +- Versionar datasets e vincular cada artefato de modelo aos dados e ao código exatos que o produziram +- Rastrear experimentos (parâmetros, métricas, artefatos) e comparar execuções objetivamente +- Operar um registro de modelos com promoção por estágios (Staging → Produção → Arquivado) +- Automatizar a implantação para que uma promoção dispare um rollout de serving +- Instrumentar o ciclo com monitoramento e um gatilho de retreino + +## Requisitos Funcionais + +1. A plataforma deve versionar datasets para que qualquer modelo seja rastreável ao snapshot exato em que treinou. +2. Toda execução de treino deve registrar parâmetros, métricas e artefatos em um rastreador de experimentos consultável. +3. O registro de modelos deve armazenar modelos com metadados e suportar transições de estágio com trilha de auditoria. +4. Promover um modelo para Produção deve disparar automaticamente uma implantação de serving sem cópia manual de arquivos. +5. O endpoint de serving deve expor a versão atual do modelo em produção e o health via API. +6. O sistema deve registrar entradas/saídas de predição para análise posterior de monitoramento e drift. +7. Um job de retreino deve ser disparável tanto por agendamento quanto por um sinal de monitoramento. + +## Requisitos Não Funcionais + +- **Reprodutibilidade:** reexecutar o treino de um modelo registrado deve reproduzir as métricas dentro de uma tolerância documentada. +- **Disponibilidade:** o serving deve tolerar a falha de um único nó; meta de 99,5% para o endpoint. +- **Latência/vazão:** p95 do serving abaixo de um orçamento declarado (ex.: 200 ms) a uma taxa de requisições definida. +- **Auditabilidade:** cada promoção e implantação é atribuível a um usuário, versão de modelo e timestamp. + +## Marcos Sugeridos + +1. **Marco 1 — Rastreamento e versionamento de dados:** Suba rastreamento de experimentos (MLflow) e versionamento de datasets (DVC ou lakeFS); registre uma execução de treino de ponta a ponta. +2. **Marco 2 — Registro e promoção:** Registre modelos, implemente transições por estágios e grave a trilha de auditoria. +3. **Marco 3 — Serving automatizado:** Conecte um evento de promoção a uma implantação containerizada atrás de uma API estável. +4. **Marco 4 — Monitoramento e retreino:** Registre predições, calcule drift básico e feche o ciclo com um gatilho de retreino. + +## Esboço de Dados e Interface + +```text + +-------------+ +------------------+ + dados brutos->| Versão Dados | -> | Job de Treino | + | (DVC/lakeFS) | | logs -> Tracker | + +-------------+ +---------+--------+ + | + registra modelo + v + +------------------+ + | Registro Modelos | + | Staging|Prod|Arq | + +---------+--------+ + promover(Prod)| evento + v + +------------------+ +-----------+ + cliente-> POST /predict -------> | Serving (ver Prod)| --> | log pred | + GET /model/info +------------------+ +-----+-----+ + | + sinal drift/perf --------+--> retreino + +Modelo registrado + name, version, stage, run_id, data_version, metrics{}, created_by, created_at +``` + +## Desafios Extras + +- Adicione uma feature store para que treino e serving compartilhem as mesmas definições de features. +- Suporte implantação shadow/canary: roteie uma fatia do tráfego para uma versão candidata. +- Adicione grafos de linhagem ligando dados → execução → modelo → implantação visualmente. +- Imponha portões de aprovação (um segundo revisor) antes da promoção para Produção. + +## Definição de Pronto + +- [ ] Qualquer modelo em produção rastreia limpo até sua versão de dados, commit de código e execução. +- [ ] Um evento de promoção implanta o modelo automaticamente, sem manuseio manual de artefatos. +- [ ] O endpoint de serving informa a versão de modelo ativa e passa nos health checks. +- [ ] Predições são registradas e uma métrica de drift é calculada de forma agendada. +- [ ] Uma execução de retreino pode ser disparada tanto por agendamento quanto por sinal de monitoramento. + +## Armadilhas Comuns + +- Tratar o rastreamento de experimentos como opcional e perder a capacidade de reproduzir o "melhor" modelo. +- Armazenar modelos como arquivos soltos em vez de entradas de registro, deixando o estado de ciclo de vida na cabeça de alguém. +- Acoplar o código de treino e de serving tão firmemente que uma mudança no serving força um retreino. +- Pular o registro de predições e depois não ter nada com que calcular drift quando a qualidade cai. + +## Recursos + +- [Documentação do MLflow](https://mlflow.org/docs/latest/index.html) — tracking, registro e empacotamento de modelos. +- [Google Cloud: MLOps — entrega contínua e pipelines de automação em ML](https://cloud.google.com/architecture/mlops-continuous-delivery-and-automation-pipelines-in-machine-learning) — a referência canônica de maturidade em MLOps. +- [Documentação do DVC](https://dvc.org/doc) — versionamento de dados e pipelines. +- [Hidden Technical Debt in Machine Learning Systems (Sculley et al., 2015)](https://papers.nips.cc/paper/2015/hash/86df7dcfd896fcaf2674f757a2463eba-Abstract.html) — por que a cola importa mais que o modelo. diff --git a/projects/data-science/advanced/02-real-time-prediction/README.md b/projects/data-science/advanced/02-real-time-prediction/README.md index a950dca..4d69c63 100644 --- a/projects/data-science/advanced/02-real-time-prediction/README.md +++ b/projects/data-science/advanced/02-real-time-prediction/README.md @@ -1,34 +1,105 @@ -# Real-time Prediction System +# Real-Time Prediction System -## Idea -Build a system for making predictions at scale with low latency. Learn about model serving and optimization for production. +> 🌐 **English** · [Português](./README.pt-BR.md) + +**Domain:** Data Science · **Level:** Advanced · **Estimated time:** 1–2 weeks + +## Overview + +Build a model-serving system that answers prediction requests at high volume with tight, predictable latency. Anyone can wrap a model in a Flask route; the hard part is holding p99 latency under budget while requests arrive in bursts, features must be fetched or computed on the fly, and the model itself may be large. This project pushes you into the real serving toolbox: request batching, model optimization (quantization, ONNX export), a warm feature cache, and graceful degradation when a dependency slows down. You will measure everything, because "fast enough" is only meaningful against numbers. + +## Prerequisites + +- A trained model you can export (scikit-learn, PyTorch, or TensorFlow) +- Solid grasp of HTTP services, concurrency, and async I/O +- Familiarity with a cache (Redis) and basic load testing (Locust, k6, or wrk) +- Comfort reading latency percentiles, not just averages ## Learning Objectives -- Optimize models for inference -- Implement low-latency serving -- Handle concurrent requests -- Manage resource usage -- Monitor system performance - -## Implementation Tips -- Implement model optimization (quantization, pruning) -- Create prediction API -- Implement caching strategies -- Use efficient serialization formats -- Create load balancing -- Implement request batching -- Add request queuing -- Create circuit breakers -- Implement fallback mechanisms -- Add performance monitoring -- Create latency dashboards -- Implement feature caching -- Build scalable infrastructure -- Add resource management - -## Key Challenges -- Latency requirements -- Throughput scaling -- Feature engineering speed -- Resource optimization -- Monitoring and debugging + +By the end, you should be able to: + +- Optimize a model for inference via quantization, pruning, or ONNX/TensorRT export +- Implement dynamic request batching to raise throughput without wrecking latency +- Design a feature cache and reason about staleness vs freshness +- Apply backpressure, timeouts, and circuit breakers so overload fails cleanly +- Measure and defend p50/p95/p99 latency and throughput under load + +## Functional Requirements + +1. The system must serve predictions over an API with a documented request/response schema. +2. Incoming requests must be dynamically batched up to a size/time window before inference. +3. Frequently used features must be served from a cache with an explicit TTL and miss path. +4. The system must enforce per-request timeouts and shed or queue load when saturated. +5. A fallback (cached prediction, default, or lighter model) must engage when the primary path fails. +6. The system must expose latency and throughput metrics per endpoint. +7. The optimized model's accuracy must be validated against the unoptimized baseline within a stated tolerance. + +## Non-Functional Requirements + +- **Latency:** p95 ≤ a stated budget (e.g. 50 ms) and p99 bounded, under the target request rate. +- **Throughput:** sustain a defined RPS (e.g. 1,000) on the target hardware. +- **Availability:** degrade rather than crash under overload; no unbounded queues. +- **Consistency:** feature cache staleness must be bounded and documented. + +## Suggested Milestones + +1. **Milestone 1 — Baseline serving:** Expose the model behind an API and measure baseline latency/throughput. +2. **Milestone 2 — Optimize the model:** Export to ONNX and/or quantize; verify accuracy delta and speedup. +3. **Milestone 3 — Batching & caching:** Add dynamic batching and a feature cache; re-measure. +4. **Milestone 4 — Resilience:** Add timeouts, circuit breakers, and a fallback; load-test to saturation. + +## Data & Interface Sketch + +```text + client --> POST /predict {features|entity_id} + | + v + +-----------------+ cache miss +--------------+ + | Feature fetch |--------------->| Feature store | + | (Redis cache) |<---------------| / DB | + +--------+--------+ +--------------+ + | + v + +-----------------+ window: N reqs or T ms + | Batching queue |------------------------+ + +--------+--------+ | + v v + +-----------------+ +----------------+ + | Optimized model | -- fail -----> | Fallback path | + | (ONNX/quantized)| | cached/default | + +--------+--------+ +----------------+ + v + response { prediction, model_version, latency_ms } + +Metrics: p50/p95/p99 latency, RPS, batch size, cache hit ratio +``` + +## Stretch Goals + +- Add a GPU path with TensorRT and compare cost/latency against CPU. +- Support A/B or shadow serving of two model versions with per-version metrics. +- Add adaptive batching that tunes the window based on live load. +- Precompute and warm the cache for the hottest entities on startup. + +## Definition of Done + +- [ ] p95 and p99 latency are measured under target load and meet the stated budget. +- [ ] The optimized model's accuracy delta versus baseline is documented and acceptable. +- [ ] Dynamic batching and the feature cache are in place with visible hit-ratio metrics. +- [ ] Overload triggers backpressure and the fallback, never an unbounded queue or crash. +- [ ] A load test report shows behavior from normal load through saturation. + +## Common Pitfalls + +- Optimizing latency on a single request and never testing under concurrent load. +- Batching so aggressively that tail latency balloons for the last request in each window. +- Caching features without a TTL, so the model quietly serves stale inputs. +- Reporting average latency and hiding a terrible p99 behind it. + +## Resources + +- [ONNX Runtime Documentation](https://onnxruntime.ai/docs/) — cross-framework inference optimization. +- [NVIDIA Triton Inference Server](https://docs.nvidia.com/deeplearning/triton-inference-server/user-guide/docs/index.html) — dynamic batching and multi-model serving. +- [TensorFlow Serving Architecture](https://www.tensorflow.org/tfx/serving/architecture) — production serving patterns. +- [Google SRE Book: Handling Overload](https://sre.google/sre-book/handling-overload/) — backpressure and graceful degradation. diff --git a/projects/data-science/advanced/02-real-time-prediction/README.pt-BR.md b/projects/data-science/advanced/02-real-time-prediction/README.pt-BR.md new file mode 100644 index 0000000..1e5d9d7 --- /dev/null +++ b/projects/data-science/advanced/02-real-time-prediction/README.pt-BR.md @@ -0,0 +1,105 @@ +# Sistema de Predição em Tempo Real + +> 🌐 [English](./README.md) · **Português** + +**Domínio:** Data Science · **Nível:** Avançado · **Tempo estimado:** 1–2 semanas + +## Visão Geral + +Construa um sistema de serving de modelos que responde a requisições de predição em alto volume com latência baixa e previsível. Qualquer um envolve um modelo em uma rota Flask; a parte difícil é manter a latência p99 dentro do orçamento enquanto as requisições chegam em rajadas, as features precisam ser buscadas ou calculadas na hora e o próprio modelo pode ser grande. Este projeto te empurra para a caixa de ferramentas real de serving: batching de requisições, otimização de modelo (quantização, export ONNX), um cache quente de features e degradação graciosa quando uma dependência fica lenta. Você vai medir tudo, porque "rápido o suficiente" só faz sentido diante de números. + +## Pré-requisitos + +- Um modelo treinado que você possa exportar (scikit-learn, PyTorch ou TensorFlow) +- Domínio sólido de serviços HTTP, concorrência e I/O assíncrono +- Familiaridade com um cache (Redis) e teste de carga básico (Locust, k6 ou wrk) +- Conforto para ler percentis de latência, não apenas médias + +## Objetivos de Aprendizado + +Ao final, você deve ser capaz de: + +- Otimizar um modelo para inferência via quantização, pruning ou export ONNX/TensorRT +- Implementar batching dinâmico de requisições para elevar a vazão sem destruir a latência +- Projetar um cache de features e raciocinar sobre staleness vs frescor +- Aplicar backpressure, timeouts e circuit breakers para que a sobrecarga falhe de forma limpa +- Medir e defender latência p50/p95/p99 e vazão sob carga + +## Requisitos Funcionais + +1. O sistema deve servir predições por uma API com schema de requisição/resposta documentado. +2. Requisições recebidas devem ser agrupadas dinamicamente até um tamanho/janela de tempo antes da inferência. +3. Features usadas com frequência devem ser servidas de um cache com TTL explícito e caminho de miss. +4. O sistema deve impor timeouts por requisição e descartar ou enfileirar carga quando saturado. +5. Um fallback (predição em cache, padrão ou modelo mais leve) deve entrar em ação quando o caminho primário falha. +6. O sistema deve expor métricas de latência e vazão por endpoint. +7. A acurácia do modelo otimizado deve ser validada contra a baseline não otimizada dentro de uma tolerância declarada. + +## Requisitos Não Funcionais + +- **Latência:** p95 ≤ um orçamento declarado (ex.: 50 ms) e p99 limitado, sob a taxa de requisições alvo. +- **Vazão:** sustentar um RPS definido (ex.: 1.000) no hardware alvo. +- **Disponibilidade:** degradar em vez de quebrar sob sobrecarga; sem filas ilimitadas. +- **Consistência:** o staleness do cache de features deve ser limitado e documentado. + +## Marcos Sugeridos + +1. **Marco 1 — Serving baseline:** Exponha o modelo atrás de uma API e meça latência/vazão baseline. +2. **Marco 2 — Otimizar o modelo:** Exporte para ONNX e/ou quantize; verifique o delta de acurácia e o ganho de velocidade. +3. **Marco 3 — Batching e cache:** Adicione batching dinâmico e um cache de features; meça de novo. +4. **Marco 4 — Resiliência:** Adicione timeouts, circuit breakers e um fallback; faça teste de carga até a saturação. + +## Esboço de Dados e Interface + +```text + cliente --> POST /predict {features|entity_id} + | + v + +-----------------+ miss cache +--------------+ + | Busca features |--------------->| Feature store | + | (cache Redis) |<---------------| / BD | + +--------+--------+ +--------------+ + | + v + +-----------------+ janela: N reqs ou T ms + | Fila de batching|------------------------+ + +--------+--------+ | + v v + +-----------------+ +----------------+ + | Modelo otimizado| -- falha ----> | Caminho fallback| + | (ONNX/quantizado)| | cache/padrão | + +--------+--------+ +----------------+ + v + resposta { prediction, model_version, latency_ms } + +Métricas: latência p50/p95/p99, RPS, tamanho de batch, taxa de acerto do cache +``` + +## Desafios Extras + +- Adicione um caminho GPU com TensorRT e compare custo/latência com CPU. +- Suporte serving A/B ou shadow de duas versões de modelo com métricas por versão. +- Adicione batching adaptativo que ajusta a janela conforme a carga ao vivo. +- Pré-calcule e aqueça o cache para as entidades mais quentes na inicialização. + +## Definição de Pronto + +- [ ] Latência p95 e p99 são medidas sob carga alvo e atendem ao orçamento declarado. +- [ ] O delta de acurácia do modelo otimizado versus baseline está documentado e é aceitável. +- [ ] Batching dinâmico e o cache de features estão no lugar com métricas visíveis de taxa de acerto. +- [ ] A sobrecarga dispara backpressure e o fallback, nunca uma fila ilimitada ou crash. +- [ ] Um relatório de teste de carga mostra o comportamento da carga normal até a saturação. + +## Armadilhas Comuns + +- Otimizar a latência de uma requisição única e nunca testar sob carga concorrente. +- Fazer batching tão agressivo que a latência de cauda explode para a última requisição de cada janela. +- Cachear features sem TTL, fazendo o modelo servir silenciosamente entradas obsoletas. +- Reportar latência média e esconder um p99 terrível atrás dela. + +## Recursos + +- [Documentação do ONNX Runtime](https://onnxruntime.ai/docs/) — otimização de inferência entre frameworks. +- [NVIDIA Triton Inference Server](https://docs.nvidia.com/deeplearning/triton-inference-server/user-guide/docs/index.html) — batching dinâmico e serving multi-modelo. +- [Arquitetura do TensorFlow Serving](https://www.tensorflow.org/tfx/serving/architecture) — padrões de serving em produção. +- [Google SRE Book: Handling Overload](https://sre.google/sre-book/handling-overload/) — backpressure e degradação graciosa. diff --git a/projects/data-science/advanced/03-automl-pipeline/README.md b/projects/data-science/advanced/03-automl-pipeline/README.md index 7e61838..82bcb90 100644 --- a/projects/data-science/advanced/03-automl-pipeline/README.md +++ b/projects/data-science/advanced/03-automl-pipeline/README.md @@ -1,34 +1,109 @@ # AutoML Pipeline -## Idea -Create an automated machine learning system that selects algorithms and hyperparameters automatically. Learn about hyperparameter optimization and algorithm selection. +> 🌐 **English** · [Português](./README.pt-BR.md) + +**Domain:** Data Science · **Level:** Advanced · **Estimated time:** 1–2 weeks + +## Overview + +Build a system that, given a tabular dataset and a target column, searches over preprocessing choices, candidate algorithms, and hyperparameters to return a good model with almost no manual tuning. AutoML is deceptively deep: the search space is enormous, compute is finite, and it is dangerously easy to overfit the validation set through repeated selection. The interesting work is the search strategy (Bayesian optimization beats grid/random for a reason), honest evaluation under a compute budget, and reporting that a human can actually trust. You are building the engine, not calling an off-the-shelf one. + +## Prerequisites + +- Strong grasp of cross-validation, data leakage, and the bias–variance tradeoff +- Experience with scikit-learn pipelines and several model families +- Familiarity with an optimization library (Optuna or Hyperopt) conceptually +- Comfort reasoning about compute budgets and parallel jobs ## Learning Objectives -- Implement algorithm selection -- Automate hyperparameter tuning -- Build search spaces -- Implement optimization strategies -- Handle diverse data types - -## Implementation Tips -- Create algorithm candidates -- Define hyperparameter search spaces -- Implement search strategies (grid, random, Bayesian) -- Add early stopping -- Create validation framework -- Implement ensemble methods -- Add algorithm preprocessing -- Create feature preprocessing -- Build meta-learners -- Implement warm starting -- Add stopping criteria -- Create result analysis -- Build user interface -- Implement multi-objective optimization - -## Key Challenges -- Search space explosion -- Computation time -- Overfitting to test data -- Algorithm diversity -- Result interpretability + +By the end, you should be able to: + +- Define a structured search space over preprocessing, algorithms, and hyperparameters +- Implement and compare search strategies (random, Bayesian, successive halving) +- Use early stopping and pruning to spend compute where it pays off +- Guard against overfitting the validation set with nested CV or a held-out gate +- Produce a leaderboard and analysis a stakeholder can interpret + +## Functional Requirements + +1. The system must accept a dataset and target and infer column types (numeric, categorical, datetime). +2. It must construct preprocessing pipelines per column type as part of the search. +3. It must search over at least three algorithm families with their hyperparameters. +4. The search must support a Bayesian strategy and honor a wall-clock or trial budget. +5. Underperforming trials must be pruned/early-stopped rather than run to completion. +6. Final model selection must use an evaluation split not touched during the search. +7. The system must output a ranked leaderboard with metrics and the winning pipeline's config. + +## Non-Functional Requirements + +- **Reproducibility:** a fixed seed and budget must reproduce the same leaderboard. +- **Throughput:** trials must run in parallel and scale with available workers. +- **Robustness:** a single failing trial must not abort the whole search. +- **Budget adherence:** the search must stop within the configured time/trial limit. + +## Suggested Milestones + +1. **Milestone 1 — Type inference & preprocessing:** Infer column types and build per-type preprocessing pipelines. +2. **Milestone 2 — Search engine:** Wire an optimizer over one algorithm family with proper CV. +3. **Milestone 3 — Multi-algorithm & pruning:** Add more families, Bayesian search, and early stopping. +4. **Milestone 4 — Honest gate & leaderboard:** Add a held-out selection gate and a reportable leaderboard. + +## Data & Interface Sketch + +```text + dataset + target + | + v + +----------------+ infers {col -> numeric|categorical|datetime} + | Type inference | + +-------+--------+ + v + +----------------------------+ + | Search controller (Optuna) | budget: N trials or T minutes + | sample -> build pipeline | + | -> CV score -> prune? | + +-------------+--------------+ + parallel workers | trials + v + +----------------------------+ + | Trial: preprocess + model | families: {trees, linear, boosting} + +-------------+--------------+ + v + +----------------------------+ + | Held-out selection gate | <- untouched split + +-------------+--------------+ + v + Leaderboard[ {rank, algo, params, cv_score, holdout_score} ] + +Anti-leakage: fit preprocessing INSIDE each CV fold, never on full data +``` + +## Stretch Goals + +- Add meta-learning warm starts from prior runs on similar datasets. +- Support multi-objective search (accuracy vs inference latency) with a Pareto front. +- Add automatic feature generation (interactions, target encoding) as search dimensions. +- Persist and resume an interrupted search from its trial history. + +## Definition of Done + +- [ ] Preprocessing is fit inside each CV fold, with no leakage from the full dataset. +- [ ] At least three algorithm families are searched with a Bayesian strategy. +- [ ] Pruning/early stopping demonstrably saves compute versus exhaustive search. +- [ ] Final selection uses a split untouched during search, and its score is reported separately. +- [ ] A fixed seed and budget reproduce the same leaderboard. + +## Common Pitfalls + +- Fitting scalers or encoders on the full dataset before CV, leaking test information. +- Selecting the "best" model on the same validation folds used for tuning, then overstating its accuracy. +- Letting one crashing trial kill the whole run instead of logging and skipping it. +- Ignoring the compute budget and reporting results that took ten times longer than allowed. + +## Resources + +- [Optuna Documentation](https://optuna.readthedocs.io/en/stable/) — Bayesian search, pruners, and study persistence. +- [scikit-learn: Common pitfalls and recommended practices](https://scikit-learn.org/stable/common_pitfalls.html) — leakage and evaluation done right. +- [Auto-sklearn (Feurer et al., 2015)](https://papers.nips.cc/paper/2015/hash/11d0e6287202fced83f79975ec59a3a6-Abstract.html) — meta-learning and ensemble construction in AutoML. +- [Hyperband (Li et al., 2018)](https://jmlr.org/papers/v18/16-558.html) — successive halving for budget-aware search. diff --git a/projects/data-science/advanced/03-automl-pipeline/README.pt-BR.md b/projects/data-science/advanced/03-automl-pipeline/README.pt-BR.md new file mode 100644 index 0000000..d970acc --- /dev/null +++ b/projects/data-science/advanced/03-automl-pipeline/README.pt-BR.md @@ -0,0 +1,109 @@ +# Pipeline de AutoML + +> 🌐 [English](./README.md) · **Português** + +**Domínio:** Data Science · **Nível:** Avançado · **Tempo estimado:** 1–2 semanas + +## Visão Geral + +Construa um sistema que, dado um dataset tabular e uma coluna alvo, busca sobre escolhas de pré-processamento, algoritmos candidatos e hiperparâmetros para retornar um bom modelo quase sem ajuste manual. AutoML é enganosamente profundo: o espaço de busca é enorme, a computação é finita e é perigosamente fácil fazer overfitting no conjunto de validação por seleção repetida. O trabalho interessante é a estratégia de busca (otimização Bayesiana vence grid/random por um motivo), a avaliação honesta sob um orçamento de computação e um relatório em que um humano possa realmente confiar. Você está construindo o motor, não chamando um pronto de prateleira. + +## Pré-requisitos + +- Domínio sólido de validação cruzada, vazamento de dados e o tradeoff viés–variância +- Experiência com pipelines do scikit-learn e várias famílias de modelos +- Familiaridade conceitual com uma biblioteca de otimização (Optuna ou Hyperopt) +- Conforto para raciocinar sobre orçamentos de computação e jobs paralelos + +## Objetivos de Aprendizado + +Ao final, você deve ser capaz de: + +- Definir um espaço de busca estruturado sobre pré-processamento, algoritmos e hiperparâmetros +- Implementar e comparar estratégias de busca (random, Bayesiana, successive halving) +- Usar early stopping e pruning para gastar computação onde ela compensa +- Proteger-se contra overfitting no conjunto de validação com CV aninhada ou um portão held-out +- Produzir um leaderboard e uma análise que um stakeholder consiga interpretar + +## Requisitos Funcionais + +1. O sistema deve aceitar um dataset e alvo e inferir tipos de colunas (numérica, categórica, datetime). +2. Deve construir pipelines de pré-processamento por tipo de coluna como parte da busca. +3. Deve buscar sobre ao menos três famílias de algoritmos com seus hiperparâmetros. +4. A busca deve suportar uma estratégia Bayesiana e respeitar um orçamento de tempo de relógio ou de trials. +5. Trials com baixo desempenho devem ser podados/interrompidos cedo em vez de rodar até o fim. +6. A seleção final do modelo deve usar um split de avaliação não tocado durante a busca. +7. O sistema deve produzir um leaderboard ranqueado com métricas e a configuração do pipeline vencedor. + +## Requisitos Não Funcionais + +- **Reprodutibilidade:** uma semente e um orçamento fixos devem reproduzir o mesmo leaderboard. +- **Vazão:** os trials devem rodar em paralelo e escalar com os workers disponíveis. +- **Robustez:** um único trial que falha não deve abortar toda a busca. +- **Aderência ao orçamento:** a busca deve parar dentro do limite de tempo/trials configurado. + +## Marcos Sugeridos + +1. **Marco 1 — Inferência de tipos e pré-processamento:** Infira tipos de colunas e construa pipelines de pré-processamento por tipo. +2. **Marco 2 — Motor de busca:** Conecte um otimizador sobre uma família de algoritmos com CV adequada. +3. **Marco 3 — Multi-algoritmo e pruning:** Adicione mais famílias, busca Bayesiana e early stopping. +4. **Marco 4 — Portão honesto e leaderboard:** Adicione um portão de seleção held-out e um leaderboard reportável. + +## Esboço de Dados e Interface + +```text + dataset + alvo + | + v + +----------------+ infere {col -> numeric|categorical|datetime} + | Inferência tipo| + +-------+--------+ + v + +----------------------------+ + | Controlador busca (Optuna) | orçamento: N trials ou T minutos + | amostra -> monta pipeline| + | -> score CV -> podar? | + +-------------+--------------+ + workers paralelos | trials + v + +----------------------------+ + | Trial: preproc + modelo | famílias: {árvores, linear, boosting} + +-------------+--------------+ + v + +----------------------------+ + | Portão de seleção held-out | <- split não tocado + +-------------+--------------+ + v + Leaderboard[ {rank, algo, params, cv_score, holdout_score} ] + +Anti-vazamento: ajuste o pré-processamento DENTRO de cada fold da CV, nunca nos dados completos +``` + +## Desafios Extras + +- Adicione warm starts por meta-aprendizado de execuções anteriores em datasets similares. +- Suporte busca multi-objetivo (acurácia vs latência de inferência) com uma fronteira de Pareto. +- Adicione geração automática de features (interações, target encoding) como dimensões de busca. +- Persista e retome uma busca interrompida a partir do histórico de trials. + +## Definição de Pronto + +- [ ] O pré-processamento é ajustado dentro de cada fold da CV, sem vazamento do dataset completo. +- [ ] Ao menos três famílias de algoritmos são buscadas com uma estratégia Bayesiana. +- [ ] Pruning/early stopping comprovadamente economiza computação versus busca exaustiva. +- [ ] A seleção final usa um split não tocado durante a busca, e seu score é reportado separadamente. +- [ ] Uma semente e um orçamento fixos reproduzem o mesmo leaderboard. + +## Armadilhas Comuns + +- Ajustar scalers ou encoders no dataset completo antes da CV, vazando informação de teste. +- Selecionar o "melhor" modelo nos mesmos folds de validação usados para tuning e depois superestimar sua acurácia. +- Deixar um trial que quebra matar toda a execução em vez de registrar e pular. +- Ignorar o orçamento de computação e reportar resultados que levaram dez vezes mais tempo que o permitido. + +## Recursos + +- [Documentação do Optuna](https://optuna.readthedocs.io/en/stable/) — busca Bayesiana, pruners e persistência de estudos. +- [scikit-learn: armadilhas comuns e práticas recomendadas](https://scikit-learn.org/stable/common_pitfalls.html) — vazamento e avaliação feitos direito. +- [Auto-sklearn (Feurer et al., 2015)](https://papers.nips.cc/paper/2015/hash/11d0e6287202fced83f79975ec59a3a6-Abstract.html) — meta-aprendizado e construção de ensembles em AutoML. +- [Hyperband (Li et al., 2018)](https://jmlr.org/papers/v18/16-558.html) — successive halving para busca consciente de orçamento. diff --git a/projects/data-science/advanced/04-deep-learning-image/README.md b/projects/data-science/advanced/04-deep-learning-image/README.md index 29ad05c..a3b1662 100644 --- a/projects/data-science/advanced/04-deep-learning-image/README.md +++ b/projects/data-science/advanced/04-deep-learning-image/README.md @@ -1,34 +1,105 @@ -# Deep Learning Model (image classification) +# Deep Learning Image Classifier -## Idea -Build a deep learning model for image classification. Learn about convolutional neural networks and transfer learning. +> 🌐 **English** · [Português](./README.pt-BR.md) + +**Domain:** Data Science · **Level:** Advanced · **Estimated time:** 1–2 weeks + +## Overview + +Train a convolutional image classifier to production quality on a real dataset, then optimize it for deployment. The modeling is only half the project: the advanced part is doing transfer learning correctly (freeze, then fine-tune with discriminative learning rates), building an augmentation pipeline that helps rather than hurts, and then shrinking the trained network so it can serve within a memory and latency budget. You will end with a model, a reproducible training pipeline, and an optimized artifact whose accuracy loss you can quantify. + +## Prerequisites + +- Working knowledge of neural networks and backpropagation +- Experience with PyTorch or TensorFlow/Keras and GPU training +- Familiarity with a labeled image dataset (CIFAR-100, Food-101, or your own) +- Understanding of overfitting, regularization, and learning-rate schedules ## Learning Objectives -- Build CNN architectures -- Use transfer learning -- Implement data augmentation -- Train deep models -- Optimize for deployment - -## Implementation Tips -- Create CNN architecture -- Use pre-trained models (ResNet, VGG, MobileNet) -- Implement fine-tuning -- Add data augmentation -- Create training pipeline -- Implement validation strategy -- Add regularization techniques -- Create learning rate scheduling -- Implement early stopping -- Build inference pipeline -- Implement model optimization -- Create deployment strategy -- Add performance monitoring -- Build prediction interface - -## Key Challenges -- Computation requirements -- Data augmentation strategies -- Transfer learning setup -- Hyperparameter tuning -- Model deployment constraints + +By the end, you should be able to: + +- Apply transfer learning: freeze a backbone, then fine-tune with layer-wise learning rates +- Build an augmentation pipeline and measure its effect on validation accuracy +- Use learning-rate scheduling, early stopping, and checkpointing in a real training loop +- Optimize a trained model via quantization, pruning, or export (ONNX/TFLite) +- Quantify the accuracy-vs-size-vs-latency tradeoff of the optimized model + +## Functional Requirements + +1. The pipeline must load a labeled image dataset with reproducible train/val/test splits. +2. Training must start from a pre-trained backbone (ResNet, EfficientNet, or MobileNet) and fine-tune it. +3. An augmentation pipeline must be configurable and applied only to the training split. +4. Training must checkpoint the best model by validation metric and support resuming. +5. The system must report per-class metrics and a confusion matrix on the test split. +6. The trained model must be exported and optimized for inference (quantized and/or ONNX/TFLite). +7. The optimized model's accuracy must be measured against the full-precision baseline. + +## Non-Functional Requirements + +- **Reproducibility:** seeds, splits, and augmentation config must reproduce reported metrics. +- **Deployment budget:** optimized model must meet a stated size (e.g. ≤ 25 MB) and CPU latency target. +- **Accuracy tolerance:** optimization-induced accuracy drop must stay within a documented bound. +- **Throughput:** batched inference throughput on target hardware must be reported. + +## Suggested Milestones + +1. **Milestone 1 — Data & baseline:** Reproducible splits, a data loader, and a from-scratch or frozen-backbone baseline. +2. **Milestone 2 — Transfer learning:** Fine-tune with discriminative learning rates and augmentation; beat the baseline. +3. **Milestone 3 — Evaluation:** Per-class metrics, confusion matrix, and error analysis on the test split. +4. **Milestone 4 — Optimize & export:** Quantize/prune, export, and quantify the accuracy/size/latency tradeoff. + +## Data & Interface Sketch + +```text + dataset/ + train/ val/ test/ (stratified, seeded split) + | + v + +---------------------+ train-only: flips, crop, color jitter, mixup + | Augmentation | + +----------+----------+ + v + +---------------------+ backbone frozen -> then fine-tune + | Pretrained CNN | ResNet/EfficientNet/MobileNet + | + new head | LR schedule, early stop, checkpoint(best) + +----------+----------+ + v + +---------------------+ + | Evaluation | per-class P/R/F1, confusion matrix + +----------+----------+ + v + +---------------------+ quantize / prune / export + | Optimized artifact | ONNX / TFLite + +---------------------+ + report: {acc_fp32, acc_int8, size_mb, cpu_latency_ms} +``` + +## Stretch Goals + +- Add Grad-CAM visualizations to inspect what the model attends to. +- Handle class imbalance with weighted loss or focal loss and measure the effect. +- Add test-time augmentation and compare accuracy vs latency cost. +- Distill the fine-tuned model into a smaller student network. + +## Definition of Done + +- [ ] Splits, seeds, and augmentation config reproduce the reported metrics. +- [ ] The fine-tuned transfer-learning model beats the baseline on the test split. +- [ ] Per-class metrics and a confusion matrix are produced and briefly analyzed. +- [ ] An optimized artifact is exported and meets the stated size/latency budget. +- [ ] The accuracy delta between full-precision and optimized models is documented. + +## Common Pitfalls + +- Applying augmentation to the validation/test splits and inflating apparent robustness. +- Fine-tuning the whole network at a high learning rate and destroying the pre-trained weights. +- Reporting only top-1 accuracy while a minority class quietly performs terribly. +- Forgetting to re-measure accuracy after quantization and shipping a degraded model. + +## Resources + +- [PyTorch Transfer Learning Tutorial](https://pytorch.org/tutorials/beginner/transfer_learning_tutorial.html) — freezing and fine-tuning done right. +- [TensorFlow: Data augmentation](https://www.tensorflow.org/tutorials/images/data_augmentation) — building an augmentation pipeline. +- [PyTorch Quantization Documentation](https://pytorch.org/docs/stable/quantization.html) — post-training and quantization-aware approaches. +- [Deep Residual Learning for Image Recognition (He et al., 2015)](https://arxiv.org/abs/1512.03385) — the ResNet paper behind most modern backbones. diff --git a/projects/data-science/advanced/04-deep-learning-image/README.pt-BR.md b/projects/data-science/advanced/04-deep-learning-image/README.pt-BR.md new file mode 100644 index 0000000..0061427 --- /dev/null +++ b/projects/data-science/advanced/04-deep-learning-image/README.pt-BR.md @@ -0,0 +1,105 @@ +# Classificador de Imagens com Deep Learning + +> 🌐 [English](./README.md) · **Português** + +**Domínio:** Data Science · **Nível:** Avançado · **Tempo estimado:** 1–2 semanas + +## Visão Geral + +Treine um classificador de imagens convolucional com qualidade de produção em um dataset real e depois otimize-o para deployment. A modelagem é só metade do projeto: a parte avançada é fazer transfer learning corretamente (congelar e depois fazer fine-tuning com learning rates discriminativas), construir um pipeline de augmentation que ajuda em vez de atrapalhar e então encolher a rede treinada para que sirva dentro de um orçamento de memória e latência. Você vai terminar com um modelo, um pipeline de treino reproduzível e um artefato otimizado cuja perda de acurácia você consegue quantificar. + +## Pré-requisitos + +- Conhecimento prático de redes neurais e backpropagation +- Experiência com PyTorch ou TensorFlow/Keras e treino em GPU +- Familiaridade com um dataset de imagens rotulado (CIFAR-100, Food-101 ou o seu próprio) +- Entendimento de overfitting, regularização e schedules de learning rate + +## Objetivos de Aprendizado + +Ao final, você deve ser capaz de: + +- Aplicar transfer learning: congelar um backbone e depois fazer fine-tuning com learning rates por camada +- Construir um pipeline de augmentation e medir seu efeito na acurácia de validação +- Usar scheduling de learning rate, early stopping e checkpointing em um loop de treino real +- Otimizar um modelo treinado via quantização, pruning ou export (ONNX/TFLite) +- Quantificar o tradeoff acurácia-vs-tamanho-vs-latência do modelo otimizado + +## Requisitos Funcionais + +1. O pipeline deve carregar um dataset de imagens rotulado com splits treino/val/teste reproduzíveis. +2. O treino deve partir de um backbone pré-treinado (ResNet, EfficientNet ou MobileNet) e fazer fine-tuning. +3. Um pipeline de augmentation deve ser configurável e aplicado apenas ao split de treino. +4. O treino deve fazer checkpoint do melhor modelo pela métrica de validação e suportar retomada. +5. O sistema deve reportar métricas por classe e uma matriz de confusão no split de teste. +6. O modelo treinado deve ser exportado e otimizado para inferência (quantizado e/ou ONNX/TFLite). +7. A acurácia do modelo otimizado deve ser medida contra a baseline em precisão total. + +## Requisitos Não Funcionais + +- **Reprodutibilidade:** sementes, splits e config de augmentation devem reproduzir as métricas reportadas. +- **Orçamento de deployment:** o modelo otimizado deve atender a um tamanho declarado (ex.: ≤ 25 MB) e a uma meta de latência em CPU. +- **Tolerância de acurácia:** a queda de acurácia induzida pela otimização deve ficar dentro de um limite documentado. +- **Vazão:** a vazão de inferência em batch no hardware alvo deve ser reportada. + +## Marcos Sugeridos + +1. **Marco 1 — Dados e baseline:** Splits reproduzíveis, um data loader e uma baseline do zero ou com backbone congelado. +2. **Marco 2 — Transfer learning:** Faça fine-tuning com learning rates discriminativas e augmentation; supere a baseline. +3. **Marco 3 — Avaliação:** Métricas por classe, matriz de confusão e análise de erros no split de teste. +4. **Marco 4 — Otimizar e exportar:** Quantize/pode, exporte e quantifique o tradeoff acurácia/tamanho/latência. + +## Esboço de Dados e Interface + +```text + dataset/ + train/ val/ test/ (split estratificado, com semente) + | + v + +---------------------+ só treino: flips, crop, color jitter, mixup + | Augmentation | + +----------+----------+ + v + +---------------------+ backbone congelado -> depois fine-tune + | CNN pré-treinada | ResNet/EfficientNet/MobileNet + | + nova head | schedule LR, early stop, checkpoint(melhor) + +----------+----------+ + v + +---------------------+ + | Avaliação | P/R/F1 por classe, matriz de confusão + +----------+----------+ + v + +---------------------+ quantizar / podar / exportar + | Artefato otimizado | ONNX / TFLite + +---------------------+ + relatório: {acc_fp32, acc_int8, size_mb, cpu_latency_ms} +``` + +## Desafios Extras + +- Adicione visualizações Grad-CAM para inspecionar onde o modelo presta atenção. +- Trate desbalanceamento de classes com loss ponderada ou focal loss e meça o efeito. +- Adicione test-time augmentation e compare acurácia vs custo de latência. +- Destile o modelo com fine-tuning em uma rede aluno menor. + +## Definição de Pronto + +- [ ] Splits, sementes e config de augmentation reproduzem as métricas reportadas. +- [ ] O modelo de transfer learning com fine-tuning supera a baseline no split de teste. +- [ ] Métricas por classe e uma matriz de confusão são produzidas e brevemente analisadas. +- [ ] Um artefato otimizado é exportado e atende ao orçamento de tamanho/latência declarado. +- [ ] O delta de acurácia entre os modelos em precisão total e otimizado está documentado. + +## Armadilhas Comuns + +- Aplicar augmentation aos splits de validação/teste e inflar a robustez aparente. +- Fazer fine-tuning de toda a rede com learning rate alta e destruir os pesos pré-treinados. +- Reportar apenas acurácia top-1 enquanto uma classe minoritária vai silenciosamente muito mal. +- Esquecer de remedir a acurácia após a quantização e enviar um modelo degradado. + +## Recursos + +- [Tutorial de Transfer Learning do PyTorch](https://pytorch.org/tutorials/beginner/transfer_learning_tutorial.html) — congelamento e fine-tuning feitos direito. +- [TensorFlow: Data augmentation](https://www.tensorflow.org/tutorials/images/data_augmentation) — construindo um pipeline de augmentation. +- [Documentação de Quantização do PyTorch](https://pytorch.org/docs/stable/quantization.html) — abordagens post-training e quantization-aware. +- [Deep Residual Learning for Image Recognition (He et al., 2015)](https://arxiv.org/abs/1512.03385) — o paper da ResNet por trás da maioria dos backbones modernos. diff --git a/projects/data-science/advanced/05-nlp-transformer/README.md b/projects/data-science/advanced/05-nlp-transformer/README.md index 38a44ef..5f38069 100644 --- a/projects/data-science/advanced/05-nlp-transformer/README.md +++ b/projects/data-science/advanced/05-nlp-transformer/README.md @@ -1,34 +1,105 @@ -# NLP Transformer-based System +# NLP Transformer System -## Idea -Build a natural language processing system using transformer models. Learn about advanced NLP and large language models. +> 🌐 **English** · [Português](./README.pt-BR.md) + +**Domain:** Data Science · **Level:** Advanced · **Estimated time:** 1–2 weeks + +## Overview + +Build a production-grade NLP service around a pre-trained transformer, fine-tuned for one concrete task (classification, extraction, or summarization) and served under a real latency and memory budget. The interesting engineering lives at the edges of the model: efficient tokenization and truncation for long inputs, parameter-efficient fine-tuning so you can train on modest hardware, quantized inference so it fits in memory, and honest evaluation that includes a look at bias and failure modes. You will fine-tune, serve, measure, and interrogate the model — not just call an API. + +## Prerequisites + +- Understanding of the transformer architecture (attention, tokenization, embeddings) +- Experience with the Hugging Face `transformers` library +- Familiarity with a labeled text dataset for your chosen task +- Comfort with GPU memory constraints and mixed-precision training ## Learning Objectives -- Use pre-trained transformers -- Fine-tune for specific tasks -- Implement inference -- Handle multiple NLP tasks -- Optimize for production - -## Implementation Tips -- Load pre-trained models (BERT, GPT, T5) -- Implement fine-tuning pipelines -- Create task-specific adapters -- Add prompt engineering -- Implement batch inference -- Create efficient tokenization -- Build inference optimization -- Add multi-task learning -- Implement quantization -- Create model deployment -- Build API interface -- Add performance monitoring -- Create explainability tools -- Implement bias detection - -## Key Challenges -- Model size and memory -- Fine-tuning efficiency -- Inference latency -- Task adaptation -- Bias and fairness + +By the end, you should be able to: + +- Fine-tune a pre-trained transformer for a specific task, including full and parameter-efficient (LoRA) approaches +- Handle tokenization, truncation, and long inputs correctly +- Optimize inference via quantization, batching, and appropriate decoding settings +- Serve the model behind an API within a latency and memory budget +- Evaluate task quality alongside bias, calibration, and failure modes + +## Functional Requirements + +1. The system must fine-tune a pre-trained transformer on a labeled dataset for one task. +2. Tokenization must handle truncation/padding and inputs exceeding the model's context window. +3. Fine-tuning must support a parameter-efficient method (e.g. LoRA) as an alternative to full fine-tuning. +4. Inference must be quantized and batched, with configurable decoding parameters where relevant. +5. The model must be served over an API with a documented request/response schema. +6. Evaluation must report task metrics plus at least one bias/fairness probe. +7. The optimized (quantized) model's quality must be compared against the full-precision version. + +## Non-Functional Requirements + +- **Latency:** serving p95 within a stated budget at the target batch size. +- **Memory:** the served model must fit within a declared GPU/CPU memory ceiling. +- **Reproducibility:** fine-tuning with a fixed seed and config reproduces reported metrics. +- **Robustness:** malformed or over-length inputs must be handled without crashing. + +## Suggested Milestones + +1. **Milestone 1 — Data & tokenization:** Prepare the dataset and a tokenization pipeline handling long inputs. +2. **Milestone 2 — Fine-tune:** Fine-tune the model (full and LoRA); track and compare runs. +3. **Milestone 3 — Optimize & serve:** Quantize, batch, and expose an API within budget. +4. **Milestone 4 — Evaluate & probe:** Report task metrics and run a bias/failure-mode analysis. + +## Data & Interface Sketch + +```text + labeled text + | + v + +--------------------+ truncate/pad, chunk long docs + | Tokenizer | + +---------+----------+ + v + +--------------------+ full FT OR LoRA adapters + | Pretrained model | mixed precision, seed, checkpoint(best) + | (BERT/T5/LLM) | + +---------+----------+ + v + +--------------------+ int8/4-bit quantization, dynamic batching + | Optimized inference| + +---------+----------+ + v + POST /infer { text | texts[] } -> { label|spans|summary, score, model_version } + + Evaluation: task metric (F1/ROUGE/acc) + + bias probe (per-group performance gap) + + quality delta: fp16 vs quantized +``` + +## Stretch Goals + +- Add retrieval augmentation so the model grounds answers in a document store. +- Support multi-task inference behind one endpoint via task-specific adapters. +- Add streaming generation for summarization/generation tasks. +- Add a calibration analysis (reliability diagram) for classification confidence. + +## Definition of Done + +- [ ] The model is fine-tuned and beats a zero-shot or baseline on the task metric. +- [ ] Tokenization handles over-length inputs without silent truncation errors. +- [ ] A LoRA run is compared against full fine-tuning on quality and cost. +- [ ] The quantized, batched model is served within the stated latency/memory budget. +- [ ] Evaluation includes task metrics and at least one bias/fairness probe. + +## Common Pitfalls + +- Silently truncating long inputs and losing the part of the text that carried the signal. +- Full fine-tuning on hardware too small for it instead of reaching for LoRA/quantization. +- Comparing to no baseline, so you cannot tell if fine-tuning actually helped. +- Reporting aggregate accuracy while a demographic subgroup performs far worse. + +## Resources + +- [Hugging Face Transformers Documentation](https://huggingface.co/docs/transformers/index) — fine-tuning, tokenization, and inference. +- [Hugging Face PEFT (LoRA) Documentation](https://huggingface.co/docs/peft/index) — parameter-efficient fine-tuning. +- [Attention Is All You Need (Vaswani et al., 2017)](https://arxiv.org/abs/1706.03762) — the transformer architecture. +- [LoRA: Low-Rank Adaptation of Large Language Models (Hu et al., 2021)](https://arxiv.org/abs/2106.09685) — the LoRA method. diff --git a/projects/data-science/advanced/05-nlp-transformer/README.pt-BR.md b/projects/data-science/advanced/05-nlp-transformer/README.pt-BR.md new file mode 100644 index 0000000..852e008 --- /dev/null +++ b/projects/data-science/advanced/05-nlp-transformer/README.pt-BR.md @@ -0,0 +1,105 @@ +# Sistema de NLP com Transformer + +> 🌐 [English](./README.md) · **Português** + +**Domínio:** Data Science · **Nível:** Avançado · **Tempo estimado:** 1–2 semanas + +## Visão Geral + +Construa um serviço de NLP de nível de produção em torno de um transformer pré-treinado, com fine-tuning para uma tarefa concreta (classificação, extração ou sumarização) e servido sob um orçamento real de latência e memória. A engenharia interessante vive nas bordas do modelo: tokenização e truncamento eficientes para entradas longas, fine-tuning eficiente em parâmetros para treinar em hardware modesto, inferência quantizada para caber na memória e avaliação honesta que inclui um olhar sobre viés e modos de falha. Você vai fazer fine-tuning, servir, medir e interrogar o modelo — não apenas chamar uma API. + +## Pré-requisitos + +- Entendimento da arquitetura transformer (atenção, tokenização, embeddings) +- Experiência com a biblioteca `transformers` da Hugging Face +- Familiaridade com um dataset de texto rotulado para a tarefa escolhida +- Conforto com restrições de memória de GPU e treino em precisão mista + +## Objetivos de Aprendizado + +Ao final, você deve ser capaz de: + +- Fazer fine-tuning de um transformer pré-treinado para uma tarefa específica, incluindo abordagens completa e eficiente em parâmetros (LoRA) +- Lidar com tokenização, truncamento e entradas longas corretamente +- Otimizar a inferência via quantização, batching e configurações de decodificação apropriadas +- Servir o modelo atrás de uma API dentro de um orçamento de latência e memória +- Avaliar a qualidade da tarefa junto com viés, calibração e modos de falha + +## Requisitos Funcionais + +1. O sistema deve fazer fine-tuning de um transformer pré-treinado em um dataset rotulado para uma tarefa. +2. A tokenização deve lidar com truncamento/padding e entradas que excedem a janela de contexto do modelo. +3. O fine-tuning deve suportar um método eficiente em parâmetros (ex.: LoRA) como alternativa ao fine-tuning completo. +4. A inferência deve ser quantizada e em batch, com parâmetros de decodificação configuráveis quando relevante. +5. O modelo deve ser servido por uma API com schema de requisição/resposta documentado. +6. A avaliação deve reportar métricas da tarefa mais ao menos uma sonda de viés/justiça. +7. A qualidade do modelo otimizado (quantizado) deve ser comparada com a versão em precisão total. + +## Requisitos Não Funcionais + +- **Latência:** p95 do serving dentro de um orçamento declarado no tamanho de batch alvo. +- **Memória:** o modelo servido deve caber dentro de um teto de memória GPU/CPU declarado. +- **Reprodutibilidade:** o fine-tuning com semente e config fixas reproduz as métricas reportadas. +- **Robustez:** entradas malformadas ou longas demais devem ser tratadas sem crash. + +## Marcos Sugeridos + +1. **Marco 1 — Dados e tokenização:** Prepare o dataset e um pipeline de tokenização que lida com entradas longas. +2. **Marco 2 — Fine-tuning:** Faça fine-tuning do modelo (completo e LoRA); rastreie e compare execuções. +3. **Marco 3 — Otimizar e servir:** Quantize, agrupe em batch e exponha uma API dentro do orçamento. +4. **Marco 4 — Avaliar e sondar:** Reporte métricas da tarefa e rode uma análise de viés/modos de falha. + +## Esboço de Dados e Interface + +```text + texto rotulado + | + v + +--------------------+ trunca/padding, fatia docs longos + | Tokenizer | + +---------+----------+ + v + +--------------------+ FT completo OU adapters LoRA + | Modelo pré-treinado| precisão mista, semente, checkpoint(melhor) + | (BERT/T5/LLM) | + +---------+----------+ + v + +--------------------+ quantização int8/4-bit, batching dinâmico + | Inferência otimiz. | + +---------+----------+ + v + POST /infer { text | texts[] } -> { label|spans|summary, score, model_version } + + Avaliação: métrica da tarefa (F1/ROUGE/acc) + + sonda de viés (gap de desempenho por grupo) + + delta de qualidade: fp16 vs quantizado +``` + +## Desafios Extras + +- Adicione augmentation por retrieval para que o modelo fundamente respostas em um repositório de documentos. +- Suporte inferência multi-tarefa atrás de um endpoint via adapters específicos por tarefa. +- Adicione geração em streaming para tarefas de sumarização/geração. +- Adicione uma análise de calibração (diagrama de confiabilidade) para a confiança de classificação. + +## Definição de Pronto + +- [ ] O modelo tem fine-tuning e supera um zero-shot ou baseline na métrica da tarefa. +- [ ] A tokenização lida com entradas longas demais sem erros silenciosos de truncamento. +- [ ] Uma execução LoRA é comparada com o fine-tuning completo em qualidade e custo. +- [ ] O modelo quantizado e em batch é servido dentro do orçamento de latência/memória declarado. +- [ ] A avaliação inclui métricas da tarefa e ao menos uma sonda de viés/justiça. + +## Armadilhas Comuns + +- Truncar silenciosamente entradas longas e perder a parte do texto que carregava o sinal. +- Fazer fine-tuning completo em hardware pequeno demais em vez de recorrer a LoRA/quantização. +- Não comparar com nenhuma baseline, sem saber se o fine-tuning realmente ajudou. +- Reportar acurácia agregada enquanto um subgrupo demográfico tem desempenho muito pior. + +## Recursos + +- [Documentação do Hugging Face Transformers](https://huggingface.co/docs/transformers/index) — fine-tuning, tokenização e inferência. +- [Documentação do Hugging Face PEFT (LoRA)](https://huggingface.co/docs/peft/index) — fine-tuning eficiente em parâmetros. +- [Attention Is All You Need (Vaswani et al., 2017)](https://arxiv.org/abs/1706.03762) — a arquitetura transformer. +- [LoRA: Low-Rank Adaptation of Large Language Models (Hu et al., 2021)](https://arxiv.org/abs/2106.09685) — o método LoRA. diff --git a/projects/data-science/advanced/06-recommendation-scale/README.md b/projects/data-science/advanced/06-recommendation-scale/README.md index 782498a..6a1ddb5 100644 --- a/projects/data-science/advanced/06-recommendation-scale/README.md +++ b/projects/data-science/advanced/06-recommendation-scale/README.md @@ -1,34 +1,107 @@ # Recommendation System at Scale -## Idea -Build a recommendation system designed for large-scale deployment. Learn about scalable algorithms and real-time processing. +> 🌐 **English** · [Português](./README.pt-BR.md) + +**Domain:** Data Science · **Level:** Advanced · **Estimated time:** 1–2 weeks + +## Overview + +Design a recommendation system that stays fast and relevant when the catalog is huge and traffic is heavy. The naive "score every item for every user" approach dies at scale, so this project centers on the two-stage industry pattern: a cheap candidate-retrieval step that narrows millions of items to a few hundred, followed by a heavier ranking model over that shortlist. Around it you will handle cold start, keep results diverse, run online updates, and measure quality with an A/B-style offline evaluation. The goal is a system whose latency and quality both hold up as the catalog grows. + +## Prerequisites + +- Understanding of collaborative filtering and matrix factorization +- Experience with embeddings and approximate nearest-neighbor search +- Familiarity with a streaming or batch data tool (Kafka, Spark, or similar) +- Comfort with offline ranking metrics (recall@k, NDCG, MAP) ## Learning Objectives -- Implement scalable algorithms -- Handle massive datasets -- Build real-time recommendations -- Implement online learning -- Monitor recommendation quality - -## Implementation Tips -- Create distributed recommendation engine -- Implement matrix factorization at scale -- Add real-time data processing -- Create online learning systems -- Implement feature caching -- Build ranking pipelines -- Add diversity algorithms -- Create exploration vs exploitation -- Implement context-aware recommendations -- Build feedback loops -- Create A/B testing framework -- Add performance optimization -- Implement monitoring -- Build explainability - -## Key Challenges -- Scalability to billions of items -- Real-time updates -- Cold start problems -- Diversity at scale -- Model performance maintenance + +By the end, you should be able to: + +- Build a two-stage retrieval-then-ranking recommendation architecture +- Use embeddings plus ANN indexing for sub-linear candidate retrieval +- Handle cold start for new users and items +- Balance relevance against diversity and freshness in the ranker +- Evaluate recommendations offline with ranking metrics and reason about online A/B design + +## Functional Requirements + +1. The system must generate candidates for a user from a large catalog in sub-linear time (ANN, not full scan). +2. A ranking model must re-score candidates using richer features than the retrieval stage. +3. The system must handle cold start for new users and new items with an explicit strategy. +4. Recommendations must include a diversity/de-duplication step so results are not near-identical. +5. The system must support online updates so new interactions influence future recommendations. +6. Offline evaluation must report ranking metrics (recall@k, NDCG) on a held-out period. +7. The system must expose a recommendation API returning ranked items with scores. + +## Non-Functional Requirements + +- **Latency:** end-to-end recommendation p95 within a stated budget at target QPS. +- **Scalability:** retrieval latency must stay sub-linear as the catalog grows by an order of magnitude. +- **Freshness:** new interactions must influence recommendations within a bounded delay. +- **Consistency:** the offline evaluation split must respect time (no future leakage into the past). + +## Suggested Milestones + +1. **Milestone 1 — Embeddings & retrieval:** Train item/user embeddings and build an ANN index for candidate retrieval. +2. **Milestone 2 — Ranking:** Add a ranking model over candidates with interaction and context features. +3. **Milestone 3 — Cold start & diversity:** Add cold-start handling and a diversity re-ranking step. +4. **Milestone 4 — Online & evaluation:** Add online updates and a time-respecting offline evaluation harness. + +## Data & Interface Sketch + +```text + interactions (user, item, ts, signal) + | + v + +------------------+ train user/item embeddings + | Embedding model | + +--------+---------+ + v + +------------------+ millions -> ~hundreds + | ANN retrieval | (FAISS/ScaNN) <-- cold start fallback: popularity/content + +--------+---------+ + v + +------------------+ rich features: recency, context, cross features + | Ranking model | + +--------+---------+ + v + +------------------+ MMR / category caps + | Diversity re-rank| + +--------+---------+ + v + GET /recommend?user_id=U&k=20 -> [ {item_id, score, reason} ... ] + + Eval: split by TIME; recall@k, NDCG@k on the future window + Online: stream new interactions -> update embeddings/features +``` + +## Stretch Goals + +- Add a bandit (epsilon-greedy or Thompson sampling) for exploration vs exploitation. +- Support session-based recommendations using sequence models. +- Add a feature store shared between offline training and online serving. +- Precompute recommendations for the hottest users and serve them from a cache. + +## Definition of Done + +- [ ] Candidate retrieval uses ANN and stays sub-linear as the catalog grows. +- [ ] A ranking stage re-scores candidates with features beyond those used in retrieval. +- [ ] Cold-start users and items get sensible recommendations via an explicit fallback. +- [ ] A diversity step prevents near-duplicate result lists. +- [ ] Offline evaluation respects time ordering and reports recall@k and NDCG. + +## Common Pitfalls + +- Scoring the entire catalog per request and blowing the latency budget as it grows. +- Evaluating with a random split, leaking future interactions into the training window. +- Optimizing pure relevance until every list looks identical and users disengage. +- Ignoring cold start, so new items are never surfaced and never gather signal. + +## Resources + +- [Google: Recommendation Systems course](https://developers.google.com/machine-learning/recommendation) — retrieval, ranking, and candidate generation. +- [FAISS Documentation](https://faiss.ai/) — approximate nearest-neighbor search at scale. +- [Deep Neural Networks for YouTube Recommendations (Covington et al., 2016)](https://research.google/pubs/pub45530/) — the canonical two-stage architecture. +- [Matrix Factorization Techniques for Recommender Systems (Koren et al., 2009)](https://ieeexplore.ieee.org/document/5197422) — foundational collaborative filtering. diff --git a/projects/data-science/advanced/06-recommendation-scale/README.pt-BR.md b/projects/data-science/advanced/06-recommendation-scale/README.pt-BR.md new file mode 100644 index 0000000..ffbe30d --- /dev/null +++ b/projects/data-science/advanced/06-recommendation-scale/README.pt-BR.md @@ -0,0 +1,107 @@ +# Sistema de Recomendação em Escala + +> 🌐 [English](./README.md) · **Português** + +**Domínio:** Data Science · **Nível:** Avançado · **Tempo estimado:** 1–2 semanas + +## Visão Geral + +Projete um sistema de recomendação que permanece rápido e relevante quando o catálogo é enorme e o tráfego é pesado. A abordagem ingênua de "pontuar cada item para cada usuário" morre em escala, então este projeto se centra no padrão de dois estágios da indústria: um passo barato de recuperação de candidatos que reduz milhões de itens para algumas centenas, seguido de um modelo de ranking mais pesado sobre essa lista curta. Ao redor disso você vai tratar cold start, manter os resultados diversos, rodar atualizações online e medir qualidade com uma avaliação offline estilo A/B. O objetivo é um sistema cuja latência e qualidade ambas se sustentam conforme o catálogo cresce. + +## Pré-requisitos + +- Entendimento de filtragem colaborativa e fatoração de matrizes +- Experiência com embeddings e busca por vizinhos mais próximos aproximada +- Familiaridade com uma ferramenta de dados em streaming ou batch (Kafka, Spark ou similar) +- Conforto com métricas de ranking offline (recall@k, NDCG, MAP) + +## Objetivos de Aprendizado + +Ao final, você deve ser capaz de: + +- Construir uma arquitetura de recomendação de dois estágios: recuperação e depois ranking +- Usar embeddings mais indexação ANN para recuperação de candidatos sublinear +- Tratar cold start para novos usuários e itens +- Equilibrar relevância contra diversidade e frescor no ranker +- Avaliar recomendações offline com métricas de ranking e raciocinar sobre o design de A/B online + +## Requisitos Funcionais + +1. O sistema deve gerar candidatos para um usuário a partir de um catálogo grande em tempo sublinear (ANN, não varredura completa). +2. Um modelo de ranking deve repontuar candidatos usando features mais ricas que o estágio de recuperação. +3. O sistema deve tratar cold start para novos usuários e novos itens com uma estratégia explícita. +4. As recomendações devem incluir um passo de diversidade/de-duplicação para que os resultados não sejam quase idênticos. +5. O sistema deve suportar atualizações online para que novas interações influenciem recomendações futuras. +6. A avaliação offline deve reportar métricas de ranking (recall@k, NDCG) em um período held-out. +7. O sistema deve expor uma API de recomendação retornando itens ranqueados com scores. + +## Requisitos Não Funcionais + +- **Latência:** p95 da recomendação ponta a ponta dentro de um orçamento declarado no QPS alvo. +- **Escalabilidade:** a latência de recuperação deve permanecer sublinear conforme o catálogo cresce uma ordem de magnitude. +- **Frescor:** novas interações devem influenciar as recomendações dentro de um atraso limitado. +- **Consistência:** o split de avaliação offline deve respeitar o tempo (sem vazamento do futuro para o passado). + +## Marcos Sugeridos + +1. **Marco 1 — Embeddings e recuperação:** Treine embeddings de item/usuário e construa um índice ANN para recuperação de candidatos. +2. **Marco 2 — Ranking:** Adicione um modelo de ranking sobre os candidatos com features de interação e contexto. +3. **Marco 3 — Cold start e diversidade:** Adicione tratamento de cold start e um passo de re-ranking por diversidade. +4. **Marco 4 — Online e avaliação:** Adicione atualizações online e um harness de avaliação offline que respeita o tempo. + +## Esboço de Dados e Interface + +```text + interações (user, item, ts, sinal) + | + v + +------------------+ treina embeddings user/item + | Modelo embedding | + +--------+---------+ + v + +------------------+ milhões -> ~centenas + | Recuperação ANN | (FAISS/ScaNN) <-- fallback cold start: popularidade/conteúdo + +--------+---------+ + v + +------------------+ features ricas: recência, contexto, cross features + | Modelo de ranking| + +--------+---------+ + v + +------------------+ MMR / limites por categoria + | Re-rank divers. | + +--------+---------+ + v + GET /recommend?user_id=U&k=20 -> [ {item_id, score, reason} ... ] + + Aval: split por TEMPO; recall@k, NDCG@k na janela futura + Online: stream de novas interações -> atualiza embeddings/features +``` + +## Desafios Extras + +- Adicione um bandit (epsilon-greedy ou Thompson sampling) para exploração vs explotação. +- Suporte recomendações baseadas em sessão usando modelos de sequência. +- Adicione uma feature store compartilhada entre treino offline e serving online. +- Pré-calcule recomendações para os usuários mais quentes e sirva-as de um cache. + +## Definição de Pronto + +- [ ] A recuperação de candidatos usa ANN e permanece sublinear conforme o catálogo cresce. +- [ ] Um estágio de ranking repontua candidatos com features além das usadas na recuperação. +- [ ] Usuários e itens em cold start recebem recomendações sensatas via um fallback explícito. +- [ ] Um passo de diversidade evita listas de resultados quase duplicadas. +- [ ] A avaliação offline respeita a ordenação temporal e reporta recall@k e NDCG. + +## Armadilhas Comuns + +- Pontuar o catálogo inteiro por requisição e estourar o orçamento de latência conforme ele cresce. +- Avaliar com um split aleatório, vazando interações futuras para a janela de treino. +- Otimizar relevância pura até que toda lista pareça idêntica e os usuários se desengajem. +- Ignorar cold start, de modo que novos itens nunca são exibidos e nunca reúnem sinal. + +## Recursos + +- [Google: curso de Sistemas de Recomendação](https://developers.google.com/machine-learning/recommendation) — recuperação, ranking e geração de candidatos. +- [Documentação do FAISS](https://faiss.ai/) — busca por vizinhos mais próximos aproximada em escala. +- [Deep Neural Networks for YouTube Recommendations (Covington et al., 2016)](https://research.google/pubs/pub45530/) — a arquitetura canônica de dois estágios. +- [Matrix Factorization Techniques for Recommender Systems (Koren et al., 2009)](https://ieeexplore.ieee.org/document/5197422) — filtragem colaborativa fundamental. diff --git a/projects/data-science/advanced/07-ml-monitoring/README.md b/projects/data-science/advanced/07-ml-monitoring/README.md index 68a2e5d..9046bbe 100644 --- a/projects/data-science/advanced/07-ml-monitoring/README.md +++ b/projects/data-science/advanced/07-ml-monitoring/README.md @@ -1,34 +1,103 @@ # ML Monitoring System -## Idea -Create a comprehensive monitoring system for machine learning models in production. Learn about model health and performance tracking. +> 🌐 **English** · [Português](./README.pt-BR.md) + +**Domain:** Data Science · **Level:** Advanced · **Estimated time:** 1–2 weeks + +## Overview + +Build a monitoring system that watches models in production and tells you when they are quietly going wrong. A deployed model rarely fails loudly; it degrades as the world drifts away from its training data, and by the time business metrics dip the damage is done. This project centers on detecting that drift early: monitoring input feature distributions, prediction distributions, and — when labels eventually arrive — real performance. You will implement statistical drift tests, tune alert thresholds against false positives, and close the loop with an automated retraining trigger. The deliverable is the safety net, not the model. + +## Prerequisites + +- Familiarity with models in production and how they degrade +- Understanding of statistical distances and tests (PSI, KS test, chi-squared) +- Experience with a metrics/dashboard stack (Prometheus + Grafana or similar) +- Comfort with time-series data and delayed ground-truth labels ## Learning Objectives -- Monitor model performance -- Detect model degradation -- Track data quality -- Implement alerting -- Create dashboards - -## Implementation Tips -- Implement performance tracking -- Monitor prediction distributions -- Track feature distributions -- Detect data drift -- Implement model drift detection -- Add outlier detection -- Create performance dashboards -- Implement alert rules -- Add automated retraining triggers -- Create incident tracking -- Build historical analysis -- Implement explainability monitoring -- Add bias detection -- Create compliance tracking - -## Key Challenges -- Defining relevant metrics -- Alert threshold tuning -- False positive rates -- Real-time processing -- Multi-model monitoring + +By the end, you should be able to: + +- Distinguish data drift, concept drift, and label delay, and monitor each appropriately +- Implement statistical drift detection on features and predictions +- Compute real performance once delayed labels arrive +- Tune alert thresholds to balance early detection against false positives +- Trigger automated retraining from a monitoring signal + +## Functional Requirements + +1. The system must log model inputs, predictions, and (when available) ground-truth labels. +2. It must compute feature drift per feature against a reference/training distribution. +3. It must monitor the prediction distribution for shifts independent of labels. +4. When labels arrive, it must compute performance metrics over the corresponding window. +5. It must raise alerts when drift or performance crosses configurable thresholds. +6. It must present dashboards showing drift and performance trends over time. +7. It must expose a retraining trigger that fires on a sustained alert condition. + +## Non-Functional Requirements + +- **Timeliness:** drift on a monitored feature must be detectable within a bounded window. +- **False-positive control:** alert thresholds must be tunable and the false-positive rate reported. +- **Scalability:** monitoring must handle many features and multiple models without linear blowup in cost. +- **Reproducibility:** the reference distribution and thresholds must be versioned. + +## Suggested Milestones + +1. **Milestone 1 — Logging:** Capture inputs, predictions, and labels with timestamps and model version. +2. **Milestone 2 — Drift detection:** Implement feature and prediction drift tests against a reference. +3. **Milestone 3 — Performance & alerts:** Compute delayed-label performance and add threshold alerts. +4. **Milestone 4 — Dashboards & retraining:** Build trend dashboards and wire a retraining trigger. + +## Data & Interface Sketch + +```text + serving --> prediction log { ts, model_version, features{}, pred, [label] } + | + v + +--------------------------+ window vs reference distribution + | Drift detectors | feature: PSI / KS ; pred: population shift + +------------+-------------+ + v + +--------------------------+ arrives late; joined by request_id + | Performance calc (labels)| accuracy, AUC, calibration over window + +------------+-------------+ + v + +--------------------------+ thresholds (versioned) + | Alerting | sustained breach -> notify + trigger + +------------+-------------+ + v + Dashboards (drift/perf trends) + POST /retrain (on sustained alert) + + Metrics per feature: PSI, distance-to-reference, missing-rate + Reference: frozen training-period distribution, versioned +``` + +## Stretch Goals + +- Add automatic segmentation to find which slice is drifting, not just that drift exists. +- Support multivariate drift detection, not only per-feature. +- Add a "silent failure" detector using prediction confidence when labels are absent. +- Track drift across multiple model versions on one dashboard. + +## Definition of Done + +- [ ] Inputs, predictions, and labels are logged and joinable by request ID. +- [ ] Feature and prediction drift are computed against a versioned reference distribution. +- [ ] Delayed-label performance is computed over the correct time window. +- [ ] Alerts fire on sustained threshold breaches, with a reported false-positive rate. +- [ ] A sustained alert can trigger a retraining job automatically. + +## Common Pitfalls + +- Monitoring only accuracy and being blind until labels arrive weeks later. +- Alerting on every tiny distribution wobble, training the team to ignore alerts. +- Comparing against a stale reference and treating normal seasonality as drift. +- Failing to join predictions to labels correctly, so performance numbers are wrong. + +## Resources + +- [Google: Data Validation for Machine Learning / TFX](https://www.tensorflow.org/tfx/guide/tfdv) — distribution and schema skew detection. +- [Evidently AI Documentation](https://docs.evidentlyai.com/) — drift metrics and monitoring reports. +- [A Survey on Concept Drift Adaptation (Gama et al., 2014)](https://dl.acm.org/doi/10.1145/2523813) — types of drift and detection methods. +- [Population Stability Index (PSI) explained](https://www.mdpi.com/2227-9091/7/2/53) — a standard drift metric for tabular features. diff --git a/projects/data-science/advanced/07-ml-monitoring/README.pt-BR.md b/projects/data-science/advanced/07-ml-monitoring/README.pt-BR.md new file mode 100644 index 0000000..3e5333d --- /dev/null +++ b/projects/data-science/advanced/07-ml-monitoring/README.pt-BR.md @@ -0,0 +1,103 @@ +# Sistema de Monitoramento de ML + +> 🌐 [English](./README.md) · **Português** + +**Domínio:** Data Science · **Nível:** Avançado · **Tempo estimado:** 1–2 semanas + +## Visão Geral + +Construa um sistema de monitoramento que observa modelos em produção e avisa quando eles começam a errar silenciosamente. Um modelo implantado raramente falha de forma barulhenta; ele degrada conforme o mundo se afasta de seus dados de treino, e quando as métricas de negócio caem o estrago já está feito. Este projeto se centra em detectar esse drift cedo: monitorar distribuições de features de entrada, distribuições de predição e — quando os rótulos eventualmente chegam — o desempenho real. Você vai implementar testes estatísticos de drift, ajustar limiares de alerta contra falsos positivos e fechar o ciclo com um gatilho de retreino automático. O entregável é a rede de segurança, não o modelo. + +## Pré-requisitos + +- Familiaridade com modelos em produção e como eles degradam +- Entendimento de distâncias e testes estatísticos (PSI, teste KS, qui-quadrado) +- Experiência com uma stack de métricas/dashboard (Prometheus + Grafana ou similar) +- Conforto com dados de série temporal e rótulos de verdade atrasados + +## Objetivos de Aprendizado + +Ao final, você deve ser capaz de: + +- Distinguir drift de dados, drift de conceito e atraso de rótulo, e monitorar cada um apropriadamente +- Implementar detecção estatística de drift em features e predições +- Calcular o desempenho real assim que os rótulos atrasados chegam +- Ajustar limiares de alerta para equilibrar detecção precoce contra falsos positivos +- Disparar retreino automático a partir de um sinal de monitoramento + +## Requisitos Funcionais + +1. O sistema deve registrar entradas do modelo, predições e (quando disponíveis) rótulos de verdade. +2. Deve calcular drift de feature por feature contra uma distribuição de referência/treino. +3. Deve monitorar a distribuição de predição em busca de mudanças independentes dos rótulos. +4. Quando os rótulos chegam, deve calcular métricas de desempenho sobre a janela correspondente. +5. Deve emitir alertas quando o drift ou o desempenho cruzam limiares configuráveis. +6. Deve apresentar dashboards mostrando tendências de drift e desempenho ao longo do tempo. +7. Deve expor um gatilho de retreino que dispara em uma condição de alerta sustentada. + +## Requisitos Não Funcionais + +- **Tempestividade:** o drift em uma feature monitorada deve ser detectável dentro de uma janela limitada. +- **Controle de falsos positivos:** os limiares de alerta devem ser ajustáveis e a taxa de falsos positivos reportada. +- **Escalabilidade:** o monitoramento deve lidar com muitas features e múltiplos modelos sem explosão linear de custo. +- **Reprodutibilidade:** a distribuição de referência e os limiares devem ser versionados. + +## Marcos Sugeridos + +1. **Marco 1 — Registro:** Capture entradas, predições e rótulos com timestamps e versão do modelo. +2. **Marco 2 — Detecção de drift:** Implemente testes de drift de feature e predição contra uma referência. +3. **Marco 3 — Desempenho e alertas:** Calcule o desempenho com rótulos atrasados e adicione alertas por limiar. +4. **Marco 4 — Dashboards e retreino:** Construa dashboards de tendência e conecte um gatilho de retreino. + +## Esboço de Dados e Interface + +```text + serving --> log de predição { ts, model_version, features{}, pred, [label] } + | + v + +--------------------------+ janela vs distribuição de referência + | Detectores de drift | feature: PSI / KS ; pred: mudança populacional + +------------+-------------+ + v + +--------------------------+ chega atrasado; unido por request_id + | Cálculo perf (rótulos) | acurácia, AUC, calibração na janela + +------------+-------------+ + v + +--------------------------+ limiares (versionados) + | Alertas | violação sustentada -> notifica + dispara + +------------+-------------+ + v + Dashboards (tendências drift/perf) + POST /retrain (em alerta sustentado) + + Métricas por feature: PSI, distância-à-referência, taxa-de-ausência + Referência: distribuição do período de treino congelada, versionada +``` + +## Desafios Extras + +- Adicione segmentação automática para achar qual fatia está com drift, não apenas que há drift. +- Suporte detecção de drift multivariada, não apenas por feature. +- Adicione um detector de "falha silenciosa" usando a confiança da predição quando faltam rótulos. +- Rastreie drift entre múltiplas versões de modelo em um único dashboard. + +## Definição de Pronto + +- [ ] Entradas, predições e rótulos são registrados e uníveis por request ID. +- [ ] Drift de feature e de predição são calculados contra uma distribuição de referência versionada. +- [ ] O desempenho com rótulos atrasados é calculado sobre a janela de tempo correta. +- [ ] Alertas disparam em violações de limiar sustentadas, com uma taxa de falsos positivos reportada. +- [ ] Um alerta sustentado pode disparar um job de retreino automaticamente. + +## Armadilhas Comuns + +- Monitorar apenas a acurácia e ficar cego até os rótulos chegarem semanas depois. +- Alertar em cada pequena oscilação de distribuição, treinando a equipe a ignorar alertas. +- Comparar contra uma referência obsoleta e tratar sazonalidade normal como drift. +- Não unir predições a rótulos corretamente, tornando os números de desempenho errados. + +## Recursos + +- [Google: Data Validation para Machine Learning / TFX](https://www.tensorflow.org/tfx/guide/tfdv) — detecção de skew de distribuição e schema. +- [Documentação do Evidently AI](https://docs.evidentlyai.com/) — métricas de drift e relatórios de monitoramento. +- [A Survey on Concept Drift Adaptation (Gama et al., 2014)](https://dl.acm.org/doi/10.1145/2523813) — tipos de drift e métodos de detecção. +- [Population Stability Index (PSI) explicado](https://www.mdpi.com/2227-9091/7/2/53) — uma métrica de drift padrão para features tabulares. diff --git a/projects/data-science/advanced/08-federated-learning/README.md b/projects/data-science/advanced/08-federated-learning/README.md index 6187b3e..a301f5e 100644 --- a/projects/data-science/advanced/08-federated-learning/README.md +++ b/projects/data-science/advanced/08-federated-learning/README.md @@ -1,34 +1,102 @@ # Federated Learning Simulation -## Idea -Simulate a federated learning system where multiple parties train models collaboratively without sharing raw data. +> 🌐 **English** · [Português](./README.pt-BR.md) + +**Domain:** Data Science · **Level:** Advanced · **Estimated time:** 1–2 weeks + +## Overview + +Simulate a system where many clients train a shared model together without ever sending their raw data to a central server. Each client trains locally on its own data, sends only model updates, and a server aggregates them into a new global model. It sounds simple until the realities hit: clients hold non-IID data, some are slow or drop out, communication is expensive, and the updates themselves can leak information. This project has you implement the FedAvg loop, then confront heterogeneity, stragglers, communication cost, and privacy — the four things that separate a toy from a real federated system. + +## Prerequisites + +- Solid understanding of gradient-based training and model averaging +- Experience with PyTorch or TensorFlow for the local training step +- Familiarity with the concept of differential privacy +- Comfort simulating distributed processes (threads, processes, or a framework) ## Learning Objectives -- Understand federated learning concepts -- Implement distributed training -- Handle communication efficiency -- Manage privacy preservation -- Evaluate convergence - -## Implementation Tips -- Create multiple client simulators -- Implement local training -- Create model aggregation -- Add communication rounds -- Implement privacy mechanisms (differential privacy) -- Handle stragglers -- Create convergence analysis -- Implement heterogeneous data -- Add compression techniques -- Create personalization -- Implement robustness to attacks -- Add fairness mechanisms -- Build monitoring system -- Create evaluation framework - -## Key Challenges -- Communication efficiency -- Convergence with heterogeneous data -- Privacy preservation -- Computational heterogeneity -- Result validation + +By the end, you should be able to: + +- Implement the federated averaging (FedAvg) training loop across simulated clients +- Handle non-IID data partitions and measure their effect on convergence +- Deal with stragglers and client dropout without stalling a round +- Reduce communication cost via update compression or fewer rounds +- Add a privacy mechanism (differential privacy or secure aggregation) and quantify its cost + +## Functional Requirements + +1. The simulation must run multiple clients, each training locally on a private data partition. +2. A server must aggregate client updates into a global model each communication round. +3. Data partitions must support both IID and non-IID distributions across clients. +4. The system must tolerate stragglers and dropped clients within a round. +5. It must implement a communication-reduction technique (compression or local epochs). +6. It must offer a privacy mechanism (e.g. DP-SGD) that can be toggled and measured. +7. It must track and report global-model convergence across rounds. + +## Non-Functional Requirements + +- **Convergence:** the global model must converge under non-IID data within a documented round budget. +- **Communication efficiency:** report bytes-per-round and total communication versus a centralized baseline. +- **Privacy:** when DP is enabled, report the privacy budget (epsilon) and its accuracy cost. +- **Robustness:** a round must complete even if a configurable fraction of clients drop out. + +## Suggested Milestones + +1. **Milestone 1 — FedAvg core:** Simulate clients, local training, and server averaging on IID data. +2. **Milestone 2 — Heterogeneity:** Introduce non-IID partitions and measure the convergence hit. +3. **Milestone 3 — Robustness & communication:** Handle stragglers/dropout and add update compression. +4. **Milestone 4 — Privacy:** Add DP-SGD, sweep epsilon, and quantify the privacy–accuracy tradeoff. + +## Data & Interface Sketch + +```text + +-------------------- Server --------------------+ + | global model w_t | + | broadcast w_t | + +-----+-----------+-----------+------------------+ + | | | + +------v--+ +-----v---+ +----v----+ ... (K clients) + | Client1 | | Client2 | | ClientK | + | local | | local | | local | private data (IID or non-IID) + | train | | train | | train | + | -> dw_1 | | -> dw_2 | | -> dw_K | (+ DP noise, compression) + +----+----+ +----+----+ +----+----+ + | | | + +------ aggregate (weighted avg) ------+ + | + w_{t+1} = sum_k (n_k/n) * (w_t + dw_k) + + Round drops clients past a deadline (straggler handling) + Track: global acc per round, bytes/round, epsilon (if DP on) +``` + +## Stretch Goals + +- Add secure aggregation so the server never sees individual updates in the clear. +- Add personalization: a shared base with per-client fine-tuned heads. +- Simulate an adversarial client (model poisoning) and add a robust aggregator (e.g. trimmed mean). +- Compare FedAvg against FedProx under strong heterogeneity. + +## Definition of Done + +- [ ] FedAvg converges on IID data across simulated clients. +- [ ] Non-IID partitions are supported and their convergence impact is measured. +- [ ] Rounds complete despite a configurable fraction of straggling/dropped clients. +- [ ] A communication-reduction technique is implemented and its savings reported. +- [ ] DP can be enabled, with epsilon and the accuracy cost reported. + +## Common Pitfalls + +- Testing only on IID data and never seeing the convergence problems that define federated learning. +- Waiting synchronously for every client, so one straggler stalls the whole round. +- Adding differential privacy without tracking the actual epsilon, so "private" is meaningless. +- Averaging updates unweighted when clients hold very different amounts of data. + +## Resources + +- [Communication-Efficient Learning of Deep Networks from Decentralized Data (McMahan et al., 2017)](https://arxiv.org/abs/1602.05629) — the FedAvg paper. +- [Advances and Open Problems in Federated Learning (Kairouz et al., 2019)](https://arxiv.org/abs/1912.04977) — the comprehensive survey. +- [TensorFlow Federated Documentation](https://www.tensorflow.org/federated) — a framework for federated computation. +- [Deep Learning with Differential Privacy (Abadi et al., 2016)](https://arxiv.org/abs/1607.00133) — DP-SGD and the privacy budget. diff --git a/projects/data-science/advanced/08-federated-learning/README.pt-BR.md b/projects/data-science/advanced/08-federated-learning/README.pt-BR.md new file mode 100644 index 0000000..8b8396f --- /dev/null +++ b/projects/data-science/advanced/08-federated-learning/README.pt-BR.md @@ -0,0 +1,102 @@ +# Simulação de Aprendizado Federado + +> 🌐 [English](./README.md) · **Português** + +**Domínio:** Data Science · **Nível:** Avançado · **Tempo estimado:** 1–2 semanas + +## Visão Geral + +Simule um sistema onde muitos clientes treinam um modelo compartilhado juntos sem nunca enviar seus dados brutos para um servidor central. Cada cliente treina localmente com seus próprios dados, envia apenas atualizações do modelo, e um servidor as agrega em um novo modelo global. Parece simples até as realidades baterem: os clientes têm dados não-IID, alguns são lentos ou caem, a comunicação é cara e as próprias atualizações podem vazar informação. Neste projeto você implementa o loop FedAvg e depois enfrenta heterogeneidade, stragglers, custo de comunicação e privacidade — as quatro coisas que separam um brinquedo de um sistema federado real. + +## Pré-requisitos + +- Entendimento sólido de treino baseado em gradiente e média de modelos +- Experiência com PyTorch ou TensorFlow para o passo de treino local +- Familiaridade com o conceito de privacidade diferencial +- Conforto para simular processos distribuídos (threads, processos ou um framework) + +## Objetivos de Aprendizado + +Ao final, você deve ser capaz de: + +- Implementar o loop de treino de média federada (FedAvg) entre clientes simulados +- Tratar partições de dados não-IID e medir seu efeito na convergência +- Lidar com stragglers e dropout de clientes sem travar uma rodada +- Reduzir o custo de comunicação via compressão de atualizações ou menos rodadas +- Adicionar um mecanismo de privacidade (privacidade diferencial ou agregação segura) e quantificar seu custo + +## Requisitos Funcionais + +1. A simulação deve rodar múltiplos clientes, cada um treinando localmente em uma partição de dados privada. +2. Um servidor deve agregar as atualizações dos clientes em um modelo global a cada rodada de comunicação. +3. As partições de dados devem suportar distribuições IID e não-IID entre clientes. +4. O sistema deve tolerar stragglers e clientes que caem dentro de uma rodada. +5. Deve implementar uma técnica de redução de comunicação (compressão ou épocas locais). +6. Deve oferecer um mecanismo de privacidade (ex.: DP-SGD) que possa ser ligado e medido. +7. Deve rastrear e reportar a convergência do modelo global ao longo das rodadas. + +## Requisitos Não Funcionais + +- **Convergência:** o modelo global deve convergir sob dados não-IID dentro de um orçamento de rodadas documentado. +- **Eficiência de comunicação:** reporte bytes-por-rodada e comunicação total versus uma baseline centralizada. +- **Privacidade:** quando a DP está ativa, reporte o orçamento de privacidade (epsilon) e seu custo de acurácia. +- **Robustez:** uma rodada deve completar mesmo que uma fração configurável de clientes caia. + +## Marcos Sugeridos + +1. **Marco 1 — Núcleo FedAvg:** Simule clientes, treino local e média no servidor em dados IID. +2. **Marco 2 — Heterogeneidade:** Introduza partições não-IID e meça o impacto na convergência. +3. **Marco 3 — Robustez e comunicação:** Trate stragglers/dropout e adicione compressão de atualizações. +4. **Marco 4 — Privacidade:** Adicione DP-SGD, varra o epsilon e quantifique o tradeoff privacidade–acurácia. + +## Esboço de Dados e Interface + +```text + +-------------------- Servidor ------------------+ + | modelo global w_t | + | broadcast w_t | + +-----+-----------+-----------+------------------+ + | | | + +------v--+ +-----v---+ +----v----+ ... (K clientes) + | Cliente1| | Cliente2| | ClienteK| + | treino | | treino | | treino | dados privados (IID ou não-IID) + | local | | local | | local | + | -> dw_1 | | -> dw_2 | | -> dw_K | (+ ruído DP, compressão) + +----+----+ +----+----+ +----+----+ + | | | + +------ agrega (média ponderada) ------+ + | + w_{t+1} = soma_k (n_k/n) * (w_t + dw_k) + + A rodada descarta clientes após um prazo (tratamento de straggler) + Rastreie: acc global por rodada, bytes/rodada, epsilon (se DP ativo) +``` + +## Desafios Extras + +- Adicione agregação segura para que o servidor nunca veja atualizações individuais em claro. +- Adicione personalização: uma base compartilhada com heads ajustadas por cliente. +- Simule um cliente adversário (envenenamento de modelo) e adicione um agregador robusto (ex.: média aparada). +- Compare FedAvg contra FedProx sob forte heterogeneidade. + +## Definição de Pronto + +- [ ] FedAvg converge em dados IID entre clientes simulados. +- [ ] Partições não-IID são suportadas e seu impacto na convergência é medido. +- [ ] As rodadas completam apesar de uma fração configurável de clientes lentos/caídos. +- [ ] Uma técnica de redução de comunicação é implementada e sua economia reportada. +- [ ] A DP pode ser ativada, com o epsilon e o custo de acurácia reportados. + +## Armadilhas Comuns + +- Testar apenas em dados IID e nunca ver os problemas de convergência que definem o aprendizado federado. +- Esperar sincronamente por cada cliente, fazendo um straggler travar a rodada inteira. +- Adicionar privacidade diferencial sem rastrear o epsilon real, tornando "privado" sem sentido. +- Fazer média das atualizações sem ponderação quando os clientes têm quantidades de dados muito diferentes. + +## Recursos + +- [Communication-Efficient Learning of Deep Networks from Decentralized Data (McMahan et al., 2017)](https://arxiv.org/abs/1602.05629) — o paper do FedAvg. +- [Advances and Open Problems in Federated Learning (Kairouz et al., 2019)](https://arxiv.org/abs/1912.04977) — o survey abrangente. +- [Documentação do TensorFlow Federated](https://www.tensorflow.org/federated) — um framework para computação federada. +- [Deep Learning with Differential Privacy (Abadi et al., 2016)](https://arxiv.org/abs/1607.00133) — DP-SGD e o orçamento de privacidade. diff --git a/projects/data-science/advanced/09-explainable-ai/README.md b/projects/data-science/advanced/09-explainable-ai/README.md index 4571d29..f8f6305 100644 --- a/projects/data-science/advanced/09-explainable-ai/README.md +++ b/projects/data-science/advanced/09-explainable-ai/README.md @@ -1,34 +1,107 @@ # Explainable AI Tool -## Idea -Build a tool for making machine learning model predictions explainable and interpretable. +> 🌐 **English** · [Português](./README.pt-BR.md) + +**Domain:** Data Science · **Level:** Advanced · **Estimated time:** 1–2 weeks + +## Overview + +Build a tool that explains why a model made a given prediction, at both the single-prediction level and the whole-model level. As models move into decisions that affect people — credit, hiring, healthcare — "the model said so" is not an acceptable answer, and in some jurisdictions it is not a legal one either. This project has you implement the core explainability methods (SHAP, LIME, counterfactuals), reason about when each is trustworthy, layer a fairness/bias analysis on top, and present it all so a non-technical stakeholder can act on it. The hard part is not computing an explanation — it is making one that is faithful and honest. + +## Prerequisites + +- Familiarity with common model families (trees, gradient boosting, neural nets) +- Understanding of feature attribution and model-agnostic vs model-specific methods +- Experience with a plotting/dashboard library +- Comfort discussing fairness metrics and their tradeoffs ## Learning Objectives -- Implement feature importance methods -- Create visual explanations -- Understand model decisions -- Detect bias -- Build explainability tools - -## Implementation Tips -- Implement SHAP values -- Add LIME explanations -- Create feature attribution -- Build decision trees explanations -- Implement counterfactual explanations -- Create visual dashboards -- Add influence analysis -- Implement prototype examples -- Create fairness analysis -- Add bias detection -- Build interactive explanations -- Create trustworthiness scores -- Implement audit logs -- Build compliance reports - -## Key Challenges -- Explanation accuracy -- Real-time computation -- Complex model interpretation -- Feature interaction visualization -- Stakeholder communication + +By the end, you should be able to: + +- Produce local explanations with SHAP and LIME and know their assumptions and limits +- Produce global explanations (feature importance, dependence) faithful to the model +- Generate actionable counterfactual explanations ("change X to flip the outcome") +- Run a bias/fairness analysis across protected groups +- Communicate explanations to a non-technical audience without overclaiming + +## Functional Requirements + +1. The tool must accept a trained model and dataset and produce local explanations for individual predictions. +2. It must produce global explanations summarizing overall feature influence. +3. It must implement at least two methods (e.g. SHAP and LIME) and let the user compare them. +4. It must generate counterfactual explanations describing minimal input changes to alter a prediction. +5. It must compute fairness metrics across at least one protected attribute. +6. It must present explanations visually in a way a non-expert can interpret. +7. It must flag when an explanation is unreliable (e.g. extrapolation outside the data manifold). + +## Non-Functional Requirements + +- **Faithfulness:** explanations must be validated against a ground-truth method where one exists (e.g. exact SHAP for trees). +- **Latency:** local explanations must be produced within an interactive budget for the target model. +- **Reproducibility:** explanations for the same input and model must be stable across runs (seeded). +- **Auditability:** every explanation must be logged with model version and input. + +## Suggested Milestones + +1. **Milestone 1 — Local explanations:** Implement SHAP and LIME for single predictions with visual output. +2. **Milestone 2 — Global view:** Add global feature importance and dependence plots. +3. **Milestone 3 — Counterfactuals & fairness:** Generate counterfactuals and compute group fairness metrics. +4. **Milestone 4 — Trust & presentation:** Add reliability flags and a stakeholder-facing report/dashboard. + +## Data & Interface Sketch + +```text + trained model + dataset + | + v + +-------------------------+ pick an instance x + | Local explainers | + | SHAP(x) -> phi_i | per-feature contribution + | LIME(x) -> weights | local surrogate + | compare + agreement | + +-----------+-------------+ + | + +-------------------------+ over dataset + | Global explainers | mean|phi|, dependence plots + +-----------+-------------+ + | + +-------------------------+ minimal delta to flip prediction + | Counterfactual search | "raise income by X -> approved" + +-----------+-------------+ + | + +-------------------------+ per protected group + | Fairness analysis | demographic parity, equal opp. gap + +-----------+-------------+ + v + Report/dashboard + reliability flag (in-distribution?) + audit log +``` + +## Stretch Goals + +- Add anchor explanations (high-precision if-then rules) alongside SHAP/LIME. +- Add example-based explanations (prototypes and criticisms, influential training points). +- Support explanation for image or text models, not only tabular. +- Add a "contest this decision" flow that surfaces the counterfactual to the affected user. + +## Definition of Done + +- [ ] Local explanations (SHAP and LIME) are produced and visually compared. +- [ ] Global feature importance and dependence are shown faithfully to the model. +- [ ] Counterfactuals describe minimal, feasible input changes to flip a prediction. +- [ ] Fairness metrics are computed for at least one protected group. +- [ ] Explanations are flagged when the input is outside the training distribution. + +## Common Pitfalls + +- Presenting LIME/SHAP weights as causal when they are only associational. +- Explaining a single prediction and generalizing it to the whole model's behavior. +- Producing counterfactuals that are mathematically valid but practically impossible (e.g. "reduce your age"). +- Reporting one fairness metric as if fairness were a single number, hiding the tradeoffs. + +## Resources + +- [SHAP Documentation](https://shap.readthedocs.io/en/latest/) — unified feature attribution based on Shapley values. +- [A Unified Approach to Interpreting Model Predictions (Lundberg & Lee, 2017)](https://arxiv.org/abs/1705.07874) — the SHAP paper. +- ["Why Should I Trust You?": Explaining the Predictions of Any Classifier (Ribeiro et al., 2016)](https://arxiv.org/abs/1602.04938) — the LIME paper. +- [Interpretable Machine Learning (Molnar) — online book](https://christophm.github.io/interpretable-ml-book/) — methods, assumptions, and pitfalls. diff --git a/projects/data-science/advanced/09-explainable-ai/README.pt-BR.md b/projects/data-science/advanced/09-explainable-ai/README.pt-BR.md new file mode 100644 index 0000000..0f63ca6 --- /dev/null +++ b/projects/data-science/advanced/09-explainable-ai/README.pt-BR.md @@ -0,0 +1,107 @@ +# Ferramenta de IA Explicável + +> 🌐 [English](./README.md) · **Português** + +**Domínio:** Data Science · **Nível:** Avançado · **Tempo estimado:** 1–2 semanas + +## Visão Geral + +Construa uma ferramenta que explica por que um modelo fez uma dada predição, tanto no nível de uma única predição quanto no nível do modelo inteiro. Conforme os modelos entram em decisões que afetam pessoas — crédito, contratação, saúde — "o modelo disse" não é uma resposta aceitável, e em algumas jurisdições também não é uma resposta legal. Neste projeto você implementa os métodos centrais de explicabilidade (SHAP, LIME, contrafactuais), raciocina sobre quando cada um é confiável, sobrepõe uma análise de justiça/viés e apresenta tudo de forma que um stakeholder não técnico consiga agir. A parte difícil não é calcular uma explicação — é fazer uma que seja fiel e honesta. + +## Pré-requisitos + +- Familiaridade com famílias de modelos comuns (árvores, gradient boosting, redes neurais) +- Entendimento de atribuição de features e métodos agnósticos vs específicos de modelo +- Experiência com uma biblioteca de plots/dashboard +- Conforto para discutir métricas de justiça e seus tradeoffs + +## Objetivos de Aprendizado + +Ao final, você deve ser capaz de: + +- Produzir explicações locais com SHAP e LIME e conhecer suas suposições e limites +- Produzir explicações globais (importância de feature, dependência) fiéis ao modelo +- Gerar explicações contrafactuais acionáveis ("mude X para inverter o resultado") +- Rodar uma análise de viés/justiça entre grupos protegidos +- Comunicar explicações a um público não técnico sem exagerar nas afirmações + +## Requisitos Funcionais + +1. A ferramenta deve aceitar um modelo treinado e dataset e produzir explicações locais para predições individuais. +2. Deve produzir explicações globais resumindo a influência geral das features. +3. Deve implementar ao menos dois métodos (ex.: SHAP e LIME) e permitir ao usuário compará-los. +4. Deve gerar explicações contrafactuais descrevendo mudanças mínimas de entrada para alterar uma predição. +5. Deve calcular métricas de justiça entre ao menos um atributo protegido. +6. Deve apresentar explicações visualmente de forma que um não-especialista consiga interpretar. +7. Deve sinalizar quando uma explicação é não confiável (ex.: extrapolação fora do manifold dos dados). + +## Requisitos Não Funcionais + +- **Fidelidade:** as explicações devem ser validadas contra um método de verdade quando existir (ex.: SHAP exato para árvores). +- **Latência:** explicações locais devem ser produzidas dentro de um orçamento interativo para o modelo alvo. +- **Reprodutibilidade:** explicações para a mesma entrada e modelo devem ser estáveis entre execuções (com semente). +- **Auditabilidade:** cada explicação deve ser registrada com versão do modelo e entrada. + +## Marcos Sugeridos + +1. **Marco 1 — Explicações locais:** Implemente SHAP e LIME para predições únicas com saída visual. +2. **Marco 2 — Visão global:** Adicione importância global de features e plots de dependência. +3. **Marco 3 — Contrafactuais e justiça:** Gere contrafactuais e calcule métricas de justiça por grupo. +4. **Marco 4 — Confiança e apresentação:** Adicione flags de confiabilidade e um relatório/dashboard voltado ao stakeholder. + +## Esboço de Dados e Interface + +```text + modelo treinado + dataset + | + v + +-------------------------+ escolha uma instância x + | Explicadores locais | + | SHAP(x) -> phi_i | contribuição por feature + | LIME(x) -> pesos | surrogate local + | comparar + concordância| + +-----------+-------------+ + | + +-------------------------+ sobre o dataset + | Explicadores globais | média|phi|, plots de dependência + +-----------+-------------+ + | + +-------------------------+ delta mínimo para inverter a predição + | Busca contrafactual | "aumente a renda em X -> aprovado" + +-----------+-------------+ + | + +-------------------------+ por grupo protegido + | Análise de justiça | paridade demográfica, gap de opp. igual + +-----------+-------------+ + v + Relatório/dashboard + flag de confiabilidade (na distribuição?) + log de auditoria +``` + +## Desafios Extras + +- Adicione explicações por âncora (regras if-then de alta precisão) junto de SHAP/LIME. +- Adicione explicações baseadas em exemplos (protótipos e críticas, pontos de treino influentes). +- Suporte explicação para modelos de imagem ou texto, não apenas tabulares. +- Adicione um fluxo de "contestar esta decisão" que exibe o contrafactual ao usuário afetado. + +## Definição de Pronto + +- [ ] Explicações locais (SHAP e LIME) são produzidas e comparadas visualmente. +- [ ] Importância global de features e dependência são mostradas fielmente ao modelo. +- [ ] Contrafactuais descrevem mudanças de entrada mínimas e viáveis para inverter uma predição. +- [ ] Métricas de justiça são calculadas para ao menos um grupo protegido. +- [ ] As explicações são sinalizadas quando a entrada está fora da distribuição de treino. + +## Armadilhas Comuns + +- Apresentar pesos de LIME/SHAP como causais quando são apenas associativos. +- Explicar uma única predição e generalizá-la para o comportamento do modelo inteiro. +- Produzir contrafactuais matematicamente válidos mas praticamente impossíveis (ex.: "reduza sua idade"). +- Reportar uma métrica de justiça como se justiça fosse um único número, escondendo os tradeoffs. + +## Recursos + +- [Documentação do SHAP](https://shap.readthedocs.io/en/latest/) — atribuição unificada de features baseada em valores de Shapley. +- [A Unified Approach to Interpreting Model Predictions (Lundberg & Lee, 2017)](https://arxiv.org/abs/1705.07874) — o paper do SHAP. +- ["Why Should I Trust You?": Explaining the Predictions of Any Classifier (Ribeiro et al., 2016)](https://arxiv.org/abs/1602.04938) — o paper do LIME. +- [Interpretable Machine Learning (Molnar) — livro online](https://christophm.github.io/interpretable-ml-book/) — métodos, suposições e armadilhas. diff --git a/projects/data-science/advanced/10-multi-model-ensemble/README.md b/projects/data-science/advanced/10-multi-model-ensemble/README.md index b217573..1d11bd8 100644 --- a/projects/data-science/advanced/10-multi-model-ensemble/README.md +++ b/projects/data-science/advanced/10-multi-model-ensemble/README.md @@ -1,34 +1,106 @@ # Multi-Model Ensemble System -## Idea -Create an ensemble system combining multiple machine learning models for improved predictions. +> 🌐 **English** · [Português](./README.pt-BR.md) + +**Domain:** Data Science · **Level:** Advanced · **Estimated time:** 1–2 weeks + +## Overview + +Build a system that combines several models into an ensemble that beats any of them alone — and, just as importantly, knows when it does not. Ensembling is not "average some models"; its power comes from diversity, and combining correlated models buys nothing while multiplying inference cost. This project has you assemble a diverse model pool, implement real combination strategies (stacking with a meta-learner, weighted blending, voting), measure diversity honestly, and weigh the accuracy gain against the compute and latency you pay for it. The interesting tension is that the best ensemble is rarely "all of them." + +## Prerequisites + +- Solid grasp of bias–variance and why diverse errors cancel +- Experience training multiple model families and doing proper cross-validation +- Understanding of stacking, blending, and the risk of meta-learner leakage +- Comfort measuring inference cost, not just accuracy ## Learning Objectives -- Implement ensemble methods -- Combine predictions effectively -- Handle model diversity -- Optimize ensemble performance -- Monitor ensemble health - -## Implementation Tips -- Create diverse model pool -- Implement stacking -- Add blending strategies -- Create weighted averaging -- Implement meta-learners -- Add voting mechanisms -- Create boosting integration -- Implement cascade models -- Add diversity metrics -- Create performance tracking -- Implement ensemble optimization -- Add online learning -- Build explainability for ensembles -- Create monitoring systems - -## Key Challenges -- Model diversity creation -- Optimal weighting -- Computation efficiency -- Ensemble explainability -- Heterogeneous model performance + +By the end, you should be able to: + +- Construct a deliberately diverse pool of base models and measure their diversity +- Implement stacking with out-of-fold predictions to avoid leakage into the meta-learner +- Compare stacking, weighted blending, and voting on the same task +- Weigh ensemble accuracy gains against added latency and compute +- Prune the ensemble to the subset that carries most of the benefit + +## Functional Requirements + +1. The system must train and manage a pool of at least three diverse base models. +2. It must compute out-of-fold predictions so the meta-learner never sees in-fold leakage. +3. It must implement at least two combination strategies (e.g. stacking and weighted blending). +4. It must measure ensemble diversity (e.g. pairwise disagreement or error correlation). +5. It must report ensemble performance against the best single model and a naive average. +6. It must expose the ensemble behind a prediction interface with per-model contribution visible. +7. It must support pruning the pool to a smaller subset with a stated accuracy/cost tradeoff. + +## Non-Functional Requirements + +- **Accuracy vs cost:** the ensemble's accuracy gain must be reported alongside its added latency/compute. +- **Latency:** total ensemble inference must stay within a stated budget (base models may run in parallel). +- **Reproducibility:** fold assignments, seeds, and weights must reproduce reported results. +- **Robustness:** failure of one base model must degrade the ensemble gracefully, not break it. + +## Suggested Milestones + +1. **Milestone 1 — Diverse pool:** Train several distinct model families and measure their pairwise diversity. +2. **Milestone 2 — Stacking:** Generate out-of-fold predictions and train a meta-learner without leakage. +3. **Milestone 3 — Compare strategies:** Add weighted blending and voting; compare against best-single and naive-average. +4. **Milestone 4 — Prune & serve:** Prune to a cost-effective subset and serve with per-model contributions. + +## Data & Interface Sketch + +```text + training data + | + +--> Model A (trees) \ + +--> Model B (boosting) > base pool (diverse!) + +--> Model C (neural net) / + +--> Model D (linear) / + | + v out-of-fold predictions (no leakage) + +-----------------------------+ + | OOF prediction matrix | rows=samples, cols=base models + +--------------+--------------+ + v + +------ combine (choose) ------+ + | stacking: meta-learner(OOF) | + | blending: weighted avg | + | voting: majority/soft | + +--------------+--------------+ + v + diversity: pairwise disagreement, error-correlation matrix + report: ensemble vs best-single vs naive-avg (acc AND latency) + + GET /predict -> { prediction, per_model: {A:.., B:..}, weights } +``` + +## Stretch Goals + +- Add dynamic per-instance weighting (choose experts based on the input region). +- Add online updating so weights adapt as new labeled data arrives. +- Add explainability that attributes the final prediction back to contributing models. +- Search for the optimal subset with a greedy or evolutionary ensemble-selection method. + +## Definition of Done + +- [ ] The base pool has measured diversity, not just multiple copies of the same model. +- [ ] Stacking uses out-of-fold predictions with no leakage into the meta-learner. +- [ ] At least two combination strategies are compared against best-single and naive-average baselines. +- [ ] Accuracy gains are reported alongside the added latency/compute cost. +- [ ] A pruned subset is offered with an explicit accuracy-vs-cost tradeoff. + +## Common Pitfalls + +- Building a "diverse" ensemble of highly correlated models that adds cost but no accuracy. +- Training the meta-learner on in-fold predictions and leaking, inflating apparent gains. +- Reporting only the accuracy win and hiding that inference now costs 5x as much. +- Assuming more models is always better instead of pruning to the effective subset. + +## Resources + +- [scikit-learn: Ensemble methods](https://scikit-learn.org/stable/modules/ensemble.html) — stacking, voting, and boosting APIs and theory. +- [Stacked Generalization (Wolpert, 1992)](https://www.sciencedirect.com/science/article/abs/pii/S0893608005800231) — the original stacking paper. +- [Ensemble Selection from Libraries of Models (Caruana et al., 2004)](https://dl.acm.org/doi/10.1145/1015330.1015432) — greedy ensemble pruning. +- [Popular Ensemble Methods: An Empirical Study (Opitz & Maclin, 1999)](https://www.jair.org/index.php/jair/article/view/10239) — why diversity drives ensemble gains. diff --git a/projects/data-science/advanced/10-multi-model-ensemble/README.pt-BR.md b/projects/data-science/advanced/10-multi-model-ensemble/README.pt-BR.md new file mode 100644 index 0000000..02d1a7b --- /dev/null +++ b/projects/data-science/advanced/10-multi-model-ensemble/README.pt-BR.md @@ -0,0 +1,106 @@ +# Sistema de Ensemble Multi-Modelo + +> 🌐 [English](./README.md) · **Português** + +**Domínio:** Data Science · **Nível:** Avançado · **Tempo estimado:** 1–2 semanas + +## Visão Geral + +Construa um sistema que combina vários modelos em um ensemble que supera qualquer um deles sozinho — e, tão importante quanto, sabe quando não supera. Fazer ensemble não é "tirar a média de alguns modelos"; seu poder vem da diversidade, e combinar modelos correlacionados não compra nada enquanto multiplica o custo de inferência. Neste projeto você monta um pool diverso de modelos, implementa estratégias reais de combinação (stacking com meta-learner, blending ponderado, votação), mede a diversidade honestamente e pesa o ganho de acurácia contra a computação e a latência que você paga por ele. A tensão interessante é que o melhor ensemble raramente é "todos eles". + +## Pré-requisitos + +- Domínio sólido de viés–variância e por que erros diversos se cancelam +- Experiência treinando múltiplas famílias de modelos e fazendo validação cruzada adequada +- Entendimento de stacking, blending e o risco de vazamento no meta-learner +- Conforto para medir custo de inferência, não apenas acurácia + +## Objetivos de Aprendizado + +Ao final, você deve ser capaz de: + +- Construir um pool deliberadamente diverso de modelos base e medir sua diversidade +- Implementar stacking com predições out-of-fold para evitar vazamento no meta-learner +- Comparar stacking, blending ponderado e votação na mesma tarefa +- Pesar os ganhos de acurácia do ensemble contra a latência e computação adicionadas +- Podar o ensemble para o subconjunto que carrega a maior parte do benefício + +## Requisitos Funcionais + +1. O sistema deve treinar e gerenciar um pool de ao menos três modelos base diversos. +2. Deve calcular predições out-of-fold para que o meta-learner nunca veja vazamento in-fold. +3. Deve implementar ao menos duas estratégias de combinação (ex.: stacking e blending ponderado). +4. Deve medir a diversidade do ensemble (ex.: discordância par a par ou correlação de erros). +5. Deve reportar o desempenho do ensemble contra o melhor modelo único e uma média ingênua. +6. Deve expor o ensemble atrás de uma interface de predição com a contribuição por modelo visível. +7. Deve suportar a poda do pool para um subconjunto menor com um tradeoff declarado de acurácia/custo. + +## Requisitos Não Funcionais + +- **Acurácia vs custo:** o ganho de acurácia do ensemble deve ser reportado junto de sua latência/computação adicionada. +- **Latência:** a inferência total do ensemble deve permanecer dentro de um orçamento declarado (modelos base podem rodar em paralelo). +- **Reprodutibilidade:** atribuições de fold, sementes e pesos devem reproduzir os resultados reportados. +- **Robustez:** a falha de um modelo base deve degradar o ensemble graciosamente, não quebrá-lo. + +## Marcos Sugeridos + +1. **Marco 1 — Pool diverso:** Treine várias famílias de modelos distintas e meça sua diversidade par a par. +2. **Marco 2 — Stacking:** Gere predições out-of-fold e treine um meta-learner sem vazamento. +3. **Marco 3 — Comparar estratégias:** Adicione blending ponderado e votação; compare contra o melhor-único e a média-ingênua. +4. **Marco 4 — Podar e servir:** Pode para um subconjunto custo-efetivo e sirva com contribuições por modelo. + +## Esboço de Dados e Interface + +```text + dados de treino + | + +--> Modelo A (árvores) \ + +--> Modelo B (boosting) > pool base (diverso!) + +--> Modelo C (rede neural)/ + +--> Modelo D (linear) / + | + v predições out-of-fold (sem vazamento) + +-----------------------------+ + | Matriz de predições OOF | linhas=amostras, cols=modelos base + +--------------+--------------+ + v + +------ combinar (escolha) ----+ + | stacking: meta-learner(OOF) | + | blending: média ponderada | + | votação: maioria/soft | + +--------------+--------------+ + v + diversidade: discordância par a par, matriz de correlação de erros + relatório: ensemble vs melhor-único vs média-ingênua (acc E latência) + + GET /predict -> { prediction, per_model: {A:.., B:..}, weights } +``` + +## Desafios Extras + +- Adicione ponderação dinâmica por instância (escolha especialistas com base na região da entrada). +- Adicione atualização online para que os pesos se adaptem conforme chegam novos dados rotulados. +- Adicione explicabilidade que atribui a predição final de volta aos modelos contribuintes. +- Busque o subconjunto ótimo com um método guloso ou evolutivo de seleção de ensemble. + +## Definição de Pronto + +- [ ] O pool base tem diversidade medida, não apenas múltiplas cópias do mesmo modelo. +- [ ] O stacking usa predições out-of-fold sem vazamento no meta-learner. +- [ ] Ao menos duas estratégias de combinação são comparadas contra as baselines de melhor-único e média-ingênua. +- [ ] Os ganhos de acurácia são reportados junto do custo de latência/computação adicionado. +- [ ] Um subconjunto podado é oferecido com um tradeoff explícito de acurácia-vs-custo. + +## Armadilhas Comuns + +- Construir um ensemble "diverso" de modelos altamente correlacionados que adiciona custo mas nenhuma acurácia. +- Treinar o meta-learner em predições in-fold e vazar, inflando os ganhos aparentes. +- Reportar apenas o ganho de acurácia e esconder que a inferência agora custa 5x mais. +- Assumir que mais modelos é sempre melhor em vez de podar para o subconjunto efetivo. + +## Recursos + +- [scikit-learn: métodos de Ensemble](https://scikit-learn.org/stable/modules/ensemble.html) — APIs e teoria de stacking, votação e boosting. +- [Stacked Generalization (Wolpert, 1992)](https://www.sciencedirect.com/science/article/abs/pii/S0893608005800231) — o paper original de stacking. +- [Ensemble Selection from Libraries of Models (Caruana et al., 2004)](https://dl.acm.org/doi/10.1145/1015330.1015432) — poda gulosa de ensemble. +- [Popular Ensemble Methods: An Empirical Study (Opitz & Maclin, 1999)](https://www.jair.org/index.php/jair/article/view/10239) — por que a diversidade impulsiona os ganhos de ensemble. diff --git a/projects/data-science/beginner/01-data-cleaning-csv/README.md b/projects/data-science/beginner/01-data-cleaning-csv/README.md index 6f090a2..9f33189 100644 --- a/projects/data-science/beginner/01-data-cleaning-csv/README.md +++ b/projects/data-science/beginner/01-data-cleaning-csv/README.md @@ -1,34 +1,92 @@ # Data Cleaning Pipeline (CSV) -## Idea -Create a pipeline to clean and transform raw CSV data. Learn about data quality, handling missing values, and data validation. +> 🌐 **English** · [Português](./README.pt-BR.md) + +**Domain:** Data Science · **Level:** Beginner · **Estimated time:** 3–6 hours + +## Overview + +Raw data is almost never analysis-ready: columns have inconsistent casing, numbers arrive as strings with currency symbols, dates come in five formats, and some rows are duplicated or half-empty. In this project you build a repeatable pipeline that takes a messy CSV and produces a clean, validated one — plus a short report describing exactly what was changed and why. The goal is not a one-off notebook full of manual fixes but a set of ordered, documented steps you can rerun on next month's export and get the same result. + +## Prerequisites + +- Basic Python and familiarity with a dataframe library (pandas or Polars) +- Understanding of common data types (string, integer, float, date, boolean) +- Ability to read a CSV and inspect its columns +- A messy real-world dataset — the [Kaggle Titanic dataset](https://www.kaggle.com/c/titanic/data) or any government open-data CSV works well because it has missing values and mixed types ## Learning Objectives -- Load and explore CSV data -- Handle missing values -- Remove duplicates -- Validate data quality -- Transform and normalize data - -## Implementation Tips -- Load CSV with pandas -- Analyze data structure and types -- Identify and handle missing values (drop, fill, interpolate) -- Remove duplicate rows -- Normalize numeric values -- Handle outliers -- Standardize categorical values -- Validate data constraints -- Create data quality report -- Implement error logging -- Create before/after comparison -- Save cleaned data -- Document transformation steps -- Create reproducible pipeline - -## Key Challenges -- Missing value handling strategy -- Outlier detection and handling -- Data type inconsistencies -- Categorical value standardization -- Pipeline reproducibility + +By the end, you should be able to: + +- Profile a dataset to find missing values, duplicates, and type problems +- Choose and justify a missing-value strategy (drop, fill, interpolate) per column +- Detect outliers with a simple, defensible rule (IQR or z-score) +- Standardize categorical labels and normalize numeric ranges +- Express cleaning as ordered, reproducible steps rather than ad-hoc edits + +## Functional Requirements + +1. The pipeline must load a source CSV and report row count, column count, and dtype per column. +2. It must detect and remove exact duplicate rows, reporting how many were dropped. +3. Each column with missing values must have an explicitly chosen handling strategy, not a silent default. +4. Categorical values must be standardized (e.g. `"USA"`, `"usa"`, `" US "` collapse to one label). +5. At least one numeric column must be checked for outliers using a stated rule. +6. The pipeline must output a cleaned CSV plus a written summary of every transformation applied. +7. Running the pipeline twice on the same input must produce identical output. + +## Suggested Milestones + +1. **Milestone 1 — Profile:** Load the CSV and produce a quality report: shape, dtypes, null counts, duplicate count. +2. **Milestone 2 — Clean:** Apply duplicate removal, missing-value handling, and categorical standardization as discrete steps. +3. **Milestone 3 — Validate & report:** Add outlier and constraint checks, emit the cleaned file, and write a before/after summary. + +## Data & Interface Sketch + +```text +Cleaning report (per column) + name: string + dtype: inferred type + null_count: integer + null_strategy: "drop" | "fill_mean" | "fill_mode" | "interpolate" | "keep" + notes: string + +Pipeline stages (ordered, each rerunnable) + 1. load -> raw dataframe + profile + 2. dedupe -> removes exact-duplicate rows + 3. handle_nulls -> applies per-column strategy + 4. standardize -> trims, lowercases, maps categorical synonyms + 5. validate -> range/constraint checks, outlier flags + 6. save -> cleaned.csv + report.md + +Rows in: N Rows out: M Duplicates removed: N-M +``` + +## Stretch Goals + +- Add a config file (YAML/JSON) that declares per-column rules so the pipeline is data-driven, not hard-coded. +- Emit a data-quality score before and after to quantify improvement. +- Log rejected or quarantined rows to a separate file instead of dropping them silently. +- Add schema validation with a library like Pandera or Great Expectations. + +## Definition of Done + +- [ ] The pipeline turns the raw CSV into a cleaned CSV with no manual edits in between. +- [ ] Every missing-value decision is explicit and recorded in the report. +- [ ] Duplicate and outlier counts appear in the output summary. +- [ ] Categorical labels are consistent across the cleaned column. +- [ ] Running the pipeline twice yields verifiably equal output. + +## Common Pitfalls + +- Filling missing numeric values with the mean before removing outliers, which skews the mean. +- Dropping rows with any null and silently losing most of the dataset — check how much you discard. +- Standardizing categories with a manual list that breaks the moment a new label appears. +- Treating ID or ZIP-code columns as numbers, so leading zeros vanish and math is applied to them. + +## Resources + +- [pandas: Working with missing data](https://pandas.pydata.org/docs/user_guide/missing_data.html) — the canonical guide to `dropna`, `fillna`, and interpolation. +- [scikit-learn: Imputation of missing values](https://scikit-learn.org/stable/modules/impute.html) — strategies beyond simple fills. +- [Wikipedia: Interquartile range](https://en.wikipedia.org/wiki/Interquartile_range) — the IQR rule for outlier detection. +- [Great Expectations docs](https://docs.greatexpectations.io/) — declarative data validation if you take the stretch goal. diff --git a/projects/data-science/beginner/01-data-cleaning-csv/README.pt-BR.md b/projects/data-science/beginner/01-data-cleaning-csv/README.pt-BR.md new file mode 100644 index 0000000..9b1dc1b --- /dev/null +++ b/projects/data-science/beginner/01-data-cleaning-csv/README.pt-BR.md @@ -0,0 +1,92 @@ +# Pipeline de Limpeza de Dados (CSV) + +> 🌐 [English](./README.md) · **Português** + +**Domínio:** Data Science · **Nível:** Iniciante · **Tempo estimado:** 3–6 horas + +## Visão Geral + +Dados brutos quase nunca estão prontos para análise: colunas têm capitalização inconsistente, números chegam como strings com símbolos de moeda, datas vêm em cinco formatos e algumas linhas estão duplicadas ou pela metade. Neste projeto você constrói um pipeline repetível que pega um CSV bagunçado e produz um limpo e validado — além de um relatório curto descrevendo exatamente o que mudou e por quê. O objetivo não é um notebook cheio de correções manuais, mas um conjunto de passos ordenados e documentados que você pode reexecutar na exportação do mês seguinte e obter o mesmo resultado. + +## Pré-requisitos + +- Python básico e familiaridade com uma biblioteca de dataframes (pandas ou Polars) +- Entendimento dos tipos de dados comuns (string, inteiro, float, data, booleano) +- Capacidade de ler um CSV e inspecionar suas colunas +- Um conjunto de dados real e bagunçado — o [dataset Titanic do Kaggle](https://www.kaggle.com/c/titanic/data) ou qualquer CSV de dados abertos governamentais funciona bem por ter valores ausentes e tipos mistos + +## Objetivos de Aprendizado + +Ao final, você deve ser capaz de: + +- Perfilar um conjunto de dados para encontrar valores ausentes, duplicatas e problemas de tipo +- Escolher e justificar uma estratégia de valores ausentes (descartar, preencher, interpolar) por coluna +- Detectar outliers com uma regra simples e defensável (IQR ou z-score) +- Padronizar rótulos categóricos e normalizar faixas numéricas +- Expressar a limpeza como passos ordenados e reprodutíveis em vez de edições ad-hoc + +## Requisitos Funcionais + +1. O pipeline deve carregar um CSV de origem e relatar contagem de linhas, de colunas e dtype por coluna. +2. Deve detectar e remover linhas duplicadas exatas, relatando quantas foram removidas. +3. Cada coluna com valores ausentes deve ter uma estratégia de tratamento escolhida explicitamente, não um padrão silencioso. +4. Valores categóricos devem ser padronizados (ex.: `"USA"`, `"usa"`, `" US "` colapsam para um único rótulo). +5. Ao menos uma coluna numérica deve ser verificada quanto a outliers usando uma regra declarada. +6. O pipeline deve gerar um CSV limpo mais um resumo escrito de toda transformação aplicada. +7. Executar o pipeline duas vezes sobre a mesma entrada deve produzir saída idêntica. + +## Marcos Sugeridos + +1. **Marco 1 — Perfilar:** Carregue o CSV e produza um relatório de qualidade: dimensões, dtypes, contagem de nulos, contagem de duplicatas. +2. **Marco 2 — Limpar:** Aplique remoção de duplicatas, tratamento de valores ausentes e padronização categórica como passos distintos. +3. **Marco 3 — Validar e relatar:** Adicione verificações de outliers e restrições, gere o arquivo limpo e escreva um resumo antes/depois. + +## Esboço de Dados e Interface + +```text +Relatório de limpeza (por coluna) + name: string + dtype: tipo inferido + null_count: inteiro + null_strategy: "drop" | "fill_mean" | "fill_mode" | "interpolate" | "keep" + notes: string + +Estágios do pipeline (ordenados, cada um reexecutável) + 1. load -> dataframe bruto + perfil + 2. dedupe -> remove linhas duplicadas exatas + 3. handle_nulls -> aplica estratégia por coluna + 4. standardize -> trim, lowercase, mapeia sinônimos categóricos + 5. validate -> checagens de faixa/restrição, flags de outlier + 6. save -> cleaned.csv + report.md + +Linhas entrada: N Linhas saída: M Duplicatas removidas: N-M +``` + +## Desafios Extras + +- Adicione um arquivo de configuração (YAML/JSON) que declare regras por coluna para o pipeline ser orientado a dados, não fixo no código. +- Emita uma pontuação de qualidade de dados antes e depois para quantificar a melhoria. +- Registre linhas rejeitadas ou em quarentena em um arquivo separado em vez de descartá-las silenciosamente. +- Adicione validação de esquema com uma biblioteca como Pandera ou Great Expectations. + +## Definição de Pronto + +- [ ] O pipeline transforma o CSV bruto em um CSV limpo sem edições manuais no meio do caminho. +- [ ] Toda decisão de valor ausente é explícita e registrada no relatório. +- [ ] Contagens de duplicatas e outliers aparecem no resumo de saída. +- [ ] Rótulos categóricos são consistentes ao longo da coluna limpa. +- [ ] Executar o pipeline duas vezes produz saída verificavelmente igual. + +## Armadilhas Comuns + +- Preencher valores numéricos ausentes com a média antes de remover outliers, o que distorce a média. +- Descartar linhas com qualquer nulo e perder silenciosamente a maior parte do conjunto — verifique quanto você descarta. +- Padronizar categorias com uma lista manual que quebra no momento em que um novo rótulo aparece. +- Tratar colunas de ID ou CEP como números, fazendo zeros à esquerda sumirem e aplicando matemática a elas. + +## Recursos + +- [pandas: Working with missing data](https://pandas.pydata.org/docs/user_guide/missing_data.html) — o guia canônico de `dropna`, `fillna` e interpolação. +- [scikit-learn: Imputation of missing values](https://scikit-learn.org/stable/modules/impute.html) — estratégias além de preenchimentos simples. +- [Wikipedia: Interquartile range](https://en.wikipedia.org/wiki/Interquartile_range) — a regra IQR para detecção de outliers. +- [Great Expectations docs](https://docs.greatexpectations.io/) — validação declarativa de dados se você encarar o desafio extra. diff --git a/projects/data-science/beginner/02-basic-eda-notebook/README.md b/projects/data-science/beginner/02-basic-eda-notebook/README.md index 54f0a27..e30ba18 100644 --- a/projects/data-science/beginner/02-basic-eda-notebook/README.md +++ b/projects/data-science/beginner/02-basic-eda-notebook/README.md @@ -1,34 +1,90 @@ # Basic EDA Notebook -## Idea -Create an exploratory data analysis notebook with visualizations and statistical summaries. Learn about data exploration and hypothesis generation. +> 🌐 **English** · [Português](./README.pt-BR.md) + +**Domain:** Data Science · **Level:** Beginner · **Estimated time:** 3–6 hours + +## Overview + +Before anyone trains a model, someone has to actually look at the data. Exploratory Data Analysis (EDA) is that first honest look — you describe each variable, plot its distribution, check how features relate, and surface the questions worth asking next. In this project you build an EDA notebook on a dataset of your choice and, crucially, end with written findings a non-technical reader could follow. The deliverable is not a wall of charts but a narrative: here is what the data contains, here is what surprised me, here is what I would investigate further. + +## Prerequisites + +- Basic Python and a dataframe library (pandas) +- A plotting library (Matplotlib or Seaborn) +- Comfort running a Jupyter or Colab notebook +- A tabular dataset with a mix of numeric and categorical columns — the [UCI Adult / Census Income dataset](https://archive.ics.uci.edu/dataset/2/adult) or a Kaggle CSV are good picks ## Learning Objectives -- Load and understand data structure -- Generate statistical summaries -- Create visualizations -- Identify patterns and relationships -- Document findings - -## Implementation Tips -- Load data and check dimensions -- Generate descriptive statistics -- Visualize distributions -- Create correlation matrix -- Plot relationships between variables -- Identify missing values -- Find outliers -- Create categorical summaries -- Build visualizations (histograms, scatter plots, box plots) -- Generate insights and questions -- Create executive summary -- Document methodology -- Include interpretation -- Create reproducible notebook - -## Key Challenges -- Large dataset handling -- Visualization interpretation -- Pattern identification -- Hypothesis formulation -- Result communication + +By the end, you should be able to: + +- Summarize a dataset's shape, types, and descriptive statistics +- Choose the right chart for a variable (histogram, box plot, bar chart, scatter) +- Read a correlation matrix and reason about relationships, not just numbers +- Spot missing values, outliers, and suspicious distributions +- Turn observations into clear, prioritized questions and a written summary + +## Functional Requirements + +1. The notebook must load the dataset and report its dimensions and per-column data types. +2. It must produce descriptive statistics for numeric columns and value counts for categorical ones. +3. It must visualize the distribution of at least three variables with appropriate chart types. +4. It must show relationships between at least two pairs of variables (e.g. scatter or grouped bar). +5. It must include a correlation matrix for numeric features with a short interpretation. +6. It must explicitly report missing values and any outliers found. +7. It must end with a written summary of findings and follow-up questions. + +## Suggested Milestones + +1. **Milestone 1 — Describe:** Load the data, report shape and types, generate descriptive stats and value counts. +2. **Milestone 2 — Visualize:** Plot distributions and relationships; build the correlation matrix. +3. **Milestone 3 — Synthesize:** Document missing values, outliers, and a prioritized list of findings and next questions. + +## Data & Interface Sketch + +```text +Notebook structure (top to bottom) + 1. Setup & load -> df, shape (rows, cols), dtypes + 2. Univariate -> describe() for numerics, value_counts() for categoricals + histograms + box plots + 3. Bivariate -> scatter (num vs num), grouped bar (cat vs num) + 4. Correlation -> numeric correlation matrix + heatmap + 5. Data quality -> null counts per column, outlier notes + 6. Findings -> 3-5 bullet insights + open questions + +Chart-to-question mapping + distribution of one variable -> histogram / box plot + category frequencies -> bar chart + relationship between two nums -> scatter plot + numeric split by category -> grouped/box by group +``` + +## Stretch Goals + +- Add an automated profiling report (ydata-profiling / pandas-profiling) and compare it to your hand-made analysis. +- Formulate one hypothesis and test it with a simple statistical test (t-test or chi-square). +- Add interactive charts with Plotly so a reader can hover and filter. +- Segment the analysis by a key category and compare distributions across segments. + +## Definition of Done + +- [ ] The notebook runs top to bottom without errors on a fresh kernel. +- [ ] Every chart has a title, axis labels, and a one-line takeaway. +- [ ] Missing values and outliers are quantified, not just mentioned. +- [ ] The correlation matrix is interpreted in words, not left as a raw grid. +- [ ] The final summary states findings a non-technical reader could understand. + +## Common Pitfalls + +- Plotting dozens of charts with no narrative, so the reader learns nothing. +- Reading correlation as causation — a strong coefficient is a hint, not a conclusion. +- Using a histogram for a categorical variable or a bar chart for a continuous one. +- Ignoring axis scales, so an outlier flattens every other bar into invisibility. + +## Resources + +- [pandas: Essential basic functionality](https://pandas.pydata.org/docs/user_guide/basics.html) — `describe`, `info`, `value_counts` and friends. +- [Seaborn: Overview of plotting functions](https://seaborn.pydata.org/tutorial/function_overview.html) — picking the right chart. +- [From Data to Viz](https://www.data-to-viz.com/) — a decision tree from data shape to appropriate chart. +- [ydata-profiling docs](https://docs.profiling.ydata.ai/) — automated EDA reports for the stretch goal. diff --git a/projects/data-science/beginner/02-basic-eda-notebook/README.pt-BR.md b/projects/data-science/beginner/02-basic-eda-notebook/README.pt-BR.md new file mode 100644 index 0000000..ad0b6f2 --- /dev/null +++ b/projects/data-science/beginner/02-basic-eda-notebook/README.pt-BR.md @@ -0,0 +1,90 @@ +# Notebook Básico de EDA + +> 🌐 [English](./README.md) · **Português** + +**Domínio:** Data Science · **Nível:** Iniciante · **Tempo estimado:** 3–6 horas + +## Visão Geral + +Antes de alguém treinar um modelo, alguém precisa de fato olhar para os dados. A Análise Exploratória de Dados (EDA) é esse primeiro olhar honesto — você descreve cada variável, plota sua distribuição, verifica como as features se relacionam e levanta as perguntas que valem a pena investigar em seguida. Neste projeto você constrói um notebook de EDA sobre um conjunto de dados à sua escolha e, crucialmente, termina com achados escritos que um leitor não técnico conseguiria acompanhar. A entrega não é uma parede de gráficos, mas uma narrativa: eis o que os dados contêm, eis o que me surpreendeu, eis o que eu investigaria mais a fundo. + +## Pré-requisitos + +- Python básico e uma biblioteca de dataframes (pandas) +- Uma biblioteca de plotagem (Matplotlib ou Seaborn) +- Conforto para rodar um notebook Jupyter ou Colab +- Um conjunto de dados tabular com mistura de colunas numéricas e categóricas — o [dataset Adult / Census Income da UCI](https://archive.ics.uci.edu/dataset/2/adult) ou um CSV do Kaggle são boas escolhas + +## Objetivos de Aprendizado + +Ao final, você deve ser capaz de: + +- Resumir dimensões, tipos e estatísticas descritivas de um conjunto de dados +- Escolher o gráfico certo para uma variável (histograma, box plot, gráfico de barras, dispersão) +- Ler uma matriz de correlação e raciocinar sobre relações, não apenas números +- Identificar valores ausentes, outliers e distribuições suspeitas +- Transformar observações em perguntas claras e priorizadas e em um resumo escrito + +## Requisitos Funcionais + +1. O notebook deve carregar o conjunto de dados e relatar suas dimensões e tipos por coluna. +2. Deve produzir estatísticas descritivas para colunas numéricas e contagens de valores para as categóricas. +3. Deve visualizar a distribuição de ao menos três variáveis com tipos de gráfico apropriados. +4. Deve mostrar relações entre ao menos dois pares de variáveis (ex.: dispersão ou barras agrupadas). +5. Deve incluir uma matriz de correlação para features numéricas com uma interpretação curta. +6. Deve relatar explicitamente valores ausentes e quaisquer outliers encontrados. +7. Deve terminar com um resumo escrito dos achados e perguntas de acompanhamento. + +## Marcos Sugeridos + +1. **Marco 1 — Descrever:** Carregue os dados, relate dimensões e tipos, gere estatísticas descritivas e contagens de valores. +2. **Marco 2 — Visualizar:** Plote distribuições e relações; construa a matriz de correlação. +3. **Marco 3 — Sintetizar:** Documente valores ausentes, outliers e uma lista priorizada de achados e próximas perguntas. + +## Esboço de Dados e Interface + +```text +Estrutura do notebook (de cima para baixo) + 1. Setup e load -> df, dimensões (linhas, colunas), dtypes + 2. Univariada -> describe() para numéricas, value_counts() para categóricas + histogramas + box plots + 3. Bivariada -> dispersão (num vs num), barras agrupadas (cat vs num) + 4. Correlação -> matriz de correlação numérica + heatmap + 5. Qualidade de dados -> contagem de nulos por coluna, notas de outlier + 6. Achados -> 3-5 insights em bullets + perguntas em aberto + +Mapeamento gráfico-para-pergunta + distribuição de uma variável -> histograma / box plot + frequências de categorias -> gráfico de barras + relação entre dois numéricos -> gráfico de dispersão + numérico dividido por categoria -> agrupado/box por grupo +``` + +## Desafios Extras + +- Adicione um relatório de profiling automatizado (ydata-profiling / pandas-profiling) e compare com sua análise feita à mão. +- Formule uma hipótese e teste-a com um teste estatístico simples (teste t ou qui-quadrado). +- Adicione gráficos interativos com Plotly para que o leitor possa passar o mouse e filtrar. +- Segmente a análise por uma categoria-chave e compare distribuições entre segmentos. + +## Definição de Pronto + +- [ ] O notebook roda de cima a baixo sem erros em um kernel novo. +- [ ] Todo gráfico tem título, rótulos de eixo e uma conclusão de uma linha. +- [ ] Valores ausentes e outliers são quantificados, não apenas mencionados. +- [ ] A matriz de correlação é interpretada em palavras, não deixada como uma grade crua. +- [ ] O resumo final expõe achados que um leitor não técnico conseguiria entender. + +## Armadilhas Comuns + +- Plotar dezenas de gráficos sem narrativa, de modo que o leitor não aprende nada. +- Ler correlação como causalidade — um coeficiente forte é uma pista, não uma conclusão. +- Usar um histograma para uma variável categórica ou um gráfico de barras para uma contínua. +- Ignorar as escalas dos eixos, de modo que um outlier achata todas as outras barras até a invisibilidade. + +## Recursos + +- [pandas: Essential basic functionality](https://pandas.pydata.org/docs/user_guide/basics.html) — `describe`, `info`, `value_counts` e afins. +- [Seaborn: Overview of plotting functions](https://seaborn.pydata.org/tutorial/function_overview.html) — escolhendo o gráfico certo. +- [From Data to Viz](https://www.data-to-viz.com/) — uma árvore de decisão da forma dos dados ao gráfico apropriado. +- [ydata-profiling docs](https://docs.profiling.ydata.ai/) — relatórios de EDA automatizados para o desafio extra. diff --git a/projects/data-science/beginner/03-linear-regression/README.md b/projects/data-science/beginner/03-linear-regression/README.md index db350d2..07c50d2 100644 --- a/projects/data-science/beginner/03-linear-regression/README.md +++ b/projects/data-science/beginner/03-linear-regression/README.md @@ -1,34 +1,91 @@ # Linear Regression Model -## Idea -Build a linear regression model to predict continuous values. Learn about model training, evaluation, and interpretation. +> 🌐 **English** · [Português](./README.pt-BR.md) + +**Domain:** Data Science · **Level:** Beginner · **Estimated time:** 3–6 hours + +## Overview + +Linear regression is the "hello world" of predictive modeling, and it is worth doing properly because every habit you form here — splitting data, measuring error honestly, checking assumptions — carries into every model you ever build. In this project you predict a continuous target (house price, fuel efficiency, tip amount) from a handful of features, then interpret what the model learned and how much to trust it. The point is not a high score; it is understanding why the score is what it is and what the coefficients actually mean. + +## Prerequisites + +- Basic Python and pandas +- scikit-learn installed +- Comfort with the idea of features (inputs) and a target (output) +- A regression dataset with a numeric target — the [scikit-learn California Housing dataset](https://scikit-learn.org/stable/modules/generated/sklearn.datasets.fetch_california_housing.html) or the [UCI Auto MPG dataset](https://archive.ics.uci.edu/dataset/9/auto+mpg) work well ## Learning Objectives -- Prepare features and target -- Train regression model -- Evaluate model performance -- Interpret coefficients -- Make predictions - -## Implementation Tips -- Load and explore data -- Feature selection and engineering -- Split data into train/test sets -- Train linear regression model -- Evaluate with metrics (R-squared, RMSE, MAE) -- Create residual plots -- Check assumptions (linearity, normality) -- Interpret model coefficients -- Implement cross-validation -- Handle feature scaling -- Create prediction intervals -- Visualize fitted line -- Document model findings -- Save trained model - -## Key Challenges -- Feature selection -- Handling non-linearity -- Assumption validation -- Overfitting prevention -- Model interpretation + +By the end, you should be able to: + +- Split data into train and test sets and explain why the split matters +- Train a linear regression model and generate predictions +- Evaluate with R², RMSE, and MAE, and explain what each measures +- Read a residual plot to check whether a linear model is appropriate +- Interpret coefficients in the units of the problem, mindful of feature scaling + +## Functional Requirements + +1. The workflow must load the dataset and select a numeric target plus at least three features. +2. It must split data into training and test sets before any model is fit. +3. It must train a linear regression model on the training set only. +4. It must report R², RMSE, and MAE computed on the held-out test set. +5. It must produce a residual plot (predicted vs residuals) and comment on the pattern. +6. It must report and interpret the learned coefficients. +7. It must use k-fold cross-validation to check that the score is stable, not a lucky split. + +## Suggested Milestones + +1. **Milestone 1 — Prepare & split:** Load data, choose target and features, scale if needed, split train/test. +2. **Milestone 2 — Train & evaluate:** Fit the model, predict on the test set, report R²/RMSE/MAE. +3. **Milestone 3 — Diagnose:** Plot residuals, interpret coefficients, run cross-validation for stability. + +## Data & Interface Sketch + +```text +Model I/O + X (features): matrix [n_samples, n_features] (numeric) + y (target): vector [n_samples] (continuous) + prediction: y_hat = intercept + sum(coef_i * x_i) + +Evaluation report + R2: fraction of variance explained (1.0 = perfect, 0 = mean baseline) + RMSE: error in target units, penalizes large misses + MAE: average absolute error in target units + CV: mean +/- std of R2 across k folds + +Residual check + plot(predicted, actual - predicted) + random cloud around 0 -> linear model is reasonable + curve or funnel shape -> non-linearity or heteroscedasticity +``` + +## Stretch Goals + +- Add polynomial features and compare against the plain linear model without overfitting. +- Apply Ridge or Lasso regularization and observe the effect on coefficients. +- Engineer a new feature from existing columns and measure whether it helps. +- Add prediction intervals so each prediction carries an uncertainty range. + +## Definition of Done + +- [ ] The model is trained on training data only and scored on unseen test data. +- [ ] R², RMSE, and MAE are all reported and explained in one sentence each. +- [ ] A residual plot exists and its shape is interpreted. +- [ ] Coefficients are reported in the problem's units, with scaling accounted for. +- [ ] Cross-validation confirms the test score is not a fluke of one split. + +## Common Pitfalls + +- Evaluating on the training set and celebrating a score the model will never repeat. +- Interpreting raw coefficients when features are on wildly different scales. +- Fitting the scaler on the full dataset (leaking test info) instead of on train only. +- Chasing a higher R² while ignoring residuals that clearly show a non-linear relationship. + +## Resources + +- [scikit-learn: Linear Models](https://scikit-learn.org/stable/modules/linear_model.html) — the reference for `LinearRegression`, Ridge, and Lasso. +- [scikit-learn: Cross-validation](https://scikit-learn.org/stable/modules/cross_validation.html) — how and why to use k-fold. +- [Wikipedia: Coefficient of determination (R²)](https://en.wikipedia.org/wiki/Coefficient_of_determination) — what R² does and does not tell you. +- [STAT 501: Regression Methods (Penn State)](https://online.stat.psu.edu/stat501/) — a free, thorough course on regression assumptions. diff --git a/projects/data-science/beginner/03-linear-regression/README.pt-BR.md b/projects/data-science/beginner/03-linear-regression/README.pt-BR.md new file mode 100644 index 0000000..76b69d2 --- /dev/null +++ b/projects/data-science/beginner/03-linear-regression/README.pt-BR.md @@ -0,0 +1,91 @@ +# Modelo de Regressão Linear + +> 🌐 [English](./README.md) · **Português** + +**Domínio:** Data Science · **Nível:** Iniciante · **Tempo estimado:** 3–6 horas + +## Visão Geral + +Regressão linear é o "hello world" da modelagem preditiva, e vale a pena fazê-la direito porque todo hábito que você forma aqui — dividir os dados, medir o erro honestamente, checar as premissas — se propaga para todo modelo que você venha a construir. Neste projeto você prevê um alvo contínuo (preço de imóvel, eficiência de combustível, valor de gorjeta) a partir de um punhado de features, e então interpreta o que o modelo aprendeu e o quanto confiar nele. O objetivo não é uma pontuação alta; é entender por que a pontuação é o que é e o que os coeficientes de fato significam. + +## Pré-requisitos + +- Python básico e pandas +- scikit-learn instalado +- Conforto com a ideia de features (entradas) e um alvo (saída) +- Um conjunto de dados de regressão com alvo numérico — o [dataset California Housing do scikit-learn](https://scikit-learn.org/stable/modules/generated/sklearn.datasets.fetch_california_housing.html) ou o [dataset Auto MPG da UCI](https://archive.ics.uci.edu/dataset/9/auto+mpg) funcionam bem + +## Objetivos de Aprendizado + +Ao final, você deve ser capaz de: + +- Dividir os dados em conjuntos de treino e teste e explicar por que a divisão importa +- Treinar um modelo de regressão linear e gerar previsões +- Avaliar com R², RMSE e MAE, e explicar o que cada um mede +- Ler um gráfico de resíduos para checar se um modelo linear é apropriado +- Interpretar coeficientes nas unidades do problema, atento à escala das features + +## Requisitos Funcionais + +1. O fluxo deve carregar o conjunto de dados e selecionar um alvo numérico mais ao menos três features. +2. Deve dividir os dados em conjuntos de treino e teste antes de qualquer modelo ser ajustado. +3. Deve treinar um modelo de regressão linear apenas no conjunto de treino. +4. Deve relatar R², RMSE e MAE calculados no conjunto de teste separado. +5. Deve produzir um gráfico de resíduos (previsto vs resíduos) e comentar o padrão. +6. Deve relatar e interpretar os coeficientes aprendidos. +7. Deve usar validação cruzada k-fold para checar que a pontuação é estável, não uma divisão de sorte. + +## Marcos Sugeridos + +1. **Marco 1 — Preparar e dividir:** Carregue os dados, escolha alvo e features, escale se necessário, divida treino/teste. +2. **Marco 2 — Treinar e avaliar:** Ajuste o modelo, preveja no conjunto de teste, relate R²/RMSE/MAE. +3. **Marco 3 — Diagnosticar:** Plote resíduos, interprete coeficientes, rode validação cruzada para estabilidade. + +## Esboço de Dados e Interface + +```text +Entrada/Saída do modelo + X (features): matriz [n_amostras, n_features] (numérico) + y (alvo): vetor [n_amostras] (contínuo) + previsão: y_hat = intercepto + soma(coef_i * x_i) + +Relatório de avaliação + R2: fração da variância explicada (1.0 = perfeito, 0 = baseline da média) + RMSE: erro nas unidades do alvo, penaliza erros grandes + MAE: erro absoluto médio nas unidades do alvo + CV: média +/- desvio do R2 ao longo de k folds + +Checagem de resíduos + plot(previsto, real - previsto) + nuvem aleatória em torno de 0 -> modelo linear é razoável + curva ou formato de funil -> não-linearidade ou heterocedasticidade +``` + +## Desafios Extras + +- Adicione features polinomiais e compare com o modelo linear puro sem sobreajustar. +- Aplique regularização Ridge ou Lasso e observe o efeito nos coeficientes. +- Crie uma nova feature a partir de colunas existentes e meça se ela ajuda. +- Adicione intervalos de previsão para que cada previsão carregue uma faixa de incerteza. + +## Definição de Pronto + +- [ ] O modelo é treinado apenas com dados de treino e pontuado com dados de teste não vistos. +- [ ] R², RMSE e MAE são todos relatados e explicados em uma frase cada. +- [ ] Existe um gráfico de resíduos e seu formato é interpretado. +- [ ] Coeficientes são relatados nas unidades do problema, com a escala considerada. +- [ ] A validação cruzada confirma que a pontuação de teste não é acaso de uma única divisão. + +## Armadilhas Comuns + +- Avaliar no conjunto de treino e comemorar uma pontuação que o modelo nunca repetirá. +- Interpretar coeficientes crus quando as features estão em escalas muito diferentes. +- Ajustar o scaler no conjunto de dados completo (vazando info de teste) em vez de apenas no treino. +- Perseguir um R² maior enquanto ignora resíduos que claramente mostram uma relação não-linear. + +## Recursos + +- [scikit-learn: Linear Models](https://scikit-learn.org/stable/modules/linear_model.html) — a referência para `LinearRegression`, Ridge e Lasso. +- [scikit-learn: Cross-validation](https://scikit-learn.org/stable/modules/cross_validation.html) — como e por que usar k-fold. +- [Wikipedia: Coefficient of determination (R²)](https://en.wikipedia.org/wiki/Coefficient_of_determination) — o que o R² diz e o que não diz. +- [STAT 501: Regression Methods (Penn State)](https://online.stat.psu.edu/stat501/) — um curso gratuito e completo sobre premissas de regressão. diff --git a/projects/data-science/beginner/04-classification-iris/README.md b/projects/data-science/beginner/04-classification-iris/README.md index f334cf3..0d53b01 100644 --- a/projects/data-science/beginner/04-classification-iris/README.md +++ b/projects/data-science/beginner/04-classification-iris/README.md @@ -1,34 +1,90 @@ # Classification Model (Iris dataset) -## Idea -Build a classification model using the Iris dataset to predict flower species. Learn about classification algorithms and evaluation metrics. +> 🌐 **English** · [Português](./README.pt-BR.md) + +**Domain:** Data Science · **Level:** Beginner · **Estimated time:** 3–6 hours + +## Overview + +The Iris dataset — 150 flowers, four measurements, three species — is the classic first classification problem, and it is small enough that you can focus entirely on the workflow rather than fighting the data. In this project you train a model to predict a flower's species from its petal and sepal measurements, then evaluate it honestly with a confusion matrix and per-class metrics. Because two of the three species overlap, you also learn that accuracy alone can hide real weaknesses, and that precision and recall tell the fuller story. + +## Prerequisites + +- Basic Python and pandas +- scikit-learn installed +- Understanding of the difference between classification (categories) and regression (numbers) +- The dataset is built in: `sklearn.datasets.load_iris` — see the [scikit-learn Iris reference](https://scikit-learn.org/stable/modules/generated/sklearn.datasets.load_iris.html) ## Learning Objectives -- Prepare classification dataset -- Train classification model -- Evaluate classification performance -- Handle multi-class classification -- Interpret results - -## Implementation Tips -- Load Iris dataset -- Explore data distribution -- Split data into train/test -- Train classifier (Decision Tree, Random Forest, SVM) -- Evaluate with metrics (accuracy, precision, recall, F1) -- Create confusion matrix -- Plot feature importance -- Implement cross-validation -- Tune hyperparameters -- Create ROC curves -- Visualize decision boundaries -- Compare multiple models -- Save trained model -- Create prediction interface - -## Key Challenges -- Class imbalance -- Model comparison -- Hyperparameter tuning -- Feature selection -- Overfitting prevention + +By the end, you should be able to: + +- Frame a multi-class classification problem and prepare labeled data +- Train a classifier (Decision Tree, k-NN, or Random Forest) and predict classes +- Read a confusion matrix to see which classes get confused +- Compute and interpret accuracy, precision, recall, and F1 per class +- Use cross-validation and a train/test split to estimate real-world performance + +## Functional Requirements + +1. The workflow must load the Iris data and inspect class balance and feature ranges. +2. It must split the data into stratified training and test sets. +3. It must train at least one classifier on the training set. +4. It must report accuracy plus per-class precision, recall, and F1 on the test set. +5. It must produce and interpret a confusion matrix. +6. It must use cross-validation to confirm the result is stable. +7. It must compare at least two different classifiers on the same split. + +## Suggested Milestones + +1. **Milestone 1 — Explore & split:** Load Iris, check class balance, do a stratified train/test split. +2. **Milestone 2 — Train & evaluate:** Fit a classifier, build the confusion matrix, report the classification metrics. +3. **Milestone 3 — Compare:** Train a second model, cross-validate both, and explain which you would pick and why. + +## Data & Interface Sketch + +```text +Model I/O + features (X): [sepal_length, sepal_width, petal_length, petal_width] (cm, float) + target (y): species in {setosa, versicolor, virginica} + prediction: one of the three species labels + +Confusion matrix (rows = actual, cols = predicted) + setosa versicolor virginica + setosa 50 0 0 + versicolor 0 47 3 + virginica 0 2 48 + -> setosa is trivially separable; the confusion lives between versicolor & virginica + +Per-class report + precision = TP / (TP + FP) recall = TP / (TP + FN) F1 = harmonic mean +``` + +## Stretch Goals + +- Tune hyperparameters with grid search and report whether it actually helped. +- Reduce to two features and plot the decision boundary to see how the classifier splits space. +- Add one-vs-rest ROC curves and compare AUC across classes. +- Build a tiny prediction interface that takes four measurements and returns a species with confidence. + +## Definition of Done + +- [ ] The train/test split is stratified so class balance is preserved. +- [ ] Accuracy and per-class precision/recall/F1 are all reported. +- [ ] The confusion matrix is shown and its off-diagonal cells are explained. +- [ ] At least two classifiers are compared on the same data. +- [ ] Cross-validation confirms the chosen model's score is stable. + +## Common Pitfalls + +- Judging the model on accuracy alone, missing that one class is systematically confused. +- Doing a non-stratified split so one species is underrepresented in the test set. +- Leaking information by scaling or tuning on the full dataset before the split. +- Overfitting a deep Decision Tree to 150 points and mistaking memorization for skill. + +## Resources + +- [scikit-learn: Iris dataset reference](https://scikit-learn.org/stable/modules/generated/sklearn.datasets.load_iris.html) — the built-in loader and feature description. +- [scikit-learn: Classification metrics](https://scikit-learn.org/stable/modules/model_evaluation.html#classification-metrics) — precision, recall, F1, and the classification report. +- [scikit-learn: Confusion matrix](https://scikit-learn.org/stable/modules/generated/sklearn.metrics.confusion_matrix.html) — how to compute and read it. +- [Google ML Crash Course: Classification](https://developers.google.com/machine-learning/crash-course/classification) — accessible grounding in the metrics. diff --git a/projects/data-science/beginner/04-classification-iris/README.pt-BR.md b/projects/data-science/beginner/04-classification-iris/README.pt-BR.md new file mode 100644 index 0000000..32dc26c --- /dev/null +++ b/projects/data-science/beginner/04-classification-iris/README.pt-BR.md @@ -0,0 +1,90 @@ +# Modelo de Classificação (dataset Iris) + +> 🌐 [English](./README.md) · **Português** + +**Domínio:** Data Science · **Nível:** Iniciante · **Tempo estimado:** 3–6 horas + +## Visão Geral + +O dataset Iris — 150 flores, quatro medidas, três espécies — é o clássico primeiro problema de classificação, e é pequeno o suficiente para você focar inteiramente no fluxo de trabalho em vez de brigar com os dados. Neste projeto você treina um modelo para prever a espécie de uma flor a partir das medidas de pétala e sépala, e então o avalia honestamente com uma matriz de confusão e métricas por classe. Como duas das três espécies se sobrepõem, você também aprende que só a acurácia pode esconder fraquezas reais, e que precisão e recall contam a história mais completa. + +## Pré-requisitos + +- Python básico e pandas +- scikit-learn instalado +- Entendimento da diferença entre classificação (categorias) e regressão (números) +- O conjunto de dados já vem embutido: `sklearn.datasets.load_iris` — veja a [referência Iris do scikit-learn](https://scikit-learn.org/stable/modules/generated/sklearn.datasets.load_iris.html) + +## Objetivos de Aprendizado + +Ao final, você deve ser capaz de: + +- Formular um problema de classificação multiclasse e preparar dados rotulados +- Treinar um classificador (Árvore de Decisão, k-NN ou Random Forest) e prever classes +- Ler uma matriz de confusão para ver quais classes se confundem +- Calcular e interpretar acurácia, precisão, recall e F1 por classe +- Usar validação cruzada e uma divisão treino/teste para estimar o desempenho real + +## Requisitos Funcionais + +1. O fluxo deve carregar os dados Iris e inspecionar o balanceamento de classes e as faixas das features. +2. Deve dividir os dados em conjuntos de treino e teste estratificados. +3. Deve treinar ao menos um classificador no conjunto de treino. +4. Deve relatar acurácia mais precisão, recall e F1 por classe no conjunto de teste. +5. Deve produzir e interpretar uma matriz de confusão. +6. Deve usar validação cruzada para confirmar que o resultado é estável. +7. Deve comparar ao menos dois classificadores diferentes na mesma divisão. + +## Marcos Sugeridos + +1. **Marco 1 — Explorar e dividir:** Carregue Iris, cheque o balanceamento de classes, faça uma divisão treino/teste estratificada. +2. **Marco 2 — Treinar e avaliar:** Ajuste um classificador, construa a matriz de confusão, relate as métricas de classificação. +3. **Marco 3 — Comparar:** Treine um segundo modelo, valide ambos por cruzamento e explique qual escolheria e por quê. + +## Esboço de Dados e Interface + +```text +Entrada/Saída do modelo + features (X): [sepal_length, sepal_width, petal_length, petal_width] (cm, float) + alvo (y): espécie em {setosa, versicolor, virginica} + previsão: um dos três rótulos de espécie + +Matriz de confusão (linhas = real, colunas = previsto) + setosa versicolor virginica + setosa 50 0 0 + versicolor 0 47 3 + virginica 0 2 48 + -> setosa é trivialmente separável; a confusão vive entre versicolor & virginica + +Relatório por classe + precisão = TP / (TP + FP) recall = TP / (TP + FN) F1 = média harmônica +``` + +## Desafios Extras + +- Ajuste hiperparâmetros com grid search e relate se realmente ajudou. +- Reduza a duas features e plote a fronteira de decisão para ver como o classificador divide o espaço. +- Adicione curvas ROC um-contra-todos e compare o AUC entre classes. +- Construa uma pequena interface de previsão que recebe quatro medidas e retorna uma espécie com confiança. + +## Definição de Pronto + +- [ ] A divisão treino/teste é estratificada para preservar o balanceamento de classes. +- [ ] Acurácia e precisão/recall/F1 por classe são todos relatados. +- [ ] A matriz de confusão é mostrada e suas células fora da diagonal são explicadas. +- [ ] Ao menos dois classificadores são comparados nos mesmos dados. +- [ ] A validação cruzada confirma que a pontuação do modelo escolhido é estável. + +## Armadilhas Comuns + +- Julgar o modelo só pela acurácia, sem perceber que uma classe é sistematicamente confundida. +- Fazer uma divisão não estratificada, deixando uma espécie sub-representada no conjunto de teste. +- Vazar informação escalando ou ajustando no conjunto completo antes da divisão. +- Sobreajustar uma Árvore de Decisão profunda a 150 pontos e confundir memorização com habilidade. + +## Recursos + +- [scikit-learn: Iris dataset reference](https://scikit-learn.org/stable/modules/generated/sklearn.datasets.load_iris.html) — o loader embutido e a descrição das features. +- [scikit-learn: Classification metrics](https://scikit-learn.org/stable/modules/model_evaluation.html#classification-metrics) — precisão, recall, F1 e o relatório de classificação. +- [scikit-learn: Confusion matrix](https://scikit-learn.org/stable/modules/generated/sklearn.metrics.confusion_matrix.html) — como computar e ler. +- [Google ML Crash Course: Classification](https://developers.google.com/machine-learning/crash-course/classification) — base acessível sobre as métricas. diff --git a/projects/data-science/beginner/05-visualization-dashboard/README.md b/projects/data-science/beginner/05-visualization-dashboard/README.md index e1e8835..2848d09 100644 --- a/projects/data-science/beginner/05-visualization-dashboard/README.md +++ b/projects/data-science/beginner/05-visualization-dashboard/README.md @@ -1,34 +1,91 @@ # Data Visualization Dashboard -## Idea -Create an interactive dashboard displaying visualizations of a dataset. Learn about visualization libraries and dashboard tools. +> 🌐 **English** · [Português](./README.pt-BR.md) + +**Domain:** Data Science · **Level:** Beginner · **Estimated time:** 3–6 hours + +## Overview + +A static chart answers one question; a dashboard lets a user ask their own. In this project you take a dataset and build a small interactive dashboard where a reader can filter, select, and drill into the data to reach conclusions you did not pre-write. The challenge is restraint: a good dashboard has a clear purpose and three or four well-chosen views, not fifteen charts competing for attention. You will practice choosing the right chart per question, wiring filters to update every view at once, and designing a layout that reads top-to-bottom like an argument. + +## Prerequisites + +- Basic Python and pandas +- A dashboard framework (Streamlit or Dash) and a plotting library (Plotly, Matplotlib, or Seaborn) +- Comfort loading a dataset into a dataframe +- A dataset with categories to filter on and numbers to aggregate — a [Kaggle](https://www.kaggle.com/datasets) sales, weather, or sports CSV works well ## Learning Objectives -- Create multiple visualization types -- Build interactive dashboard -- Implement filtering -- Add interactivity -- Share insights visually - -## Implementation Tips -- Use visualization library (Plotly, Matplotlib, Seaborn) -- Create various chart types -- Implement dashboard framework (Streamlit, Dash, Jupyter) -- Add filters and selectors -- Create responsive layouts -- Add hover information -- Implement drill-down -- Create KPI cards -- Add export functionality -- Implement color schemes -- Create linked visualizations -- Add annotations -- Create documentation -- Deploy dashboard - -## Key Challenges -- Dashboard responsiveness -- Real-time data updates -- Interactivity complexity -- Color and design choices -- Performance optimization + +By the end, you should be able to: + +- Define a dashboard's single purpose and the questions it should answer +- Match each question to an appropriate chart type +- Wire interactive filters that update multiple linked views together +- Aggregate data on the fly in response to user selections +- Lay out KPI summaries and charts so the story reads clearly + +## Functional Requirements + +1. The dashboard must load a dataset and display at least three distinct chart types. +2. It must provide at least one filter (dropdown, slider, or date range) that updates the views. +3. Changing a filter must update every affected chart, not just one. +4. It must show at least two summary KPI figures (totals, averages, counts). +5. Charts must have titles, axis labels, and readable legends. +6. The layout must group related views and read in a sensible order. +7. It must handle an empty filter result gracefully (no crash, a clear message). + +## Suggested Milestones + +1. **Milestone 1 — Static views:** Load the data and render the core charts and KPIs without interactivity. +2. **Milestone 2 — Interactivity:** Add filters and wire them so all views update from the same selection. +3. **Milestone 3 — Polish:** Arrange the layout, handle empty states, and add hover detail or annotations. + +## Data & Interface Sketch + +```text +Dashboard layout + +-----------------------------------------------------+ + | Title + one-line purpose | + | [Filter: category v] [Filter: date range] | + +------------------+----------------+-----------------+ + | KPI: total | KPI: average | KPI: count | + +------------------+----------------+-----------------+ + | Trend chart (line, time on x) | + +-----------------------------------------------------+ + | Breakdown (bar) | Distribution (histogram/box) | + +-----------------------------------------------------+ + +Interaction model + filter change -> re-query dataframe -> recompute KPIs -> redraw all charts + empty result -> show "No data for this selection" instead of blank charts +``` + +## Stretch Goals + +- Add drill-down: clicking a bar filters the other charts to that segment. +- Add an export button that downloads the currently filtered data as CSV. +- Add a date-range comparison (this period vs previous) with delta indicators. +- Deploy the dashboard publicly (Streamlit Community Cloud or similar) and share the link. + +## Definition of Done + +- [ ] The dashboard has a stated purpose and three or more chart types. +- [ ] At least one filter updates every dependent view simultaneously. +- [ ] KPIs recompute correctly when filters change. +- [ ] Every chart is labeled and legible without explanation. +- [ ] An empty filter selection shows a message, not a crash or blank screen. + +## Common Pitfalls + +- Cramming in every chart you can make instead of the few that serve the purpose. +- Filters that update one chart but leave the KPIs or other views stale. +- Recomputing the full dataset on every keystroke, making the dashboard sluggish. +- Color choices that look nice but encode nothing, or that fail for colorblind users. + +## Resources + +- [Streamlit documentation](https://docs.streamlit.io/) — the fastest way to a Python dashboard. +- [Plotly Python graphing library](https://plotly.com/python/) — interactive charts with built-in hover and zoom. +- [Dash documentation](https://dash.plotly.com/) — a more customizable dashboard framework. +- [Google Material: Data visualization](https://m2.material.io/design/communication/data-visualization.html) — layout and color guidance. diff --git a/projects/data-science/beginner/05-visualization-dashboard/README.pt-BR.md b/projects/data-science/beginner/05-visualization-dashboard/README.pt-BR.md new file mode 100644 index 0000000..fd5d3a1 --- /dev/null +++ b/projects/data-science/beginner/05-visualization-dashboard/README.pt-BR.md @@ -0,0 +1,91 @@ +# Dashboard de Visualização de Dados + +> 🌐 [English](./README.md) · **Português** + +**Domínio:** Data Science · **Nível:** Iniciante · **Tempo estimado:** 3–6 horas + +## Visão Geral + +Um gráfico estático responde a uma pergunta; um dashboard deixa o usuário fazer a própria. Neste projeto você pega um conjunto de dados e constrói um pequeno dashboard interativo onde o leitor pode filtrar, selecionar e aprofundar nos dados para chegar a conclusões que você não pré-escreveu. O desafio é a contenção: um bom dashboard tem um propósito claro e três ou quatro visões bem escolhidas, não quinze gráficos disputando atenção. Você vai praticar escolher o gráfico certo por pergunta, ligar filtros que atualizam todas as visões de uma vez e desenhar um layout que se lê de cima para baixo como um argumento. + +## Pré-requisitos + +- Python básico e pandas +- Um framework de dashboard (Streamlit ou Dash) e uma biblioteca de plotagem (Plotly, Matplotlib ou Seaborn) +- Conforto para carregar um conjunto de dados em um dataframe +- Um conjunto de dados com categorias para filtrar e números para agregar — um CSV de vendas, clima ou esportes do [Kaggle](https://www.kaggle.com/datasets) funciona bem + +## Objetivos de Aprendizado + +Ao final, você deve ser capaz de: + +- Definir o propósito único de um dashboard e as perguntas que ele deve responder +- Associar cada pergunta a um tipo de gráfico apropriado +- Ligar filtros interativos que atualizam múltiplas visões vinculadas juntas +- Agregar dados em tempo real em resposta às seleções do usuário +- Dispor resumos de KPI e gráficos para que a história se leia com clareza + +## Requisitos Funcionais + +1. O dashboard deve carregar um conjunto de dados e exibir ao menos três tipos distintos de gráfico. +2. Deve prover ao menos um filtro (dropdown, slider ou intervalo de datas) que atualize as visões. +3. Mudar um filtro deve atualizar cada gráfico afetado, não apenas um. +4. Deve mostrar ao menos dois números-resumo de KPI (totais, médias, contagens). +5. Gráficos devem ter títulos, rótulos de eixo e legendas legíveis. +6. O layout deve agrupar visões relacionadas e ler em uma ordem sensata. +7. Deve tratar um resultado de filtro vazio com elegância (sem travar, com uma mensagem clara). + +## Marcos Sugeridos + +1. **Marco 1 — Visões estáticas:** Carregue os dados e renderize os gráficos e KPIs principais sem interatividade. +2. **Marco 2 — Interatividade:** Adicione filtros e ligue-os para que todas as visões atualizem a partir da mesma seleção. +3. **Marco 3 — Acabamento:** Organize o layout, trate estados vazios e adicione detalhe no hover ou anotações. + +## Esboço de Dados e Interface + +```text +Layout do dashboard + +-----------------------------------------------------+ + | Título + propósito em uma linha | + | [Filtro: categoria v] [Filtro: intervalo de datas] | + +------------------+----------------+-----------------+ + | KPI: total | KPI: média | KPI: contagem | + +------------------+----------------+-----------------+ + | Gráfico de tendência (linha, tempo no x) | + +-----------------------------------------------------+ + | Decomposição (barra) | Distribuição (histograma/box)| + +-----------------------------------------------------+ + +Modelo de interação + mudança de filtro -> re-consulta dataframe -> recomputa KPIs -> redesenha gráficos + resultado vazio -> mostra "Sem dados para esta seleção" em vez de gráficos em branco +``` + +## Desafios Extras + +- Adicione drill-down: clicar em uma barra filtra os outros gráficos para aquele segmento. +- Adicione um botão de exportação que baixa os dados filtrados atuais como CSV. +- Adicione uma comparação de intervalo de datas (período atual vs anterior) com indicadores de delta. +- Publique o dashboard (Streamlit Community Cloud ou similar) e compartilhe o link. + +## Definição de Pronto + +- [ ] O dashboard tem um propósito declarado e três ou mais tipos de gráfico. +- [ ] Ao menos um filtro atualiza toda visão dependente simultaneamente. +- [ ] KPIs recomputam corretamente quando os filtros mudam. +- [ ] Todo gráfico é rotulado e legível sem explicação. +- [ ] Uma seleção de filtro vazia mostra uma mensagem, não um travamento ou tela em branco. + +## Armadilhas Comuns + +- Enfiar todo gráfico possível em vez dos poucos que servem ao propósito. +- Filtros que atualizam um gráfico mas deixam os KPIs ou outras visões desatualizados. +- Recomputar o conjunto completo a cada tecla, deixando o dashboard lento. +- Escolhas de cor bonitas mas que não codificam nada, ou que falham para usuários daltônicos. + +## Recursos + +- [Streamlit documentation](https://docs.streamlit.io/) — o caminho mais rápido para um dashboard em Python. +- [Plotly Python graphing library](https://plotly.com/python/) — gráficos interativos com hover e zoom embutidos. +- [Dash documentation](https://dash.plotly.com/) — um framework de dashboard mais customizável. +- [Google Material: Data visualization](https://m2.material.io/design/communication/data-visualization.html) — orientação de layout e cor. diff --git a/projects/data-science/beginner/06-recommendation-system/README.md b/projects/data-science/beginner/06-recommendation-system/README.md index ed0bada..539e5b1 100644 --- a/projects/data-science/beginner/06-recommendation-system/README.md +++ b/projects/data-science/beginner/06-recommendation-system/README.md @@ -1,34 +1,92 @@ # Simple Recommendation System -## Idea -Build a basic recommendation system using similarity metrics. Learn about recommendation algorithms and user preferences. +> 🌐 **English** · [Português](./README.pt-BR.md) + +**Domain:** Data Science · **Level:** Beginner · **Estimated time:** 3–6 hours + +## Overview + +"Because you watched X, you might like Y" is powered by a surprisingly approachable idea: find things that are similar and recommend those. In this project you build a basic recommender from a ratings dataset using similarity metrics — either item-to-item ("people who liked this also liked...") or user-to-user ("people like you enjoyed..."). You will build the interaction matrix, compute similarities, generate top-N recommendations, and confront the two problems every recommender faces: what to do about brand-new users or items (cold start) and how to know whether the recommendations are any good. + +## Prerequisites + +- Basic Python and pandas +- NumPy, and ideally scikit-learn for similarity functions +- Understanding of a matrix as rows-by-columns of numbers +- A user-item ratings dataset — the [MovieLens 100K dataset](https://grouplens.org/datasets/movielens/100k/) is the standard choice ## Learning Objectives -- Implement similarity metrics -- Generate recommendations -- Evaluate recommendation quality -- Handle user-item interactions -- Create recommendation pipeline - -## Implementation Tips -- Create user-item interaction matrix -- Implement similarity metrics (cosine, Euclidean) -- Generate item-to-item recommendations -- Implement user-based recommendations -- Create rating predictions -- Evaluate recommendations (precision, recall) -- Handle new users/items -- Add popularity-based recommendations -- Implement hybrid approach -- Create recommendation diversity -- Add explanation for recommendations -- Implement real-time updates -- Create performance optimization -- Build evaluation framework - -## Key Challenges -- Cold start problem -- Sparsity of interaction data -- Scalability -- Recommendation diversity -- Evaluation metrics + +By the end, you should be able to: + +- Build a user-item interaction (ratings) matrix from raw records +- Compute similarity between items or users with cosine similarity +- Generate top-N recommendations from similarity scores +- Reason about the cold-start problem and offer a popularity fallback +- Evaluate recommendations with a held-out set using precision@k or recall@k + +## Functional Requirements + +1. The system must build a user-item matrix from a ratings file. +2. It must compute a similarity score between items (or users) using a stated metric. +3. Given a user or item, it must return the top-N most relevant recommendations. +4. It must exclude items the user has already rated from their recommendations. +5. It must provide a popularity-based fallback for users or items with no history. +6. It must evaluate quality on a held-out test set with precision@k or recall@k. +7. It must attach a short reason to each recommendation ("similar to X you rated highly"). + +## Suggested Milestones + +1. **Milestone 1 — Matrix:** Load ratings and build the user-item matrix, noting how sparse it is. +2. **Milestone 2 — Recommend:** Compute similarities and produce top-N recommendations, excluding seen items. +3. **Milestone 3 — Evaluate & fall back:** Hold out ratings, measure precision@k, and add a cold-start fallback. + +## Data & Interface Sketch + +```text +Interaction matrix (users x items, mostly empty) + item_1 item_2 item_3 ... item_m + user_1 5 - 3 - + user_2 - 4 - 2 + ... (sparse: most cells unrated) + +Recommendation request/response + recommend(user_id, n=5) + -> [ { item_id, score, reason: "similar to you rated 5" }, ... ] + excludes items already rated by user_id + -> if user_id unknown: return top-n most popular items + +Similarity + cosine(a, b) = dot(a, b) / (||a|| * ||b||) in {0..1} for non-negative ratings +Evaluation + precision@k = (relevant items in top-k) / k on held-out ratings +``` + +## Stretch Goals + +- Combine collaborative similarity with a popularity prior into a simple hybrid. +- Add diversity so the top-N is not five near-identical items. +- Compare item-based vs user-based recommendations on the same test set. +- Add matrix factorization (SVD) and compare its precision@k to the similarity approach. + +## Definition of Done + +- [ ] The user-item matrix is built and its sparsity is reported. +- [ ] Recommendations exclude items the user has already rated. +- [ ] A cold-start user receives sensible popularity-based recommendations. +- [ ] Precision@k or recall@k is measured on a held-out set, not the training data. +- [ ] Each recommendation carries a human-readable reason. + +## Common Pitfalls + +- Recommending items the user already rated because you forgot to mask them out. +- Ignoring sparsity — most users rate almost nothing, so naive similarity is noisy. +- Evaluating on the same ratings used to build the matrix, inflating the score. +- Letting a few blockbuster items dominate every recommendation list. + +## Resources + +- [MovieLens datasets (GroupLens)](https://grouplens.org/datasets/movielens/) — the classic ratings data. +- [scikit-learn: Pairwise metrics (cosine similarity)](https://scikit-learn.org/stable/modules/metrics.html#cosine-similarity) — computing similarity efficiently. +- [Google: Recommendation Systems crash course](https://developers.google.com/machine-learning/recommendation) — collaborative filtering and cold start explained. +- [Wikipedia: Collaborative filtering](https://en.wikipedia.org/wiki/Collaborative_filtering) — the concepts behind item- and user-based methods. diff --git a/projects/data-science/beginner/06-recommendation-system/README.pt-BR.md b/projects/data-science/beginner/06-recommendation-system/README.pt-BR.md new file mode 100644 index 0000000..0a03707 --- /dev/null +++ b/projects/data-science/beginner/06-recommendation-system/README.pt-BR.md @@ -0,0 +1,92 @@ +# Sistema de Recomendação Simples + +> 🌐 [English](./README.md) · **Português** + +**Domínio:** Data Science · **Nível:** Iniciante · **Tempo estimado:** 3–6 horas + +## Visão Geral + +"Porque você assistiu X, talvez goste de Y" é movido por uma ideia surpreendentemente acessível: encontre coisas parecidas e recomende-as. Neste projeto você constrói um recomendador básico a partir de um conjunto de dados de avaliações usando métricas de similaridade — item-a-item ("quem gostou disto também gostou de...") ou usuário-a-usuário ("pessoas como você curtiram..."). Você vai construir a matriz de interação, calcular similaridades, gerar recomendações top-N e enfrentar os dois problemas de todo recomendador: o que fazer com usuários ou itens novos (cold start) e como saber se as recomendações prestam. + +## Pré-requisitos + +- Python básico e pandas +- NumPy e, idealmente, scikit-learn para funções de similaridade +- Entendimento de uma matriz como linhas-por-colunas de números +- Um conjunto de avaliações usuário-item — o [dataset MovieLens 100K](https://grouplens.org/datasets/movielens/100k/) é a escolha padrão + +## Objetivos de Aprendizado + +Ao final, você deve ser capaz de: + +- Construir uma matriz de interação (avaliações) usuário-item a partir de registros brutos +- Calcular similaridade entre itens ou usuários com similaridade de cosseno +- Gerar recomendações top-N a partir dos escores de similaridade +- Raciocinar sobre o problema de cold start e oferecer um fallback por popularidade +- Avaliar recomendações com um conjunto separado usando precision@k ou recall@k + +## Requisitos Funcionais + +1. O sistema deve construir uma matriz usuário-item a partir de um arquivo de avaliações. +2. Deve calcular um escore de similaridade entre itens (ou usuários) usando uma métrica declarada. +3. Dado um usuário ou item, deve retornar as top-N recomendações mais relevantes. +4. Deve excluir das recomendações os itens que o usuário já avaliou. +5. Deve prover um fallback baseado em popularidade para usuários ou itens sem histórico. +6. Deve avaliar a qualidade em um conjunto de teste separado com precision@k ou recall@k. +7. Deve anexar uma razão curta a cada recomendação ("parecido com X que você avaliou alto"). + +## Marcos Sugeridos + +1. **Marco 1 — Matriz:** Carregue avaliações e construa a matriz usuário-item, notando o quão esparsa ela é. +2. **Marco 2 — Recomendar:** Calcule similaridades e produza recomendações top-N, excluindo itens já vistos. +3. **Marco 3 — Avaliar e fallback:** Separe avaliações, meça precision@k e adicione um fallback de cold start. + +## Esboço de Dados e Interface + +```text +Matriz de interação (usuários x itens, majoritariamente vazia) + item_1 item_2 item_3 ... item_m + user_1 5 - 3 - + user_2 - 4 - 2 + ... (esparsa: a maioria das células sem avaliação) + +Requisição/resposta de recomendação + recommend(user_id, n=5) + -> [ { item_id, score, reason: "parecido com que você avaliou 5" }, ... ] + exclui itens já avaliados por user_id + -> se user_id desconhecido: retorna os top-n itens mais populares + +Similaridade + cosseno(a, b) = dot(a, b) / (||a|| * ||b||) em {0..1} para avaliações não-negativas +Avaliação + precision@k = (itens relevantes no top-k) / k nas avaliações separadas +``` + +## Desafios Extras + +- Combine similaridade colaborativa com um prior de popularidade em um híbrido simples. +- Adicione diversidade para que o top-N não seja cinco itens quase idênticos. +- Compare recomendações baseadas em item vs em usuário no mesmo conjunto de teste. +- Adicione fatoração de matriz (SVD) e compare seu precision@k com a abordagem de similaridade. + +## Definição de Pronto + +- [ ] A matriz usuário-item é construída e sua esparsidade é relatada. +- [ ] As recomendações excluem itens que o usuário já avaliou. +- [ ] Um usuário em cold start recebe recomendações sensatas baseadas em popularidade. +- [ ] Precision@k ou recall@k é medido em um conjunto separado, não nos dados de treino. +- [ ] Cada recomendação carrega uma razão legível por humanos. + +## Armadilhas Comuns + +- Recomendar itens que o usuário já avaliou por esquecer de mascará-los. +- Ignorar a esparsidade — a maioria dos usuários avalia quase nada, então similaridade ingênua é ruidosa. +- Avaliar nas mesmas avaliações usadas para construir a matriz, inflando a pontuação. +- Deixar alguns itens campeões dominarem toda lista de recomendação. + +## Recursos + +- [MovieLens datasets (GroupLens)](https://grouplens.org/datasets/movielens/) — os dados clássicos de avaliações. +- [scikit-learn: Pairwise metrics (cosine similarity)](https://scikit-learn.org/stable/modules/metrics.html#cosine-similarity) — calculando similaridade de forma eficiente. +- [Google: Recommendation Systems crash course](https://developers.google.com/machine-learning/recommendation) — filtragem colaborativa e cold start explicados. +- [Wikipedia: Collaborative filtering](https://en.wikipedia.org/wiki/Collaborative_filtering) — os conceitos por trás dos métodos item- e usuário-baseados. diff --git a/projects/data-science/beginner/07-sentiment-analysis/README.md b/projects/data-science/beginner/07-sentiment-analysis/README.md index 1d696b1..2dafc5e 100644 --- a/projects/data-science/beginner/07-sentiment-analysis/README.md +++ b/projects/data-science/beginner/07-sentiment-analysis/README.md @@ -1,34 +1,90 @@ # Text Sentiment Analysis -## Idea -Create a sentiment analysis model to classify text as positive, negative, or neutral. Learn about NLP and text classification. +> 🌐 **English** · [Português](./README.pt-BR.md) + +**Domain:** Data Science · **Level:** Beginner · **Estimated time:** 3–6 hours + +## Overview + +Sentiment analysis turns free text — a review, a tweet, a support ticket — into a label like positive or negative. It is a gentle first step into Natural Language Processing because the pipeline is concrete: clean the text, turn words into numbers, train a classifier, and check where it goes wrong. In this project you build that end-to-end on a labeled dataset of reviews, and you spend real time on the failure cases, because the interesting lessons in NLP live in the misclassifications — negation, sarcasm, and domain-specific slang that a bag-of-words model simply cannot see. + +## Prerequisites + +- Basic Python and pandas +- scikit-learn installed +- Understanding of what a classifier does (maps features to a label) +- A labeled text dataset — the [IMDb movie reviews](https://ai.stanford.edu/~amaas/data/sentiment/) or the [UCI Sentiment Labelled Sentences dataset](https://archive.ics.uci.edu/dataset/331/sentiment+labelled+sentences) are good choices ## Learning Objectives -- Preprocess text data -- Extract text features -- Train sentiment classifier -- Evaluate model -- Make predictions on new text - -## Implementation Tips -- Load text dataset with labels -- Implement text preprocessing (lowercasing, tokenization, stopword removal) -- Extract features (TF-IDF, word embeddings) -- Train classifier (Naive Bayes, Logistic Regression, SVM) -- Evaluate with metrics (accuracy, precision, recall) -- Create confusion matrix -- Analyze misclassifications -- Implement cross-validation -- Handle class imbalance -- Create prediction confidence -- Add explainability -- Deploy prediction API -- Test on real-world text -- Create visualization of results - -## Key Challenges -- Text preprocessing complexity -- Feature extraction methods -- Class imbalance -- Negation handling -- Sarcasm detection + +By the end, you should be able to: + +- Preprocess raw text (lowercasing, tokenization, stopword handling) +- Convert text into numeric features with a bag-of-words or TF-IDF representation +- Train and evaluate a text classifier (Naive Bayes or Logistic Regression) +- Inspect misclassifications to understand model limitations +- Explain why a linear bag-of-words model struggles with negation and sarcasm + +## Functional Requirements + +1. The workflow must load a labeled text dataset and report class balance. +2. It must apply a documented preprocessing pipeline to the raw text. +3. It must vectorize the text into numeric features (bag-of-words or TF-IDF). +4. It must train a classifier and evaluate it on a held-out test set. +5. It must report accuracy, precision, recall, and F1, plus a confusion matrix. +6. It must surface and discuss at least three misclassified examples. +7. It must predict the sentiment of a new, hand-written sentence. + +## Suggested Milestones + +1. **Milestone 1 — Preprocess & vectorize:** Clean the text and turn it into a TF-IDF feature matrix. +2. **Milestone 2 — Train & evaluate:** Fit a classifier, report metrics, and build the confusion matrix. +3. **Milestone 3 — Error analysis:** Examine misclassifications, identify patterns, and test on your own sentences. + +## Data & Interface Sketch + +```text +Model pipeline (text -> label) + raw text "This movie was NOT good at all." + -> preprocess lowercase, strip punctuation, tokenize, (optional) remove stopwords + -> vectorize TF-IDF -> sparse vector [n_features] + -> classify -> label in {positive, negative} (+ probability) + +Data shape + input: { text: string, label: "positive" | "negative" } + vector: each token -> a weighted column; document -> a row of weights + +Error-analysis table + text | true | predicted | likely cause + "not good at all" | negative | positive | negation lost in bag-of-words + "yeah, great, another bug" | negative | positive | sarcasm +``` + +## Stretch Goals + +- Add bigrams so "not good" becomes a single feature and compare the metrics. +- Compare TF-IDF against simple word counts on the same classifier. +- Add a probability threshold so low-confidence predictions are marked "uncertain". +- Try a pretrained sentiment model (e.g. a Hugging Face pipeline) and compare it to your own. + +## Definition of Done + +- [ ] The preprocessing steps are documented and applied consistently to train and test. +- [ ] Text is vectorized and a classifier is trained on the training split only. +- [ ] Accuracy, precision, recall, F1, and a confusion matrix are all reported. +- [ ] At least three misclassifications are shown with a plausible explanation. +- [ ] The model classifies a new hand-written sentence end to end. + +## Common Pitfalls + +- Fitting the vectorizer on the full dataset, leaking test vocabulary into training. +- Removing stopwords blindly — "not" and "no" carry the sentiment you care about. +- Reporting only accuracy on an imbalanced dataset that a constant guess would beat. +- Expecting a bag-of-words model to catch sarcasm or word order it fundamentally ignores. + +## Resources + +- [scikit-learn: Working with text data](https://scikit-learn.org/stable/tutorial/text_analytics/working_with_text_data.html) — the canonical text-classification tutorial. +- [scikit-learn: TfidfVectorizer](https://scikit-learn.org/stable/modules/generated/sklearn.feature_extraction.text.TfidfVectorizer.html) — turning text into features. +- [NLTK Book, Chapter 6: Text Classification](https://www.nltk.org/book/ch06.html) — preprocessing and classification fundamentals. +- [Hugging Face: Sentiment analysis pipeline](https://huggingface.co/docs/transformers/main/en/quicktour) — a pretrained baseline for the stretch goal. diff --git a/projects/data-science/beginner/07-sentiment-analysis/README.pt-BR.md b/projects/data-science/beginner/07-sentiment-analysis/README.pt-BR.md new file mode 100644 index 0000000..97d2bc6 --- /dev/null +++ b/projects/data-science/beginner/07-sentiment-analysis/README.pt-BR.md @@ -0,0 +1,90 @@ +# Análise de Sentimento em Texto + +> 🌐 [English](./README.md) · **Português** + +**Domínio:** Data Science · **Nível:** Iniciante · **Tempo estimado:** 3–6 horas + +## Visão Geral + +Análise de sentimento transforma texto livre — uma avaliação, um tuíte, um ticket de suporte — em um rótulo como positivo ou negativo. É um primeiro passo suave no Processamento de Linguagem Natural porque o pipeline é concreto: limpe o texto, transforme palavras em números, treine um classificador e veja onde ele erra. Neste projeto você constrói isso de ponta a ponta sobre um conjunto rotulado de avaliações, e dedica tempo de verdade aos casos de erro, porque as lições interessantes de PLN vivem nas classificações erradas — negação, sarcasmo e gírias de domínio que um modelo bag-of-words simplesmente não enxerga. + +## Pré-requisitos + +- Python básico e pandas +- scikit-learn instalado +- Entendimento do que um classificador faz (mapeia features a um rótulo) +- Um conjunto de texto rotulado — as [avaliações de filmes do IMDb](https://ai.stanford.edu/~amaas/data/sentiment/) ou o [dataset Sentiment Labelled Sentences da UCI](https://archive.ics.uci.edu/dataset/331/sentiment+labelled+sentences) são boas escolhas + +## Objetivos de Aprendizado + +Ao final, você deve ser capaz de: + +- Pré-processar texto bruto (minúsculas, tokenização, tratamento de stopwords) +- Converter texto em features numéricas com uma representação bag-of-words ou TF-IDF +- Treinar e avaliar um classificador de texto (Naive Bayes ou Regressão Logística) +- Inspecionar classificações erradas para entender as limitações do modelo +- Explicar por que um modelo linear bag-of-words tropeça em negação e sarcasmo + +## Requisitos Funcionais + +1. O fluxo deve carregar um conjunto de texto rotulado e relatar o balanceamento de classes. +2. Deve aplicar um pipeline de pré-processamento documentado ao texto bruto. +3. Deve vetorizar o texto em features numéricas (bag-of-words ou TF-IDF). +4. Deve treinar um classificador e avaliá-lo em um conjunto de teste separado. +5. Deve relatar acurácia, precisão, recall e F1, além de uma matriz de confusão. +6. Deve trazer à tona e discutir ao menos três exemplos classificados errado. +7. Deve prever o sentimento de uma nova frase escrita à mão. + +## Marcos Sugeridos + +1. **Marco 1 — Pré-processar e vetorizar:** Limpe o texto e transforme-o em uma matriz de features TF-IDF. +2. **Marco 2 — Treinar e avaliar:** Ajuste um classificador, relate métricas e construa a matriz de confusão. +3. **Marco 3 — Análise de erros:** Examine classificações erradas, identifique padrões e teste com suas próprias frases. + +## Esboço de Dados e Interface + +```text +Pipeline do modelo (texto -> rótulo) + texto bruto "This movie was NOT good at all." + -> preprocess minúsculas, remove pontuação, tokeniza, (opcional) remove stopwords + -> vetoriza TF-IDF -> vetor esparso [n_features] + -> classifica -> rótulo em {positive, negative} (+ probabilidade) + +Formato dos dados + entrada: { text: string, label: "positive" | "negative" } + vetor: cada token -> uma coluna ponderada; documento -> uma linha de pesos + +Tabela de análise de erros + texto | real | previsto | causa provável + "not good at all" | negative | positive | negação perdida no bag-of-words + "yeah, great, another bug" | negative | positive | sarcasmo +``` + +## Desafios Extras + +- Adicione bigramas para que "not good" vire uma única feature e compare as métricas. +- Compare TF-IDF com contagens simples de palavras no mesmo classificador. +- Adicione um limiar de probabilidade para marcar previsões de baixa confiança como "incerto". +- Experimente um modelo de sentimento pré-treinado (ex.: um pipeline do Hugging Face) e compare com o seu. + +## Definição de Pronto + +- [ ] Os passos de pré-processamento estão documentados e aplicados de forma consistente ao treino e ao teste. +- [ ] O texto é vetorizado e um classificador é treinado apenas na divisão de treino. +- [ ] Acurácia, precisão, recall, F1 e uma matriz de confusão são todos relatados. +- [ ] Ao menos três classificações erradas são mostradas com uma explicação plausível. +- [ ] O modelo classifica uma nova frase escrita à mão de ponta a ponta. + +## Armadilhas Comuns + +- Ajustar o vetorizador no conjunto completo, vazando vocabulário de teste para o treino. +- Remover stopwords cegamente — "not" e "no" carregam o sentimento que você quer. +- Relatar só acurácia em um conjunto desbalanceado que um chute constante venceria. +- Esperar que um modelo bag-of-words capture sarcasmo ou ordem de palavras que ele fundamentalmente ignora. + +## Recursos + +- [scikit-learn: Working with text data](https://scikit-learn.org/stable/tutorial/text_analytics/working_with_text_data.html) — o tutorial canônico de classificação de texto. +- [scikit-learn: TfidfVectorizer](https://scikit-learn.org/stable/modules/generated/sklearn.feature_extraction.text.TfidfVectorizer.html) — transformando texto em features. +- [NLTK Book, Chapter 6: Text Classification](https://www.nltk.org/book/ch06.html) — fundamentos de pré-processamento e classificação. +- [Hugging Face: Sentiment analysis pipeline](https://huggingface.co/docs/transformers/main/en/quicktour) — um baseline pré-treinado para o desafio extra. diff --git a/projects/data-science/beginner/08-dataset-comparison/README.md b/projects/data-science/beginner/08-dataset-comparison/README.md index b1bd0ad..7756061 100644 --- a/projects/data-science/beginner/08-dataset-comparison/README.md +++ b/projects/data-science/beginner/08-dataset-comparison/README.md @@ -1,34 +1,90 @@ # Dataset Comparison Tool -## Idea -Create a tool to compare and analyze differences between datasets. Learn about dataset profiling and comparison techniques. +> 🌐 **English** · [Português](./README.pt-BR.md) + +**Domain:** Data Science · **Level:** Beginner · **Estimated time:** 3–6 hours + +## Overview + +When a data pipeline breaks silently, the symptom is usually a dataset that quietly changed shape: a column dropped, a distribution shifted, nulls crept in. In this project you build a tool that takes two datasets — think "last month vs this month" or "training data vs production data" — and reports exactly how they differ. It profiles each one, compares schemas and statistics side by side, flags distribution drift, and produces a readable report. This is the foundation of data monitoring and validation, and it teaches you to describe a dataset precisely enough to notice when it changes. + +## Prerequisites + +- Basic Python and pandas +- Basic descriptive statistics (mean, median, standard deviation, quantiles) +- Understanding of a dataset's schema (column names and types) +- Two related datasets to compare — two snapshots of the same [Kaggle](https://www.kaggle.com/datasets) dataset over time, or a dataset you deliberately split and perturb ## Learning Objectives -- Profile multiple datasets -- Compare distributions -- Identify differences -- Visualize comparisons -- Generate reports - -## Implementation Tips -- Load multiple datasets -- Create data profiling for each -- Compare statistical summaries -- Visualize distribution differences -- Identify missing value patterns -- Compare data types -- Analyze shape differences -- Create correlation comparisons -- Generate comparison report -- Create side-by-side visualizations -- Implement statistical tests -- Add filtering options -- Create exportable reports -- Build interactive comparison tool - -## Key Challenges -- Handling different schemas -- Large dataset comparison -- Visualization clarity -- Statistical test selection -- Report generation + +By the end, you should be able to: + +- Profile a dataset into a compact, comparable summary +- Compare two schemas and detect added, removed, or retyped columns +- Compare distributions of shared columns and quantify drift +- Choose a simple statistical test to check whether two samples differ +- Generate a clear side-by-side comparison report + +## Functional Requirements + +1. The tool must load two datasets and profile each (shape, columns, dtypes, null rates). +2. It must report schema differences: columns only in A, only in B, and type mismatches. +3. For shared numeric columns, it must compare summary statistics side by side. +4. It must flag columns whose distribution has shifted beyond a chosen threshold. +5. It must apply at least one statistical test (e.g. Kolmogorov–Smirnov or chi-square) to a shared column. +6. It must handle datasets with partially overlapping columns without crashing. +7. It must output a single readable comparison report. + +## Suggested Milestones + +1. **Milestone 1 — Profile:** Build a profiling summary for each dataset independently. +2. **Milestone 2 — Compare:** Diff the schemas and put shared-column statistics side by side. +3. **Milestone 3 — Detect drift & report:** Add a distribution test, flag drift, and assemble the report. + +## Data & Interface Sketch + +```text +Per-dataset profile + rows, cols + per column: { name, dtype, null_rate, n_unique, mean?, std?, min?, max? } + +Comparison output + schema diff + only_in_A: [ ... ] + only_in_B: [ ... ] + type_change: [ { col, type_A, type_B } ] + shared numeric columns (side by side) + col mean_A mean_B std_A std_B null_A null_B drift? + age 38.1 41.7 11.2 12.9 0.0% 3.4% YES + distribution test + KS(col) -> statistic, p_value -> "distributions differ" if p < 0.05 +``` + +## Stretch Goals + +- Add a numeric "difference score" per column and rank columns by how much they changed. +- Visualize overlaid distributions for the most-drifted columns. +- Compare categorical columns by value-frequency shift, not just presence. +- Wrap the tool so it can run on a schedule and alert when drift exceeds a threshold. + +## Definition of Done + +- [ ] Both datasets are profiled with matching summary fields. +- [ ] Schema differences (added, removed, retyped columns) are reported. +- [ ] Shared numeric columns are compared statistic-by-statistic. +- [ ] At least one distribution test is applied and its result interpreted. +- [ ] The tool runs on datasets with only partially overlapping columns. + +## Common Pitfalls + +- Assuming both datasets share every column, then crashing on the first mismatch. +- Comparing means only, missing a variance or shape change that leaves the mean intact. +- Reading a statistical test's p-value as "how big" the difference is (it is not). +- Treating tiny sample-size differences as drift when they are just noise. + +## Resources + +- [pandas: DataFrame.describe](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.describe.html) — the quick statistical profile. +- [SciPy: Kolmogorov–Smirnov test](https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.ks_2samp.html) — comparing two continuous distributions. +- [SciPy: Chi-square test](https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.chi2_contingency.html) — comparing categorical distributions. +- [Evidently AI: Data drift](https://docs.evidentlyai.com/) — how production drift monitoring formalizes this idea. diff --git a/projects/data-science/beginner/08-dataset-comparison/README.pt-BR.md b/projects/data-science/beginner/08-dataset-comparison/README.pt-BR.md new file mode 100644 index 0000000..f829329 --- /dev/null +++ b/projects/data-science/beginner/08-dataset-comparison/README.pt-BR.md @@ -0,0 +1,90 @@ +# Ferramenta de Comparação de Datasets + +> 🌐 [English](./README.md) · **Português** + +**Domínio:** Data Science · **Nível:** Iniciante · **Tempo estimado:** 3–6 horas + +## Visão Geral + +Quando um pipeline de dados quebra silenciosamente, o sintoma costuma ser um conjunto de dados que mudou de forma sem avisar: uma coluna sumiu, uma distribuição deslocou, nulos apareceram. Neste projeto você constrói uma ferramenta que recebe dois conjuntos de dados — pense "mês passado vs este mês" ou "dados de treino vs dados de produção" — e relata exatamente como diferem. Ela perfila cada um, compara esquemas e estatísticas lado a lado, sinaliza deriva (drift) de distribuição e produz um relatório legível. Essa é a base do monitoramento e validação de dados, e ensina você a descrever um conjunto com precisão suficiente para notar quando ele muda. + +## Pré-requisitos + +- Python básico e pandas +- Estatística descritiva básica (média, mediana, desvio padrão, quantis) +- Entendimento do esquema de um conjunto de dados (nomes e tipos de colunas) +- Dois conjuntos de dados relacionados para comparar — dois snapshots do mesmo dataset do [Kaggle](https://www.kaggle.com/datasets) ao longo do tempo, ou um conjunto que você divide e perturba de propósito + +## Objetivos de Aprendizado + +Ao final, você deve ser capaz de: + +- Perfilar um conjunto de dados em um resumo compacto e comparável +- Comparar dois esquemas e detectar colunas adicionadas, removidas ou com tipo alterado +- Comparar distribuições de colunas comuns e quantificar a deriva +- Escolher um teste estatístico simples para checar se duas amostras diferem +- Gerar um relatório de comparação claro, lado a lado + +## Requisitos Funcionais + +1. A ferramenta deve carregar dois conjuntos de dados e perfilar cada um (dimensões, colunas, dtypes, taxa de nulos). +2. Deve relatar diferenças de esquema: colunas só em A, só em B e incompatibilidades de tipo. +3. Para colunas numéricas compartilhadas, deve comparar estatísticas de resumo lado a lado. +4. Deve sinalizar colunas cuja distribuição deslocou além de um limiar escolhido. +5. Deve aplicar ao menos um teste estatístico (ex.: Kolmogorov–Smirnov ou qui-quadrado) a uma coluna compartilhada. +6. Deve tratar conjuntos com colunas parcialmente sobrepostas sem travar. +7. Deve gerar um único relatório de comparação legível. + +## Marcos Sugeridos + +1. **Marco 1 — Perfilar:** Construa um resumo de profiling para cada conjunto independentemente. +2. **Marco 2 — Comparar:** Faça o diff dos esquemas e coloque as estatísticas das colunas comuns lado a lado. +3. **Marco 3 — Detectar deriva e relatar:** Adicione um teste de distribuição, sinalize a deriva e monte o relatório. + +## Esboço de Dados e Interface + +```text +Perfil por dataset + linhas, colunas + por coluna: { name, dtype, null_rate, n_unique, mean?, std?, min?, max? } + +Saída da comparação + diff de esquema + only_in_A: [ ... ] + only_in_B: [ ... ] + type_change: [ { col, type_A, type_B } ] + colunas numéricas compartilhadas (lado a lado) + col mean_A mean_B std_A std_B null_A null_B drift? + age 38.1 41.7 11.2 12.9 0.0% 3.4% YES + teste de distribuição + KS(col) -> estatística, p_value -> "distribuições diferem" se p < 0.05 +``` + +## Desafios Extras + +- Adicione uma "pontuação de diferença" numérica por coluna e ranqueie as colunas pelo quanto mudaram. +- Visualize distribuições sobrepostas para as colunas com maior deriva. +- Compare colunas categóricas pela mudança de frequência de valores, não só pela presença. +- Empacote a ferramenta para rodar em agenda e alertar quando a deriva exceder um limiar. + +## Definição de Pronto + +- [ ] Ambos os conjuntos são perfilados com campos de resumo correspondentes. +- [ ] Diferenças de esquema (colunas adicionadas, removidas, com tipo alterado) são relatadas. +- [ ] Colunas numéricas compartilhadas são comparadas estatística por estatística. +- [ ] Ao menos um teste de distribuição é aplicado e seu resultado interpretado. +- [ ] A ferramenta roda em conjuntos com colunas apenas parcialmente sobrepostas. + +## Armadilhas Comuns + +- Assumir que ambos os conjuntos compartilham toda coluna e travar na primeira incompatibilidade. +- Comparar só médias, perdendo uma mudança de variância ou de forma que deixa a média intacta. +- Ler o p-valor de um teste estatístico como "o quão grande" é a diferença (não é). +- Tratar diferenças minúsculas de tamanho de amostra como deriva quando são só ruído. + +## Recursos + +- [pandas: DataFrame.describe](https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.describe.html) — o perfil estatístico rápido. +- [SciPy: Kolmogorov–Smirnov test](https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.ks_2samp.html) — comparando duas distribuições contínuas. +- [SciPy: Chi-square test](https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.chi2_contingency.html) — comparando distribuições categóricas. +- [Evidently AI: Data drift](https://docs.evidentlyai.com/) — como o monitoramento de deriva em produção formaliza essa ideia. diff --git a/projects/data-science/beginner/09-feature-importance/README.md b/projects/data-science/beginner/09-feature-importance/README.md index df94e08..44d7a5b 100644 --- a/projects/data-science/beginner/09-feature-importance/README.md +++ b/projects/data-science/beginner/09-feature-importance/README.md @@ -1,34 +1,89 @@ # Feature Importance Analysis -## Idea -Analyze which features are most important for model predictions. Learn about feature importance techniques and model interpretation. +> 🌐 **English** · [Português](./README.pt-BR.md) + +**Domain:** Data Science · **Level:** Beginner · **Estimated time:** 3–6 hours + +## Overview + +A model that predicts well but cannot explain itself is a hard sell to anyone who has to act on it. Feature importance is how you answer "which inputs actually drive the prediction?" — and it is trickier than it looks, because different methods can disagree and correlated features can steal each other's credit. In this project you train a model on a tabular dataset, then rank its features using at least two importance methods, compare the rankings, and turn the result into plain-language recommendations. The goal is interpretation you can defend, not a single leaderboard you take on faith. + +## Prerequisites + +- Basic Python, pandas, and scikit-learn +- Having trained at least one model before (see [Linear Regression Model](../03-linear-regression/) or [Classification Model](../04-classification-iris/)) +- Understanding of features and a target +- A tabular dataset with several features — the [UCI Wine Quality dataset](https://archive.ics.uci.edu/dataset/186/wine+quality) or [scikit-learn's diabetes dataset](https://scikit-learn.org/stable/modules/generated/sklearn.datasets.load_diabetes.html) work well ## Learning Objectives -- Calculate feature importance -- Visualize importance rankings -- Understand feature contributions -- Identify key predictors -- Guide feature selection - -## Implementation Tips -- Train predictive model -- Calculate feature importance (model-based, permutation, SHAP) -- Create importance rankings -- Visualize with bar charts -- Analyze feature interactions -- Create partial dependence plots -- Implement SHAP values -- Add feature engineering insights -- Compare importance across models -- Create interpretability report -- Implement feature selection based on importance -- Add confidence intervals -- Document findings -- Create actionable recommendations - -## Key Challenges -- Importance metric selection -- Handling collinearity -- Feature interaction interpretation -- Model-agnostic explanations -- Computational complexity + +By the end, you should be able to: + +- Compute feature importance with more than one method +- Explain how model-based, permutation, and SHAP importances differ +- Recognize how correlated features distort importance rankings +- Visualize and communicate importance clearly +- Translate a ranking into actionable, honestly-hedged recommendations + +## Functional Requirements + +1. The workflow must train a predictive model on a tabular dataset. +2. It must compute feature importance with at least two distinct methods. +3. It must present each ranking as a sorted, labeled bar chart. +4. It must compare the rankings and discuss where and why they disagree. +5. It must identify at least one pair of correlated features and note the effect on importance. +6. It must produce a permutation-importance ranking computed on held-out data. +7. It must end with plain-language recommendations about which features matter. + +## Suggested Milestones + +1. **Milestone 1 — Train:** Fit a model good enough to interpret, and confirm its baseline performance. +2. **Milestone 2 — Rank:** Compute model-based and permutation importance; visualize both. +3. **Milestone 3 — Reconcile:** Compare rankings, inspect correlations, and write the recommendations. + +## Data & Interface Sketch + +```text +Importance methods (all return: feature -> score) + model-based tree feature_importances_ or linear |coef| (fast, can be biased) + permutation shuffle one column, measure performance drop (model-agnostic) + SHAP per-prediction contribution, averaged (detailed, slower) + +Ranking table (compare side by side) + feature model_imp perm_imp rank_agrees? + alcohol 0.28 0.31 yes + density 0.19 0.05 NO <- likely correlated w/ alcohol + citric_acid 0.04 0.03 yes + +Correlation check + corr(density, alcohol) = -0.69 -> importance may be split/stolen between them +``` + +## Stretch Goals + +- Add SHAP values and compare their ranking to permutation importance. +- Add partial dependence plots for the top two features to show direction of effect. +- Drop the lowest-ranked features and check whether performance survives. +- Repeat the analysis with a second model type and see if the top features are stable. + +## Definition of Done + +- [ ] A trained model with a stated baseline score exists to interpret. +- [ ] At least two importance methods are computed and charted. +- [ ] Permutation importance is computed on held-out, not training, data. +- [ ] Disagreements between rankings are explained, including a correlation effect. +- [ ] Recommendations are written in plain language with appropriate caveats. + +## Common Pitfalls + +- Trusting tree-based `feature_importances_` alone — it is biased toward high-cardinality features. +- Computing permutation importance on training data, which rewards memorization. +- Reading importance as causation ("this feature causes the outcome"). +- Splitting importance across two correlated features and concluding both are weak. + +## Resources + +- [scikit-learn: Permutation feature importance](https://scikit-learn.org/stable/modules/permutation_importance.html) — the model-agnostic method and its caveats. +- [scikit-learn: Feature importances caveats](https://scikit-learn.org/stable/auto_examples/inspection/plot_permutation_importance.html) — why impurity-based importance misleads. +- [SHAP documentation](https://shap.readthedocs.io/) — additive per-prediction explanations. +- [Interpretable Machine Learning (Molnar)](https://christophm.github.io/interpretable-ml-book/) — a free book on importance and interpretation. diff --git a/projects/data-science/beginner/09-feature-importance/README.pt-BR.md b/projects/data-science/beginner/09-feature-importance/README.pt-BR.md new file mode 100644 index 0000000..ad1f534 --- /dev/null +++ b/projects/data-science/beginner/09-feature-importance/README.pt-BR.md @@ -0,0 +1,89 @@ +# Análise de Importância de Features + +> 🌐 [English](./README.md) · **Português** + +**Domínio:** Data Science · **Nível:** Iniciante · **Tempo estimado:** 3–6 horas + +## Visão Geral + +Um modelo que prevê bem mas não consegue se explicar é difícil de vender para quem precisa agir sobre ele. Importância de features é como você responde "quais entradas de fato dirigem a previsão?" — e é mais traiçoeiro do que parece, porque métodos diferentes podem discordar e features correlacionadas podem roubar o crédito umas das outras. Neste projeto você treina um modelo em um conjunto tabular, ranqueia suas features com ao menos dois métodos de importância, compara os rankings e transforma o resultado em recomendações em linguagem simples. O objetivo é interpretação que você consiga defender, não um único ranking aceito por fé. + +## Pré-requisitos + +- Python básico, pandas e scikit-learn +- Ter treinado ao menos um modelo antes (veja [Modelo de Regressão Linear](../03-linear-regression/) ou [Modelo de Classificação](../04-classification-iris/)) +- Entendimento de features e um alvo +- Um conjunto tabular com várias features — o [dataset Wine Quality da UCI](https://archive.ics.uci.edu/dataset/186/wine+quality) ou o [dataset diabetes do scikit-learn](https://scikit-learn.org/stable/modules/generated/sklearn.datasets.load_diabetes.html) funcionam bem + +## Objetivos de Aprendizado + +Ao final, você deve ser capaz de: + +- Calcular importância de features com mais de um método +- Explicar como importâncias baseadas em modelo, por permutação e SHAP diferem +- Reconhecer como features correlacionadas distorcem os rankings de importância +- Visualizar e comunicar importância com clareza +- Traduzir um ranking em recomendações acionáveis e honestamente ressalvadas + +## Requisitos Funcionais + +1. O fluxo deve treinar um modelo preditivo em um conjunto tabular. +2. Deve calcular importância de features com ao menos dois métodos distintos. +3. Deve apresentar cada ranking como um gráfico de barras ordenado e rotulado. +4. Deve comparar os rankings e discutir onde e por que discordam. +5. Deve identificar ao menos um par de features correlacionadas e notar o efeito na importância. +6. Deve produzir um ranking de importância por permutação calculado em dados separados. +7. Deve terminar com recomendações em linguagem simples sobre quais features importam. + +## Marcos Sugeridos + +1. **Marco 1 — Treinar:** Ajuste um modelo bom o bastante para interpretar e confirme seu desempenho de baseline. +2. **Marco 2 — Ranquear:** Calcule importância baseada em modelo e por permutação; visualize ambas. +3. **Marco 3 — Reconciliar:** Compare rankings, inspecione correlações e escreva as recomendações. + +## Esboço de Dados e Interface + +```text +Métodos de importância (todos retornam: feature -> escore) + baseada em modelo feature_importances_ de árvore ou |coef| linear (rápida, pode enviesar) + permutação embaralha uma coluna, mede a queda de desempenho (agnóstica ao modelo) + SHAP contribuição por previsão, média (detalhada, mais lenta) + +Tabela de ranking (comparar lado a lado) + feature model_imp perm_imp rank_concorda? + alcohol 0.28 0.31 sim + density 0.19 0.05 NAO <- provavelmente correlacionada c/ alcohol + citric_acid 0.04 0.03 sim + +Checagem de correlação + corr(density, alcohol) = -0.69 -> importância pode ser dividida/roubada entre elas +``` + +## Desafios Extras + +- Adicione valores SHAP e compare seu ranking com a importância por permutação. +- Adicione gráficos de dependência parcial para as duas features do topo para mostrar a direção do efeito. +- Remova as features pior ranqueadas e cheque se o desempenho sobrevive. +- Repita a análise com um segundo tipo de modelo e veja se as features do topo são estáveis. + +## Definição de Pronto + +- [ ] Existe um modelo treinado com uma pontuação de baseline declarada para interpretar. +- [ ] Ao menos dois métodos de importância são calculados e plotados. +- [ ] A importância por permutação é calculada em dados separados, não de treino. +- [ ] Discordâncias entre rankings são explicadas, incluindo um efeito de correlação. +- [ ] As recomendações são escritas em linguagem simples com as ressalvas apropriadas. + +## Armadilhas Comuns + +- Confiar só no `feature_importances_` baseado em árvore — ele é enviesado para features de alta cardinalidade. +- Calcular importância por permutação nos dados de treino, o que recompensa memorização. +- Ler importância como causalidade ("esta feature causa o resultado"). +- Dividir a importância entre duas features correlacionadas e concluir que ambas são fracas. + +## Recursos + +- [scikit-learn: Permutation feature importance](https://scikit-learn.org/stable/modules/permutation_importance.html) — o método agnóstico ao modelo e suas ressalvas. +- [scikit-learn: Feature importances caveats](https://scikit-learn.org/stable/auto_examples/inspection/plot_permutation_importance.html) — por que a importância por impureza engana. +- [SHAP documentation](https://shap.readthedocs.io/) — explicações aditivas por previsão. +- [Interpretable Machine Learning (Molnar)](https://christophm.github.io/interpretable-ml-book/) — um livro gratuito sobre importância e interpretação. diff --git a/projects/data-science/beginner/10-time-series-forecast/README.md b/projects/data-science/beginner/10-time-series-forecast/README.md index 698c828..63e02fc 100644 --- a/projects/data-science/beginner/10-time-series-forecast/README.md +++ b/projects/data-science/beginner/10-time-series-forecast/README.md @@ -1,34 +1,93 @@ # Time Series Basic Forecast -## Idea -Build a simple time series forecasting model to predict future values. Learn about time series data and forecasting techniques. +> 🌐 **English** · [Português](./README.pt-BR.md) + +**Domain:** Data Science · **Level:** Beginner · **Estimated time:** 3–6 hours + +## Overview + +Forecasting is prediction with a twist: the order of the data matters, tomorrow depends on today, and you can never shuffle your way to a train/test split. In this project you take a real time series — daily temperatures, monthly sales, hourly energy demand — decompose it into trend and seasonality, and build a simple forecast for the next few periods. You will learn why classic cross-validation is a trap here, how to evaluate a forecast against a naive baseline, and why a confidence interval matters more than a single predicted line. + +## Prerequisites + +- Basic Python and pandas (especially datetime indexing) +- A plotting library (Matplotlib) +- Understanding of mean and moving averages +- A time series dataset with a date column — the [UCI Air Quality dataset](https://archive.ics.uci.edu/dataset/360/air+quality) or any dated Kaggle series (retail sales, weather) works well ## Learning Objectives -- Load and understand time series data -- Implement trend and seasonality analysis -- Train forecasting model -- Evaluate forecast accuracy -- Make future predictions - -## Implementation Tips -- Load time series data -- Visualize time series -- Check for stationarity -- Implement decomposition (trend, seasonality, residuals) -- Handle missing values in series -- Train simple models (moving average, exponential smoothing) -- Evaluate with appropriate metrics (MAE, RMSE, MAPE) -- Create train/validation/test split -- Implement cross-validation -- Forecast future periods -- Create confidence intervals -- Visualize predictions vs actuals -- Implement multiple models -- Compare model performance - -## Key Challenges -- Stationarity assumptions -- Seasonal pattern detection -- Forecast horizon selection -- Anomaly handling -- Uncertainty quantification + +By the end, you should be able to: + +- Load, index, and plot a time series correctly by date +- Decompose a series into trend, seasonality, and residual components +- Split time series data chronologically, never randomly +- Build a simple forecast (moving average or exponential smoothing) and project forward +- Evaluate a forecast with MAE/RMSE/MAPE against a naive baseline, with intervals + +## Functional Requirements + +1. The workflow must load a series with a proper datetime index and plot it. +2. It must handle missing timestamps or gaps explicitly (resample or interpolate). +3. It must decompose the series into trend, seasonal, and residual components. +4. It must split the data chronologically into train and a held-out test tail. +5. It must produce a forecast for the test horizon using at least one method. +6. It must compare the forecast to a naive baseline (last value or seasonal naive). +7. It must report MAE, RMSE, and MAPE, and plot forecast vs actual with a confidence band. + +## Suggested Milestones + +1. **Milestone 1 — Load & decompose:** Index by date, fill gaps, plot, and decompose trend/seasonality. +2. **Milestone 2 — Forecast:** Split chronologically and forecast the test horizon with your chosen method. +3. **Milestone 3 — Evaluate:** Compare to a naive baseline, report error metrics, and add confidence intervals. + +## Data & Interface Sketch + +```text +Series shape + index: datetime (daily/monthly/hourly, evenly spaced) + value: numeric target + gaps: resample to fixed frequency; interpolate or forward-fill missing points + +Chronological split (NEVER random) + |------------------ train ------------------|---- test ----| + fit on train, forecast len(test) steps ahead + +Decomposition + observed = trend + seasonal + residual (additive) or trend * seasonal * residual + +Evaluation vs baseline + method MAE RMSE MAPE + naive (last) 8.2 11.0 6.1% + seasonal_naive 5.4 7.1 3.9% + your_model 4.1 5.8 3.0% <- must beat the naive baseline to be useful +``` + +## Stretch Goals + +- Add Holt-Winters exponential smoothing to capture both trend and seasonality. +- Use rolling-origin (walk-forward) validation instead of a single split. +- Compare against an ARIMA model and discuss the trade-offs. +- Widen the forecast horizon and observe how the confidence band grows with distance. + +## Definition of Done + +- [ ] The series is correctly indexed by date and gaps are handled explicitly. +- [ ] Trend and seasonality are separated and shown. +- [ ] The train/test split is strictly chronological. +- [ ] The forecast is compared to a naive baseline and beats it (or you explain why not). +- [ ] MAE, RMSE, and MAPE are reported and a confidence band is plotted. + +## Common Pitfalls + +- Shuffling the data for a random train/test split, leaking the future into the past. +- Forecasting without a naive baseline, so you cannot tell if the model adds any value. +- Ignoring seasonality and being baffled by periodic residuals. +- Reporting a single forecast line with no uncertainty, implying false precision. + +## Resources + +- [statsmodels: Time Series Analysis](https://www.statsmodels.org/stable/tsa.html) — decomposition, smoothing, and ARIMA. +- [pandas: Time series / date functionality](https://pandas.pydata.org/docs/user_guide/timeseries.html) — indexing, resampling, and rolling windows. +- [Forecasting: Principles and Practice (Hyndman)](https://otexts.com/fpp3/) — the free, authoritative forecasting textbook. +- [scikit-learn: TimeSeriesSplit](https://scikit-learn.org/stable/modules/generated/sklearn.model_selection.TimeSeriesSplit.html) — chronological cross-validation for the stretch goal. diff --git a/projects/data-science/beginner/10-time-series-forecast/README.pt-BR.md b/projects/data-science/beginner/10-time-series-forecast/README.pt-BR.md new file mode 100644 index 0000000..0441b31 --- /dev/null +++ b/projects/data-science/beginner/10-time-series-forecast/README.pt-BR.md @@ -0,0 +1,93 @@ +# Previsão Básica de Séries Temporais + +> 🌐 [English](./README.md) · **Português** + +**Domínio:** Data Science · **Nível:** Iniciante · **Tempo estimado:** 3–6 horas + +## Visão Geral + +Previsão (forecasting) é predição com uma pegadinha: a ordem dos dados importa, o amanhã depende do hoje e você nunca pode embaralhar para chegar a uma divisão treino/teste. Neste projeto você pega uma série temporal real — temperaturas diárias, vendas mensais, demanda de energia por hora — decompõe em tendência e sazonalidade e constrói uma previsão simples para os próximos períodos. Você vai aprender por que a validação cruzada clássica é uma armadilha aqui, como avaliar uma previsão contra um baseline ingênuo e por que um intervalo de confiança importa mais do que uma única linha prevista. + +## Pré-requisitos + +- Python básico e pandas (especialmente indexação por datetime) +- Uma biblioteca de plotagem (Matplotlib) +- Entendimento de média e médias móveis +- Um conjunto de série temporal com uma coluna de data — o [dataset Air Quality da UCI](https://archive.ics.uci.edu/dataset/360/air+quality) ou qualquer série datada do Kaggle (vendas de varejo, clima) funciona bem + +## Objetivos de Aprendizado + +Ao final, você deve ser capaz de: + +- Carregar, indexar e plotar uma série temporal corretamente por data +- Decompor uma série em componentes de tendência, sazonalidade e resíduo +- Dividir dados de série temporal cronologicamente, nunca aleatoriamente +- Construir uma previsão simples (média móvel ou suavização exponencial) e projetar adiante +- Avaliar uma previsão com MAE/RMSE/MAPE contra um baseline ingênuo, com intervalos + +## Requisitos Funcionais + +1. O fluxo deve carregar uma série com um índice datetime apropriado e plotá-la. +2. Deve tratar timestamps ausentes ou lacunas explicitamente (reamostrar ou interpolar). +3. Deve decompor a série em componentes de tendência, sazonalidade e resíduo. +4. Deve dividir os dados cronologicamente em treino e uma cauda de teste separada. +5. Deve produzir uma previsão para o horizonte de teste usando ao menos um método. +6. Deve comparar a previsão com um baseline ingênuo (último valor ou naive sazonal). +7. Deve relatar MAE, RMSE e MAPE, e plotar previsão vs real com uma faixa de confiança. + +## Marcos Sugeridos + +1. **Marco 1 — Carregar e decompor:** Indexe por data, preencha lacunas, plote e decomponha tendência/sazonalidade. +2. **Marco 2 — Prever:** Divida cronologicamente e preveja o horizonte de teste com o método escolhido. +3. **Marco 3 — Avaliar:** Compare com um baseline ingênuo, relate métricas de erro e adicione intervalos de confiança. + +## Esboço de Dados e Interface + +```text +Formato da série + index: datetime (diário/mensal/horário, espaçado uniformemente) + value: alvo numérico + gaps: reamostrar para frequência fixa; interpolar ou preencher pontos ausentes + +Divisão cronológica (NUNCA aleatória) + |------------------ treino -----------------|---- teste ----| + ajusta no treino, prevê len(teste) passos à frente + +Decomposição + observado = tendência + sazonal + resíduo (aditiva) ou tendência * sazonal * resíduo + +Avaliação vs baseline + método MAE RMSE MAPE + naive (último) 8.2 11.0 6.1% + naive_sazonal 5.4 7.1 3.9% + seu_modelo 4.1 5.8 3.0% <- precisa vencer o baseline ingênuo para ser útil +``` + +## Desafios Extras + +- Adicione suavização exponencial de Holt-Winters para capturar tendência e sazonalidade. +- Use validação de origem móvel (walk-forward) em vez de uma única divisão. +- Compare com um modelo ARIMA e discuta os trade-offs. +- Amplie o horizonte de previsão e observe como a faixa de confiança cresce com a distância. + +## Definição de Pronto + +- [ ] A série é corretamente indexada por data e as lacunas são tratadas explicitamente. +- [ ] Tendência e sazonalidade são separadas e mostradas. +- [ ] A divisão treino/teste é estritamente cronológica. +- [ ] A previsão é comparada com um baseline ingênuo e o vence (ou você explica por que não). +- [ ] MAE, RMSE e MAPE são relatados e uma faixa de confiança é plotada. + +## Armadilhas Comuns + +- Embaralhar os dados para uma divisão treino/teste aleatória, vazando o futuro para o passado. +- Prever sem um baseline ingênuo, sem conseguir dizer se o modelo agrega algum valor. +- Ignorar a sazonalidade e ficar perplexo com resíduos periódicos. +- Relatar uma única linha de previsão sem incerteza, implicando falsa precisão. + +## Recursos + +- [statsmodels: Time Series Analysis](https://www.statsmodels.org/stable/tsa.html) — decomposição, suavização e ARIMA. +- [pandas: Time series / date functionality](https://pandas.pydata.org/docs/user_guide/timeseries.html) — indexação, reamostragem e janelas móveis. +- [Forecasting: Principles and Practice (Hyndman)](https://otexts.com/fpp3/) — o livro-texto gratuito e definitivo sobre previsão. +- [scikit-learn: TimeSeriesSplit](https://scikit-learn.org/stable/modules/generated/sklearn.model_selection.TimeSeriesSplit.html) — validação cruzada cronológica para o desafio extra. diff --git a/projects/data-science/intermediate/01-customer-segmentation/README.md b/projects/data-science/intermediate/01-customer-segmentation/README.md index f6c64b8..41306fa 100644 --- a/projects/data-science/intermediate/01-customer-segmentation/README.md +++ b/projects/data-science/intermediate/01-customer-segmentation/README.md @@ -1,34 +1,91 @@ -# Customer Segmentation (clustering) +# Customer Segmentation (Clustering) -## Idea -Segment customers into groups based on their characteristics. Learn about clustering algorithms and business applications. +> 🌐 **English** · [Português](./README.pt-BR.md) + +**Domain:** Data Science · **Level:** Intermediate · **Estimated time:** 1–2 days + +## Overview + +Take a table of customer behaviour — recency, frequency, monetary value, tenure, product mix — and discover the natural groups hiding inside it. This is an unsupervised project, so there is no label to predict and no accuracy to chase; the win is a set of segments a marketing team can actually name and act on ("dormant high-spenders", "new bargain hunters"). The real work is upstream of the algorithm: scaling features so distance means something, choosing how many clusters to keep, and proving the grouping is stable rather than an artifact of one random seed. + +## Prerequisites + +- Comfort with a dataframe library (pandas, Polars, or R) and basic plotting +- Familiarity with descriptive statistics and standardization (z-score, min-max) +- A first exposure to K-means or nearest-neighbour thinking +- A tabular customer dataset (e.g. an e-commerce or RFM sample) ## Learning Objectives -- Prepare customer data -- Implement clustering algorithms -- Determine optimal clusters -- Analyze cluster characteristics -- Apply to business strategy - -## Implementation Tips -- Load customer data -- Preprocess and normalize features -- Implement K-means clustering -- Use elbow method to find optimal clusters -- Try alternative algorithms (DBSCAN, Hierarchical) -- Visualize clusters (PCA, t-SNE) -- Analyze cluster characteristics -- Create cluster profiles -- Implement silhouette analysis -- Add business interpretation -- Create actionable segments -- Implement clustering evaluation -- Generate business recommendations -- Build clustering pipeline - -## Key Challenges -- Optimal cluster number selection -- Feature scaling and normalization -- High-dimensional data visualization -- Cluster interpretation -- Real-time clustering + +By the end, you should be able to: + +- Engineer RFM-style features and justify each scaling choice you make +- Run K-means and pick *k* using the elbow method **and** silhouette score, not just one +- Compare a centroid method (K-means) against a density method (DBSCAN) and explain when each fits +- Reduce dimensionality with PCA for visualization without leaking it into the clustering +- Profile each cluster into a business-readable persona with supporting statistics + +## Functional Requirements + +1. The pipeline must load raw customer records and derive a documented feature table. +2. Features must be scaled, and the chosen scaler must be fit on training data only, then reused. +3. The tool must run at least two clustering algorithms and report cluster sizes for each. +4. Optimal cluster count must be selected using at least two independent diagnostics. +5. Each resulting cluster must be summarized with per-feature means and a written persona. +6. Cluster stability must be checked by re-running with different random seeds or subsamples. +7. Results must be visualized in 2D (PCA or t-SNE) with clusters colour-coded. + +## Suggested Milestones + +1. **Milestone 1 — Feature table:** Build and scale RFM features from raw transactions. +2. **Milestone 2 — Cluster & tune:** Run K-means, sweep *k*, choose it with elbow + silhouette. +3. **Milestone 3 — Compare & profile:** Add DBSCAN, check stability, and write cluster personas. + +## Data & Interface Sketch + +```text +Feature table (one row per customer) + customer_id : string + recency_days : integer (days since last purchase) + frequency : integer (# orders in window) + monetary : float (total spend) + tenure_days : integer + avg_basket : float + +Pipeline steps + 1. aggregate transactions -> per-customer features + 2. scale features (StandardScaler, fit on train split) + 3. cluster (KMeans k=2..10 | DBSCAN eps sweep) + 4. score (inertia elbow, silhouette) -> pick k + 5. project to 2D (PCA) for plotting only + 6. profile: groupby(cluster).mean() -> persona table +``` + +## Stretch Goals + +- Add Gaussian Mixture Models and compare soft vs hard cluster assignment. +- Score new customers into existing segments without refitting the whole model. +- Weight monetary features by recency to capture recent behaviour shifts. +- Build a small dashboard letting a stakeholder filter customers by segment. + +## Definition of Done + +- [ ] The feature table is reproducible from raw data with a single documented step. +- [ ] Scaling is fit on a training split only — no leakage from the full dataset. +- [ ] The chosen *k* is defended with both elbow and silhouette evidence. +- [ ] At least two algorithms are compared with a clear recommendation. +- [ ] Every cluster has a named persona backed by per-feature statistics. + +## Common Pitfalls + +- Clustering unscaled features, letting `monetary` dominate every distance. +- Reading the elbow plot as gospel — it is often ambiguous; pair it with silhouette. +- Treating DBSCAN noise points (label -1) as a real cluster in the profiles. +- Fitting PCA or the scaler on all data, then wondering why segments feel unstable. + +## Resources + +- [scikit-learn: Clustering](https://scikit-learn.org/stable/modules/clustering.html) — algorithms and trade-offs side by side. +- [scikit-learn: Silhouette analysis](https://scikit-learn.org/stable/auto_examples/cluster/plot_kmeans_silhouette_analysis.html) — choosing *k* visually. +- [Wikipedia: RFM (market research)](https://en.wikipedia.org/wiki/RFM_(market_research)) — the classic customer feature framework. +- [scikit-learn: PCA](https://scikit-learn.org/stable/modules/generated/sklearn.decomposition.PCA.html) — dimensionality reduction for visualization. diff --git a/projects/data-science/intermediate/01-customer-segmentation/README.pt-BR.md b/projects/data-science/intermediate/01-customer-segmentation/README.pt-BR.md new file mode 100644 index 0000000..cb32235 --- /dev/null +++ b/projects/data-science/intermediate/01-customer-segmentation/README.pt-BR.md @@ -0,0 +1,91 @@ +# Segmentação de Clientes (Clustering) + +> 🌐 [English](./README.md) · **Português** + +**Domínio:** Data Science · **Nível:** Intermediário · **Tempo estimado:** 1–2 dias + +## Visão Geral + +Pegue uma tabela de comportamento de clientes — recência, frequência, valor monetário, tempo de casa, mix de produtos — e descubra os grupos naturais escondidos ali dentro. Este é um projeto não supervisionado, então não há rótulo para prever nem acurácia para perseguir; a vitória é um conjunto de segmentos que um time de marketing consiga de fato nomear e usar ("gastadores dormentes", "caçadores de ofertas recentes"). O trabalho real está antes do algoritmo: escalar features para que distância signifique algo, escolher quantos clusters manter e provar que o agrupamento é estável, não um artefato de uma única semente aleatória. + +## Pré-requisitos + +- Conforto com uma biblioteca de dataframe (pandas, Polars ou R) e gráficos básicos +- Familiaridade com estatística descritiva e padronização (z-score, min-max) +- Um primeiro contato com K-means ou raciocínio de vizinhos mais próximos +- Um conjunto de dados tabular de clientes (ex.: uma amostra de e-commerce ou RFM) + +## Objetivos de Aprendizado + +Ao final, você deve ser capaz de: + +- Criar features no estilo RFM e justificar cada escolha de escala que fizer +- Rodar K-means e escolher *k* usando o método do cotovelo **e** o silhouette score, não apenas um +- Comparar um método de centroide (K-means) com um de densidade (DBSCAN) e explicar quando cada um se encaixa +- Reduzir a dimensionalidade com PCA para visualização sem vazá-la para o clustering +- Perfilar cada cluster em uma persona legível pelo negócio, com estatísticas de apoio + +## Requisitos Funcionais + +1. O pipeline deve carregar registros brutos de clientes e derivar uma tabela de features documentada. +2. As features devem ser escaladas, e o scaler escolhido deve ser ajustado só nos dados de treino e reutilizado. +3. A ferramenta deve rodar pelo menos dois algoritmos de clustering e reportar os tamanhos dos clusters de cada um. +4. O número ótimo de clusters deve ser escolhido usando pelo menos dois diagnósticos independentes. +5. Cada cluster resultante deve ser resumido com médias por feature e uma persona escrita. +6. A estabilidade dos clusters deve ser verificada reexecutando com sementes ou subamostras diferentes. +7. Os resultados devem ser visualizados em 2D (PCA ou t-SNE) com clusters coloridos. + +## Marcos Sugeridos + +1. **Marco 1 — Tabela de features:** Construa e escale features RFM a partir de transações brutas. +2. **Marco 2 — Agrupar e ajustar:** Rode K-means, varra *k*, escolha-o com cotovelo + silhouette. +3. **Marco 3 — Comparar e perfilar:** Adicione DBSCAN, cheque estabilidade e escreva as personas. + +## Esboço de Dados e Interface + +```text +Tabela de features (uma linha por cliente) + customer_id : string + recency_days : inteiro (dias desde a última compra) + frequency : inteiro (nº de pedidos na janela) + monetary : float (gasto total) + tenure_days : inteiro + avg_basket : float + +Passos do pipeline + 1. agregar transações -> features por cliente + 2. escalar features (StandardScaler, ajustar no split de treino) + 3. agrupar (KMeans k=2..10 | varredura de eps do DBSCAN) + 4. pontuar (cotovelo da inércia, silhouette) -> escolher k + 5. projetar para 2D (PCA) apenas para o gráfico + 6. perfilar: groupby(cluster).mean() -> tabela de personas +``` + +## Desafios Extras + +- Adicione Gaussian Mixture Models e compare atribuição suave vs rígida de clusters. +- Classifique novos clientes em segmentos existentes sem reajustar o modelo inteiro. +- Pondere features monetárias pela recência para capturar mudanças recentes de comportamento. +- Construa um pequeno dashboard que deixe um stakeholder filtrar clientes por segmento. + +## Definição de Pronto + +- [ ] A tabela de features é reproduzível a partir dos dados brutos com um passo documentado. +- [ ] O escalonamento é ajustado só no split de treino — sem vazamento do conjunto completo. +- [ ] O *k* escolhido é defendido com evidências de cotovelo e silhouette. +- [ ] Pelo menos dois algoritmos são comparados com uma recomendação clara. +- [ ] Todo cluster tem uma persona nomeada apoiada por estatísticas por feature. + +## Armadilhas Comuns + +- Agrupar features não escaladas, deixando `monetary` dominar toda distância. +- Ler o gráfico do cotovelo como verdade absoluta — ele costuma ser ambíguo; combine com silhouette. +- Tratar os pontos de ruído do DBSCAN (rótulo -1) como um cluster real nos perfis. +- Ajustar PCA ou o scaler em todos os dados e depois estranhar segmentos instáveis. + +## Recursos + +- [scikit-learn: Clustering](https://scikit-learn.org/stable/modules/clustering.html) — algoritmos e trade-offs lado a lado. +- [scikit-learn: Análise de silhouette](https://scikit-learn.org/stable/auto_examples/cluster/plot_kmeans_silhouette_analysis.html) — escolhendo *k* visualmente. +- [Wikipedia: RFM (market research)](https://en.wikipedia.org/wiki/RFM_(market_research)) — o framework clássico de features de clientes. +- [scikit-learn: PCA](https://scikit-learn.org/stable/modules/generated/sklearn.decomposition.PCA.html) — redução de dimensionalidade para visualização. diff --git a/projects/data-science/intermediate/02-recommendation-engine/README.md b/projects/data-science/intermediate/02-recommendation-engine/README.md index 6536201..d2e8fd4 100644 --- a/projects/data-science/intermediate/02-recommendation-engine/README.md +++ b/projects/data-science/intermediate/02-recommendation-engine/README.md @@ -1,34 +1,93 @@ -# Recommendation Engine (collaborative filtering) +# Recommendation Engine (Collaborative Filtering) -## Idea -Build a recommendation system using collaborative filtering. Learn about matrix factorization and preference prediction. +> 🌐 **English** · [Português](./README.pt-BR.md) + +**Domain:** Data Science · **Level:** Intermediate · **Estimated time:** 1–2 days + +## Overview + +Given a sparse table of who rated (or bought, or clicked) what, predict what a user will want next. This project builds a collaborative-filtering recommender and — just as importantly — an honest way to measure it. The trap in recommenders is that a naive accuracy number looks great while the recommendations are useless (always suggest the most popular item and you will be "right" a lot). You will build neighbourhood and matrix-factorization models, split ratings so the test set simulates the future, and evaluate with ranking metrics that reward putting the right items near the top. + +## Prerequisites + +- Comfort with NumPy/pandas and basic linear algebra (dot products, matrices) +- Understanding of sparse data and why a full user-item matrix is mostly empty +- Familiarity with train/test splitting concepts +- A ratings dataset (MovieLens is the canonical choice) ## Learning Objectives -- Implement collaborative filtering -- Handle sparse user-item matrices -- Make personalized recommendations -- Evaluate recommendation quality -- Handle cold-start problems - -## Implementation Tips -- Create user-item rating matrix -- Implement user-based collaborative filtering -- Implement item-based collaborative filtering -- Use matrix factorization (SVD) -- Handle missing ratings -- Implement implicit feedback models -- Create evaluation framework -- Handle cold-start users/items -- Add content-based features -- Implement hybrid approaches -- Create ranking and filtering -- Add diversity to recommendations -- Implement A/B testing framework -- Scale to large datasets - -## Key Challenges -- Data sparsity -- Cold-start problem -- Computational scalability -- Recommendation diversity -- Real-time personalization + +By the end, you should be able to: + +- Build a user-item matrix and reason about its sparsity +- Implement item-based and user-based collaborative filtering with a similarity metric +- Apply matrix factorization (SVD-style latent factors) and interpret the factors +- Split interactions *temporally or leave-one-out* so evaluation mimics real prediction +- Evaluate with ranking metrics (Precision@K, Recall@K, NDCG) rather than raw RMSE alone + +## Functional Requirements + +1. The system must build a user-item interaction matrix from raw event/rating data. +2. It must produce a top-N recommendation list for any given user. +3. It must implement at least two approaches (e.g. item-based CF and matrix factorization). +4. Interactions must be split into train/validation/test so no test interaction leaks into training. +5. The system must report Precision@K, Recall@K, and one rank-aware metric (NDCG or MAP). +6. It must handle the cold-start case: a user or item with no history returns a sensible fallback. +7. It must compare its models against a popularity baseline and report the lift. + +## Suggested Milestones + +1. **Milestone 1 — Matrix & baseline:** Build the interaction matrix and a most-popular baseline. +2. **Milestone 2 — CF & factorization:** Add item-based CF and an SVD-style model. +3. **Milestone 3 — Evaluate & rank:** Split data, compute ranking metrics, compare to baseline. + +## Data & Interface Sketch + +```text +Interaction record + user_id : string + item_id : string + rating : float | implicit 1.0 + ts : epoch seconds + +Matrix R (users x items), mostly empty (sparse) + +Pipeline steps + 1. split: per-user leave-last-N-out -> train / valid / test + 2. build R from train only + 3. model: + item-CF -> similarity(item_i, item_j) via cosine + MF -> R ~= U * V^T (latent factors) + 4. recommend: score unseen items, take top-N + 5. evaluate on test: Precision@K, Recall@K, NDCG@K + 6. compare vs popularity baseline -> lift +``` + +## Stretch Goals + +- Add a hybrid model mixing content features (genre, tags) with collaborative signal. +- Introduce diversity/novelty into the ranking so it does not only surface blockbusters. +- Support implicit feedback with confidence weighting instead of explicit ratings. +- Serve recommendations behind a small API that returns top-N for a user id. + +## Definition of Done + +- [ ] No test interaction is ever visible to a model during training. +- [ ] Top-N lists are produced for users, including cold-start fallbacks. +- [ ] At least two models are evaluated with the same ranking metrics. +- [ ] A popularity baseline is included and beaten (or the gap is explained). +- [ ] Metric definitions (K value, split strategy) are documented. + +## Common Pitfalls + +- Random-splitting ratings so a user's future leaks into their training rows. +- Reporting RMSE only — a low error can still rank items badly for top-N. +- Forgetting the popularity baseline, so you cannot tell if the model adds value. +- Treating unseen items as disliked (0) when the feedback is implicit, not negative. + +## Resources + +- [MovieLens datasets](https://grouplens.org/datasets/movielens/) — the standard recommender benchmark. +- [Google: Recommendation Systems course](https://developers.google.com/machine-learning/recommendation) — CF and matrix factorization explained. +- [Surprise library docs](https://surprise.readthedocs.io/en/stable/) — reference for CF and evaluation splits. +- [Wikipedia: Discounted cumulative gain](https://en.wikipedia.org/wiki/Discounted_cumulative_gain) — how NDCG rewards ranking order. diff --git a/projects/data-science/intermediate/02-recommendation-engine/README.pt-BR.md b/projects/data-science/intermediate/02-recommendation-engine/README.pt-BR.md new file mode 100644 index 0000000..6210da2 --- /dev/null +++ b/projects/data-science/intermediate/02-recommendation-engine/README.pt-BR.md @@ -0,0 +1,93 @@ +# Motor de Recomendação (Filtragem Colaborativa) + +> 🌐 [English](./README.md) · **Português** + +**Domínio:** Data Science · **Nível:** Intermediário · **Tempo estimado:** 1–2 dias + +## Visão Geral + +Dada uma tabela esparsa de quem avaliou (ou comprou, ou clicou) o quê, preveja o que um usuário vai querer a seguir. Este projeto constrói um recomendador por filtragem colaborativa e — igualmente importante — uma forma honesta de medi-lo. A armadilha em recomendadores é que um número ingênuo de acurácia parece ótimo enquanto as recomendações são inúteis (sempre sugira o item mais popular e você vai "acertar" bastante). Você vai construir modelos de vizinhança e de fatoração de matriz, dividir as avaliações para que o conjunto de teste simule o futuro e avaliar com métricas de ranking que recompensam colocar os itens certos no topo. + +## Pré-requisitos + +- Conforto com NumPy/pandas e álgebra linear básica (produtos escalares, matrizes) +- Entender dados esparsos e por que uma matriz usuário-item completa é quase toda vazia +- Familiaridade com conceitos de divisão treino/teste +- Um conjunto de avaliações (MovieLens é a escolha canônica) + +## Objetivos de Aprendizado + +Ao final, você deve ser capaz de: + +- Construir uma matriz usuário-item e raciocinar sobre sua esparsidade +- Implementar filtragem colaborativa baseada em itens e em usuários com uma métrica de similaridade +- Aplicar fatoração de matriz (fatores latentes estilo SVD) e interpretar os fatores +- Dividir interações *temporalmente ou por leave-one-out* para que a avaliação imite a predição real +- Avaliar com métricas de ranking (Precision@K, Recall@K, NDCG) em vez de apenas RMSE + +## Requisitos Funcionais + +1. O sistema deve construir uma matriz de interação usuário-item a partir de eventos/avaliações brutos. +2. Deve produzir uma lista de recomendações top-N para qualquer usuário dado. +3. Deve implementar pelo menos duas abordagens (ex.: CF baseada em itens e fatoração de matriz). +4. As interações devem ser divididas em treino/validação/teste para que nenhuma interação de teste vaze para o treino. +5. O sistema deve reportar Precision@K, Recall@K e uma métrica sensível ao rank (NDCG ou MAP). +6. Deve tratar o caso cold-start: um usuário ou item sem histórico retorna um fallback sensato. +7. Deve comparar seus modelos com um baseline de popularidade e reportar o ganho. + +## Marcos Sugeridos + +1. **Marco 1 — Matriz e baseline:** Construa a matriz de interação e um baseline de mais populares. +2. **Marco 2 — CF e fatoração:** Adicione CF baseada em itens e um modelo estilo SVD. +3. **Marco 3 — Avaliar e ranquear:** Divida os dados, calcule métricas de ranking, compare ao baseline. + +## Esboço de Dados e Interface + +```text +Registro de interação + user_id : string + item_id : string + rating : float | implícito 1.0 + ts : segundos epoch + +Matriz R (usuários x itens), quase toda vazia (esparsa) + +Passos do pipeline + 1. dividir: leave-last-N-out por usuário -> treino / valid / teste + 2. construir R apenas com o treino + 3. modelar: + item-CF -> similaridade(item_i, item_j) via cosseno + MF -> R ~= U * V^T (fatores latentes) + 4. recomendar: pontuar itens não vistos, pegar top-N + 5. avaliar no teste: Precision@K, Recall@K, NDCG@K + 6. comparar vs baseline de popularidade -> ganho +``` + +## Desafios Extras + +- Adicione um modelo híbrido misturando features de conteúdo (gênero, tags) com o sinal colaborativo. +- Introduza diversidade/novidade no ranking para não trazer só os campeões de bilheteria. +- Suporte feedback implícito com ponderação por confiança em vez de avaliações explícitas. +- Sirva recomendações atrás de uma pequena API que retorne top-N para um id de usuário. + +## Definição de Pronto + +- [ ] Nenhuma interação de teste jamais fica visível a um modelo durante o treino. +- [ ] Listas top-N são produzidas para usuários, incluindo fallbacks de cold-start. +- [ ] Pelo menos dois modelos são avaliados com as mesmas métricas de ranking. +- [ ] Um baseline de popularidade é incluído e superado (ou a diferença é explicada). +- [ ] As definições das métricas (valor de K, estratégia de divisão) estão documentadas. + +## Armadilhas Comuns + +- Dividir avaliações aleatoriamente, deixando o futuro de um usuário vazar para suas linhas de treino. +- Reportar só RMSE — um erro baixo ainda pode ranquear itens mal para o top-N. +- Esquecer o baseline de popularidade, sem saber se o modelo agrega valor. +- Tratar itens não vistos como não gostados (0) quando o feedback é implícito, não negativo. + +## Recursos + +- [Datasets MovieLens](https://grouplens.org/datasets/movielens/) — o benchmark padrão de recomendadores. +- [Google: curso de Sistemas de Recomendação](https://developers.google.com/machine-learning/recommendation) — CF e fatoração de matriz explicados. +- [Documentação da biblioteca Surprise](https://surprise.readthedocs.io/en/stable/) — referência para CF e divisões de avaliação. +- [Wikipedia: Discounted cumulative gain](https://en.wikipedia.org/wiki/Discounted_cumulative_gain) — como o NDCG recompensa a ordem do ranking. diff --git a/projects/data-science/intermediate/03-nlp-pipeline/README.md b/projects/data-science/intermediate/03-nlp-pipeline/README.md index 26de20e..ea6eb98 100644 --- a/projects/data-science/intermediate/03-nlp-pipeline/README.md +++ b/projects/data-science/intermediate/03-nlp-pipeline/README.md @@ -1,34 +1,90 @@ -# NLP Pipeline (tokenization + embeddings) +# NLP Pipeline (Tokenization + Embeddings) -## Idea -Create an NLP pipeline for text processing and feature extraction. Learn about tokenization, embeddings, and text representation. +> 🌐 **English** · [Português](./README.pt-BR.md) + +**Domain:** Data Science · **Level:** Intermediate · **Estimated time:** 1–2 days + +## Overview + +Raw text is not something a model can consume — it has to become numbers first. This project builds the pipeline that does that conversion end to end: clean and tokenize documents, turn tokens into vectors (from a sparse TF-IDF matrix up to dense embeddings), and package the result so a downstream classifier or search index can use it. The point is not to train the fanciest model but to build the reusable, well-tested transformation layer that every text project needs, and to prove your representations actually capture meaning by measuring them on a small downstream task. + +## Prerequisites + +- Comfort with Python string handling and a dataframe library +- Understanding of what a vector is and cosine similarity +- Familiarity with train/test splitting for evaluation +- A text dataset with labels (e.g. sentiment reviews or topic-tagged news) ## Learning Objectives -- Implement text preprocessing -- Extract word embeddings -- Create document representations -- Build NLP workflows -- Apply to downstream tasks - -## Implementation Tips -- Implement tokenization strategies -- Add stopword removal -- Implement stemming/lemmatization -- Create word vectors (Word2Vec, GloVe) -- Build document embeddings (averaged, TF-IDF) -- Implement sentence transformers -- Create vocabulary management -- Handle out-of-vocabulary words -- Add ngram features -- Implement subword tokenization -- Create efficient embeddings -- Add contextual embeddings (BERT) -- Build scalable pipeline -- Create embeddings visualization - -## Key Challenges -- Preprocessing complexity -- Embedding quality -- Vocabulary management -- Multi-language support -- Computational efficiency + +By the end, you should be able to: + +- Build a configurable preprocessing stage (lowercasing, tokenization, stopwords, lemmatization) +- Produce both sparse (TF-IDF) and dense (Word2Vec/GloVe or transformer) document vectors +- Fit the vectorizer on training text only and transform validation/test with it +- Measure embedding quality on a downstream classification task, not just by eyeballing +- Handle out-of-vocabulary tokens and document the vocabulary you keep + +## Functional Requirements + +1. The pipeline must accept raw documents and emit a documented, reusable feature matrix. +2. Preprocessing steps must be individually toggle-able and their effect observable. +3. The vectorizer must be fit on the training split only, then applied to held-out data. +4. It must offer at least two representations (TF-IDF and one embedding-based) for comparison. +5. It must evaluate each representation on the same downstream classifier and report metrics. +6. Out-of-vocabulary and empty-document cases must be handled without crashing. +7. Vocabulary size and coverage must be reported. + +## Suggested Milestones + +1. **Milestone 1 — Preprocess:** Tokenize, normalize, and build a clean vocabulary. +2. **Milestone 2 — Vectorize:** Produce TF-IDF and embedding representations. +3. **Milestone 3 — Evaluate:** Train a simple classifier on each and compare metrics. + +## Data & Interface Sketch + +```text +Document record + doc_id : string + text : raw string + label : category (for downstream eval) + +Pipeline steps + 1. split docs -> train / valid / test + 2. preprocess: normalize -> tokenize -> stopwords -> lemmatize + 3. fit vectorizer on TRAIN tokens + tfidf -> sparse matrix (n_docs x vocab) + embed -> mean/pooled word vectors -> dense (n_docs x dim) + 4. transform valid/test with the fitted vectorizer + 5. eval: LogisticRegression on each -> accuracy / macro-F1 + 6. report vocab size, OOV rate, coverage +``` + +## Stretch Goals + +- Add subword tokenization (BPE/WordPiece) and measure its effect on OOV rate. +- Swap in contextual embeddings from a pretrained transformer and compare cost vs gain. +- Visualize embeddings in 2D (UMAP/t-SNE) coloured by label to inspect separability. +- Cache preprocessed tokens so re-running vectorization does not re-tokenize. + +## Definition of Done + +- [ ] The pipeline turns raw text into a feature matrix in one documented call. +- [ ] The vectorizer is fit on training data only — no vocabulary leaks from test. +- [ ] Two representations are compared on the same held-out classification task. +- [ ] OOV and empty documents are handled gracefully with a defined policy. +- [ ] Vocabulary size and OOV rate are reported. + +## Common Pitfalls + +- Fitting TF-IDF on the whole corpus, leaking test vocabulary and inflating scores. +- Over-cleaning text (stripping negations, emojis) and destroying signal the label depends on. +- Averaging word vectors without handling documents where every token is OOV. +- Comparing representations with different classifiers, so you cannot isolate the cause. + +## Resources + +- [spaCy 101](https://spacy.io/usage/spacy-101) — tokenization, lemmatization, and pipelines. +- [scikit-learn: Text feature extraction](https://scikit-learn.org/stable/modules/feature_extraction.html#text-feature-extraction) — TF-IDF in depth. +- [Jay Alammar: The Illustrated Word2Vec](https://jalammar.github.io/illustrated-word2vec/) — how word embeddings work. +- [Sentence Transformers docs](https://www.sbert.net/) — modern dense document embeddings. diff --git a/projects/data-science/intermediate/03-nlp-pipeline/README.pt-BR.md b/projects/data-science/intermediate/03-nlp-pipeline/README.pt-BR.md new file mode 100644 index 0000000..be4903a --- /dev/null +++ b/projects/data-science/intermediate/03-nlp-pipeline/README.pt-BR.md @@ -0,0 +1,90 @@ +# Pipeline de NLP (Tokenização + Embeddings) + +> 🌐 [English](./README.md) · **Português** + +**Domínio:** Data Science · **Nível:** Intermediário · **Tempo estimado:** 1–2 dias + +## Visão Geral + +Texto bruto não é algo que um modelo consiga consumir — ele precisa virar números primeiro. Este projeto constrói o pipeline que faz essa conversão de ponta a ponta: limpar e tokenizar documentos, transformar tokens em vetores (de uma matriz esparsa TF-IDF até embeddings densos) e empacotar o resultado para que um classificador ou índice de busca posterior possa usá-lo. O objetivo não é treinar o modelo mais sofisticado, mas construir a camada de transformação reutilizável e bem testada que todo projeto de texto precisa, e provar que suas representações de fato capturam significado medindo-as numa pequena tarefa posterior. + +## Pré-requisitos + +- Conforto com manipulação de strings em Python e uma biblioteca de dataframe +- Entender o que é um vetor e a similaridade por cosseno +- Familiaridade com divisão treino/teste para avaliação +- Um conjunto de texto com rótulos (ex.: reviews de sentimento ou notícias com tópicos) + +## Objetivos de Aprendizado + +Ao final, você deve ser capaz de: + +- Construir um estágio de pré-processamento configurável (minúsculas, tokenização, stopwords, lematização) +- Produzir vetores de documento esparsos (TF-IDF) e densos (Word2Vec/GloVe ou transformer) +- Ajustar o vetorizador só no texto de treino e transformar validação/teste com ele +- Medir a qualidade do embedding numa tarefa de classificação posterior, não só no olho +- Tratar tokens fora do vocabulário (OOV) e documentar o vocabulário que você mantém + +## Requisitos Funcionais + +1. O pipeline deve aceitar documentos brutos e emitir uma matriz de features documentada e reutilizável. +2. Os passos de pré-processamento devem ser individualmente ligáveis/desligáveis e seu efeito observável. +3. O vetorizador deve ser ajustado só no split de treino e então aplicado aos dados retidos. +4. Deve oferecer pelo menos duas representações (TF-IDF e uma baseada em embedding) para comparação. +5. Deve avaliar cada representação no mesmo classificador posterior e reportar métricas. +6. Os casos de OOV e documento vazio devem ser tratados sem quebrar. +7. O tamanho e a cobertura do vocabulário devem ser reportados. + +## Marcos Sugeridos + +1. **Marco 1 — Pré-processar:** Tokenize, normalize e construa um vocabulário limpo. +2. **Marco 2 — Vetorizar:** Produza representações TF-IDF e por embedding. +3. **Marco 3 — Avaliar:** Treine um classificador simples em cada uma e compare as métricas. + +## Esboço de Dados e Interface + +```text +Registro de documento + doc_id : string + text : string bruta + label : categoria (para avaliação posterior) + +Passos do pipeline + 1. dividir docs -> treino / valid / teste + 2. pré-processar: normalizar -> tokenizar -> stopwords -> lematizar + 3. ajustar vetorizador nos tokens de TREINO + tfidf -> matriz esparsa (n_docs x vocab) + embed -> vetores de palavra agregados -> denso (n_docs x dim) + 4. transformar valid/teste com o vetorizador ajustado + 5. avaliar: LogisticRegression em cada -> acurácia / macro-F1 + 6. reportar tamanho do vocab, taxa de OOV, cobertura +``` + +## Desafios Extras + +- Adicione tokenização por subpalavras (BPE/WordPiece) e meça seu efeito na taxa de OOV. +- Troque por embeddings contextuais de um transformer pré-treinado e compare custo vs ganho. +- Visualize embeddings em 2D (UMAP/t-SNE) coloridos por rótulo para inspecionar a separabilidade. +- Faça cache dos tokens pré-processados para que reexecutar a vetorização não re-tokenize. + +## Definição de Pronto + +- [ ] O pipeline transforma texto bruto em matriz de features em uma chamada documentada. +- [ ] O vetorizador é ajustado só nos dados de treino — sem vazar vocabulário do teste. +- [ ] Duas representações são comparadas na mesma tarefa de classificação retida. +- [ ] OOV e documentos vazios são tratados graciosamente com uma política definida. +- [ ] O tamanho do vocabulário e a taxa de OOV são reportados. + +## Armadilhas Comuns + +- Ajustar TF-IDF no corpus inteiro, vazando o vocabulário de teste e inflando os scores. +- Limpar texto demais (removendo negações, emojis) e destruir o sinal do qual o rótulo depende. +- Fazer média de vetores de palavra sem tratar documentos onde todo token é OOV. +- Comparar representações com classificadores diferentes, sem conseguir isolar a causa. + +## Recursos + +- [spaCy 101](https://spacy.io/usage/spacy-101) — tokenização, lematização e pipelines. +- [scikit-learn: extração de features de texto](https://scikit-learn.org/stable/modules/feature_extraction.html#text-feature-extraction) — TF-IDF em profundidade. +- [Jay Alammar: The Illustrated Word2Vec](https://jalammar.github.io/illustrated-word2vec/) — como embeddings de palavras funcionam. +- [Documentação do Sentence Transformers](https://www.sbert.net/) — embeddings densos modernos de documentos. diff --git a/projects/data-science/intermediate/04-fraud-detection/README.md b/projects/data-science/intermediate/04-fraud-detection/README.md index b505e80..e1a94bf 100644 --- a/projects/data-science/intermediate/04-fraud-detection/README.md +++ b/projects/data-science/intermediate/04-fraud-detection/README.md @@ -1,34 +1,96 @@ # Fraud Detection Model -## Idea -Build a model to detect fraudulent transactions. Learn about anomaly detection and handling imbalanced data. +> 🌐 **English** · [Português](./README.pt-BR.md) + +**Domain:** Data Science · **Level:** Intermediate · **Estimated time:** 1–2 days + +## Overview + +Fraud is rare — maybe one transaction in a thousand — and that rarity breaks every intuition you have about accuracy. A model that predicts "not fraud" for everything scores 99.9% accurate and catches zero fraud. This project is about building a classifier that actually finds the needle: engineering features that expose fraud patterns, handling the class imbalance honestly, and evaluating with metrics that survive skew (precision, recall, PR-AUC). You will also confront the business reality that a false positive (blocking a real customer) and a false negative (missing fraud) cost very different amounts, so the decision threshold is a design choice, not a default. + +## Prerequisites + +- Comfort training a classifier (logistic regression, tree ensembles) in scikit-learn or similar +- Understanding of the confusion matrix and precision/recall +- Familiarity with train/validation/test splitting +- An imbalanced transaction dataset (e.g. the Kaggle credit-card fraud set) ## Learning Objectives -- Handle imbalanced classification -- Detect anomalies -- Implement fraud detection pipeline -- Evaluate on appropriate metrics -- Handle operational constraints - -## Implementation Tips -- Load fraud dataset (imbalanced) -- Handle class imbalance (SMOTE, class weights) -- Feature engineering for fraud patterns -- Train multiple models -- Use appropriate evaluation metrics (precision, recall, F1, AUC-ROC) -- Implement anomaly detection methods -- Create fraud score -- Set decision thresholds -- Implement real-time detection -- Add false positive handling -- Create explainability -- Implement monitoring -- Build feedback loop -- Create alert system - -## Key Challenges -- Class imbalance handling -- Feature engineering for fraud -- False positive costs -- Model interpretability -- Real-time performance + +By the end, you should be able to: + +- Engineer transaction features (velocity, amount deviation, time-of-day) that expose fraud +- Handle imbalance with resampling (SMOTE) and/or class weights, applied only to training data +- Choose evaluation metrics that are meaningful under heavy skew (PR-AUC, recall at fixed precision) +- Tune a decision threshold against an explicit cost trade-off, not the default 0.5 +- Produce per-prediction explanations to support an analyst reviewing an alert + +## Functional Requirements + +1. The pipeline must split data into train/validation/test *before* any resampling or fitting. +2. Resampling or class weighting must be applied to the training fold only. +3. It must engineer at least three fraud-relevant features from the raw fields. +4. It must report precision, recall, F1, and PR-AUC — not accuracy alone. +5. It must expose a tunable decision threshold and show the precision/recall trade-off curve. +6. It must output a fraud score per transaction, not just a hard label. +7. It must include a way to explain why a given transaction was flagged. + +## Suggested Milestones + +1. **Milestone 1 — Split & features:** Split data, then engineer fraud-pattern features. +2. **Milestone 2 — Train & balance:** Train models with imbalance handling on the train fold. +3. **Milestone 3 — Evaluate & threshold:** Report skew-aware metrics and tune the threshold. + +## Data & Interface Sketch + +```text +Transaction record + txn_id : string + amount : float + ts : epoch seconds + merchant : category + is_fraud : 0 | 1 (very rare) + +Engineered features + amount_zscore_per_user + txns_last_1h (velocity) + hour_of_day + amount_vs_merchant_median + +Pipeline steps + 1. split -> train / valid / test (stratified on is_fraud) + 2. engineer features on each split independently + 3. resample TRAIN only (SMOTE | class_weight) + 4. train (logreg | gradient-boosted trees) + 5. evaluate valid: PR-AUC, recall@precision, confusion matrix + 6. pick threshold via cost curve -> apply to test +``` + +## Stretch Goals + +- Add an unsupervised anomaly detector (Isolation Forest) and blend it with the classifier. +- Simulate a cost matrix and report expected monetary loss at each threshold. +- Add temporal validation (train on past, test on future) to catch concept drift. +- Build a simple alert queue that ranks flagged transactions by score. + +## Definition of Done + +- [ ] The split happens before any fitting or resampling — zero leakage. +- [ ] Resampling touches only the training fold; validation/test stay at natural prevalence. +- [ ] Reported metrics include PR-AUC and recall at a stated precision, not accuracy. +- [ ] The decision threshold is chosen deliberately with a documented trade-off. +- [ ] Each flagged transaction comes with a human-readable reason. + +## Common Pitfalls + +- Applying SMOTE before the split, leaking synthetic neighbours into validation. +- Reporting 99% accuracy on a 0.1% fraud rate and calling it a success. +- Leaving the threshold at 0.5 when the cost of a miss dwarfs a false alarm (or vice versa). +- Engineering features using future information (e.g. a label-derived aggregate). + +## Resources + +- [scikit-learn: Imbalanced classification metrics](https://scikit-learn.org/stable/modules/model_evaluation.html#precision-recall-f-measure-metrics) — precision, recall, PR curves. +- [imbalanced-learn docs](https://imbalanced-learn.org/stable/) — SMOTE and resampling done right. +- [Google: Classification on imbalanced data](https://developers.google.com/machine-learning/data-prep/construct/sampling-splitting/imbalanced-data) — practical guidance. +- [Kaggle: Credit Card Fraud Detection dataset](https://www.kaggle.com/datasets/mlg-ulb/creditcardfraud) — a canonical imbalanced set. diff --git a/projects/data-science/intermediate/04-fraud-detection/README.pt-BR.md b/projects/data-science/intermediate/04-fraud-detection/README.pt-BR.md new file mode 100644 index 0000000..07c91d5 --- /dev/null +++ b/projects/data-science/intermediate/04-fraud-detection/README.pt-BR.md @@ -0,0 +1,96 @@ +# Modelo de Detecção de Fraude + +> 🌐 [English](./README.md) · **Português** + +**Domínio:** Data Science · **Nível:** Intermediário · **Tempo estimado:** 1–2 dias + +## Visão Geral + +Fraude é rara — talvez uma transação em mil — e essa raridade quebra toda intuição que você tem sobre acurácia. Um modelo que prevê "não é fraude" para tudo atinge 99,9% de acurácia e pega zero fraudes. Este projeto é sobre construir um classificador que de fato encontra a agulha: criar features que expõem padrões de fraude, tratar o desbalanceamento de classes de forma honesta e avaliar com métricas que sobrevivem ao desbalanço (precisão, recall, PR-AUC). Você também vai encarar a realidade de negócio de que um falso positivo (bloquear um cliente real) e um falso negativo (deixar passar fraude) custam valores bem diferentes, então o limiar de decisão é uma escolha de projeto, não um padrão. + +## Pré-requisitos + +- Conforto para treinar um classificador (regressão logística, ensembles de árvores) em scikit-learn ou similar +- Entender a matriz de confusão e precisão/recall +- Familiaridade com divisão treino/validação/teste +- Um conjunto de transações desbalanceado (ex.: o dataset de fraude de cartão do Kaggle) + +## Objetivos de Aprendizado + +Ao final, você deve ser capaz de: + +- Criar features de transação (velocidade, desvio de valor, hora do dia) que expõem fraude +- Tratar desbalanceamento com reamostragem (SMOTE) e/ou pesos de classe, aplicados só ao treino +- Escolher métricas de avaliação significativas sob forte desbalanço (PR-AUC, recall a precisão fixa) +- Ajustar um limiar de decisão contra um trade-off de custo explícito, não o padrão 0.5 +- Produzir explicações por predição para apoiar um analista revisando um alerta + +## Requisitos Funcionais + +1. O pipeline deve dividir os dados em treino/validação/teste *antes* de qualquer reamostragem ou ajuste. +2. Reamostragem ou ponderação de classe deve ser aplicada só ao fold de treino. +3. Deve criar pelo menos três features relevantes para fraude a partir dos campos brutos. +4. Deve reportar precisão, recall, F1 e PR-AUC — não acurácia sozinha. +5. Deve expor um limiar de decisão ajustável e mostrar a curva de trade-off precisão/recall. +6. Deve produzir um score de fraude por transação, não apenas um rótulo rígido. +7. Deve incluir uma forma de explicar por que uma transação foi sinalizada. + +## Marcos Sugeridos + +1. **Marco 1 — Dividir e features:** Divida os dados e então crie features de padrão de fraude. +2. **Marco 2 — Treinar e balancear:** Treine modelos com tratamento de desbalanço no fold de treino. +3. **Marco 3 — Avaliar e limiar:** Reporte métricas sensíveis ao desbalanço e ajuste o limiar. + +## Esboço de Dados e Interface + +```text +Registro de transação + txn_id : string + amount : float + ts : segundos epoch + merchant : categoria + is_fraud : 0 | 1 (muito raro) + +Features criadas + amount_zscore_per_user + txns_last_1h (velocidade) + hour_of_day + amount_vs_merchant_median + +Passos do pipeline + 1. dividir -> treino / valid / teste (estratificado em is_fraud) + 2. criar features em cada split independentemente + 3. reamostrar só o TREINO (SMOTE | class_weight) + 4. treinar (logreg | árvores com gradient boosting) + 5. avaliar valid: PR-AUC, recall@precisão, matriz de confusão + 6. escolher limiar via curva de custo -> aplicar ao teste +``` + +## Desafios Extras + +- Adicione um detector de anomalia não supervisionado (Isolation Forest) e combine-o com o classificador. +- Simule uma matriz de custo e reporte a perda monetária esperada em cada limiar. +- Adicione validação temporal (treinar no passado, testar no futuro) para pegar concept drift. +- Construa uma fila de alertas simples que ranqueie transações sinalizadas por score. + +## Definição de Pronto + +- [ ] A divisão acontece antes de qualquer ajuste ou reamostragem — zero vazamento. +- [ ] A reamostragem toca só o fold de treino; validação/teste ficam na prevalência natural. +- [ ] As métricas reportadas incluem PR-AUC e recall a uma precisão declarada, não acurácia. +- [ ] O limiar de decisão é escolhido deliberadamente com um trade-off documentado. +- [ ] Cada transação sinalizada vem com um motivo legível por humanos. + +## Armadilhas Comuns + +- Aplicar SMOTE antes da divisão, vazando vizinhos sintéticos para a validação. +- Reportar 99% de acurácia numa taxa de fraude de 0,1% e chamar isso de sucesso. +- Deixar o limiar em 0.5 quando o custo de um erro supera de longe um falso alarme (ou vice-versa). +- Criar features usando informação do futuro (ex.: um agregado derivado do rótulo). + +## Recursos + +- [scikit-learn: métricas de classificação desbalanceada](https://scikit-learn.org/stable/modules/model_evaluation.html#precision-recall-f-measure-metrics) — precisão, recall, curvas PR. +- [Documentação do imbalanced-learn](https://imbalanced-learn.org/stable/) — SMOTE e reamostragem bem feitos. +- [Google: Classificação em dados desbalanceados](https://developers.google.com/machine-learning/data-prep/construct/sampling-splitting/imbalanced-data) — orientação prática. +- [Kaggle: dataset Credit Card Fraud Detection](https://www.kaggle.com/datasets/mlg-ulb/creditcardfraud) — um conjunto desbalanceado canônico. diff --git a/projects/data-science/intermediate/05-ab-testing-tool/README.md b/projects/data-science/intermediate/05-ab-testing-tool/README.md index 966ad7b..bec6897 100644 --- a/projects/data-science/intermediate/05-ab-testing-tool/README.md +++ b/projects/data-science/intermediate/05-ab-testing-tool/README.md @@ -1,34 +1,97 @@ # A/B Testing Analysis Tool -## Idea -Build a tool for analyzing A/B test results with statistical rigor. Learn about hypothesis testing and experimental design. +> 🌐 **English** · [Português](./README.pt-BR.md) + +**Domain:** Data Science · **Level:** Intermediate · **Estimated time:** 1–2 days + +## Overview + +Someone ran an experiment: version A got one button, version B got another, and now there is a spreadsheet of conversions. Did B actually win, or is the difference noise? This project builds the tool that answers that question with statistical rigour instead of vibes. You will compute the sample size a test *should* have had before it started, run the right significance test for the metric type, report a confidence interval and effect size rather than a bare p-value, and guard against the classic ways experiments lie — peeking early, testing many metrics, and confusing "not significant" with "no effect". + +## Prerequisites + +- Understanding of means, proportions, variance, and the normal distribution +- Familiarity with the idea of hypothesis testing (null vs alternative) +- Comfort with a stats library (SciPy, statsmodels) and a dataframe tool +- Sample experiment data with a group label and an outcome per unit ## Learning Objectives -- Design A/B tests -- Implement statistical tests -- Calculate sample size -- Analyze test results -- Draw valid conclusions - -## Implementation Tips -- Design test structure -- Calculate required sample size -- Implement statistical tests (t-test, chi-square) -- Add significance level configuration -- Create power analysis -- Implement multiple hypothesis correction -- Add confidence intervals -- Create effect size calculation -- Visualize test results -- Implement guardrail metrics -- Add temporal analysis -- Create result interpretation -- Implement simulation framework -- Build reporting interface - -## Key Challenges -- Multiple testing problem -- Sample size determination -- Confounding variables -- Test duration optimization -- Result interpretation + +By the end, you should be able to: + +- Calculate required sample size from a baseline rate, minimum detectable effect, power, and alpha +- Pick the correct test for the metric (two-proportion z-test, Welch's t-test, chi-square) +- Report a confidence interval and effect size, not just a p-value +- Apply a multiple-comparison correction when several metrics are evaluated +- Explain why peeking at results early inflates the false-positive rate + +## Functional Requirements + +1. The tool must compute required sample size given baseline, MDE, power, and significance level. +2. It must select and run the appropriate test based on whether the metric is a rate or a mean. +3. It must output a point estimate, confidence interval, effect size, and p-value together. +4. It must apply a correction (Bonferroni or Benjamini-Hochberg) when more than one metric is tested. +5. It must flag when the observed sample is below the required size and warn about underpowering. +6. It must include at least one guardrail metric check alongside the primary metric. +7. It must produce a plain-language verdict ("significant lift of X% [CI]" or "inconclusive"). + +## Suggested Milestones + +1. **Milestone 1 — Power & sizing:** Implement sample-size and power calculations. +2. **Milestone 2 — Testing:** Run the correct significance test with CI and effect size. +3. **Milestone 3 — Rigour:** Add multiple-comparison correction and guardrail/peeking checks. + +## Data & Interface Sketch + +```text +Experiment record (one per unit) + unit_id : string + group : "control" | "variant" + metric : float | 0/1 (conversion) + +Analysis output + n_per_group, observed rates/means + test_used : "two-prop z" | "welch t" | "chi2" + estimate : diff of rates/means + ci_95 : [low, high] + effect_size : Cohen's h / d + p_value, corrected_p + verdict : "significant" | "inconclusive" + power_warning : bool + +Steps + 1. required_n = f(baseline, mde, power=0.8, alpha=0.05) + 2. choose test by metric type + 3. compute estimate, CI, effect size, p + 4. correct p across metrics + 5. render verdict + power warning +``` + +## Stretch Goals + +- Add a sequential/Bayesian analysis so early looks are valid by design. +- Run an A/A test on real data to confirm the false-positive rate matches alpha. +- Support ratio metrics (e.g. revenue per user) with the delta method for variance. +- Add a simulation mode that generates data at a known effect to validate the tool. + +## Definition of Done + +- [ ] Sample size is computed from stated inputs and shown before any conclusion. +- [ ] The test chosen matches the metric type and its assumption is checked. +- [ ] Every result carries a confidence interval and effect size, not just a p-value. +- [ ] Multiple metrics trigger a correction and the corrected p-values are reported. +- [ ] The verdict is stated in plain language with the caveat when underpowered. + +## Common Pitfalls + +- Reporting a p-value with no effect size, so a trivial difference looks important. +- Testing ten metrics at alpha 0.05 and celebrating the one that "won" by chance. +- Treating p > 0.05 as proof of no difference rather than insufficient evidence. +- Using a t-test on a binary conversion metric where a proportion test belongs. + +## Resources + +- [Kohavi et al.: Trustworthy Online Controlled Experiments](https://experimentguide.com/) — the definitive practitioner reference. +- [statsmodels: Power and sample size](https://www.statsmodels.org/stable/stats.html#power-and-sample-size-calculations) — implementation reference. +- [Wikipedia: Multiple comparisons problem](https://en.wikipedia.org/wiki/Multiple_comparisons_problem) — why corrections matter. +- [Evan Miller: How Not to Run an A/B Test](https://www.evanmiller.org/how-not-to-run-an-ab-test.html) — the peeking problem explained. diff --git a/projects/data-science/intermediate/05-ab-testing-tool/README.pt-BR.md b/projects/data-science/intermediate/05-ab-testing-tool/README.pt-BR.md new file mode 100644 index 0000000..8cef15f --- /dev/null +++ b/projects/data-science/intermediate/05-ab-testing-tool/README.pt-BR.md @@ -0,0 +1,97 @@ +# Ferramenta de Análise de Testes A/B + +> 🌐 [English](./README.md) · **Português** + +**Domínio:** Data Science · **Nível:** Intermediário · **Tempo estimado:** 1–2 dias + +## Visão Geral + +Alguém rodou um experimento: a versão A tinha um botão, a versão B tinha outro, e agora há uma planilha de conversões. B realmente venceu, ou a diferença é ruído? Este projeto constrói a ferramenta que responde a essa pergunta com rigor estatístico em vez de achismo. Você vai calcular o tamanho de amostra que um teste *deveria* ter tido antes de começar, rodar o teste de significância certo para o tipo de métrica, reportar um intervalo de confiança e um tamanho de efeito em vez de um p-valor solto, e se proteger das formas clássicas de um experimento mentir — espiar cedo, testar muitas métricas e confundir "não significativo" com "sem efeito". + +## Pré-requisitos + +- Entender médias, proporções, variância e a distribuição normal +- Familiaridade com a ideia de teste de hipóteses (nula vs alternativa) +- Conforto com uma biblioteca de estatística (SciPy, statsmodels) e uma ferramenta de dataframe +- Dados de experimento com um rótulo de grupo e um resultado por unidade + +## Objetivos de Aprendizado + +Ao final, você deve ser capaz de: + +- Calcular o tamanho de amostra necessário a partir de taxa base, efeito mínimo detectável, poder e alfa +- Escolher o teste correto para a métrica (z-test de duas proporções, t-test de Welch, qui-quadrado) +- Reportar um intervalo de confiança e tamanho de efeito, não só um p-valor +- Aplicar uma correção de comparações múltiplas quando várias métricas são avaliadas +- Explicar por que espiar resultados cedo infla a taxa de falsos positivos + +## Requisitos Funcionais + +1. A ferramenta deve calcular o tamanho de amostra necessário dados base, MDE, poder e nível de significância. +2. Deve selecionar e rodar o teste apropriado conforme a métrica seja uma taxa ou uma média. +3. Deve produzir uma estimativa pontual, intervalo de confiança, tamanho de efeito e p-valor juntos. +4. Deve aplicar uma correção (Bonferroni ou Benjamini-Hochberg) quando mais de uma métrica é testada. +5. Deve sinalizar quando a amostra observada está abaixo do tamanho necessário e avisar sobre baixo poder. +6. Deve incluir pelo menos uma checagem de métrica de guardrail junto à métrica principal. +7. Deve produzir um veredito em linguagem simples ("ganho significativo de X% [IC]" ou "inconclusivo"). + +## Marcos Sugeridos + +1. **Marco 1 — Poder e dimensionamento:** Implemente os cálculos de tamanho de amostra e poder. +2. **Marco 2 — Teste:** Rode o teste de significância correto com IC e tamanho de efeito. +3. **Marco 3 — Rigor:** Adicione correção de comparações múltiplas e checagens de guardrail/espiar. + +## Esboço de Dados e Interface + +```text +Registro do experimento (um por unidade) + unit_id : string + group : "control" | "variant" + metric : float | 0/1 (conversão) + +Saída da análise + n_por_grupo, taxas/médias observadas + teste_usado : "z 2-prop" | "welch t" | "chi2" + estimativa : diferença de taxas/médias + ic_95 : [baixo, alto] + tamanho_efeito: h de Cohen / d + p_valor, p_corrigido + veredito : "significativo" | "inconclusivo" + aviso_poder : bool + +Passos + 1. n_necessario = f(base, mde, poder=0.8, alfa=0.05) + 2. escolher teste pelo tipo de métrica + 3. calcular estimativa, IC, tamanho de efeito, p + 4. corrigir p entre as métricas + 5. renderizar veredito + aviso de poder +``` + +## Desafios Extras + +- Adicione uma análise sequencial/Bayesiana para que olhares antecipados sejam válidos por design. +- Rode um teste A/A em dados reais para confirmar que a taxa de falso positivo bate com o alfa. +- Suporte métricas de razão (ex.: receita por usuário) com o método delta para a variância. +- Adicione um modo de simulação que gera dados com efeito conhecido para validar a ferramenta. + +## Definição de Pronto + +- [ ] O tamanho de amostra é calculado a partir de entradas declaradas e mostrado antes de qualquer conclusão. +- [ ] O teste escolhido combina com o tipo de métrica e sua suposição é verificada. +- [ ] Todo resultado carrega um intervalo de confiança e tamanho de efeito, não só um p-valor. +- [ ] Múltiplas métricas disparam uma correção e os p-valores corrigidos são reportados. +- [ ] O veredito é declarado em linguagem simples, com a ressalva quando o poder é baixo. + +## Armadilhas Comuns + +- Reportar um p-valor sem tamanho de efeito, fazendo uma diferença trivial parecer importante. +- Testar dez métricas a alfa 0.05 e comemorar a única que "venceu" por acaso. +- Tratar p > 0.05 como prova de ausência de diferença em vez de evidência insuficiente. +- Usar um t-test numa métrica de conversão binária onde cabe um teste de proporção. + +## Recursos + +- [Kohavi et al.: Trustworthy Online Controlled Experiments](https://experimentguide.com/) — a referência definitiva para praticantes. +- [statsmodels: poder e tamanho de amostra](https://www.statsmodels.org/stable/stats.html#power-and-sample-size-calculations) — referência de implementação. +- [Wikipedia: problema de comparações múltiplas](https://en.wikipedia.org/wiki/Multiple_comparisons_problem) — por que correções importam. +- [Evan Miller: How Not to Run an A/B Test](https://www.evanmiller.org/how-not-to-run-an-ab-test.html) — o problema de espiar explicado. diff --git a/projects/data-science/intermediate/06-feature-engineering/README.md b/projects/data-science/intermediate/06-feature-engineering/README.md index a652d5f..306115a 100644 --- a/projects/data-science/intermediate/06-feature-engineering/README.md +++ b/projects/data-science/intermediate/06-feature-engineering/README.md @@ -1,34 +1,94 @@ # Feature Engineering Pipeline -## Idea -Create a pipeline for feature engineering and selection. Learn about feature creation, transformation, and importance ranking. +> 🌐 **English** · [Português](./README.pt-BR.md) + +**Domain:** Data Science · **Level:** Intermediate · **Estimated time:** 1–2 days + +## Overview + +Models are only as good as the features you feed them, and raw columns are rarely the right features. This project builds a reusable pipeline that transforms raw data into model-ready features: encoding categoricals, scaling numerics, creating interactions and temporal features, and then *selecting* the subset that actually helps. The discipline that separates this from a pile of ad-hoc transformations is leak-free fitting — every transformer learns its parameters from the training fold only — and honest selection, where you prove a smaller feature set holds up on held-out data rather than just fitting the training noise better. + +## Prerequisites + +- Comfort with a dataframe library and scikit-learn (or an equivalent) transformers +- Understanding of the difference between fitting and transforming +- Familiarity with train/validation/test splitting +- A tabular dataset with mixed numeric and categorical columns and a target ## Learning Objectives -- Implement feature transformations -- Create new features -- Select important features -- Implement feature selection algorithms -- Build automated pipelines - -## Implementation Tips -- Implement numerical transformations (scaling, binning, polynomial) -- Add categorical transformations (encoding, grouping) -- Create interaction features -- Implement temporal features -- Add domain-specific features -- Implement feature selection methods (filter, wrapper, embedded) -- Create automated feature discovery -- Add validation for features -- Implement feature monitoring -- Create feature importance rankings -- Build feature store -- Add feature versioning -- Create reproducible pipelines -- Implement feature engineering automation - -## Key Challenges -- Feature explosion -- Feature interaction discovery -- High-dimensional data -- Feature importance calculation -- Real-time feature engineering + +By the end, you should be able to: + +- Build a composable pipeline of transformers that fits on train and transforms any split +- Encode categoricals (one-hot, target/mean with smoothing) without leaking the target +- Create interaction, polynomial, and time-derived features and judge which earn their keep +- Apply filter, wrapper, and embedded feature-selection methods and compare them +- Rank feature importance and validate that pruned features do not hurt held-out performance + +## Functional Requirements + +1. The pipeline must be a single fitted object that transforms train, validation, and test identically. +2. All transformer parameters (scaler stats, encoding maps) must be learned from training data only. +3. It must generate at least three engineered feature types (interaction, temporal, categorical encoding). +4. It must implement at least two feature-selection strategies and report the features each keeps. +5. It must produce a ranked feature-importance table. +6. It must compare model performance on the full vs selected feature set on held-out data. +7. It must handle unseen categorical values at transform time without crashing. + +## Suggested Milestones + +1. **Milestone 1 — Transformers:** Build encoding, scaling, and generation steps into one pipeline. +2. **Milestone 2 — Selection:** Add and compare feature-selection strategies. +3. **Milestone 3 — Validate:** Rank importance and confirm the selected set holds on test. + +## Data & Interface Sketch + +```text +Raw row + id : string + age : int + signup_date : date + plan : category + target : numeric | class + +Pipeline (fit on TRAIN only) + numeric -> impute -> scale + category -> encode (one-hot | smoothed target) + temporal -> days_since, day_of_week, is_weekend + generate -> interactions, polynomial terms + select -> filter (mutual info) | embedded (L1 / tree importance) + +Outputs + feature_matrix per split + importance table: feature -> score + perf(full) vs perf(selected) on held-out +``` + +## Stretch Goals + +- Add a lightweight feature store: persist fitted transformers and version the feature set. +- Detect and drop highly-correlated features automatically before modelling. +- Add automated feature generation (e.g. deep feature synthesis) and prune the explosion. +- Track feature distributions so a downstream drift check can reuse them. + +## Definition of Done + +- [ ] One fitted pipeline transforms all splits identically and reproducibly. +- [ ] No transformer sees validation or test data during fitting — no target leakage. +- [ ] At least two selection strategies are compared with the features each retains listed. +- [ ] A ranked importance table is produced. +- [ ] Selected-set performance is compared to full-set on held-out data. + +## Common Pitfalls + +- Fitting the scaler or target encoder on the whole dataset, leaking test statistics. +- Target-encoding a high-cardinality column without smoothing or out-of-fold computation. +- Reading feature importance from the training fit and assuming it generalizes. +- Crashing on an unseen category at inference because the encoder never planned for it. + +## Resources + +- [scikit-learn: Pipelines and composite estimators](https://scikit-learn.org/stable/modules/compose.html) — building leak-free pipelines. +- [scikit-learn: Feature selection](https://scikit-learn.org/stable/modules/feature_selection.html) — filter, wrapper, embedded methods. +- [category_encoders docs](https://contrib.scikit-learn.org/category_encoders/) — target encoding done safely. +- [Kaggle: Feature Engineering course](https://www.kaggle.com/learn/feature-engineering) — practical patterns and pitfalls. diff --git a/projects/data-science/intermediate/06-feature-engineering/README.pt-BR.md b/projects/data-science/intermediate/06-feature-engineering/README.pt-BR.md new file mode 100644 index 0000000..fd1a44b --- /dev/null +++ b/projects/data-science/intermediate/06-feature-engineering/README.pt-BR.md @@ -0,0 +1,94 @@ +# Pipeline de Engenharia de Features + +> 🌐 [English](./README.md) · **Português** + +**Domínio:** Data Science · **Nível:** Intermediário · **Tempo estimado:** 1–2 dias + +## Visão Geral + +Modelos são tão bons quanto as features que você fornece, e colunas brutas raramente são as features certas. Este projeto constrói um pipeline reutilizável que transforma dados brutos em features prontas para o modelo: codificar categóricas, escalar numéricas, criar interações e features temporais e então *selecionar* o subconjunto que de fato ajuda. A disciplina que separa isso de uma pilha de transformações ad-hoc é o ajuste sem vazamento — cada transformador aprende seus parâmetros só no fold de treino — e a seleção honesta, em que você prova que um conjunto menor de features se sustenta em dados retidos, em vez de apenas ajustar melhor o ruído do treino. + +## Pré-requisitos + +- Conforto com uma biblioteca de dataframe e transformadores do scikit-learn (ou equivalente) +- Entender a diferença entre ajustar (fit) e transformar (transform) +- Familiaridade com divisão treino/validação/teste +- Um conjunto tabular com colunas numéricas e categóricas mistas e um alvo + +## Objetivos de Aprendizado + +Ao final, você deve ser capaz de: + +- Construir um pipeline componível de transformadores que ajusta no treino e transforma qualquer split +- Codificar categóricas (one-hot, target/mean com suavização) sem vazar o alvo +- Criar features de interação, polinomiais e derivadas de tempo e julgar quais valem a pena +- Aplicar métodos de seleção filter, wrapper e embedded e compará-los +- Ranquear a importância das features e validar que features podadas não prejudicam o desempenho retido + +## Requisitos Funcionais + +1. O pipeline deve ser um único objeto ajustado que transforma treino, validação e teste de forma idêntica. +2. Todos os parâmetros dos transformadores (estatísticas do scaler, mapas de codificação) devem ser aprendidos só no treino. +3. Deve gerar pelo menos três tipos de feature (interação, temporal, codificação categórica). +4. Deve implementar pelo menos duas estratégias de seleção e reportar as features que cada uma mantém. +5. Deve produzir uma tabela de importância de features ranqueada. +6. Deve comparar o desempenho do modelo no conjunto completo vs selecionado em dados retidos. +7. Deve tratar valores categóricos não vistos no momento do transform sem quebrar. + +## Marcos Sugeridos + +1. **Marco 1 — Transformadores:** Construa codificação, escalonamento e geração num só pipeline. +2. **Marco 2 — Seleção:** Adicione e compare estratégias de seleção de features. +3. **Marco 3 — Validar:** Ranqueie importância e confirme que o conjunto selecionado se sustenta no teste. + +## Esboço de Dados e Interface + +```text +Linha bruta + id : string + age : int + signup_date : date + plan : categoria + target : numérico | classe + +Pipeline (ajustar só no TREINO) + numérico -> imputar -> escalar + categoria -> codificar (one-hot | target suavizado) + temporal -> days_since, day_of_week, is_weekend + gerar -> interações, termos polinomiais + selecionar-> filter (info mútua) | embedded (L1 / importância de árvore) + +Saídas + matriz de features por split + tabela de importância: feature -> score + perf(completo) vs perf(selecionado) em dados retidos +``` + +## Desafios Extras + +- Adicione um feature store leve: persista transformadores ajustados e versione o conjunto de features. +- Detecte e descarte features altamente correlacionadas automaticamente antes de modelar. +- Adicione geração automática de features (ex.: deep feature synthesis) e pode a explosão. +- Rastreie distribuições de features para que uma checagem de drift posterior possa reutilizá-las. + +## Definição de Pronto + +- [ ] Um pipeline ajustado transforma todos os splits de forma idêntica e reproduzível. +- [ ] Nenhum transformador vê dados de validação ou teste durante o ajuste — sem vazamento do alvo. +- [ ] Pelo menos duas estratégias de seleção são comparadas com as features retidas por cada uma listadas. +- [ ] Uma tabela de importância ranqueada é produzida. +- [ ] O desempenho do conjunto selecionado é comparado ao completo em dados retidos. + +## Armadilhas Comuns + +- Ajustar o scaler ou o target encoder no conjunto inteiro, vazando estatísticas de teste. +- Fazer target encoding de uma coluna de alta cardinalidade sem suavização ou cálculo out-of-fold. +- Ler a importância das features do ajuste de treino e supor que ela generaliza. +- Quebrar numa categoria não vista na inferência porque o encoder nunca a previu. + +## Recursos + +- [scikit-learn: Pipelines e estimadores compostos](https://scikit-learn.org/stable/modules/compose.html) — construindo pipelines sem vazamento. +- [scikit-learn: Seleção de features](https://scikit-learn.org/stable/modules/feature_selection.html) — métodos filter, wrapper, embedded. +- [Documentação do category_encoders](https://contrib.scikit-learn.org/category_encoders/) — target encoding feito com segurança. +- [Kaggle: curso de Feature Engineering](https://www.kaggle.com/learn/feature-engineering) — padrões práticos e armadilhas. diff --git a/projects/data-science/intermediate/07-model-evaluation/README.md b/projects/data-science/intermediate/07-model-evaluation/README.md index 39d0e4f..3147a6e 100644 --- a/projects/data-science/intermediate/07-model-evaluation/README.md +++ b/projects/data-science/intermediate/07-model-evaluation/README.md @@ -1,34 +1,94 @@ # Model Evaluation Framework -## Idea -Build a comprehensive framework for evaluating and comparing machine learning models. Learn about metrics, validation, and model selection. +> 🌐 **English** · [Português](./README.pt-BR.md) + +**Domain:** Data Science · **Level:** Intermediate · **Estimated time:** 1–2 days + +## Overview + +Two models, one dataset — which is better? The honest answer is harder than reading off a single accuracy number. This project builds a framework that evaluates and compares models the way a careful practitioner does: with proper cross-validation, a suite of task-appropriate metrics, confidence intervals around each score, and a statistical test to decide whether one model truly beats another or just got a luckier split. You will learn that the *evaluation protocol* is itself a design decision — the wrong split strategy or the wrong metric can crown the wrong model with total confidence. + +## Prerequisites + +- Comfort training classifiers/regressors and reading a confusion matrix +- Understanding of overfitting and the train/validation/test split rationale +- Familiarity with scikit-learn's estimator interface (fit/predict) +- A labelled dataset (classification or regression) to evaluate models on ## Learning Objectives -- Implement cross-validation -- Calculate diverse metrics -- Compare models fairly -- Handle different data distributions -- Make model selection decisions - -## Implementation Tips -- Implement cross-validation strategies -- Create metric calculation suite -- Implement stratified sampling -- Add time-series validation -- Create learning curves -- Implement validation curves -- Add ROC/AUC analysis -- Create confusion matrices -- Implement confidence intervals -- Add statistical significance tests -- Create model comparison framework -- Implement ensemble evaluation -- Build evaluation reports -- Create reproducible validation - -## Key Challenges -- Metric selection -- Validation strategy appropriateness -- Overfitting detection -- Class imbalance handling -- Statistical rigor + +By the end, you should be able to: + +- Implement k-fold, stratified, and time-series cross-validation and know when each applies +- Assemble a metric suite matched to the task (ROC-AUC, PR-AUC, F1 for classification; RMSE, MAE, R² for regression) +- Attach confidence intervals to metrics via cross-validation folds or bootstrapping +- Run a statistical test (paired, e.g. corrected resampled t-test) to compare two models +- Diagnose over/underfitting with learning and validation curves + +## Functional Requirements + +1. The framework must support multiple cross-validation strategies selectable per run. +2. It must compute a configurable suite of metrics appropriate to the task type. +3. It must report a mean and confidence interval (or standard deviation across folds) for each metric. +4. It must compare at least two models on identical folds and report which wins. +5. It must apply a statistical significance test to the model comparison. +6. It must produce learning and/or validation curves for overfitting diagnosis. +7. It must keep the final test set untouched until the single last evaluation. + +## Suggested Milestones + +1. **Milestone 1 — CV & metrics:** Implement CV strategies and the metric suite. +2. **Milestone 2 — Intervals & curves:** Add confidence intervals and learning curves. +3. **Milestone 3 — Compare:** Run models on shared folds and test significance of the gap. + +## Data & Interface Sketch + +```text +Eval config + task : "classification" | "regression" + cv : "kfold" | "stratified" | "timeseries" + folds : int + metrics : [ ... task-appropriate ... ] + models : [ estimatorA, estimatorB ] + +Steps + 1. hold out final TEST set, untouched + 2. for each model: + cross_validate over SAME folds + collect per-fold scores + 3. summarize: mean +/- CI per metric + 4. compare: paired test on fold scores -> p + 5. learning_curve(model) -> train vs valid gap + 6. one final eval on TEST for the chosen model + +Output: metric table + winner + significance +``` + +## Stretch Goals + +- Add nested cross-validation so hyperparameter tuning does not leak into the score. +- Support calibration curves and Brier score for probabilistic classifiers. +- Add a cost-sensitive metric driven by a user-supplied cost matrix. +- Generate a one-page markdown/HTML report per comparison run. + +## Definition of Done + +- [ ] At least three CV strategies are implemented and chosen appropriately per task. +- [ ] Every metric is reported with a mean and an interval, never a bare point estimate. +- [ ] Two models are compared on identical folds with a significance test on the difference. +- [ ] Learning/validation curves reveal over- or underfitting. +- [ ] The test set is evaluated exactly once, at the end. + +## Common Pitfalls + +- Using plain k-fold on imbalanced data instead of stratified folds. +- Using random CV on time series, letting the model peek at the future. +- Declaring a winner from a 0.2% metric gap that is well inside the fold variance. +- Tuning hyperparameters on the test set, so the final number is optimistic. + +## Resources + +- [scikit-learn: Cross-validation](https://scikit-learn.org/stable/modules/cross_validation.html) — strategies and pitfalls. +- [scikit-learn: Metrics and scoring](https://scikit-learn.org/stable/modules/model_evaluation.html) — the full metric catalogue. +- [Nadeau & Bengio: Inference for the Generalization Error](https://link.springer.com/article/10.1023/A:1024068626366) — the corrected resampled t-test. +- [scikit-learn: Learning curves](https://scikit-learn.org/stable/modules/learning_curve.html) — diagnosing bias vs variance. diff --git a/projects/data-science/intermediate/07-model-evaluation/README.pt-BR.md b/projects/data-science/intermediate/07-model-evaluation/README.pt-BR.md new file mode 100644 index 0000000..6fe28de --- /dev/null +++ b/projects/data-science/intermediate/07-model-evaluation/README.pt-BR.md @@ -0,0 +1,94 @@ +# Framework de Avaliação de Modelos + +> 🌐 [English](./README.md) · **Português** + +**Domínio:** Data Science · **Nível:** Intermediário · **Tempo estimado:** 1–2 dias + +## Visão Geral + +Dois modelos, um conjunto de dados — qual é melhor? A resposta honesta é mais difícil do que ler um único número de acurácia. Este projeto constrói um framework que avalia e compara modelos como um praticante cuidadoso faz: com validação cruzada apropriada, um conjunto de métricas adequadas à tarefa, intervalos de confiança em torno de cada score e um teste estatístico para decidir se um modelo realmente vence outro ou só teve um split mais sortudo. Você vai aprender que o *protocolo de avaliação* é em si uma decisão de projeto — a estratégia de split errada ou a métrica errada pode coroar o modelo errado com total confiança. + +## Pré-requisitos + +- Conforto para treinar classificadores/regressores e ler uma matriz de confusão +- Entender overfitting e a razão da divisão treino/validação/teste +- Familiaridade com a interface de estimadores do scikit-learn (fit/predict) +- Um conjunto rotulado (classificação ou regressão) para avaliar modelos + +## Objetivos de Aprendizado + +Ao final, você deve ser capaz de: + +- Implementar validação cruzada k-fold, estratificada e de séries temporais e saber quando cada uma se aplica +- Montar um conjunto de métricas casado com a tarefa (ROC-AUC, PR-AUC, F1 para classificação; RMSE, MAE, R² para regressão) +- Anexar intervalos de confiança às métricas via folds de validação cruzada ou bootstrapping +- Rodar um teste estatístico (pareado, ex.: t-test reamostrado corrigido) para comparar dois modelos +- Diagnosticar over/underfitting com curvas de aprendizado e de validação + +## Requisitos Funcionais + +1. O framework deve suportar múltiplas estratégias de validação cruzada selecionáveis por execução. +2. Deve calcular um conjunto configurável de métricas apropriadas ao tipo de tarefa. +3. Deve reportar uma média e um intervalo de confiança (ou desvio-padrão entre folds) para cada métrica. +4. Deve comparar pelo menos dois modelos nos mesmos folds e reportar qual vence. +5. Deve aplicar um teste de significância estatística à comparação de modelos. +6. Deve produzir curvas de aprendizado e/ou de validação para diagnóstico de overfitting. +7. Deve manter o conjunto de teste final intocado até a última avaliação única. + +## Marcos Sugeridos + +1. **Marco 1 — CV e métricas:** Implemente as estratégias de CV e o conjunto de métricas. +2. **Marco 2 — Intervalos e curvas:** Adicione intervalos de confiança e curvas de aprendizado. +3. **Marco 3 — Comparar:** Rode os modelos nos folds compartilhados e teste a significância da diferença. + +## Esboço de Dados e Interface + +```text +Config de avaliação + task : "classification" | "regression" + cv : "kfold" | "stratified" | "timeseries" + folds : int + metrics : [ ... apropriadas à tarefa ... ] + models : [ estimadorA, estimadorB ] + +Passos + 1. reservar conjunto de TESTE final, intocado + 2. para cada modelo: + cross_validate sobre os MESMOS folds + coletar scores por fold + 3. resumir: média +/- IC por métrica + 4. comparar: teste pareado nos scores de fold -> p + 5. learning_curve(modelo) -> gap treino vs valid + 6. uma avaliação final no TESTE para o modelo escolhido + +Saída: tabela de métricas + vencedor + significância +``` + +## Desafios Extras + +- Adicione validação cruzada aninhada para que a busca de hiperparâmetros não vaze para o score. +- Suporte curvas de calibração e Brier score para classificadores probabilísticos. +- Adicione uma métrica sensível a custo guiada por uma matriz de custo fornecida pelo usuário. +- Gere um relatório de uma página em markdown/HTML por execução de comparação. + +## Definição de Pronto + +- [ ] Pelo menos três estratégias de CV são implementadas e escolhidas apropriadamente por tarefa. +- [ ] Toda métrica é reportada com uma média e um intervalo, nunca uma estimativa pontual solta. +- [ ] Dois modelos são comparados em folds idênticos com um teste de significância na diferença. +- [ ] Curvas de aprendizado/validação revelam over- ou underfitting. +- [ ] O conjunto de teste é avaliado exatamente uma vez, no final. + +## Armadilhas Comuns + +- Usar k-fold simples em dados desbalanceados em vez de folds estratificados. +- Usar CV aleatória em séries temporais, deixando o modelo espiar o futuro. +- Declarar um vencedor a partir de um gap de 0,2% que está bem dentro da variância entre folds. +- Ajustar hiperparâmetros no conjunto de teste, tornando o número final otimista. + +## Recursos + +- [scikit-learn: Validação cruzada](https://scikit-learn.org/stable/modules/cross_validation.html) — estratégias e armadilhas. +- [scikit-learn: Métricas e scoring](https://scikit-learn.org/stable/modules/model_evaluation.html) — o catálogo completo de métricas. +- [Nadeau & Bengio: Inference for the Generalization Error](https://link.springer.com/article/10.1023/A:1024068626366) — o t-test reamostrado corrigido. +- [scikit-learn: Curvas de aprendizado](https://scikit-learn.org/stable/modules/learning_curve.html) — diagnosticando viés vs variância. diff --git a/projects/data-science/intermediate/08-data-drift-detection/README.md b/projects/data-science/intermediate/08-data-drift-detection/README.md index ec08103..b8b66ac 100644 --- a/projects/data-science/intermediate/08-data-drift-detection/README.md +++ b/projects/data-science/intermediate/08-data-drift-detection/README.md @@ -1,34 +1,93 @@ # Data Drift Detection -## Idea -Implement a system to detect when data distribution changes over time. Learn about monitoring and maintaining model performance. +> 🌐 **English** · [Português](./README.pt-BR.md) + +**Domain:** Data Science · **Level:** Intermediate · **Estimated time:** 1–2 days + +## Overview + +A model trained on last year's data quietly rots when this year's data stops looking like it. This project builds a monitor that watches incoming data against a reference (training) distribution and raises a flag when they diverge — before the model's predictions silently degrade. You will implement statistical distance tests per feature, distinguish feature drift from prediction drift, set thresholds that separate genuine shift from ordinary noise, and produce an interpretable report that says not just *that* drift happened but *which* features moved and by how much. The methodology hinge is a clean, frozen reference window compared against sliding production windows. + +## Prerequisites + +- Comfort with a dataframe library and basic statistics (distributions, quantiles) +- Understanding of the training vs serving data distinction +- Familiarity with hypothesis testing (p-values, test statistics) +- A dataset you can split into a reference period and later "production" batches ## Learning Objectives -- Detect distribution shifts -- Monitor data quality -- Track statistical metrics -- Trigger alerts -- Implement retraining - -## Implementation Tips -- Implement drift detection methods (Kolmogorov-Smirnov test, Population Stability Index) -- Monitor feature distributions -- Track prediction distributions -- Implement thresholds for alerts -- Create visualization of drifts -- Add performance tracking -- Implement automated retraining triggers -- Create monitoring dashboard -- Add data quality checks -- Implement alert system -- Create documentation of drifts -- Build historical tracking -- Implement drift explanations -- Create mitigation strategies - -## Key Challenges -- Drift detection sensitivity -- Distinguishing real drift from noise -- Multi-dimensional drift -- Alert false positives -- Automated response triggers + +By the end, you should be able to: + +- Freeze a reference distribution from training data and compare batches against it +- Detect numeric drift with the Kolmogorov-Smirnov test and categorical drift with chi-square or PSI +- Compute Population Stability Index and interpret its conventional thresholds +- Separate feature (covariate) drift from prediction/target drift and label drift +- Set noise-aware thresholds so ordinary variation does not trigger constant false alarms + +## Functional Requirements + +1. The monitor must accept a reference dataset and successive production batches. +2. It must compute a per-feature drift statistic appropriate to the feature type. +3. It must report Population Stability Index per feature with a severity band (stable/moderate/severe). +4. It must distinguish input-feature drift from prediction-distribution drift. +5. It must apply configurable thresholds and emit an alert only when they are crossed. +6. It must rank which features drifted most in a given batch. +7. It must track drift over time so trends are visible, not just point-in-time snapshots. + +## Suggested Milestones + +1. **Milestone 1 — Reference & tests:** Freeze the reference and implement per-feature drift tests. +2. **Milestone 2 — PSI & alerts:** Add PSI, severity bands, and threshold-based alerting. +3. **Milestone 3 — Track & rank:** Log drift over batches and rank the top movers. + +## Data & Interface Sketch + +```text +Reference window (from training data) + per numeric feature: histogram / quantiles + per categorical : category frequencies + +Batch check + for each feature: + numeric -> KS test statistic, p_value + categorical -> chi-square | PSI + psi = sum( (p_i - q_i) * ln(p_i / q_i) ) + band: psi<0.1 stable | 0.1-0.25 moderate | >0.25 severe + +Report + batch_id, ts + feature -> {psi, test_p, band} + prediction_drift: {psi on model output} + alert: any(band == severe) + top_movers: features sorted by psi desc +``` + +## Stretch Goals + +- Add multivariate drift detection (e.g. a domain classifier that tries to tell reference from batch). +- Correlate detected drift with an observed drop in model performance where labels arrive late. +- Add automatic reference-window refresh with a documented policy and guardrails. +- Build a small time-series dashboard of PSI per feature. + +## Definition of Done + +- [ ] A frozen reference is compared against each production batch, never re-fit silently. +- [ ] Numeric and categorical features each use an appropriate drift test. +- [ ] PSI is reported per feature with severity bands. +- [ ] Feature drift and prediction drift are reported separately. +- [ ] Alerts fire only past configured thresholds and top movers are ranked. + +## Common Pitfalls + +- Comparing against a reference that keeps updating, so real drift is masked. +- Flagging every tiny p-value on huge batches, where even trivial shifts are "significant". +- Watching only input features and missing that the prediction mix has shifted. +- Using one global threshold for features with very different natural variance. + +## Resources + +- [Evidently AI: Data drift guide](https://docs.evidentlyai.com/) — practical drift detection and reports. +- [Wikipedia: Kolmogorov–Smirnov test](https://en.wikipedia.org/wiki/Kolmogorov%E2%80%93Smirnov_test) — the numeric drift workhorse. +- [Population Stability Index explained](https://www.listendata.com/2015/05/population-stability-index.html) — PSI formula and thresholds. +- [Google: ML data and concept drift](https://developers.google.com/machine-learning/managing-ml-projects/monitoring) — monitoring in production. diff --git a/projects/data-science/intermediate/08-data-drift-detection/README.pt-BR.md b/projects/data-science/intermediate/08-data-drift-detection/README.pt-BR.md new file mode 100644 index 0000000..edcc97b --- /dev/null +++ b/projects/data-science/intermediate/08-data-drift-detection/README.pt-BR.md @@ -0,0 +1,93 @@ +# Detecção de Data Drift + +> 🌐 [English](./README.md) · **Português** + +**Domínio:** Data Science · **Nível:** Intermediário · **Tempo estimado:** 1–2 dias + +## Visão Geral + +Um modelo treinado nos dados do ano passado apodrece silenciosamente quando os dados deste ano deixam de se parecer com eles. Este projeto constrói um monitor que observa os dados que chegam contra uma distribuição de referência (de treino) e levanta um alerta quando elas divergem — antes que as predições do modelo degradem sem aviso. Você vai implementar testes de distância estatística por feature, distinguir drift de feature de drift de predição, definir limiares que separam mudança genuína de ruído comum e produzir um relatório interpretável que diz não só *que* houve drift, mas *quais* features se moveram e por quanto. O eixo metodológico é uma janela de referência limpa e congelada, comparada contra janelas deslizantes de produção. + +## Pré-requisitos + +- Conforto com uma biblioteca de dataframe e estatística básica (distribuições, quantis) +- Entender a distinção entre dados de treino e de serving +- Familiaridade com teste de hipóteses (p-valores, estatísticas de teste) +- Um conjunto que você possa dividir em um período de referência e lotes posteriores de "produção" + +## Objetivos de Aprendizado + +Ao final, você deve ser capaz de: + +- Congelar uma distribuição de referência a partir dos dados de treino e comparar lotes contra ela +- Detectar drift numérico com o teste de Kolmogorov-Smirnov e drift categórico com qui-quadrado ou PSI +- Calcular o Population Stability Index e interpretar seus limiares convencionais +- Separar drift de feature (covariável) de drift de predição/alvo e drift de rótulo +- Definir limiares cientes do ruído para que a variação comum não dispare falsos alarmes constantes + +## Requisitos Funcionais + +1. O monitor deve aceitar um conjunto de referência e lotes sucessivos de produção. +2. Deve calcular uma estatística de drift por feature apropriada ao tipo da feature. +3. Deve reportar o Population Stability Index por feature com uma faixa de severidade (estável/moderado/severo). +4. Deve distinguir drift de feature de entrada de drift da distribuição de predição. +5. Deve aplicar limiares configuráveis e emitir um alerta só quando eles são ultrapassados. +6. Deve ranquear quais features sofreram mais drift em um lote dado. +7. Deve rastrear drift ao longo do tempo para que tendências sejam visíveis, não só snapshots pontuais. + +## Marcos Sugeridos + +1. **Marco 1 — Referência e testes:** Congele a referência e implemente testes de drift por feature. +2. **Marco 2 — PSI e alertas:** Adicione PSI, faixas de severidade e alertas por limiar. +3. **Marco 3 — Rastrear e ranquear:** Registre drift ao longo dos lotes e ranqueie os que mais moveram. + +## Esboço de Dados e Interface + +```text +Janela de referência (dos dados de treino) + por feature numérica : histograma / quantis + por feature categórica: frequências de categoria + +Checagem de lote + para cada feature: + numérica -> estatística do teste KS, p_value + categórica -> qui-quadrado | PSI + psi = soma( (p_i - q_i) * ln(p_i / q_i) ) + faixa: psi<0.1 estável | 0.1-0.25 moderado | >0.25 severo + +Relatório + batch_id, ts + feature -> {psi, test_p, faixa} + prediction_drift: {psi na saída do modelo} + alerta: any(faixa == severo) + top_movers: features ordenadas por psi desc +``` + +## Desafios Extras + +- Adicione detecção de drift multivariado (ex.: um classificador de domínio que tenta separar referência de lote). +- Correlacione o drift detectado com uma queda observada de desempenho onde os rótulos chegam atrasados. +- Adicione atualização automática da janela de referência com política documentada e guardrails. +- Construa um pequeno dashboard de séries temporais de PSI por feature. + +## Definição de Pronto + +- [ ] Uma referência congelada é comparada contra cada lote de produção, nunca reajustada silenciosamente. +- [ ] Features numéricas e categóricas usam, cada uma, um teste de drift apropriado. +- [ ] O PSI é reportado por feature com faixas de severidade. +- [ ] Drift de feature e drift de predição são reportados separadamente. +- [ ] Alertas disparam só além dos limiares configurados e os top movers são ranqueados. + +## Armadilhas Comuns + +- Comparar contra uma referência que fica se atualizando, mascarando o drift real. +- Sinalizar todo p-valor minúsculo em lotes enormes, onde até mudanças triviais são "significativas". +- Observar só as features de entrada e não perceber que a mistura de predições mudou. +- Usar um limiar global único para features com variâncias naturais muito diferentes. + +## Recursos + +- [Evidently AI: guia de data drift](https://docs.evidentlyai.com/) — detecção prática de drift e relatórios. +- [Wikipedia: teste de Kolmogorov–Smirnov](https://en.wikipedia.org/wiki/Kolmogorov%E2%80%93Smirnov_test) — o cavalo de batalha do drift numérico. +- [Population Stability Index explicado](https://www.listendata.com/2015/05/population-stability-index.html) — fórmula e limiares do PSI. +- [Google: drift de dados e conceito em ML](https://developers.google.com/machine-learning/managing-ml-projects/monitoring) — monitoramento em produção. diff --git a/projects/data-science/intermediate/09-time-series-arima/README.md b/projects/data-science/intermediate/09-time-series-arima/README.md index 9f4be42..fe1fc11 100644 --- a/projects/data-science/intermediate/09-time-series-arima/README.md +++ b/projects/data-science/intermediate/09-time-series-arima/README.md @@ -1,34 +1,89 @@ # Time Series Forecasting (ARIMA) -## Idea -Build a time series forecasting model using ARIMA methodology. Learn about advanced time series techniques and parameter selection. +> 🌐 **English** · [Português](./README.pt-BR.md) + +**Domain:** Data Science · **Level:** Intermediate · **Estimated time:** 1–2 days + +## Overview + +Time series break the assumptions most models rely on: the observations are ordered, correlated with their own past, and you must never let the future leak backward. This project builds an ARIMA forecasting workflow the right way — test for stationarity, difference until the series is stable, read ACF/PACF plots to propose model orders, fit and validate on a chronological hold-out, and produce forecasts *with* prediction intervals so the uncertainty is honest. The discipline that separates a real forecast from a fantasy is the split: training always precedes the validation window in time, and metrics are computed on genuinely future points. + +## Prerequisites + +- Comfort with a dataframe library and plotting time-indexed data +- Understanding of mean, variance, autocorrelation, and trend/seasonality +- Familiarity with a stats/forecasting library (statsmodels, pmdarima) +- A univariate time series with enough history (daily/monthly observations) ## Learning Objectives -- Check time series stationarity -- Implement ARIMA model -- Select appropriate parameters -- Make accurate forecasts -- Handle uncertainty - -## Implementation Tips -- Implement stationarity testing (ADF test) -- Apply differencing if needed -- Use ACF/PACF plots for parameter selection -- Implement ARIMA model -- Add seasonal ARIMA (SARIMA) -- Implement model validation -- Create forecast intervals -- Add exogenous variables (ARIMAX) -- Implement model comparison -- Handle missing values -- Create residual diagnostics -- Implement multiple forecasts -- Build forecasting pipeline -- Add performance tracking - -## Key Challenges -- Parameter selection complexity -- Stationarity assumptions -- Handling structural breaks -- Multivariate forecasting -- Long-term forecast accuracy + +By the end, you should be able to: + +- Test stationarity with the Augmented Dickey-Fuller test and difference to achieve it +- Read ACF and PACF plots to propose candidate (p, d, q) orders +- Fit ARIMA/SARIMA and select orders by AIC/BIC alongside residual diagnostics +- Validate with a chronological train/validation split and rolling-origin backtesting +- Produce point forecasts with prediction intervals and evaluate with MAE, RMSE, and MAPE + +## Functional Requirements + +1. The workflow must test stationarity and apply differencing until the series is stationary. +2. It must use ACF/PACF evidence to justify candidate model orders, not only auto-search. +3. It must split the series chronologically — training strictly before validation in time. +4. It must fit ARIMA and seasonal ARIMA and compare them via information criteria and error metrics. +5. It must run residual diagnostics (autocorrelation, normality) to check model adequacy. +6. It must output forecasts with prediction intervals, not point estimates alone. +7. It must evaluate forecasts with at least two error metrics on the held-out window. + +## Suggested Milestones + +1. **Milestone 1 — Stationarity:** Test with ADF, difference, and inspect ACF/PACF. +2. **Milestone 2 — Fit & diagnose:** Fit ARIMA/SARIMA, select orders, check residuals. +3. **Milestone 3 — Forecast & backtest:** Produce interval forecasts and rolling-origin evaluation. + +## Data & Interface Sketch + +```text +Series + ts : ordered timestamp (index) + value : float + +Steps + 1. plot + decompose (trend / seasonal / residual) + 2. ADF test -> stationary? if not, difference (d) + 3. ACF/PACF -> candidate p, q (seasonal: P, D, Q, s) + 4. split chronologically: train = [t0 .. tk] , valid = (tk .. tn] + 5. fit ARIMA(p,d,q) / SARIMA -> pick by AIC + residual check + 6. forecast horizon h with 95% prediction interval + 7. metrics on valid: MAE, RMSE, MAPE + 8. rolling-origin backtest for stability +``` + +## Stretch Goals + +- Add exogenous regressors (ARIMAX/SARIMAX) such as holidays or price. +- Compare ARIMA against a simple baseline (naive/seasonal-naive) and a Prophet-style model. +- Handle missing timestamps and structural breaks explicitly. +- Automate order selection with pmdarima and reconcile it against your manual ACF/PACF read. + +## Definition of Done + +- [ ] Stationarity is tested and the differencing order is justified. +- [ ] Candidate orders are supported by ACF/PACF, not just auto-arima. +- [ ] The split is strictly chronological — no future data in training. +- [ ] Residual diagnostics confirm the model captured the structure. +- [ ] Forecasts include prediction intervals and are scored with at least two metrics. + +## Common Pitfalls + +- Random-splitting a time series, leaking future observations into training. +- Forecasting on a non-stationary series and trusting the confidence bands. +- Reading MAPE on a series with values near zero, where it explodes meaninglessly. +- Ignoring seasonality, then blaming ARIMA for missing an obvious yearly cycle. + +## Resources + +- [Hyndman & Athanasopoulos: Forecasting Principles and Practice](https://otexts.com/fpp3/) — the canonical free textbook. +- [statsmodels: ARIMA and SARIMAX](https://www.statsmodels.org/stable/tsa.html) — implementation and diagnostics. +- [Duke: Identifying ARIMA models via ACF/PACF](https://people.duke.edu/~rnau/411arim.htm) — how to read the plots. +- [Wikipedia: Augmented Dickey–Fuller test](https://en.wikipedia.org/wiki/Augmented_Dickey%E2%80%93Fuller_test) — the stationarity check. diff --git a/projects/data-science/intermediate/09-time-series-arima/README.pt-BR.md b/projects/data-science/intermediate/09-time-series-arima/README.pt-BR.md new file mode 100644 index 0000000..3f4df97 --- /dev/null +++ b/projects/data-science/intermediate/09-time-series-arima/README.pt-BR.md @@ -0,0 +1,89 @@ +# Previsão de Séries Temporais (ARIMA) + +> 🌐 [English](./README.md) · **Português** + +**Domínio:** Data Science · **Nível:** Intermediário · **Tempo estimado:** 1–2 dias + +## Visão Geral + +Séries temporais quebram as suposições em que a maioria dos modelos confia: as observações são ordenadas, correlacionadas com o próprio passado, e você nunca pode deixar o futuro vazar para trás. Este projeto constrói um fluxo de previsão ARIMA do jeito certo — testar estacionariedade, diferenciar até a série ficar estável, ler gráficos ACF/PACF para propor ordens do modelo, ajustar e validar em um hold-out cronológico, e produzir previsões *com* intervalos de predição para que a incerteza seja honesta. A disciplina que separa uma previsão real de uma fantasia é o split: o treino sempre precede a janela de validação no tempo, e as métricas são calculadas em pontos genuinamente futuros. + +## Pré-requisitos + +- Conforto com uma biblioteca de dataframe e plotagem de dados indexados no tempo +- Entender média, variância, autocorrelação e tendência/sazonalidade +- Familiaridade com uma biblioteca de estatística/previsão (statsmodels, pmdarima) +- Uma série temporal univariada com histórico suficiente (observações diárias/mensais) + +## Objetivos de Aprendizado + +Ao final, você deve ser capaz de: + +- Testar estacionariedade com o teste Augmented Dickey-Fuller e diferenciar para alcançá-la +- Ler gráficos ACF e PACF para propor ordens candidatas (p, d, q) +- Ajustar ARIMA/SARIMA e selecionar ordens por AIC/BIC junto a diagnósticos de resíduos +- Validar com um split cronológico treino/validação e backtesting de origem móvel +- Produzir previsões pontuais com intervalos de predição e avaliar com MAE, RMSE e MAPE + +## Requisitos Funcionais + +1. O fluxo deve testar estacionariedade e aplicar diferenciação até a série ficar estacionária. +2. Deve usar evidência de ACF/PACF para justificar ordens candidatas, não só busca automática. +3. Deve dividir a série cronologicamente — treino estritamente antes da validação no tempo. +4. Deve ajustar ARIMA e ARIMA sazonal e compará-los via critérios de informação e métricas de erro. +5. Deve rodar diagnósticos de resíduos (autocorrelação, normalidade) para checar a adequação do modelo. +6. Deve produzir previsões com intervalos de predição, não estimativas pontuais sozinhas. +7. Deve avaliar as previsões com pelo menos duas métricas de erro na janela retida. + +## Marcos Sugeridos + +1. **Marco 1 — Estacionariedade:** Teste com ADF, diferencie e inspecione ACF/PACF. +2. **Marco 2 — Ajustar e diagnosticar:** Ajuste ARIMA/SARIMA, selecione ordens, cheque resíduos. +3. **Marco 3 — Prever e backtest:** Produza previsões com intervalo e avaliação de origem móvel. + +## Esboço de Dados e Interface + +```text +Série + ts : timestamp ordenado (índice) + value : float + +Passos + 1. plotar + decompor (tendência / sazonal / resíduo) + 2. teste ADF -> estacionária? se não, diferenciar (d) + 3. ACF/PACF -> candidatos p, q (sazonal: P, D, Q, s) + 4. dividir cronologicamente: treino = [t0 .. tk] , valid = (tk .. tn] + 5. ajustar ARIMA(p,d,q) / SARIMA -> escolher por AIC + checagem de resíduo + 6. prever horizonte h com intervalo de predição de 95% + 7. métricas no valid: MAE, RMSE, MAPE + 8. backtest de origem móvel para estabilidade +``` + +## Desafios Extras + +- Adicione regressores exógenos (ARIMAX/SARIMAX) como feriados ou preço. +- Compare ARIMA com um baseline simples (naive/naive sazonal) e um modelo estilo Prophet. +- Trate timestamps faltantes e quebras estruturais explicitamente. +- Automatize a seleção de ordens com pmdarima e reconcilie com sua leitura manual de ACF/PACF. + +## Definição de Pronto + +- [ ] A estacionariedade é testada e a ordem de diferenciação é justificada. +- [ ] As ordens candidatas são apoiadas por ACF/PACF, não só por auto-arima. +- [ ] O split é estritamente cronológico — sem dados do futuro no treino. +- [ ] Os diagnósticos de resíduos confirmam que o modelo capturou a estrutura. +- [ ] As previsões incluem intervalos de predição e são avaliadas com pelo menos duas métricas. + +## Armadilhas Comuns + +- Dividir a série aleatoriamente, vazando observações futuras para o treino. +- Prever sobre uma série não estacionária e confiar nas bandas de confiança. +- Ler MAPE numa série com valores perto de zero, onde ele explode sem sentido. +- Ignorar a sazonalidade e depois culpar o ARIMA por perder um ciclo anual óbvio. + +## Recursos + +- [Hyndman & Athanasopoulos: Forecasting Principles and Practice](https://otexts.com/fpp3/) — o livro-texto gratuito canônico. +- [statsmodels: ARIMA e SARIMAX](https://www.statsmodels.org/stable/tsa.html) — implementação e diagnósticos. +- [Duke: Identificando modelos ARIMA via ACF/PACF](https://people.duke.edu/~rnau/411arim.htm) — como ler os gráficos. +- [Wikipedia: teste Augmented Dickey–Fuller](https://en.wikipedia.org/wiki/Augmented_Dickey%E2%80%93Fuller_test) — a checagem de estacionariedade. diff --git a/projects/data-science/intermediate/10-ml-pipeline/README.md b/projects/data-science/intermediate/10-ml-pipeline/README.md index 5516522..140ff17 100644 --- a/projects/data-science/intermediate/10-ml-pipeline/README.md +++ b/projects/data-science/intermediate/10-ml-pipeline/README.md @@ -1,34 +1,95 @@ -# ML Pipeline (train + validate + deploy) +# ML Pipeline (Train + Validate + Deploy) -## Idea -Create a complete machine learning pipeline from training to deployment. Learn about workflow automation and model serving. +> 🌐 **English** · [Português](./README.pt-BR.md) + +**Domain:** Data Science · **Level:** Intermediate · **Estimated time:** 1–2 days + +## Overview + +A notebook that trains a good model is a start; a pipeline you can re-run tomorrow, on new data, with a versioned result you can serve, is the actual job. This project ties together everything an intermediate practitioner needs: a reproducible flow from raw data through feature engineering, training, validation, and a served prediction endpoint, with the model and its metrics versioned in a registry. The methodological spine is a clean train/validation/test split enforced *inside* the pipeline, so every re-run evaluates honestly and the number you promote to "production" is the one measured on data the model never saw. + +## Prerequisites + +- Comfort training a model and building a feature transformer (see [Feature Engineering Pipeline](../06-feature-engineering/)) +- Understanding of train/validation/test methodology and evaluation metrics +- Familiarity with functions/modules and a serving option (a small HTTP framework) +- A labelled dataset suitable for a supervised task ## Learning Objectives -- Implement automated training -- Set up model validation -- Deploy models -- Monitor performance -- Handle updates - -## Implementation Tips -- Create data loading and preprocessing -- Implement model training loop -- Add validation and testing -- Create model versioning -- Implement model registry -- Add performance tracking -- Create deployment pipeline -- Implement model serving -- Add monitoring and alerting -- Create update mechanisms -- Implement A/B testing framework -- Add rollback capabilities -- Create documentation -- Build reproducible workflows - -## Key Challenges -- Pipeline complexity -- Data versioning -- Model versioning -- Dependency management -- Monitoring and debugging + +By the end, you should be able to: + +- Compose data loading, feature engineering, training, and evaluation into one runnable pipeline +- Enforce a leak-free train/validation/test split as a pipeline stage, not an afterthought +- Persist a trained model with its metrics and metadata in a simple registry +- Serve predictions from the persisted model behind an endpoint +- Re-run the whole pipeline reproducibly and compare a new model version to the current one + +## Functional Requirements + +1. The pipeline must run end to end from raw data to an evaluated, saved model with one command. +2. It must split data into train/validation/test and fit all transformers on training data only. +3. It must evaluate on the held-out test set and record the metrics with the model artifact. +4. It must version each model (id, timestamp, metrics, data hash) in a registry. +5. It must load a chosen model version and serve predictions behind an endpoint. +6. It must validate incoming prediction inputs and reject malformed requests. +7. It must let a new model be compared against the current one before promotion. + +## Suggested Milestones + +1. **Milestone 1 — Train pipeline:** Load, split, engineer features, train, evaluate on test. +2. **Milestone 2 — Registry:** Persist model + metrics + metadata and version it. +3. **Milestone 3 — Serve & compare:** Load a version, serve predictions, compare candidates. + +## Data & Interface Sketch + +```text +Registry entry + model_id : string + created_at : ISO-8601 + metrics : { accuracy, f1, auc, ... on TEST } + data_hash : string (which data produced it) + path : artifact location + +Pipeline stages + 1. load raw -> validate schema + 2. split -> train / valid / test (fixed seed, recorded) + 3. fit feature transformers on TRAIN + 4. train model; tune on VALID + 5. final eval on TEST -> metrics + 6. register(model, metrics, metadata) + +Serving + POST /predict body: { features: {...} } + -> 200 { prediction, model_id } | 400 invalid + GET /models -> list versions + metrics +``` + +## Stretch Goals + +- Add scheduled retraining and only promote a candidate if it beats the incumbent on test. +- Emit basic monitoring (prediction latency, input distribution) for a drift check to consume. +- Add rollback: repoint serving to a previous model version by id. +- Containerize the serving component and parameterize the model version it loads. + +## Definition of Done + +- [ ] One command runs load → split → features → train → test-eval → register. +- [ ] Transformers are fit on training data only; the test metric is on unseen data. +- [ ] Every model version carries its metrics, timestamp, and data hash in the registry. +- [ ] The endpoint serves a chosen version and validates its inputs. +- [ ] A new candidate can be compared to the current model before promotion. + +## Common Pitfalls + +- Fitting the scaler/encoder before the split, so the "test" metric is inflated. +- Serving a model without recording which data or code produced it — unreproducible. +- Skipping input validation, so the endpoint crashes or silently mispredicts on bad payloads. +- Promoting a new model on a validation number while never touching the true test set. + +## Resources + +- [scikit-learn: Pipeline](https://scikit-learn.org/stable/modules/generated/sklearn.pipeline.Pipeline.html) — composing reproducible flows. +- [MLflow: Tracking and Model Registry](https://mlflow.org/docs/latest/index.html) — versioning models and metrics. +- [Google: MLOps continuous delivery](https://cloud.google.com/architecture/mlops-continuous-delivery-and-automation-pipelines-in-machine-learning) — pipeline maturity levels. +- [FastAPI docs](https://fastapi.tiangolo.com/) — a common way to serve model predictions. diff --git a/projects/data-science/intermediate/10-ml-pipeline/README.pt-BR.md b/projects/data-science/intermediate/10-ml-pipeline/README.pt-BR.md new file mode 100644 index 0000000..f35a878 --- /dev/null +++ b/projects/data-science/intermediate/10-ml-pipeline/README.pt-BR.md @@ -0,0 +1,95 @@ +# Pipeline de ML (Treinar + Validar + Implantar) + +> 🌐 [English](./README.md) · **Português** + +**Domínio:** Data Science · **Nível:** Intermediário · **Tempo estimado:** 1–2 dias + +## Visão Geral + +Um notebook que treina um bom modelo é um começo; um pipeline que você pode reexecutar amanhã, sobre dados novos, com um resultado versionado que você consegue servir, é o trabalho de verdade. Este projeto amarra tudo o que um praticante intermediário precisa: um fluxo reproduzível dos dados brutos passando por engenharia de features, treino, validação e um endpoint de predição servido, com o modelo e suas métricas versionados em um registro. A espinha metodológica é um split limpo treino/validação/teste imposto *dentro* do pipeline, para que cada reexecução avalie honestamente e o número que você promove a "produção" seja o medido em dados que o modelo nunca viu. + +## Pré-requisitos + +- Conforto para treinar um modelo e construir um transformador de features (veja [Pipeline de Engenharia de Features](../06-feature-engineering/)) +- Entender a metodologia treino/validação/teste e métricas de avaliação +- Familiaridade com funções/módulos e uma opção de serving (um pequeno framework HTTP) +- Um conjunto rotulado adequado a uma tarefa supervisionada + +## Objetivos de Aprendizado + +Ao final, você deve ser capaz de: + +- Compor carregamento de dados, engenharia de features, treino e avaliação em um pipeline executável +- Impor um split treino/validação/teste sem vazamento como um estágio do pipeline, não um remendo +- Persistir um modelo treinado com suas métricas e metadados em um registro simples +- Servir predições a partir do modelo persistido atrás de um endpoint +- Reexecutar o pipeline inteiro de forma reproduzível e comparar uma nova versão do modelo com a atual + +## Requisitos Funcionais + +1. O pipeline deve rodar de ponta a ponta dos dados brutos a um modelo avaliado e salvo com um comando. +2. Deve dividir os dados em treino/validação/teste e ajustar todos os transformadores só no treino. +3. Deve avaliar no conjunto de teste retido e registrar as métricas junto ao artefato do modelo. +4. Deve versionar cada modelo (id, timestamp, métricas, hash dos dados) em um registro. +5. Deve carregar uma versão de modelo escolhida e servir predições atrás de um endpoint. +6. Deve validar as entradas de predição e rejeitar requisições malformadas. +7. Deve permitir que um novo modelo seja comparado com o atual antes da promoção. + +## Marcos Sugeridos + +1. **Marco 1 — Pipeline de treino:** Carregar, dividir, criar features, treinar, avaliar no teste. +2. **Marco 2 — Registro:** Persistir modelo + métricas + metadados e versioná-lo. +3. **Marco 3 — Servir e comparar:** Carregar uma versão, servir predições, comparar candidatos. + +## Esboço de Dados e Interface + +```text +Entrada do registro + model_id : string + created_at : ISO-8601 + metrics : { accuracy, f1, auc, ... no TESTE } + data_hash : string (quais dados o produziram) + path : local do artefato + +Estágios do pipeline + 1. carregar bruto -> validar schema + 2. dividir -> treino / valid / teste (seed fixa, registrada) + 3. ajustar transformadores de feature no TREINO + 4. treinar modelo; ajustar no VALID + 5. avaliação final no TESTE -> métricas + 6. registrar(modelo, métricas, metadados) + +Serving + POST /predict body: { features: {...} } + -> 200 { prediction, model_id } | 400 inválido + GET /models -> listar versões + métricas +``` + +## Desafios Extras + +- Adicione retreino agendado e só promova um candidato se ele superar o vigente no teste. +- Emita monitoramento básico (latência de predição, distribuição de entrada) para uma checagem de drift consumir. +- Adicione rollback: reaponte o serving para uma versão anterior do modelo por id. +- Containerize o componente de serving e parametrize a versão do modelo que ele carrega. + +## Definição de Pronto + +- [ ] Um comando roda carregar → dividir → features → treinar → avaliar-no-teste → registrar. +- [ ] Os transformadores são ajustados só nos dados de treino; a métrica de teste é em dados não vistos. +- [ ] Toda versão de modelo carrega suas métricas, timestamp e hash dos dados no registro. +- [ ] O endpoint serve uma versão escolhida e valida suas entradas. +- [ ] Um novo candidato pode ser comparado ao modelo atual antes da promoção. + +## Armadilhas Comuns + +- Ajustar o scaler/encoder antes do split, inflando a métrica de "teste". +- Servir um modelo sem registrar quais dados ou código o produziram — irreproduzível. +- Pular a validação de entrada, deixando o endpoint quebrar ou prever errado silenciosamente com payloads ruins. +- Promover um novo modelo por um número de validação sem nunca tocar o verdadeiro conjunto de teste. + +## Recursos + +- [scikit-learn: Pipeline](https://scikit-learn.org/stable/modules/generated/sklearn.pipeline.Pipeline.html) — compondo fluxos reproduzíveis. +- [MLflow: Tracking e Model Registry](https://mlflow.org/docs/latest/index.html) — versionando modelos e métricas. +- [Google: entrega contínua de MLOps](https://cloud.google.com/architecture/mlops-continuous-delivery-and-automation-pipelines-in-machine-learning) — níveis de maturidade de pipeline. +- [Documentação do FastAPI](https://fastapi.tiangolo.com/) — uma forma comum de servir predições de modelo. diff --git a/projects/devops/advanced/01-multi-cluster-k8s/README.md b/projects/devops/advanced/01-multi-cluster-k8s/README.md index d1ec720..d0bb35e 100644 --- a/projects/devops/advanced/01-multi-cluster-k8s/README.md +++ b/projects/devops/advanced/01-multi-cluster-k8s/README.md @@ -1,34 +1,94 @@ # Multi-Cluster Kubernetes Architecture -## Idea -Design a multi-cluster Kubernetes setup for high availability. Learn about distributed Kubernetes systems. +> 🌐 **English** · [Português](./README.pt-BR.md) + +**Domain:** DevOps · **Level:** Advanced · **Estimated time:** 1–2 weeks + +## Overview + +Run a single logical platform across several Kubernetes clusters so that the loss of one cluster — or an entire availability zone — does not take your workloads down. You will stand up at least two clusters, give them a shared identity and networking story, and put a control plane in front that decides where workloads run and how traffic reaches them. The interesting problems are not "install Kubernetes twice"; they are cluster discovery, cross-cluster service resolution, config propagation without drift, and a failover that is fast enough to matter but conservative enough not to flap. Treat this as an exercise in reasoning about blast radius: what breaks when one cluster dies, and how do you prove recovery beforehand? + +## Prerequisites + +- Solid single-cluster Kubernetes experience — Deployments, Services, Ingress, RBAC ([Kubernetes Deployment](../../intermediate/) work is a good stepping stone if you need one) +- Comfort with a managed or self-hosted cluster provider (EKS, GKE, AKS, or kubeadm) +- Understanding of DNS, load balancing, and the L4/L7 distinction +- Familiarity with declarative config and a tool like Helm or Kustomize ## Learning Objectives -- Manage multiple clusters -- Handle cluster federation -- Implement failover -- Manage data consistency -- Monitor multi-cluster - -## Implementation Tips -- Set up multiple Kubernetes clusters -- Implement cluster federation -- Create service mesh for cluster communication -- Implement multi-cluster networking -- Add traffic management -- Create disaster recovery -- Implement data replication -- Add cluster-level monitoring -- Create cost optimization -- Implement compliance across clusters -- Add security policies -- Create operational tooling -- Build management dashboards -- Implement automated failover - -## Key Challenges -- Inter-cluster networking -- Data consistency -- Complex failover -- Monitoring complexity -- Cost management + +By the end, you should be able to: + +- Design a multi-cluster topology and justify federation vs. independent clusters +- Register clusters with a central control plane and propagate configuration consistently +- Route traffic across clusters with health-aware failover and locality preference +- Replicate or partition state deliberately, reasoning about consistency trade-offs +- Define availability targets and measure recovery time against them + +## Functional Requirements + +1. The platform must run across at least two clusters with a single point of workload placement. +2. A service in one cluster must be resolvable and reachable from another cluster. +3. Configuration changes must propagate to all target clusters without manual per-cluster editing. +4. When a cluster becomes unhealthy, traffic must fail over to a surviving cluster automatically. +5. The system must expose per-cluster and aggregate health so operators can see blast radius. +6. Failover and failback must be reversible and must not lose in-flight requests silently. +7. Access control and security policies must apply uniformly across all clusters. + +## Suggested Milestones + +1. **Milestone 1 — Two clusters, shared identity:** Provision the clusters, establish networking and a common trust root, verify pod-to-pod reachability across clusters. +2. **Milestone 2 — Placement & propagation:** Introduce a control plane (Karmada, Cluster API, or fleet tooling) that schedules workloads and syncs config to both clusters. +3. **Milestone 3 — Cross-cluster traffic & failover:** Add global service resolution and a health-aware router, then kill a cluster and measure recovery. +4. **Milestone 4 — Guardrails:** Uniform RBAC/network policy, aggregate observability, and a documented disaster-recovery runbook. + +## Data & Interface Sketch + +```text + ┌────────────────────────┐ + operators / GitOps ─▶│ Control Plane / Fleet │ (placement, config sync) + └───────────┬────────────┘ + ┌──────────┴──────────┐ + ▼ ▼ + ┌────────────┐ ┌────────────┐ + Global LB ───▶│ Cluster A │ │ Cluster B │◀─── Global LB + (GeoDNS / │ us-east │◀──mTLS─▶│ eu-west │ + Anycast) └────────────┘ └────────────┘ + svc: api cross-cluster svc: api + service discovery + +Non-functional targets to state up front: + availability >= 99.95% platform-wide (survives 1 cluster loss) + failover RTO < 60s to shift traffic off a dead cluster + config drift 0 undetected divergences between clusters +``` + +## Stretch Goals + +- Add a third cluster and test placement policies that respect region/zone locality. +- Introduce stateful workload replication (e.g. a replicated datastore) and reason about its RPO. +- Automate failback with a canary re-entry so recovered clusters don't take full load instantly. +- Add cost-awareness so the scheduler prefers cheaper clusters when SLOs allow. + +## Definition of Done + +- [ ] Two or more clusters run under a single control plane with config synced automatically. +- [ ] A service is reachable cross-cluster and survives one cluster being deleted. +- [ ] Failover happens within your stated RTO and is observable in a dashboard. +- [ ] There is no undetected config drift — a check flags divergence. +- [ ] A disaster-recovery runbook exists and has been rehearsed at least once. + +## Common Pitfalls + +- Treating multi-cluster as "prod + DR" and never actually exercising failover, so it fails when needed. +- Overlapping pod/service CIDRs across clusters, making cross-cluster routing impossible without NAT. +- Letting each cluster drift because config is applied manually instead of reconciled from one source. +- Replicating state naively and discovering split-brain the hard way during a partition. +- Ignoring the cost and operational tax of the extra cluster until the bill or the pager arrives. + +## Resources + +- [Kubernetes: Multi-cluster concepts](https://kubernetes.io/docs/concepts/cluster-administration/) — cluster administration fundamentals. +- [Karmada documentation](https://karmada.io/docs/) — a CNCF multi-cluster orchestration control plane. +- [Cluster API](https://cluster-api.sigs.k8s.io/) — declarative cluster lifecycle management. +- [Google SRE Book: Managing Critical State](https://sre.google/sre-book/managing-critical-state/) — consistency and failover trade-offs. diff --git a/projects/devops/advanced/01-multi-cluster-k8s/README.pt-BR.md b/projects/devops/advanced/01-multi-cluster-k8s/README.pt-BR.md new file mode 100644 index 0000000..d99be50 --- /dev/null +++ b/projects/devops/advanced/01-multi-cluster-k8s/README.pt-BR.md @@ -0,0 +1,95 @@ +# Arquitetura Kubernetes Multi-Cluster + +> 🌐 [English](./README.md) · **Português** + +**Domínio:** DevOps · **Nível:** Avançado · **Tempo estimado:** 1–2 semanas + +## Visão Geral + +Execute uma única plataforma lógica sobre vários clusters Kubernetes, de modo que a perda de um cluster — ou de uma zona de disponibilidade inteira — não derrube suas cargas de trabalho. Você vai subir pelo menos dois clusters, dar a eles uma identidade e uma estratégia de rede compartilhadas, e colocar na frente um plano de controle que decide onde as cargas rodam e como o tráfego chega até elas. Os problemas interessantes não são "instalar o Kubernetes duas vezes"; são descoberta de clusters, resolução de serviços entre clusters, propagação de configuração sem drift e um failover rápido o bastante para importar, mas conservador o bastante para não oscilar. Encare isto como um exercício de raciocínio sobre raio de impacto: o que quebra quando um cluster morre, e como você prova a recuperação de antemão? + +## Pré-requisitos + +- Experiência sólida com Kubernetes de cluster único — Deployments, Services, Ingress, RBAC ([trabalho com Kubernetes Deployment](../../intermediate/) é um bom degrau, se precisar) +- Conforto com um provedor de cluster gerenciado ou próprio (EKS, GKE, AKS ou kubeadm) +- Entendimento de DNS, balanceamento de carga e a distinção L4/L7 +- Familiaridade com configuração declarativa e uma ferramenta como Helm ou Kustomize + +## Objetivos de Aprendizado + +Ao final, você deve ser capaz de: + +- Desenhar uma topologia multi-cluster e justificar federação vs. clusters independentes +- Registrar clusters em um plano de controle central e propagar configuração de forma consistente +- Rotear tráfego entre clusters com failover ciente de saúde e preferência por localidade +- Replicar ou particionar estado deliberadamente, raciocinando sobre trade-offs de consistência +- Definir metas de disponibilidade e medir o tempo de recuperação em relação a elas + +## Requisitos Funcionais + +1. A plataforma deve rodar em pelo menos dois clusters com um único ponto de posicionamento de cargas. +2. Um serviço em um cluster deve ser resolvível e alcançável a partir de outro cluster. +3. Mudanças de configuração devem propagar para todos os clusters-alvo sem edição manual por cluster. +4. Quando um cluster ficar não saudável, o tráfego deve migrar para um cluster sobrevivente automaticamente. +5. O sistema deve expor saúde por cluster e agregada para que operadores vejam o raio de impacto. +6. Failover e failback devem ser reversíveis e não podem perder requisições em andamento silenciosamente. +7. Controle de acesso e políticas de segurança devem se aplicar de forma uniforme em todos os clusters. + +## Marcos Sugeridos + +1. **Marco 1 — Dois clusters, identidade compartilhada:** Provisione os clusters, estabeleça rede e uma raiz de confiança comum, verifique a alcançabilidade pod-a-pod entre clusters. +2. **Marco 2 — Posicionamento e propagação:** Introduza um plano de controle (Karmada, Cluster API ou ferramenta de fleet) que agenda cargas e sincroniza config nos dois clusters. +3. **Marco 3 — Tráfego entre clusters e failover:** Adicione resolução global de serviços e um roteador ciente de saúde, então mate um cluster e meça a recuperação. +4. **Marco 4 — Salvaguardas:** RBAC/network policy uniformes, observabilidade agregada e um runbook documentado de recuperação de desastres. + +## Esboço de Dados e Interface + +```text + ┌────────────────────────┐ + operadores / GitOps ─▶│ Plano de Controle / │ (posicionamento, sync config) + │ Fleet │ + └───────────┬────────────┘ + ┌──────────┴──────────┐ + ▼ ▼ + ┌────────────┐ ┌────────────┐ + LB Global ───▶│ Cluster A │ │ Cluster B │◀─── LB Global + (GeoDNS / │ us-east │◀──mTLS─▶│ eu-west │ + Anycast) └────────────┘ └────────────┘ + svc: api descoberta de serviço svc: api + entre clusters + +Metas não-funcionais a declarar de antemão: + disponibilidade >= 99,95% na plataforma (sobrevive à perda de 1 cluster) + RTO de failover < 60s para tirar tráfego de um cluster morto + drift de config 0 divergências não detectadas entre clusters +``` + +## Desafios Extras + +- Adicione um terceiro cluster e teste políticas de posicionamento que respeitem localidade de região/zona. +- Introduza replicação de carga com estado (ex.: um datastore replicado) e raciocine sobre seu RPO. +- Automatize o failback com uma reentrada canário para que clusters recuperados não peguem carga total de imediato. +- Adicione consciência de custo para que o escalonador prefira clusters mais baratos quando os SLOs permitirem. + +## Definição de Pronto + +- [ ] Dois ou mais clusters rodam sob um único plano de controle com config sincronizada automaticamente. +- [ ] Um serviço é alcançável entre clusters e sobrevive à exclusão de um cluster. +- [ ] O failover ocorre dentro do seu RTO declarado e é observável em um dashboard. +- [ ] Não há drift de config não detectado — uma verificação sinaliza divergência. +- [ ] Existe um runbook de recuperação de desastres e ele foi ensaiado ao menos uma vez. + +## Armadilhas Comuns + +- Tratar multi-cluster como "prod + DR" e nunca exercitar o failover de verdade, então ele falha na hora que precisa. +- Sobrepor CIDRs de pod/service entre clusters, tornando o roteamento entre clusters impossível sem NAT. +- Deixar cada cluster derivar porque a config é aplicada manualmente em vez de reconciliada de uma fonte única. +- Replicar estado de forma ingênua e descobrir split-brain do jeito difícil durante uma partição. +- Ignorar o custo e o imposto operacional do cluster extra até a fatura ou o pager chegarem. + +## Recursos + +- [Kubernetes: conceitos multi-cluster](https://kubernetes.io/docs/concepts/cluster-administration/) — fundamentos de administração de cluster. +- [Documentação do Karmada](https://karmada.io/docs/) — um plano de controle de orquestração multi-cluster da CNCF. +- [Cluster API](https://cluster-api.sigs.k8s.io/) — gerenciamento declarativo do ciclo de vida de clusters. +- [Google SRE Book: Managing Critical State](https://sre.google/sre-book/managing-critical-state/) — trade-offs de consistência e failover. diff --git a/projects/devops/advanced/02-gitops-pipeline/README.md b/projects/devops/advanced/02-gitops-pipeline/README.md index 83ad63d..f3adfed 100644 --- a/projects/devops/advanced/02-gitops-pipeline/README.md +++ b/projects/devops/advanced/02-gitops-pipeline/README.md @@ -1,34 +1,101 @@ # GitOps Pipeline -## Idea -Implement GitOps practices where Git is the source of truth. Learn about declarative deployment. +> 🌐 **English** · [Português](./README.pt-BR.md) + +**Domain:** DevOps · **Level:** Advanced · **Estimated time:** 1–2 weeks + +## Overview + +Make Git the single source of truth for what runs in your clusters, and let a reconciler — not a human running `kubectl apply` — converge reality to the declared state. You will build a pipeline where a merge to a repository triggers an automatic, auditable deployment, where any manual change to the cluster is detected as drift and reverted, and where rollbacks are just `git revert`. The hard parts are the ones people skip in demos: keeping secrets out of plaintext Git, structuring repos so multiple environments don't step on each other, adding approval gates without turning GitOps back into ClickOps, and proving that "the repo describes the cluster" is actually true. Done well, your deploy history and your Git history become the same thing. + +## Prerequisites + +- Working Kubernetes knowledge and comfort with declarative manifests +- Experience with Git branching, pull requests, and review workflows +- Familiarity with Helm or Kustomize for environment overlays +- Basic understanding of secret management concepts (encryption at rest, KMS) ## Learning Objectives -- Use Git as source of truth -- Implement continuous reconciliation -- Automate deployment -- Handle drift detection -- Manage configuration - -## Implementation Tips -- Set up GitOps operator (ArgoCD, Flux) -- Create deployment repositories -- Implement automatic synchronization -- Add drift detection -- Create approval workflows -- Implement multi-environment -- Add secret management -- Create monitoring integration -- Implement rollback capability -- Add policy enforcement -- Create audit logging -- Implement progressive delivery -- Build operational tooling -- Create compliance tracking - -## Key Challenges -- Git workflow complexity -- Drift detection -- Secret management in Git -- Approval workflows -- Operational complexity + +By the end, you should be able to: + +- Model desired state in Git and have an operator continuously reconcile it +- Detect and remediate configuration drift automatically +- Structure repositories for multiple environments and progressive promotion +- Handle secrets safely in a Git-driven workflow +- Roll back a deployment purely through Git history and observe the reconciler recover + +## Functional Requirements + +1. A merge to the target branch must trigger a deployment with no manual `kubectl` step. +2. The operator must continuously reconcile cluster state against the repository. +3. Manual changes to managed resources must be detected as drift and reported or reverted. +4. Secrets must never be committed in plaintext; they must be encrypted or externally referenced. +5. Promotion from one environment to the next must be an explicit, reviewable action. +6. A `git revert` of a deployment commit must roll the cluster back to the prior state. +7. Every change to the cluster must be traceable to a commit, author, and approval. + +## Suggested Milestones + +1. **Milestone 1 — Reconcile from Git:** Install an operator (Argo CD or Flux), point it at a repo, and watch it deploy and self-heal. +2. **Milestone 2 — Drift & rollback:** Make a manual change and confirm drift detection; then roll back via `git revert`. +3. **Milestone 3 — Multi-environment:** Structure dev/staging/prod with overlays and add a promotion workflow with approval. +4. **Milestone 4 — Secrets & policy:** Add sealed/encrypted secrets and a policy check that blocks non-compliant manifests before merge. + +## Data & Interface Sketch + +```text + developer ──PR──▶ Git repo (source of truth) + │ desired state (manifests / Helm / Kustomize) + ▼ + ┌───────────────┐ reconcile loop (every N sec) + │ GitOps Operator│──────────────┐ + │ (Argo / Flux) │ │ + └───────┬───────┘ ▼ + │ apply / prune ┌─────────────┐ + └────────────────▶│ Cluster │ + │ live state │ + drift? ◀──compare─┤ │ + └─────────────┘ + +Repo layout (one option): + apps//base/ shared manifests + apps//overlays/dev/ env-specific patches + apps//overlays/prod/ + secrets/ -> SealedSecrets / SOPS-encrypted only + +Non-functional targets: + sync latency < 3 min from merge to converged + drift MTTR auto-reverted or alerted < 5 min + auditability 100% of changes traceable to a commit +``` + +## Stretch Goals + +- Add progressive delivery (Argo Rollouts / Flagger) so promotions are canaried automatically. +- Wire in policy-as-code (OPA/Gatekeeper or Kyverno) as a merge gate and an admission gate. +- Support multiple clusters from one control repo with per-cluster targeting. +- Add notifications and a deploy dashboard so the team sees sync status without opening the CLI. + +## Definition of Done + +- [ ] A merge deploys automatically; no human runs `kubectl apply` in the happy path. +- [ ] Manual drift is detected and either reverted or clearly alerted. +- [ ] Secrets are encrypted or externalized — nothing sensitive is in plaintext in Git. +- [ ] Multiple environments are promoted through an explicit, reviewable flow. +- [ ] A `git revert` demonstrably rolls the cluster back. + +## Common Pitfalls + +- Committing plaintext secrets "temporarily" — they live forever in history. +- One giant repo with no environment separation, so a dev change can reach prod. +- Disabling auto-sync/prune to "be safe," which quietly reintroduces manual drift. +- Treating the operator as fire-and-forget and never watching for failed syncs. +- Approval gates so heavy that people bypass GitOps entirely for "urgent" fixes. + +## Resources + +- [Argo CD documentation](https://argo-cd.readthedocs.io/) — declarative GitOps for Kubernetes. +- [Flux documentation](https://fluxcd.io/flux/) — the CNCF GitOps toolkit. +- [OpenGitOps principles](https://opengitops.dev/) — the four core GitOps principles. +- [SOPS](https://github.com/getsops/sops) — encrypting secrets for safe storage in Git. diff --git a/projects/devops/advanced/02-gitops-pipeline/README.pt-BR.md b/projects/devops/advanced/02-gitops-pipeline/README.pt-BR.md new file mode 100644 index 0000000..d5a3bfb --- /dev/null +++ b/projects/devops/advanced/02-gitops-pipeline/README.pt-BR.md @@ -0,0 +1,101 @@ +# Pipeline GitOps + +> 🌐 [English](./README.md) · **Português** + +**Domínio:** DevOps · **Nível:** Avançado · **Tempo estimado:** 1–2 semanas + +## Visão Geral + +Faça do Git a única fonte de verdade sobre o que roda nos seus clusters e deixe um reconciliador — não um humano rodando `kubectl apply` — convergir a realidade ao estado declarado. Você vai construir um pipeline em que um merge em um repositório dispara um deploy automático e auditável, em que qualquer mudança manual no cluster é detectada como drift e revertida, e em que rollbacks são apenas `git revert`. As partes difíceis são justamente as que as pessoas pulam nas demos: manter segredos fora do Git em texto puro, estruturar repositórios para que múltiplos ambientes não se atropelem, adicionar portões de aprovação sem transformar GitOps de volta em ClickOps, e provar que "o repo descreve o cluster" é de fato verdade. Bem feito, seu histórico de deploy e seu histórico de Git viram a mesma coisa. + +## Pré-requisitos + +- Conhecimento funcional de Kubernetes e conforto com manifests declarativos +- Experiência com branches Git, pull requests e fluxos de revisão +- Familiaridade com Helm ou Kustomize para overlays de ambiente +- Entendimento básico de conceitos de gestão de segredos (criptografia em repouso, KMS) + +## Objetivos de Aprendizado + +Ao final, você deve ser capaz de: + +- Modelar o estado desejado no Git e ter um operador reconciliando-o continuamente +- Detectar e remediar drift de configuração automaticamente +- Estruturar repositórios para múltiplos ambientes e promoção progressiva +- Tratar segredos com segurança em um fluxo dirigido por Git +- Reverter um deploy puramente pelo histórico do Git e observar o reconciliador recuperar + +## Requisitos Funcionais + +1. Um merge no branch-alvo deve disparar um deploy sem passo manual de `kubectl`. +2. O operador deve reconciliar continuamente o estado do cluster com o repositório. +3. Mudanças manuais em recursos gerenciados devem ser detectadas como drift e reportadas ou revertidas. +4. Segredos nunca devem ser commitados em texto puro; devem ser criptografados ou referenciados externamente. +5. A promoção de um ambiente para o próximo deve ser uma ação explícita e revisável. +6. Um `git revert` de um commit de deploy deve reverter o cluster ao estado anterior. +7. Toda mudança no cluster deve ser rastreável até um commit, um autor e uma aprovação. + +## Marcos Sugeridos + +1. **Marco 1 — Reconciliar a partir do Git:** Instale um operador (Argo CD ou Flux), aponte-o para um repo e observe-o fazer deploy e autocorreção. +2. **Marco 2 — Drift e rollback:** Faça uma mudança manual e confirme a detecção de drift; depois reverta via `git revert`. +3. **Marco 3 — Multi-ambiente:** Estruture dev/staging/prod com overlays e adicione um fluxo de promoção com aprovação. +4. **Marco 4 — Segredos e política:** Adicione segredos selados/criptografados e uma verificação de política que bloqueia manifests não conformes antes do merge. + +## Esboço de Dados e Interface + +```text + dev ──PR──▶ repo Git (fonte de verdade) + │ estado desejado (manifests / Helm / Kustomize) + ▼ + ┌────────────────┐ loop de reconciliação (a cada N s) + │ Operador GitOps│──────────────┐ + │ (Argo / Flux) │ │ + └───────┬────────┘ ▼ + │ apply / prune ┌─────────────┐ + └────────────────▶│ Cluster │ + │ estado vivo │ + drift? ◀──compara─┤ │ + └─────────────┘ + +Layout do repo (uma opção): + apps//base/ manifests compartilhados + apps//overlays/dev/ patches por ambiente + apps//overlays/prod/ + secrets/ -> apenas SealedSecrets / criptografado com SOPS + +Metas não-funcionais: + latência de sync < 3 min do merge à convergência + MTTR de drift auto-revertido ou alertado < 5 min + auditabilidade 100% das mudanças rastreáveis a um commit +``` + +## Desafios Extras + +- Adicione entrega progressiva (Argo Rollouts / Flagger) para que promoções sejam canário automaticamente. +- Conecte política como código (OPA/Gatekeeper ou Kyverno) como portão de merge e portão de admissão. +- Suporte múltiplos clusters a partir de um repo de controle com direcionamento por cluster. +- Adicione notificações e um dashboard de deploy para que o time veja o status de sync sem abrir a CLI. + +## Definição de Pronto + +- [ ] Um merge faz deploy automaticamente; nenhum humano roda `kubectl apply` no caminho feliz. +- [ ] Drift manual é detectado e revertido ou claramente alertado. +- [ ] Segredos são criptografados ou externalizados — nada sensível fica em texto puro no Git. +- [ ] Múltiplos ambientes são promovidos por um fluxo explícito e revisável. +- [ ] Um `git revert` comprovadamente reverte o cluster. + +## Armadilhas Comuns + +- Commitar segredos em texto puro "temporariamente" — eles vivem para sempre no histórico. +- Um repo gigante sem separação de ambientes, de modo que uma mudança de dev pode chegar à prod. +- Desabilitar auto-sync/prune "por segurança", o que silenciosamente reintroduz drift manual. +- Tratar o operador como esqueça-e-pronto e nunca monitorar syncs que falharam. +- Portões de aprovação tão pesados que as pessoas contornam o GitOps por completo para correções "urgentes". + +## Recursos + +- [Documentação do Argo CD](https://argo-cd.readthedocs.io/) — GitOps declarativo para Kubernetes. +- [Documentação do Flux](https://fluxcd.io/flux/) — o toolkit GitOps da CNCF. +- [Princípios OpenGitOps](https://opengitops.dev/) — os quatro princípios centrais de GitOps. +- [SOPS](https://github.com/getsops/sops) — criptografando segredos para armazenamento seguro no Git. diff --git a/projects/devops/advanced/03-chaos-engineering/README.md b/projects/devops/advanced/03-chaos-engineering/README.md index b105c22..bad356e 100644 --- a/projects/devops/advanced/03-chaos-engineering/README.md +++ b/projects/devops/advanced/03-chaos-engineering/README.md @@ -1,34 +1,101 @@ # Chaos Engineering Setup -## Idea -Implement chaos engineering to test system resilience. Learn about failure injection and resilience testing. +> 🌐 **English** · [Português](./README.pt-BR.md) + +**Domain:** DevOps · **Level:** Advanced · **Estimated time:** 1–2 weeks + +## Overview + +Deliberately break your own system — under control — to learn how it fails before your users teach you the hard way. You will build a chaos engineering practice: form a hypothesis ("if a pod dies, the service stays within its latency SLO"), inject a real fault, measure the impact against a steady-state baseline, and either confirm resilience or file the weakness you found. The discipline that separates chaos engineering from "randomly killing things" is the scientific method plus blast-radius control: every experiment must have a defined scope, an automatic abort condition, and a way to stop instantly. The goal is not chaos for its own sake; it is confidence, backed by evidence, that your system degrades gracefully. + +## Prerequisites + +- A running application with meaningful dependencies (a datastore, a downstream service) to disrupt +- Observability in place — metrics and ideally traces — so you can measure steady state +- Comfort with Kubernetes or your target platform's failure primitives +- Understanding of SLIs/SLOs so you know what "still healthy" means ## Learning Objectives -- Design failure scenarios -- Inject failures -- Measure impact -- Improve resilience -- Automate testing - -## Implementation Tips -- Choose chaos tool (Gremlin, Chaos Mesh) -- Design failure scenarios -- Implement failure injection -- Add metrics collection -- Create hypothesis testing -- Implement blast radius control -- Add automated detection -- Create recovery procedures -- Implement safe rollback -- Add monitoring during chaos -- Create incident response -- Implement learning tracking -- Build chaos dashboard -- Create runbooks - -## Key Challenges -- Blast radius control -- Production safety -- Realistic failure simulation -- Metrics interpretation -- Cultural adoption + +By the end, you should be able to: + +- Define steady-state hypotheses in measurable SLI terms +- Inject faults (pod kills, latency, network partition, resource exhaustion) safely +- Enforce blast-radius limits and automatic abort conditions +- Measure experiment impact and distinguish signal from noise +- Turn discovered weaknesses into tracked, fixed resilience improvements + +## Functional Requirements + +1. Each experiment must declare a steady-state hypothesis in terms of a measurable SLI. +2. The system must inject at least three distinct fault types (e.g. pod kill, latency, partition). +3. Every experiment must have a bounded blast radius (namespace, percentage, or label selector). +4. An automatic abort must halt the experiment if a guardrail metric breaches a threshold. +5. There must be a single, reliable "stop everything now" control. +6. Results must be recorded: hypothesis, fault, observed impact, pass/fail, follow-up. +7. Experiments must be repeatable so a fix can be verified against the same fault. + +## Suggested Milestones + +1. **Milestone 1 — Baseline & hypothesis:** Establish steady-state SLIs and write your first hypothesis. +2. **Milestone 2 — First injection:** Kill a pod within a tight blast radius, measure recovery, record the result. +3. **Milestone 3 — Guardrails:** Add automatic abort on SLO breach and a global halt switch. +4. **Milestone 4 — Fault library & schedule:** Add latency, partition, and resource faults; run experiments on a cadence and track findings to closure. + +## Data & Interface Sketch + +```text + ┌──────────────┐ 1. read baseline ┌───────────────┐ + │ Experiment │──────────────────────▶│ Observability │ + │ definition │ │ (SLIs/metrics)│ + └──────┬───────┘ └──────┬────────┘ + │ 2. inject fault │ 4. compare + ▼ (bounded blast radius) │ vs steady state + ┌──────────────┐ ▼ + │ Chaos engine │ guardrail breach? ┌───────────┐ + │ (Chaos Mesh/ │◀────── abort/halt ──────│ Verdict │ + │ LitmusChaos)│ │ pass/fail │ + └──────────────┘ └───────────┘ + +Experiment record: + hypothesis: "p99 latency stays < 300ms if 1 of 3 pods dies" + fault: pod-kill, selector app=api, 33% of replicas + blast_radius: namespace=staging, max 1 pod + abort_if: error_rate > 5% OR p99 > 600ms + result: pass | fail + follow-up ticket + +Non-functional targets: + blast radius never exceeds declared scope + abort latency < 10s from breach to halt + MTTR observed recorded for every failure mode tested +``` + +## Stretch Goals + +- Progress from staging to a controlled game day in production with a small blast radius. +- Add automated, scheduled experiments in CI so regressions in resilience are caught. +- Inject application-level faults (dependency errors, slow responses) not just infra faults. +- Correlate experiment results with real past incidents to prioritize which faults to test. + +## Definition of Done + +- [ ] At least three fault types run with a declared, enforced blast radius. +- [ ] Every experiment has an automatic abort and a working global halt. +- [ ] Steady-state hypotheses are measured against real SLIs, not guesses. +- [ ] Discovered weaknesses are tracked and at least one has been fixed and re-verified. +- [ ] Experiment results are recorded in a repeatable, reviewable format. + +## Common Pitfalls + +- Running chaos with no steady-state baseline, so you can't tell if the fault mattered. +- No abort condition — a "small" experiment cascades into a real outage. +- Testing only pod kills, missing the latency and partition faults that cause real incidents. +- Treating a passed experiment as permanent; systems change, so experiments must recur. +- Running in prod before the guardrails and culture are ready, eroding trust in the practice. + +## Resources + +- [Principles of Chaos Engineering](https://principlesofchaos.org/) — the foundational definition and method. +- [Chaos Mesh documentation](https://chaos-mesh.org/docs/) — a CNCF chaos platform for Kubernetes. +- [LitmusChaos documentation](https://docs.litmuschaos.io/) — open-source chaos engineering framework. +- [Google SRE Book: Embracing Risk](https://sre.google/sre-book/embracing-risk/) — error budgets and reasoning about failure. diff --git a/projects/devops/advanced/03-chaos-engineering/README.pt-BR.md b/projects/devops/advanced/03-chaos-engineering/README.pt-BR.md new file mode 100644 index 0000000..f6fc250 --- /dev/null +++ b/projects/devops/advanced/03-chaos-engineering/README.pt-BR.md @@ -0,0 +1,101 @@ +# Configuração de Chaos Engineering + +> 🌐 [English](./README.md) · **Português** + +**Domínio:** DevOps · **Nível:** Avançado · **Tempo estimado:** 1–2 semanas + +## Visão Geral + +Quebre deliberadamente o seu próprio sistema — sob controle — para aprender como ele falha antes que seus usuários lhe ensinem do jeito difícil. Você vai construir uma prática de chaos engineering: formular uma hipótese ("se um pod morrer, o serviço permanece dentro do seu SLO de latência"), injetar uma falha real, medir o impacto em relação a um baseline de estado estável, e então confirmar a resiliência ou registrar a fraqueza encontrada. A disciplina que separa chaos engineering de "matar coisas aleatoriamente" é o método científico somado ao controle do raio de impacto: todo experimento deve ter escopo definido, uma condição de aborto automático e uma forma de parar instantaneamente. O objetivo não é caos por si só; é confiança, sustentada por evidências, de que seu sistema degrada de forma graciosa. + +## Pré-requisitos + +- Uma aplicação em execução com dependências relevantes (um datastore, um serviço a jusante) para perturbar +- Observabilidade instalada — métricas e idealmente traces — para medir o estado estável +- Conforto com Kubernetes ou as primitivas de falha da sua plataforma-alvo +- Entendimento de SLIs/SLOs para saber o que significa "ainda saudável" + +## Objetivos de Aprendizado + +Ao final, você deve ser capaz de: + +- Definir hipóteses de estado estável em termos mensuráveis de SLI +- Injetar falhas (morte de pods, latência, partição de rede, exaustão de recursos) com segurança +- Impor limites de raio de impacto e condições de aborto automático +- Medir o impacto do experimento e distinguir sinal de ruído +- Transformar fraquezas descobertas em melhorias de resiliência rastreadas e corrigidas + +## Requisitos Funcionais + +1. Cada experimento deve declarar uma hipótese de estado estável em termos de um SLI mensurável. +2. O sistema deve injetar pelo menos três tipos distintos de falha (ex.: morte de pod, latência, partição). +3. Todo experimento deve ter um raio de impacto limitado (namespace, porcentagem ou seletor de label). +4. Um aborto automático deve interromper o experimento se uma métrica de guarda cruzar um limiar. +5. Deve existir um controle único e confiável de "pare tudo agora". +6. Resultados devem ser registrados: hipótese, falha, impacto observado, sucesso/falha, acompanhamento. +7. Experimentos devem ser repetíveis para que uma correção possa ser verificada contra a mesma falha. + +## Marcos Sugeridos + +1. **Marco 1 — Baseline e hipótese:** Estabeleça SLIs de estado estável e escreva sua primeira hipótese. +2. **Marco 2 — Primeira injeção:** Mate um pod dentro de um raio de impacto apertado, meça a recuperação, registre o resultado. +3. **Marco 3 — Salvaguardas:** Adicione aborto automático em violação de SLO e um interruptor global de parada. +4. **Marco 4 — Biblioteca de falhas e agenda:** Adicione falhas de latência, partição e recurso; rode experimentos com cadência e leve descobertas até o encerramento. + +## Esboço de Dados e Interface + +```text + ┌──────────────┐ 1. lê baseline ┌───────────────┐ + │ Definição │──────────────────────▶│ Observabilidade│ + │ do experim. │ │ (SLIs/métricas)│ + └──────┬───────┘ └──────┬────────┘ + │ 2. injeta falha │ 4. compara + ▼ (raio de impacto limitado) │ vs estado estável + ┌──────────────┐ ▼ + │ Motor de chaos│ violação de guarda? ┌───────────┐ + │ (Chaos Mesh/ │◀────── aborta/para ──────│ Veredito │ + │ LitmusChaos)│ │ ok/falha │ + └──────────────┘ └───────────┘ + +Registro do experimento: + hipótese: "latência p99 fica < 300ms se 1 de 3 pods morrer" + falha: pod-kill, seletor app=api, 33% das réplicas + raio_impacto: namespace=staging, máx 1 pod + aborta_se: taxa_erro > 5% OU p99 > 600ms + resultado: ok | falha + ticket de acompanhamento + +Metas não-funcionais: + raio de impacto nunca excede o escopo declarado + latência de aborto < 10s da violação à parada + MTTR observado registrado para cada modo de falha testado +``` + +## Desafios Extras + +- Evolua de staging para um game day controlado em produção com um raio de impacto pequeno. +- Adicione experimentos automatizados e agendados no CI para pegar regressões de resiliência. +- Injete falhas em nível de aplicação (erros de dependência, respostas lentas), não apenas falhas de infra. +- Correlacione resultados de experimentos com incidentes reais passados para priorizar quais falhas testar. + +## Definição de Pronto + +- [ ] Pelo menos três tipos de falha rodam com um raio de impacto declarado e imposto. +- [ ] Todo experimento tem um aborto automático e uma parada global funcional. +- [ ] Hipóteses de estado estável são medidas contra SLIs reais, não palpites. +- [ ] Fraquezas descobertas são rastreadas e ao menos uma foi corrigida e reverificada. +- [ ] Resultados dos experimentos são registrados em um formato repetível e revisável. + +## Armadilhas Comuns + +- Rodar chaos sem baseline de estado estável, sem saber se a falha importou. +- Nenhuma condição de aborto — um experimento "pequeno" vira uma queda real em cascata. +- Testar apenas mortes de pod, ignorando as falhas de latência e partição que causam incidentes reais. +- Tratar um experimento aprovado como permanente; sistemas mudam, então experimentos devem recorrer. +- Rodar em prod antes de as salvaguardas e a cultura estarem prontas, corroendo a confiança na prática. + +## Recursos + +- [Principles of Chaos Engineering](https://principlesofchaos.org/) — a definição e o método fundacionais. +- [Documentação do Chaos Mesh](https://chaos-mesh.org/docs/) — uma plataforma de chaos da CNCF para Kubernetes. +- [Documentação do LitmusChaos](https://docs.litmuschaos.io/) — framework de chaos engineering open-source. +- [Google SRE Book: Embracing Risk](https://sre.google/sre-book/embracing-risk/) — error budgets e raciocínio sobre falha. diff --git a/projects/devops/advanced/04-observability-platform/README.md b/projects/devops/advanced/04-observability-platform/README.md index 18c6f56..fe44f0f 100644 --- a/projects/devops/advanced/04-observability-platform/README.md +++ b/projects/devops/advanced/04-observability-platform/README.md @@ -1,34 +1,104 @@ # Full Observability Platform -## Idea -Build a complete observability platform with logs, metrics, and traces. Learn about production visibility. +> 🌐 **English** · [Português](./README.pt-BR.md) + +**Domain:** DevOps · **Level:** Advanced · **Estimated time:** 1–2 weeks + +## Overview + +Build the platform that answers "what is happening in production, and why?" by unifying the three pillars — metrics, logs, and traces — behind a correlation story that lets an operator jump from a spiking dashboard to the exact trace to the specific log line. You will instrument services, ship telemetry through a collector, store each signal in an appropriate backend, and tie them together with shared identifiers so a single request can be followed end to end. The advanced challenges are the ones that decide whether this survives contact with real traffic: cardinality control on metrics, sampling on traces, retention and cost at volume, and alerts that page a human only when a human is actually needed. A good observability platform turns debugging from archaeology into a query. + +## Prerequisites + +- One or more running services you can instrument (ideally with a request path across services) +- Familiarity with Prometheus-style metrics and PromQL basics +- Understanding of structured logging and distributed tracing concepts +- Comfort deploying stateful backends and a telemetry collector ## Learning Objectives -- Collect metrics -- Aggregate logs -- Implement tracing -- Create dashboards -- Build alerting - -## Implementation Tips -- Implement metrics collection -- Set up log aggregation -- Add distributed tracing -- Create correlation IDs -- Build unified dashboards -- Implement alerting system -- Add anomaly detection -- Create incident management -- Implement auto-remediation -- Add cost optimization -- Create retention policies -- Implement access control -- Build compliance features -- Create operational tooling - -## Key Challenges -- Data volume management -- Cost at scale -- Alert tuning -- Data correlation -- Operational complexity + +By the end, you should be able to: + +- Instrument services for metrics, logs, and traces using open standards (OpenTelemetry) +- Correlate the three signals via trace/span IDs and consistent labels +- Control cardinality, sampling, and retention to keep cost and volume sane +- Build dashboards and alerts driven by SLIs, not vanity metrics +- Design alerting that minimizes false pages while catching real degradation + +## Functional Requirements + +1. Services must emit metrics, structured logs, and distributed traces via a common pipeline. +2. A single request must be traceable across at least two services with a shared trace ID. +3. A dashboard must present SLIs (latency, error rate, saturation) for each key service. +4. Logs must be searchable and joinable to a trace via a correlation identifier. +5. Alerts must fire on SLO burn, not raw thresholds, and route to a notification channel. +6. The platform must apply sampling and/or cardinality limits to bound cost. +7. Retention policies must be defined per signal and enforced. + +## Suggested Milestones + +1. **Milestone 1 — Metrics & dashboards:** Scrape metrics, define SLIs, and build a service dashboard. +2. **Milestone 2 — Logs & tracing:** Add structured logs and distributed tracing through a collector. +3. **Milestone 3 — Correlation:** Wire trace IDs into logs so you can pivot signal to signal. +4. **Milestone 4 — Alerting & cost control:** Add SLO-burn alerts, sampling, cardinality limits, and retention policies. + +## Data & Interface Sketch + +```text + services (OTel SDK) + │ metrics │ logs │ traces + ▼ ▼ ▼ + ┌──────────────────────────────────┐ + │ OpenTelemetry Collector │ (batch, sample, enrich) + └───────┬──────────┬──────────┬────┘ + ▼ ▼ ▼ + ┌──────────┐ ┌────────┐ ┌────────┐ + │Prometheus│ │ Loki │ │ Tempo/ │ + │ (metrics)│ │ (logs) │ │ Jaeger │ + └────┬─────┘ └───┬────┘ └───┬────┘ + └──────┬────┴──────────┘ + ▼ correlate by trace_id + labels + ┌───────────┐ ┌────────────┐ + │ Grafana │ │ Alertmanager│──▶ notify + │ dashboards│ │ (SLO burn) │ + └───────────┘ └────────────┘ + +Correlation contract: + every log line carries: trace_id, span_id, service, level + every metric carries: service, route, status (bounded label set) + +Non-functional targets: + metric cardinality bounded (< N series per service) + trace sampling head or tail sampling to cap volume + alert precision page only on SLO burn; noise ratio tracked +``` + +## Stretch Goals + +- Add exemplars linking a metric spike directly to a representative trace. +- Introduce anomaly detection or multi-window multi-burn-rate SLO alerting. +- Add tenant/team isolation so cost and access are attributable. +- Build a "one-click from alert to root cause" workflow across the three signals. + +## Definition of Done + +- [ ] All three signals flow through a single collector pipeline. +- [ ] One request is followed end-to-end across services via a trace ID. +- [ ] A log line can be pivoted to its trace and vice versa. +- [ ] Alerts fire on SLO burn and route to a real channel, with false pages minimized. +- [ ] Sampling, cardinality limits, and retention are configured and enforced. + +## Common Pitfalls + +- Unbounded label cardinality (user IDs, URLs) that explodes the metrics backend and cost. +- Collecting all three signals but never correlating them, so debugging still means three tabs. +- Threshold alerts that page at 3 a.m. for a transient blip nobody needs to act on. +- No sampling on traces, so ingestion and storage cost grows linearly with traffic forever. +- Treating dashboards as the product; the product is fast answers, which need SLIs and correlation. + +## Resources + +- [OpenTelemetry documentation](https://opentelemetry.io/docs/) — vendor-neutral instrumentation standard. +- [Prometheus documentation](https://prometheus.io/docs/) — metrics collection and PromQL. +- [Google SRE Book: Monitoring Distributed Systems](https://sre.google/sre-book/monitoring-distributed-systems/) — the four golden signals. +- [Google SRE Workbook: Alerting on SLOs](https://sre.google/workbook/alerting-on-slos/) — burn-rate alerting done right. diff --git a/projects/devops/advanced/04-observability-platform/README.pt-BR.md b/projects/devops/advanced/04-observability-platform/README.pt-BR.md new file mode 100644 index 0000000..13eaa9a --- /dev/null +++ b/projects/devops/advanced/04-observability-platform/README.pt-BR.md @@ -0,0 +1,104 @@ +# Plataforma Completa de Observabilidade + +> 🌐 [English](./README.md) · **Português** + +**Domínio:** DevOps · **Nível:** Avançado · **Tempo estimado:** 1–2 semanas + +## Visão Geral + +Construa a plataforma que responde "o que está acontecendo em produção, e por quê?" unificando os três pilares — métricas, logs e traces — atrás de uma história de correlação que permite ao operador saltar de um dashboard disparando para o trace exato e para a linha de log específica. Você vai instrumentar serviços, enviar telemetria por um coletor, armazenar cada sinal em um backend apropriado e amarrá-los com identificadores compartilhados para que uma única requisição seja seguida de ponta a ponta. Os desafios avançados são os que decidem se isso sobrevive ao contato com tráfego real: controle de cardinalidade nas métricas, amostragem nos traces, retenção e custo em volume, e alertas que acionam um humano apenas quando um humano é de fato necessário. Uma boa plataforma de observabilidade transforma depuração de arqueologia em uma query. + +## Pré-requisitos + +- Um ou mais serviços em execução que você possa instrumentar (idealmente com um caminho de requisição entre serviços) +- Familiaridade com métricas no estilo Prometheus e o básico de PromQL +- Entendimento de logging estruturado e conceitos de tracing distribuído +- Conforto para implantar backends com estado e um coletor de telemetria + +## Objetivos de Aprendizado + +Ao final, você deve ser capaz de: + +- Instrumentar serviços para métricas, logs e traces usando padrões abertos (OpenTelemetry) +- Correlacionar os três sinais via IDs de trace/span e labels consistentes +- Controlar cardinalidade, amostragem e retenção para manter custo e volume sob controle +- Construir dashboards e alertas guiados por SLIs, não por métricas de vaidade +- Projetar alertas que minimizam falsos acionamentos enquanto pegam degradação real + +## Requisitos Funcionais + +1. Serviços devem emitir métricas, logs estruturados e traces distribuídos por um pipeline comum. +2. Uma única requisição deve ser rastreável entre pelo menos dois serviços com um trace ID compartilhado. +3. Um dashboard deve apresentar SLIs (latência, taxa de erro, saturação) para cada serviço-chave. +4. Logs devem ser pesquisáveis e vinculáveis a um trace por um identificador de correlação. +5. Alertas devem disparar em queima de SLO, não em limiares brutos, e rotear para um canal de notificação. +6. A plataforma deve aplicar amostragem e/ou limites de cardinalidade para limitar o custo. +7. Políticas de retenção devem ser definidas por sinal e impostas. + +## Marcos Sugeridos + +1. **Marco 1 — Métricas e dashboards:** Colete métricas, defina SLIs e construa um dashboard de serviço. +2. **Marco 2 — Logs e tracing:** Adicione logs estruturados e tracing distribuído através de um coletor. +3. **Marco 3 — Correlação:** Conecte trace IDs aos logs para poder pivotar de sinal para sinal. +4. **Marco 4 — Alertas e controle de custo:** Adicione alertas de queima de SLO, amostragem, limites de cardinalidade e políticas de retenção. + +## Esboço de Dados e Interface + +```text + serviços (SDK OTel) + │ métricas │ logs │ traces + ▼ ▼ ▼ + ┌──────────────────────────────────┐ + │ Coletor OpenTelemetry │ (batch, amostra, enriquece) + └───────┬──────────┬──────────┬────┘ + ▼ ▼ ▼ + ┌──────────┐ ┌────────┐ ┌────────┐ + │Prometheus│ │ Loki │ │ Tempo/ │ + │ (métricas)│ │ (logs) │ │ Jaeger │ + └────┬─────┘ └───┬────┘ └───┬────┘ + └──────┬────┴──────────┘ + ▼ correlaciona por trace_id + labels + ┌───────────┐ ┌────────────┐ + │ Grafana │ │ Alertmanager│──▶ notifica + │ dashboards│ │(queima SLO)│ + └───────────┘ └────────────┘ + +Contrato de correlação: + toda linha de log carrega: trace_id, span_id, service, level + toda métrica carrega: service, route, status (conjunto limitado de labels) + +Metas não-funcionais: + cardinalidade de métrica limitada (< N séries por serviço) + amostragem de trace head ou tail sampling para limitar volume + precisão de alerta aciona só em queima de SLO; taxa de ruído monitorada +``` + +## Desafios Extras + +- Adicione exemplars ligando um pico de métrica diretamente a um trace representativo. +- Introduza detecção de anomalias ou alertas de SLO por múltiplas janelas e taxas de queima. +- Adicione isolamento por tenant/time para que custo e acesso sejam atribuíveis. +- Construa um fluxo de "um clique do alerta à causa raiz" atravessando os três sinais. + +## Definição de Pronto + +- [ ] Os três sinais fluem por um único pipeline de coletor. +- [ ] Uma requisição é seguida de ponta a ponta entre serviços via um trace ID. +- [ ] Uma linha de log pode ser pivotada para seu trace e vice-versa. +- [ ] Alertas disparam em queima de SLO e roteiam para um canal real, com falsos acionamentos minimizados. +- [ ] Amostragem, limites de cardinalidade e retenção estão configurados e impostos. + +## Armadilhas Comuns + +- Cardinalidade de label ilimitada (IDs de usuário, URLs) que explode o backend de métricas e o custo. +- Coletar os três sinais mas nunca correlacioná-los, então depurar ainda significa três abas. +- Alertas por limiar que acionam às 3h por uma oscilação transitória sobre a qual ninguém precisa agir. +- Nenhuma amostragem nos traces, então o custo de ingestão e armazenamento cresce linearmente com o tráfego para sempre. +- Tratar dashboards como o produto; o produto são respostas rápidas, que precisam de SLIs e correlação. + +## Recursos + +- [Documentação do OpenTelemetry](https://opentelemetry.io/docs/) — padrão de instrumentação neutro em relação a fornecedor. +- [Documentação do Prometheus](https://prometheus.io/docs/) — coleta de métricas e PromQL. +- [Google SRE Book: Monitoring Distributed Systems](https://sre.google/sre-book/monitoring-distributed-systems/) — os quatro sinais de ouro. +- [Google SRE Workbook: Alerting on SLOs](https://sre.google/workbook/alerting-on-slos/) — alertas por taxa de queima bem feitos. diff --git a/projects/devops/advanced/05-multi-region-deployment/README.md b/projects/devops/advanced/05-multi-region-deployment/README.md index a28ed66..4ca4174 100644 --- a/projects/devops/advanced/05-multi-region-deployment/README.md +++ b/projects/devops/advanced/05-multi-region-deployment/README.md @@ -1,34 +1,100 @@ # Multi-Region Deployment -## Idea -Deploy applications across multiple geographic regions. Learn about global infrastructure. +> 🌐 **English** · [Português](./README.pt-BR.md) + +**Domain:** DevOps · **Level:** Advanced · **Estimated time:** 1–2 weeks + +## Overview + +Serve users from more than one geographic region so that a regional outage does not become a global one, and so that a user in São Paulo isn't paying a transatlantic round-trip on every request. You will deploy the same application to at least two regions, route users to the nearest healthy region, and decide — deliberately — how state is handled across them. The genuinely hard decisions live in the data layer: do you run active-active with a globally replicated store and accept eventual consistency, or active-passive with a clear failover and an accepted recovery point? You will also confront data residency: some data legally cannot leave its region. This project is about making those trade-offs explicit and provable, not about copy-pasting a stack into two clouds. + +## Prerequisites + +- Comfort deploying an application to a single region (containers or VMs) +- Understanding of DNS, TLS, and how global load balancing works +- Familiarity with database replication concepts and consistency models +- Awareness of latency, RPO, and RTO as measurable quantities ## Learning Objectives -- Deploy across regions -- Handle data residency -- Manage traffic routing -- Implement failover -- Maintain consistency - -## Implementation Tips -- Set up multi-region infrastructure -- Implement geo-routing (GeoDNS) -- Add region affinity -- Create data replication -- Implement disaster recovery -- Add compliance per region -- Create cost optimization -- Implement monitoring -- Add alerting per region -- Create failover automation -- Implement testing across regions -- Add performance optimization -- Create operational dashboards -- Build runbooks - -## Key Challenges -- Network latency -- Data consistency -- Compliance complexity -- Cost optimization -- Operational complexity + +By the end, you should be able to: + +- Deploy an identical application footprint across multiple regions +- Route users to the nearest healthy region and fail over when one degrades +- Choose and justify an active-active vs. active-passive data strategy +- Reason about consistency, RPO, and RTO for cross-region state +- Handle data residency constraints in routing and storage + +## Functional Requirements + +1. The application must run in at least two regions serving the same functionality. +2. Users must be routed to the nearest healthy region (latency- or geo-based). +3. If a region becomes unhealthy, traffic must fail over to another region automatically. +4. The data strategy (replication or partition) must be explicit with a stated consistency model. +5. The system must define and measure RPO and RTO for a regional failure. +6. Region-restricted data must never be served from or stored in a disallowed region. +7. Failback to a recovered region must be controlled, not an instant full cutover. + +## Suggested Milestones + +1. **Milestone 1 — Two regions live:** Deploy identical stacks in two regions behind a global entry point. +2. **Milestone 2 — Geo routing & health:** Route by proximity and health-check each region. +3. **Milestone 3 — Data strategy:** Implement replication or partitioning; document consistency, RPO, RTO. +4. **Milestone 4 — Failover drill & residency:** Simulate a regional outage, measure recovery, and enforce residency rules. + +## Data & Interface Sketch + +```text + ┌──────────────────────────┐ + users ─────▶│ Global DNS / Anycast LB │ (latency/geo routing + health) + └───────┬───────────┬──────┘ + ▼ ▼ + ┌───────────┐ ┌───────────┐ + │ Region A │ │ Region B │ + │ (us-east) │ │ (sa-east) │ + │ app+cache│ │ app+cache│ + └─────┬─────┘ └─────┬─────┘ + │ data layer │ + active-active │ │ active-passive + (replicated, ◀────────────▶ (primary/replica, + eventual) replication failover promote) + +Residency rule (example): + data tagged region=BR -> only stored/served from sa-east + +Non-functional targets: + availability >= 99.99% globally (survives 1 region loss) + RTO < 5 min to shift traffic + promote data + RPO <= replication lag (state and defend it) + cross-region latency budget stated per request path +``` + +## Stretch Goals + +- Add a third region and test quorum-based writes or read-local/write-global patterns. +- Automate failback with a canary re-entry to avoid a cold region taking full load. +- Add per-region cost tracking and route cost-aware when SLOs allow. +- Run a scheduled regional failover game day and publish the measured RTO/RPO. + +## Definition of Done + +- [ ] The app serves traffic from two or more regions with proximity routing. +- [ ] A simulated regional outage fails over within the stated RTO. +- [ ] The data strategy is documented with an explicit consistency model, RPO, and RTO. +- [ ] Residency-restricted data is provably never served from a disallowed region. +- [ ] Failback is controlled and observable. + +## Common Pitfalls + +- Deploying to two regions but pointing both at one region's database — no real isolation. +- Ignoring replication lag, then losing data on failover because RPO was never measured. +- Assuming DNS failover is instant; caches and TTLs make it anything but. +- Treating data residency as an afterthought and discovering a compliance violation in prod. +- Never actually testing failover, so the "multi-region" system fails when a region does. + +## Resources + +- [AWS Well-Architected: Reliability Pillar](https://docs.aws.amazon.com/wellarchitected/latest/reliability-pillar/welcome.html) — multi-region reliability patterns. +- [Google SRE Book: Managing Critical State](https://sre.google/sre-book/managing-critical-state/) — consistency and replication trade-offs. +- [Jepsen: consistency models](https://jepsen.io/consistency) — a precise map of consistency guarantees. +- [Cloudflare: what is Anycast?](https://www.cloudflare.com/learning/cdn/glossary/anycast-network/) — how global routing directs users. diff --git a/projects/devops/advanced/05-multi-region-deployment/README.pt-BR.md b/projects/devops/advanced/05-multi-region-deployment/README.pt-BR.md new file mode 100644 index 0000000..e905890 --- /dev/null +++ b/projects/devops/advanced/05-multi-region-deployment/README.pt-BR.md @@ -0,0 +1,100 @@ +# Deploy Multi-Região + +> 🌐 [English](./README.md) · **Português** + +**Domínio:** DevOps · **Nível:** Avançado · **Tempo estimado:** 1–2 semanas + +## Visão Geral + +Atenda usuários a partir de mais de uma região geográfica para que uma queda regional não vire uma queda global, e para que um usuário em São Paulo não pague uma viagem transatlântica de ida e volta a cada requisição. Você vai implantar a mesma aplicação em pelo menos duas regiões, rotear usuários para a região saudável mais próxima e decidir — deliberadamente — como o estado é tratado entre elas. As decisões genuinamente difíceis vivem na camada de dados: você roda ativo-ativo com um store replicado globalmente aceitando consistência eventual, ou ativo-passivo com um failover claro e um ponto de recuperação aceito? Você também vai enfrentar residência de dados: alguns dados legalmente não podem deixar sua região. Este projeto é sobre tornar esses trade-offs explícitos e demonstráveis, não sobre copiar e colar uma stack em duas nuvens. + +## Pré-requisitos + +- Conforto para implantar uma aplicação em uma única região (contêineres ou VMs) +- Entendimento de DNS, TLS e como funciona o balanceamento de carga global +- Familiaridade com conceitos de replicação de banco de dados e modelos de consistência +- Consciência de latência, RPO e RTO como quantidades mensuráveis + +## Objetivos de Aprendizado + +Ao final, você deve ser capaz de: + +- Implantar uma pegada idêntica da aplicação em múltiplas regiões +- Rotear usuários para a região saudável mais próxima e fazer failover quando uma degradar +- Escolher e justificar uma estratégia de dados ativo-ativo vs. ativo-passivo +- Raciocinar sobre consistência, RPO e RTO para estado entre regiões +- Tratar restrições de residência de dados no roteamento e no armazenamento + +## Requisitos Funcionais + +1. A aplicação deve rodar em pelo menos duas regiões servindo a mesma funcionalidade. +2. Usuários devem ser roteados para a região saudável mais próxima (baseado em latência ou geo). +3. Se uma região ficar não saudável, o tráfego deve migrar para outra região automaticamente. +4. A estratégia de dados (replicação ou partição) deve ser explícita com um modelo de consistência declarado. +5. O sistema deve definir e medir RPO e RTO para uma falha regional. +6. Dados restritos por região nunca devem ser servidos de ou armazenados em uma região não permitida. +7. O failback para uma região recuperada deve ser controlado, não uma virada total instantânea. + +## Marcos Sugeridos + +1. **Marco 1 — Duas regiões no ar:** Implante stacks idênticas em duas regiões atrás de um ponto de entrada global. +2. **Marco 2 — Roteamento geo e saúde:** Roteie por proximidade e faça health-check de cada região. +3. **Marco 3 — Estratégia de dados:** Implemente replicação ou particionamento; documente consistência, RPO, RTO. +4. **Marco 4 — Simulação de failover e residência:** Simule uma queda regional, meça a recuperação e imponha regras de residência. + +## Esboço de Dados e Interface + +```text + ┌──────────────────────────┐ + usuários ─────▶│ DNS Global / LB Anycast │ (roteamento latência/geo + saúde) + └───────┬───────────┬──────┘ + ▼ ▼ + ┌───────────┐ ┌───────────┐ + │ Região A │ │ Região B │ + │ (us-east) │ │ (sa-east) │ + │ app+cache│ │ app+cache│ + └─────┬─────┘ └─────┬─────┘ + │ camada de dados│ + ativo-ativo │ │ ativo-passivo + (replicado, ◀──────────────▶ (primário/réplica, + eventual) replicação promove no failover) + +Regra de residência (exemplo): + dados marcados region=BR -> armazenados/servidos só de sa-east + +Metas não-funcionais: + disponibilidade >= 99,99% globalmente (sobrevive à perda de 1 região) + RTO < 5 min para mover tráfego + promover dados + RPO <= atraso de replicação (declare e defenda) + orçamento de latência entre regiões declarado por caminho de requisição +``` + +## Desafios Extras + +- Adicione uma terceira região e teste escritas por quórum ou padrões de leitura-local/escrita-global. +- Automatize o failback com uma reentrada canário para evitar que uma região fria pegue carga total. +- Adicione rastreamento de custo por região e roteie ciente de custo quando os SLOs permitirem. +- Rode um game day agendado de failover regional e publique o RTO/RPO medidos. + +## Definição de Pronto + +- [ ] O app atende tráfego de duas ou mais regiões com roteamento por proximidade. +- [ ] Uma queda regional simulada faz failover dentro do RTO declarado. +- [ ] A estratégia de dados está documentada com modelo de consistência, RPO e RTO explícitos. +- [ ] Dados restritos por residência comprovadamente nunca são servidos de uma região não permitida. +- [ ] O failback é controlado e observável. + +## Armadilhas Comuns + +- Implantar em duas regiões mas apontar ambas para o banco de uma só região — sem isolamento real. +- Ignorar o atraso de replicação e então perder dados no failover porque o RPO nunca foi medido. +- Assumir que o failover de DNS é instantâneo; caches e TTLs fazem dele qualquer coisa menos isso. +- Tratar residência de dados como um pensamento tardio e descobrir uma violação de conformidade em prod. +- Nunca testar o failover de verdade, então o sistema "multi-região" falha quando uma região falha. + +## Recursos + +- [AWS Well-Architected: Reliability Pillar](https://docs.aws.amazon.com/wellarchitected/latest/reliability-pillar/welcome.html) — padrões de confiabilidade multi-região. +- [Google SRE Book: Managing Critical State](https://sre.google/sre-book/managing-critical-state/) — trade-offs de consistência e replicação. +- [Jepsen: modelos de consistência](https://jepsen.io/consistency) — um mapa preciso das garantias de consistência. +- [Cloudflare: o que é Anycast?](https://www.cloudflare.com/learning/cdn/glossary/anycast-network/) — como o roteamento global direciona usuários. diff --git a/projects/devops/advanced/06-zero-downtime-deployment/README.md b/projects/devops/advanced/06-zero-downtime-deployment/README.md index de10220..7240fa4 100644 --- a/projects/devops/advanced/06-zero-downtime-deployment/README.md +++ b/projects/devops/advanced/06-zero-downtime-deployment/README.md @@ -1,34 +1,100 @@ # Zero-Downtime Deployment System -## Idea -Implement deployment strategy with zero downtime. Learn about advanced deployment patterns. +> 🌐 **English** · [Português](./README.pt-BR.md) + +**Domain:** DevOps · **Level:** Advanced · **Estimated time:** 1–2 weeks + +## Overview + +Ship new versions of a service while it is serving live traffic, without dropping a single request. You will build a deployment system that shifts traffic gradually to a new version, watches real signals while it does, and rolls back automatically the moment those signals go bad. The core idea is to make a release a controlled experiment rather than a leap of faith: a canary takes a slice of traffic, health and SLO metrics act as promotion gates, and only a healthy canary earns more traffic. You will also confront the parts that quietly cause "zero-downtime" deploys to drop requests anyway — connection draining, readiness gates, and backward-compatible schema changes. The deliverable is a repeatable pipeline where a bad deploy is a non-event. + +## Prerequisites + +- A containerized service running behind a load balancer or ingress +- Observability that exposes latency and error rate as queryable SLIs +- Familiarity with Kubernetes rollout mechanics or your platform's equivalent +- Understanding of readiness/liveness probes and connection lifecycle ## Learning Objectives -- Plan deployments -- Handle traffic shifting -- Implement health checks -- Test before switching -- Enable quick rollback - -## Implementation Tips -- Implement canary deployments -- Create traffic shifting -- Add progressive delivery -- Implement health checks -- Add automated rollback -- Create validation gates -- Implement monitoring -- Add performance tracking -- Implement feature flags -- Create experiment framework -- Build safety mechanisms -- Add rollback automation -- Create runbooks -- Build dashboard - -## Key Challenges -- Traffic shifting accuracy -- Health check completeness -- Rollback complexity -- Monitoring during deployment -- Safety guarantees + +By the end, you should be able to: + +- Implement canary and/or blue-green deployments with gradual traffic shifting +- Gate promotion on real SLI metrics, not just "pods are up" +- Roll back automatically when a health or SLO guardrail is breached +- Drain connections and use readiness gates so in-flight requests aren't dropped +- Make schema and API changes backward-compatible across versions + +## Functional Requirements + +1. A new version must receive traffic gradually, starting from a small percentage. +2. Promotion to more traffic must be gated on measured SLIs (error rate, latency). +3. If a guardrail metric breaches, the system must roll back automatically. +4. No in-flight request may be dropped during a shift or rollback (connection draining). +5. Readiness must gate traffic so a pod receives requests only when truly ready. +6. A rollback must return to the last known-good version without manual manifest surgery. +7. Every deployment must be observable: current split, canary health, and decision. + +## Suggested Milestones + +1. **Milestone 1 — Gradual shift:** Deploy a new version to a small traffic slice behind the LB. +2. **Milestone 2 — Promotion gates:** Query SLIs and promote only when the canary is healthy. +3. **Milestone 3 — Auto rollback:** Breach a guardrail on purpose and confirm automatic rollback. +4. **Milestone 4 — Safety details:** Add connection draining, readiness gates, and a backward-compatible schema change walkthrough. + +## Data & Interface Sketch + +```text + deploy v2 + │ + ▼ + ┌──────────────┐ step 1: 5% ┌───────────────┐ + │ Rollout │──────────────▶│ Traffic split │ + │ controller │ step 2: 25% │ v1 ▓▓▓░ v2 ░ │ + │ (Argo Rollouts│ step 3: 50% └──────┬────────┘ + │ / Flagger) │ step 4: 100% │ + └──────┬────────┘ ▼ + │ query SLIs ┌───────────────┐ + └──────────────────────▶│ Metrics (SLI) │ + gate: promote if healthy│ err%, latency │ + rollback if breached └───────────────┘ + +Release decision per step: + if error_rate < 1% AND p99 < 300ms for T minutes -> promote + else -> rollback to v1, drain v2 connections + +Non-functional targets: + request loss 0 dropped requests during shift/rollback + rollback MTTR < 60s from breach to full revert + availability maintained >= SLO throughout the deploy +``` + +## Stretch Goals + +- Add feature flags so code ships dark and is enabled independently of the deploy. +- Support blue-green in addition to canary and compare their trade-offs on your workload. +- Add automated analysis (multiple metrics, statistical comparison to baseline) for promotion. +- Integrate the rollout into GitOps so the desired version lives in Git and rollout is declarative. + +## Definition of Done + +- [ ] A new version is promoted gradually with SLI-gated steps. +- [ ] A deliberately bad version is rolled back automatically within the stated MTTR. +- [ ] No requests are dropped during shift or rollback (verified under load). +- [ ] Readiness gates traffic; connection draining is in place. +- [ ] A backward-compatible schema change is demonstrated across two versions. + +## Common Pitfalls + +- Treating "pods running" as "healthy" and promoting a canary that returns errors fast. +- Skipping connection draining, so rollback drops the very requests you were protecting. +- Breaking schema compatibility, so v1 and v2 can't coexist during the shift. +- No automatic rollback, leaving a human to notice the breach minutes into an incident. +- Canarying by pod count instead of traffic percentage, so the split isn't what you think. + +## Resources + +- [Argo Rollouts documentation](https://argo-rollouts.readthedocs.io/) — canary and blue-green for Kubernetes. +- [Flagger documentation](https://docs.flagger.app/) — progressive delivery with automated analysis. +- [Martin Fowler: BlueGreenDeployment](https://martinfowler.com/bliki/BlueGreenDeployment.html) — the canonical pattern description. +- [Google SRE Workbook: Canarying Releases](https://sre.google/workbook/canarying-releases/) — safe progressive rollout practice. diff --git a/projects/devops/advanced/06-zero-downtime-deployment/README.pt-BR.md b/projects/devops/advanced/06-zero-downtime-deployment/README.pt-BR.md new file mode 100644 index 0000000..8504ad5 --- /dev/null +++ b/projects/devops/advanced/06-zero-downtime-deployment/README.pt-BR.md @@ -0,0 +1,100 @@ +# Sistema de Deploy Sem Downtime + +> 🌐 [English](./README.md) · **Português** + +**Domínio:** DevOps · **Nível:** Avançado · **Tempo estimado:** 1–2 semanas + +## Visão Geral + +Publique novas versões de um serviço enquanto ele atende tráfego ao vivo, sem derrubar uma única requisição. Você vai construir um sistema de deploy que move o tráfego gradualmente para a nova versão, observa sinais reais enquanto faz isso e reverte automaticamente no instante em que esses sinais pioram. A ideia central é transformar um release em um experimento controlado em vez de um salto de fé: um canário pega uma fatia do tráfego, métricas de saúde e SLO atuam como portões de promoção, e só um canário saudável ganha mais tráfego. Você também vai enfrentar as partes que silenciosamente fazem deploys "sem downtime" derrubarem requisições mesmo assim — drenagem de conexões, portões de readiness e mudanças de schema retrocompatíveis. A entrega é um pipeline repetível em que um deploy ruim é um não-evento. + +## Pré-requisitos + +- Um serviço containerizado rodando atrás de um load balancer ou ingress +- Observabilidade que expõe latência e taxa de erro como SLIs consultáveis +- Familiaridade com a mecânica de rollout do Kubernetes ou o equivalente da sua plataforma +- Entendimento de probes de readiness/liveness e do ciclo de vida de conexões + +## Objetivos de Aprendizado + +Ao final, você deve ser capaz de: + +- Implementar deploys canário e/ou blue-green com deslocamento gradual de tráfego +- Condicionar a promoção a métricas reais de SLI, não apenas "os pods estão de pé" +- Reverter automaticamente quando uma métrica de guarda de saúde ou SLO for violada +- Drenar conexões e usar portões de readiness para não derrubar requisições em andamento +- Tornar mudanças de schema e API retrocompatíveis entre versões + +## Requisitos Funcionais + +1. Uma nova versão deve receber tráfego gradualmente, começando por uma pequena porcentagem. +2. A promoção para mais tráfego deve ser condicionada a SLIs medidos (taxa de erro, latência). +3. Se uma métrica de guarda for violada, o sistema deve reverter automaticamente. +4. Nenhuma requisição em andamento pode ser derrubada durante um deslocamento ou rollback (drenagem de conexões). +5. A readiness deve condicionar o tráfego para que um pod receba requisições só quando realmente pronto. +6. Um rollback deve retornar à última versão boa conhecida sem cirurgia manual de manifest. +7. Todo deploy deve ser observável: split atual, saúde do canário e decisão. + +## Marcos Sugeridos + +1. **Marco 1 — Deslocamento gradual:** Implante uma nova versão em uma pequena fatia de tráfego atrás do LB. +2. **Marco 2 — Portões de promoção:** Consulte SLIs e promova só quando o canário estiver saudável. +3. **Marco 3 — Rollback automático:** Viole uma guarda de propósito e confirme o rollback automático. +4. **Marco 4 — Detalhes de segurança:** Adicione drenagem de conexões, portões de readiness e um passo a passo de mudança de schema retrocompatível. + +## Esboço de Dados e Interface + +```text + deploy v2 + │ + ▼ + ┌──────────────┐ passo 1: 5% ┌───────────────┐ + │ Controlador │──────────────▶│ Split de tráf.│ + │ de rollout │ passo 2: 25%│ v1 ▓▓▓░ v2 ░ │ + │ (Argo Rollouts│ passo 3: 50%└──────┬────────┘ + │ / Flagger) │ passo 4:100% │ + └──────┬────────┘ ▼ + │ consulta SLIs ┌───────────────┐ + └──────────────────────▶│ Métricas (SLI)│ + portão: promove se sã │ erro%, latência│ + reverte se violado └───────────────┘ + +Decisão de release por passo: + se taxa_erro < 1% E p99 < 300ms por T minutos -> promove + senão -> reverte para v1, drena conexões da v2 + +Metas não-funcionais: + perda de requisição 0 requisições derrubadas durante deslocamento/rollback + MTTR de rollback < 60s da violação à reversão total + disponibilidade mantida >= SLO durante todo o deploy +``` + +## Desafios Extras + +- Adicione feature flags para que o código seja publicado "no escuro" e habilitado independente do deploy. +- Suporte blue-green além do canário e compare seus trade-offs na sua carga de trabalho. +- Adicione análise automatizada (múltiplas métricas, comparação estatística com baseline) para promoção. +- Integre o rollout ao GitOps para que a versão desejada viva no Git e o rollout seja declarativo. + +## Definição de Pronto + +- [ ] Uma nova versão é promovida gradualmente com passos condicionados por SLI. +- [ ] Uma versão deliberadamente ruim é revertida automaticamente dentro do MTTR declarado. +- [ ] Nenhuma requisição é derrubada durante deslocamento ou rollback (verificado sob carga). +- [ ] A readiness condiciona o tráfego; a drenagem de conexões está no lugar. +- [ ] Uma mudança de schema retrocompatível é demonstrada entre duas versões. + +## Armadilhas Comuns + +- Tratar "pods rodando" como "saudável" e promover um canário que retorna erros rapidamente. +- Pular a drenagem de conexões, de modo que o rollback derruba justamente as requisições que você protegia. +- Quebrar a compatibilidade de schema, de modo que v1 e v2 não conseguem coexistir durante o deslocamento. +- Nenhum rollback automático, deixando um humano notar a violação minutos dentro de um incidente. +- Canário por contagem de pods em vez de porcentagem de tráfego, então o split não é o que você pensa. + +## Recursos + +- [Documentação do Argo Rollouts](https://argo-rollouts.readthedocs.io/) — canário e blue-green para Kubernetes. +- [Documentação do Flagger](https://docs.flagger.app/) — entrega progressiva com análise automatizada. +- [Martin Fowler: BlueGreenDeployment](https://martinfowler.com/bliki/BlueGreenDeployment.html) — a descrição canônica do padrão. +- [Google SRE Workbook: Canarying Releases](https://sre.google/workbook/canarying-releases/) — prática de rollout progressivo seguro. diff --git a/projects/devops/advanced/07-service-mesh/README.md b/projects/devops/advanced/07-service-mesh/README.md index ce0fb15..f77ca82 100644 --- a/projects/devops/advanced/07-service-mesh/README.md +++ b/projects/devops/advanced/07-service-mesh/README.md @@ -1,34 +1,102 @@ # Service Mesh Implementation -## Idea -Implement a service mesh for managing microservice communication. Learn about advanced networking patterns. +> 🌐 **English** · [Português](./README.pt-BR.md) + +**Domain:** DevOps · **Level:** Advanced · **Estimated time:** 1–2 weeks + +## Overview + +Move the cross-cutting concerns of microservice communication — encryption, retries, timeouts, traffic splitting, and observability — out of every application and into a dedicated infrastructure layer. You will deploy a service mesh that injects a sidecar proxy (or a per-node proxy) alongside your services, so that traffic between them is intercepted and governed by policy rather than by code scattered across teams. The advanced work is not "run the installer"; it is deciding what belongs in the mesh versus the app, enabling mutual TLS without breaking existing traffic, writing authorization policy that is deny-by-default, and paying honest attention to the latency and resource overhead a proxy on every hop introduces. Done right, security and reliability become properties of the platform, not per-service homework. + +## Prerequisites + +- A Kubernetes cluster running at least two services that call each other +- Understanding of TLS, certificates, and mutual authentication +- Familiarity with L7 concepts: retries, timeouts, circuit breaking +- Basic observability so you can measure the overhead the mesh adds ## Learning Objectives -- Deploy service mesh -- Manage traffic -- Implement security policies -- Handle observability -- Manage retries - -## Implementation Tips -- Choose service mesh (Istio, Linkerd) -- Configure sidecar proxies -- Implement traffic management -- Add security policies -- Create authorization rules -- Implement mutual TLS -- Add observability -- Create distributed tracing -- Implement circuit breakers -- Add retry policies -- Implement rate limiting -- Create traffic shifting -- Add canary deployments -- Build operational dashboards - -## Key Challenges -- Mesh complexity -- CPU/Memory overhead -- Observability at scale -- Policy management -- Operational complexity + +By the end, you should be able to: + +- Deploy a service mesh and understand the sidecar/data-plane vs. control-plane split +- Enable mutual TLS between services without dropping traffic +- Write deny-by-default authorization policies between workloads +- Configure traffic management: retries, timeouts, circuit breaking, and splitting +- Quantify and reason about the mesh's latency and resource overhead + +## Functional Requirements + +1. Traffic between meshed services must be encrypted with mutual TLS automatically. +2. Service-to-service authorization must be deny-by-default with explicit allow rules. +3. The mesh must enforce configurable retries, timeouts, and circuit breaking. +4. Traffic splitting between service versions must be controllable without app changes. +5. The mesh must emit L7 telemetry (per-route latency, error rate) for observability. +6. Enabling the mesh must not require rewriting application networking code. +7. The added latency and resource overhead must be measured and documented. + +## Suggested Milestones + +1. **Milestone 1 — Mesh & sidecars:** Install the mesh and inject sidecars for two communicating services. +2. **Milestone 2 — mTLS & authz:** Turn on mutual TLS and write deny-by-default authorization policy. +3. **Milestone 3 — Traffic management:** Add retries, timeouts, circuit breaking, and version-based splitting. +4. **Milestone 4 — Observability & cost:** Wire up L7 telemetry and measure the mesh's overhead against a baseline. + +## Data & Interface Sketch + +```text + ┌───────────────────────┐ + │ Control Plane │ (config, certs, policy) + │ (istiod / linkerd) │ + └───────────┬───────────┘ + push config/certs│ + ┌──────────────┐ │ ┌──────────────┐ + │ Service A │ │ │ Service B │ + │ ┌──────────┐ │ │ │ ┌──────────┐ │ + ───▶ │ │ proxy │◀┼──mTLS┼──────┼▶│ proxy │ │ ───▶ + │ └────┬─────┘ │ │ │ └────┬─────┘ │ + │ app A │ │ │ app B │ + └──────────────┘ │ └──────────────┘ + data plane (sidecars enforce policy on every hop) + +Policy example (conceptual): + authz: default DENY + allow A -> B on route /orders method GET + traffic: B retries=2 timeout=2s circuit-break at 50% 5xx + split B: v1=90% v2=10% + +Non-functional targets: + added p99 latency measured per hop, kept within budget + proxy overhead CPU/mem per sidecar quantified + security 0 plaintext service-to-service traffic +``` + +## Stretch Goals + +- Compare a sidecar mesh with a sidecarless/ambient mode and measure the overhead difference. +- Extend authorization to use request identity (JWT) not just workload identity. +- Add fault injection at the mesh layer to combine with a chaos-engineering practice. +- Federate the mesh across two clusters for cross-cluster mTLS and discovery. + +## Definition of Done + +- [ ] Service-to-service traffic is mutually TLS-encrypted with no app code changes. +- [ ] Authorization is deny-by-default with explicit, tested allow rules. +- [ ] Retries, timeouts, and circuit breaking are enforced and demonstrably trigger. +- [ ] Traffic can be split between versions purely via mesh config. +- [ ] Mesh latency and resource overhead are measured and documented against a baseline. + +## Common Pitfalls + +- Turning on strict mTLS globally at once and cutting off services not yet in the mesh. +- Leaving authorization at allow-all, so the mesh adds encryption but no real access control. +- Ignoring proxy overhead until latency-sensitive paths regress in production. +- Configuring aggressive retries that amplify load and turn a blip into a retry storm. +- Putting logic in the mesh that belongs in the app (or vice versa), blurring ownership. + +## Resources + +- [Istio documentation](https://istio.io/latest/docs/) — a widely used service mesh with rich traffic policy. +- [Linkerd documentation](https://linkerd.io/2/overview/) — a lightweight, security-focused mesh. +- [SMI: Service Mesh Interface](https://smi-spec.io/) — a vendor-neutral mesh API spec. +- [Google SRE Book: Handling Overload](https://sre.google/sre-book/handling-overload/) — retries, load shedding, and circuit breaking done safely. diff --git a/projects/devops/advanced/07-service-mesh/README.pt-BR.md b/projects/devops/advanced/07-service-mesh/README.pt-BR.md new file mode 100644 index 0000000..b51ff44 --- /dev/null +++ b/projects/devops/advanced/07-service-mesh/README.pt-BR.md @@ -0,0 +1,102 @@ +# Implementação de Service Mesh + +> 🌐 [English](./README.md) · **Português** + +**Domínio:** DevOps · **Nível:** Avançado · **Tempo estimado:** 1–2 semanas + +## Visão Geral + +Mova as preocupações transversais da comunicação entre microsserviços — criptografia, retentativas, timeouts, divisão de tráfego e observabilidade — para fora de cada aplicação e para uma camada de infraestrutura dedicada. Você vai implantar um service mesh que injeta um proxy sidecar (ou um proxy por nó) ao lado dos seus serviços, de modo que o tráfego entre eles seja interceptado e governado por política em vez de por código espalhado entre times. O trabalho avançado não é "rodar o instalador"; é decidir o que pertence ao mesh versus ao app, habilitar TLS mútuo sem quebrar o tráfego existente, escrever política de autorização que seja negar-por-padrão, e prestar atenção honesta à latência e ao overhead de recursos que um proxy em cada salto introduz. Bem feito, segurança e confiabilidade viram propriedades da plataforma, não tarefa de casa de cada serviço. + +## Pré-requisitos + +- Um cluster Kubernetes rodando pelo menos dois serviços que chamam um ao outro +- Entendimento de TLS, certificados e autenticação mútua +- Familiaridade com conceitos L7: retentativas, timeouts, circuit breaking +- Observabilidade básica para medir o overhead que o mesh adiciona + +## Objetivos de Aprendizado + +Ao final, você deve ser capaz de: + +- Implantar um service mesh e entender a divisão sidecar/data-plane vs. control-plane +- Habilitar TLS mútuo entre serviços sem derrubar tráfego +- Escrever políticas de autorização negar-por-padrão entre cargas de trabalho +- Configurar gestão de tráfego: retentativas, timeouts, circuit breaking e divisão +- Quantificar e raciocinar sobre o overhead de latência e recursos do mesh + +## Requisitos Funcionais + +1. O tráfego entre serviços no mesh deve ser criptografado com TLS mútuo automaticamente. +2. A autorização serviço-a-serviço deve ser negar-por-padrão com regras de permissão explícitas. +3. O mesh deve impor retentativas, timeouts e circuit breaking configuráveis. +4. A divisão de tráfego entre versões de serviço deve ser controlável sem mudanças no app. +5. O mesh deve emitir telemetria L7 (latência por rota, taxa de erro) para observabilidade. +6. Habilitar o mesh não deve exigir reescrever o código de rede da aplicação. +7. A latência adicionada e o overhead de recursos devem ser medidos e documentados. + +## Marcos Sugeridos + +1. **Marco 1 — Mesh e sidecars:** Instale o mesh e injete sidecars para dois serviços que se comunicam. +2. **Marco 2 — mTLS e authz:** Ligue o TLS mútuo e escreva política de autorização negar-por-padrão. +3. **Marco 3 — Gestão de tráfego:** Adicione retentativas, timeouts, circuit breaking e divisão baseada em versão. +4. **Marco 4 — Observabilidade e custo:** Conecte a telemetria L7 e meça o overhead do mesh contra um baseline. + +## Esboço de Dados e Interface + +```text + ┌───────────────────────┐ + │ Control Plane │ (config, certs, política) + │ (istiod / linkerd) │ + └───────────┬───────────┘ + empurra config/certs│ + ┌──────────────┐ │ ┌──────────────┐ + │ Serviço A │ │ │ Serviço B │ + │ ┌──────────┐ │ │ │ ┌──────────┐ │ + ───▶ │ │ proxy │◀┼──mTLS┼──────┼▶│ proxy │ │ ───▶ + │ └────┬─────┘ │ │ │ └────┬─────┘ │ + │ app A │ │ │ app B │ + └──────────────┘ │ └──────────────┘ + data plane (sidecars impõem política em cada salto) + +Exemplo de política (conceitual): + authz: DENY por padrão + allow A -> B na rota /orders método GET + tráfego: B retries=2 timeout=2s circuit-break em 50% 5xx + split B: v1=90% v2=10% + +Metas não-funcionais: + latência p99 adicionada medida por salto, mantida no orçamento + overhead de proxy CPU/mem por sidecar quantificado + segurança 0 tráfego serviço-a-serviço em texto puro +``` + +## Desafios Extras + +- Compare um mesh com sidecar com um modo sem sidecar/ambient e meça a diferença de overhead. +- Estenda a autorização para usar identidade de requisição (JWT), não apenas identidade de carga. +- Adicione injeção de falhas na camada do mesh para combinar com uma prática de chaos engineering. +- Federe o mesh entre dois clusters para mTLS e descoberta entre clusters. + +## Definição de Pronto + +- [ ] O tráfego serviço-a-serviço é criptografado com TLS mútuo sem mudanças no código do app. +- [ ] A autorização é negar-por-padrão com regras de permissão explícitas e testadas. +- [ ] Retentativas, timeouts e circuit breaking são impostos e disparam de forma demonstrável. +- [ ] O tráfego pode ser dividido entre versões puramente via config do mesh. +- [ ] A latência e o overhead de recursos do mesh são medidos e documentados contra um baseline. + +## Armadilhas Comuns + +- Ligar mTLS estrito globalmente de uma vez e cortar serviços que ainda não estão no mesh. +- Deixar a autorização em permitir-tudo, de modo que o mesh adiciona criptografia mas nenhum controle de acesso real. +- Ignorar o overhead do proxy até que caminhos sensíveis à latência regridam em produção. +- Configurar retentativas agressivas que amplificam carga e transformam uma oscilação em uma tempestade de retentativas. +- Colocar no mesh lógica que pertence ao app (ou vice-versa), borrando a titularidade. + +## Recursos + +- [Documentação do Istio](https://istio.io/latest/docs/) — um service mesh amplamente usado com política de tráfego rica. +- [Documentação do Linkerd](https://linkerd.io/2/overview/) — um mesh leve e focado em segurança. +- [SMI: Service Mesh Interface](https://smi-spec.io/) — uma especificação de API de mesh neutra em relação a fornecedor. +- [Google SRE Book: Handling Overload](https://sre.google/sre-book/handling-overload/) — retentativas, descarte de carga e circuit breaking feitos com segurança. diff --git a/projects/devops/advanced/08-incident-response/README.md b/projects/devops/advanced/08-incident-response/README.md index 4d2363e..9cffc37 100644 --- a/projects/devops/advanced/08-incident-response/README.md +++ b/projects/devops/advanced/08-incident-response/README.md @@ -1,34 +1,104 @@ # Incident Response Automation -## Idea -Automate incident detection and response. Learn about automated incident management. +> 🌐 **English** · [Português](./README.pt-BR.md) + +**Domain:** DevOps · **Level:** Advanced · **Estimated time:** 1–2 weeks + +## Overview + +Build the machinery that turns a raw alert into a coordinated response: detection routes to the right on-call, an incident channel and timeline are created automatically, safe first-line remediations run without waiting for a human, and everything is recorded for a blameless post-mortem. The goal is to shrink the two numbers that define incident pain — time to detect and time to resolve — while keeping a human firmly in control of anything risky. The hard, interesting parts are the judgment calls encoded in software: which remediations are safe to automate, when to escalate versus wait, how to avoid alert fatigue that trains people to ignore the pager, and how to capture a timeline good enough that the post-mortem produces real fixes rather than blame. + +## Prerequisites + +- An observability stack that produces alerts on SLO or health signals +- A notification/chat platform to integrate (paging tool, chat channels) +- Understanding of on-call, escalation, and severity concepts +- Familiarity with runbooks and the idea of safe, reversible actions ## Learning Objectives -- Detect incidents -- Trigger automation -- Remediate automatically -- Escalate when needed -- Track resolutions - -## Implementation Tips -- Create alerting framework -- Implement detection rules -- Create remediation playbooks -- Implement auto-remediation -- Add escalation logic -- Create incident tracking -- Implement notification system -- Add metrics collection -- Create root cause analysis -- Implement learning system -- Build dashboard -- Create incident history -- Add SLO tracking -- Implement post-mortems - -## Key Challenges -- Detection accuracy -- Remedy safety -- Escalation decisions -- Learning effectiveness -- Over-automation risks + +By the end, you should be able to: + +- Route alerts to the right responder based on service and severity +- Automate incident creation: channel, timeline, and roles +- Run safe, reversible first-line remediations automatically with guardrails +- Design escalation that reaches a human when automation isn't enough +- Capture a timeline and drive a blameless post-mortem with tracked action items + +## Functional Requirements + +1. An alert must be classified by severity and routed to the correct on-call responder. +2. Declaring an incident must automatically create a channel, a timeline, and assign roles. +3. Defined safe remediations must run automatically, with a guardrail and an audit record. +4. If automation does not resolve within a threshold, the system must escalate. +5. Every human and automated action must be appended to an incident timeline. +6. Resolution must trigger a post-mortem template pre-filled from the timeline. +7. Post-mortem action items must be tracked to completion. + +## Suggested Milestones + +1. **Milestone 1 — Detect & route:** Classify alerts by severity and page the correct on-call. +2. **Milestone 2 — Incident orchestration:** Auto-create the channel, timeline, and role assignments on declare. +3. **Milestone 3 — Safe auto-remediation:** Run one reversible remediation with a guardrail and escalation fallback. +4. **Milestone 4 — Learn:** Generate a post-mortem from the timeline and track action items to closure. + +## Data & Interface Sketch + +```text + alert fires + │ classify severity (SEV1..SEV3), map service -> on-call + ▼ + ┌────────────────┐ page ┌──────────────┐ + │ Incident │────────────▶│ On-call │ + │ orchestrator │ └──────────────┘ + └───┬───────┬─────┘ + │ │ create channel + timeline + roles (IC, comms, ops) + │ ▼ + │ ┌──────────────┐ + │ │ Incident │ append every action, timestamped + │ │ timeline │ + │ └──────┬────────┘ + │ safe remediation? (guardrail: reversible, scoped) + ▼ yes -> run + record ; no/timeout -> escalate + ┌────────────────┐ resolve ┌──────────────┐ + │ Auto-remediate │────────────▶│ Post-mortem │ (blameless, action items) + └────────────────┘ └──────────────┘ + +Notification recipients use placeholder identities, e.g. oncall@example.com + +Non-functional targets: + MTTD time-to-detect measured and trending down + MTTR time-to-resolve measured per severity + alert precision actionable-alert ratio tracked (fight fatigue) + automation safety only reversible, scoped actions run unattended +``` + +## Stretch Goals + +- Add auto-detected root-cause hints by correlating the alert with recent deploys and traces. +- Introduce severity-based comms automation (status page updates, stakeholder notifications). +- Add a "practice incident" mode to rehearse the flow without a real outage. +- Track error-budget burn and auto-declare incidents when burn rate is critical. + +## Definition of Done + +- [ ] Alerts are classified and routed to the correct responder by service and severity. +- [ ] Declaring an incident auto-creates a channel, timeline, and role assignments. +- [ ] At least one safe, reversible remediation runs automatically with a guardrail. +- [ ] Escalation reaches a human when automation fails or times out. +- [ ] A post-mortem is generated from the timeline and its action items are tracked. + +## Common Pitfalls + +- Automating a remediation that is not reversible, turning a small incident into a big one. +- Alert fatigue: paging on everything until responders mute the channel that matters. +- No timeline discipline, so the post-mortem is guesswork and produces no real fixes. +- Escalation with no timeout, so an unresolved incident sits with automation forever. +- Blameful post-mortems that make people hide detail, defeating the entire point. + +## Resources + +- [Google SRE Book: Managing Incidents](https://sre.google/sre-book/managing-incidents/) — incident command and coordination. +- [Google SRE Book: Postmortem Culture](https://sre.google/sre-book/postmortem-culture/) — blameless learning done right. +- [PagerDuty Incident Response](https://response.pagerduty.com/) — a practical, open incident response guide. +- [Atlassian: Incident management](https://www.atlassian.com/incident-management) — severity, roles, and process fundamentals. diff --git a/projects/devops/advanced/08-incident-response/README.pt-BR.md b/projects/devops/advanced/08-incident-response/README.pt-BR.md new file mode 100644 index 0000000..181f36d --- /dev/null +++ b/projects/devops/advanced/08-incident-response/README.pt-BR.md @@ -0,0 +1,104 @@ +# Automação de Resposta a Incidentes + +> 🌐 [English](./README.md) · **Português** + +**Domínio:** DevOps · **Nível:** Avançado · **Tempo estimado:** 1–2 semanas + +## Visão Geral + +Construa a maquinaria que transforma um alerta bruto em uma resposta coordenada: a detecção roteia para o on-call certo, um canal de incidente e uma linha do tempo são criados automaticamente, remediações seguras de primeira linha rodam sem esperar por um humano, e tudo é registrado para um post-mortem sem culpa. O objetivo é encolher os dois números que definem a dor de um incidente — tempo para detectar e tempo para resolver — mantendo um humano firmemente no controle de qualquer coisa arriscada. As partes difíceis e interessantes são os julgamentos codificados em software: quais remediações são seguras para automatizar, quando escalar versus esperar, como evitar a fadiga de alertas que treina as pessoas a ignorar o pager, e como capturar uma linha do tempo boa o bastante para que o post-mortem produza correções reais em vez de culpa. + +## Pré-requisitos + +- Uma stack de observabilidade que produz alertas em sinais de SLO ou saúde +- Uma plataforma de notificação/chat para integrar (ferramenta de paging, canais de chat) +- Entendimento de conceitos de on-call, escalonamento e severidade +- Familiaridade com runbooks e a ideia de ações seguras e reversíveis + +## Objetivos de Aprendizado + +Ao final, você deve ser capaz de: + +- Rotear alertas ao respondente certo com base em serviço e severidade +- Automatizar a criação de incidentes: canal, linha do tempo e papéis +- Rodar remediações de primeira linha seguras e reversíveis automaticamente com salvaguardas +- Projetar escalonamento que alcança um humano quando a automação não basta +- Capturar uma linha do tempo e conduzir um post-mortem sem culpa com itens de ação rastreados + +## Requisitos Funcionais + +1. Um alerta deve ser classificado por severidade e roteado ao respondente on-call correto. +2. Declarar um incidente deve criar automaticamente um canal, uma linha do tempo e atribuir papéis. +3. Remediações seguras definidas devem rodar automaticamente, com salvaguarda e registro de auditoria. +4. Se a automação não resolver dentro de um limiar, o sistema deve escalar. +5. Toda ação humana e automatizada deve ser anexada a uma linha do tempo do incidente. +6. A resolução deve disparar um template de post-mortem pré-preenchido a partir da linha do tempo. +7. Itens de ação do post-mortem devem ser rastreados até a conclusão. + +## Marcos Sugeridos + +1. **Marco 1 — Detectar e rotear:** Classifique alertas por severidade e acione o on-call correto. +2. **Marco 2 — Orquestração de incidentes:** Auto-crie o canal, a linha do tempo e as atribuições de papel na declaração. +3. **Marco 3 — Auto-remediação segura:** Rode uma remediação reversível com salvaguarda e escalonamento de fallback. +4. **Marco 4 — Aprender:** Gere um post-mortem a partir da linha do tempo e leve os itens de ação até o encerramento. + +## Esboço de Dados e Interface + +```text + alerta dispara + │ classifica severidade (SEV1..SEV3), mapeia serviço -> on-call + ▼ + ┌────────────────┐ aciona ┌──────────────┐ + │ Orquestrador │────────────▶│ On-call │ + │ de incidente │ └──────────────┘ + └───┬───────┬─────┘ + │ │ cria canal + linha do tempo + papéis (IC, comms, ops) + │ ▼ + │ ┌──────────────┐ + │ │ Linha do tempo│ anexa cada ação, com timestamp + │ │ do incidente │ + │ └──────┬────────┘ + │ remediação segura? (salvaguarda: reversível, com escopo) + ▼ sim -> roda + registra ; não/timeout -> escala + ┌────────────────┐ resolve ┌──────────────┐ + │ Auto-remediar │────────────▶│ Post-mortem │ (sem culpa, itens de ação) + └────────────────┘ └──────────────┘ + +Destinatários de notificação usam identidades de exemplo, ex.: oncall@example.com + +Metas não-funcionais: + MTTD tempo-para-detectar medido e em queda + MTTR tempo-para-resolver medido por severidade + precisão de alerta razão de alertas acionáveis monitorada (combate à fadiga) + segurança da automação só ações reversíveis e com escopo rodam sem supervisão +``` + +## Desafios Extras + +- Adicione dicas de causa raiz auto-detectadas correlacionando o alerta com deploys recentes e traces. +- Introduza automação de comunicação por severidade (atualizações de status page, notificações a stakeholders). +- Adicione um modo "incidente de treino" para ensaiar o fluxo sem uma queda real. +- Rastreie a queima do error budget e auto-declare incidentes quando a taxa de queima for crítica. + +## Definição de Pronto + +- [ ] Alertas são classificados e roteados ao respondente correto por serviço e severidade. +- [ ] Declarar um incidente auto-cria um canal, linha do tempo e atribuições de papel. +- [ ] Pelo menos uma remediação segura e reversível roda automaticamente com salvaguarda. +- [ ] O escalonamento alcança um humano quando a automação falha ou expira. +- [ ] Um post-mortem é gerado a partir da linha do tempo e seus itens de ação são rastreados. + +## Armadilhas Comuns + +- Automatizar uma remediação que não é reversível, transformando um incidente pequeno em um grande. +- Fadiga de alertas: acionar por tudo até que os respondentes silenciem o canal que importa. +- Sem disciplina de linha do tempo, o post-mortem vira adivinhação e não produz correções reais. +- Escalonamento sem timeout, então um incidente não resolvido fica com a automação para sempre. +- Post-mortems com culpa que fazem as pessoas esconderem detalhes, derrotando todo o propósito. + +## Recursos + +- [Google SRE Book: Managing Incidents](https://sre.google/sre-book/managing-incidents/) — comando e coordenação de incidentes. +- [Google SRE Book: Postmortem Culture](https://sre.google/sre-book/postmortem-culture/) — aprendizado sem culpa bem feito. +- [PagerDuty Incident Response](https://response.pagerduty.com/) — um guia prático e aberto de resposta a incidentes. +- [Atlassian: Incident management](https://www.atlassian.com/incident-management) — fundamentos de severidade, papéis e processo. diff --git a/projects/devops/advanced/09-cost-monitoring/README.md b/projects/devops/advanced/09-cost-monitoring/README.md index 3ab16cf..d142c39 100644 --- a/projects/devops/advanced/09-cost-monitoring/README.md +++ b/projects/devops/advanced/09-cost-monitoring/README.md @@ -1,34 +1,105 @@ # Cost Monitoring System -## Idea -Build a system for monitoring and optimizing cloud costs. Learn about cloud financial management. +> 🌐 **English** · [Português](./README.pt-BR.md) + +**Domain:** DevOps · **Level:** Advanced · **Estimated time:** 1–2 weeks + +## Overview + +Turn an opaque cloud bill into an actionable, attributable, forward-looking view of spend. You will ingest cost and usage data, allocate it to teams and services via tagging, surface waste and anomalies, forecast where the bill is heading, and put guardrails in place so a runaway resource is caught before it shows up as a five-figure surprise. The advanced substance is in the allocation and the incentives: cost data is messy, tags are inconsistent, shared resources resist clean chargeback, and "just turn it off" ignores the reliability the spend buys. A good cost system does not just report numbers — it attributes them to owners, explains the trend, and makes the cost of a decision visible at the moment the decision is made. + +## Prerequisites + +- Access to a cloud provider's cost and usage export (or a realistic sample dataset) +- Understanding of your resource inventory: compute, storage, network, managed services +- Familiarity with tagging/labeling and how it drives allocation +- Basic data modeling and dashboarding skills ## Learning Objectives -- Track spending -- Identify waste -- Optimize resources -- Implement controls -- Forecast costs - -## Implementation Tips -- Integrate with cloud providers -- Collect cost data -- Create cost allocation -- Implement tagging -- Build dashboards -- Create anomaly detection -- Add cost forecasting -- Implement alerts -- Create optimization recommendations -- Build chargeback system -- Add budget controls -- Implement reservations tracking -- Create commitment tracking -- Build reporting - -## Key Challenges -- Cost complexity -- Chargeback accuracy -- Forecasting accuracy -- Optimization complexity -- Multi-cloud management + +By the end, you should be able to: + +- Ingest and normalize cloud cost and usage data +- Allocate spend to teams/services via a tagging strategy, including shared costs +- Detect waste (idle, oversized, orphaned resources) and cost anomalies +- Forecast spend and compare against budgets +- Set guardrails and alerts that catch runaway cost early without blocking legitimate work + +## Functional Requirements + +1. The system must ingest cost and usage data on a schedule and store it queryably. +2. Spend must be allocatable to a team or service, with a defined rule for shared/untagged costs. +3. The system must flag waste: idle, oversized, or orphaned resources. +4. Cost anomalies (sudden spikes vs. baseline) must be detected and alerted. +5. The system must forecast spend for the current period and compare to a budget. +6. A budget breach or forecast-to-breach must trigger an alert to the owner. +7. Reports must be attributable — every significant cost has an owner or a documented shared bucket. + +## Suggested Milestones + +1. **Milestone 1 — Ingest & model:** Load cost/usage data and model it for querying. +2. **Milestone 2 — Allocation:** Apply a tagging strategy and attribute spend to owners, handling shared costs. +3. **Milestone 3 — Waste & anomalies:** Detect idle/oversized resources and spike anomalies. +4. **Milestone 4 — Forecast & guardrails:** Forecast the period, compare to budgets, and alert on breach risk. + +## Data & Interface Sketch + +```text + cloud billing export (daily) + │ + ▼ + ┌───────────────┐ normalize + tag-based allocation + │ Cost ingester │──────────────┐ + └───────────────┘ ▼ + ┌───────────────┐ + │ Cost store │ (service, team, resource, $) + └──────┬────────┘ + ┌──────────────┬──────────┼───────────┬──────────────┐ + ▼ ▼ ▼ ▼ ▼ + allocation waste anomaly forecast budget + by team/svc finder detector (period $) guardrail + └──────────────┴──────────┴───────────┴──────────────┘ + ▼ + ┌───────────┐ alert owner (name@example.com) + │ dashboard │ on anomaly / budget breach + └───────────┘ + +Allocation record: + service: checkout team: payments cost: $/day + shared: load-balancer -> split by request share (documented rule) + +Non-functional targets: + attribution coverage >= 95% of spend mapped to an owner + anomaly detection spike flagged within 24h + forecast accuracy tracked (forecast vs. actual delta) +``` + +## Stretch Goals + +- Add a chargeback/showback report per team with trends and top drivers. +- Recommend rightsizing and commitment (reserved/savings-plan) opportunities with payback estimates. +- Add unit-economics metrics (cost per request, per tenant) so scaling decisions are cost-aware. +- Support multi-cloud so allocation and anomalies span providers. + +## Definition of Done + +- [ ] Cost/usage data is ingested on a schedule and queryable. +- [ ] At least 95% of spend is attributed to an owner, with a documented rule for shared cost. +- [ ] Waste and cost anomalies are detected and alerted. +- [ ] Spend is forecast for the period and compared against a budget. +- [ ] A budget-breach risk triggers an alert to the owner. + +## Common Pitfalls + +- Chasing raw cost totals with no allocation, so no one owns or acts on the number. +- Inconsistent tagging that leaves a large "unallocated" bucket nobody investigates. +- Anomaly alerts with no baseline, firing on normal end-of-month or scaling patterns. +- Forecasting off a short window, so seasonality makes every forecast wrong. +- Optimizing cost in isolation and quietly degrading reliability the spend was buying. + +## Resources + +- [FinOps Framework](https://www.finops.org/framework/) — the discipline of cloud financial management. +- [AWS Well-Architected: Cost Optimization Pillar](https://docs.aws.amazon.com/wellarchitected/latest/cost-optimization-pillar/welcome.html) — allocation and rightsizing patterns. +- [Google Cloud: Cost management overview](https://cloud.google.com/cost-management) — budgets, alerts, and reporting concepts. +- [Kubecost / OpenCost](https://www.opencost.io/) — open-source Kubernetes cost allocation. diff --git a/projects/devops/advanced/09-cost-monitoring/README.pt-BR.md b/projects/devops/advanced/09-cost-monitoring/README.pt-BR.md new file mode 100644 index 0000000..e09bb69 --- /dev/null +++ b/projects/devops/advanced/09-cost-monitoring/README.pt-BR.md @@ -0,0 +1,105 @@ +# Sistema de Monitoramento de Custos + +> 🌐 [English](./README.md) · **Português** + +**Domínio:** DevOps · **Nível:** Avançado · **Tempo estimado:** 1–2 semanas + +## Visão Geral + +Transforme uma fatura de nuvem opaca em uma visão acionável, atribuível e prospectiva do gasto. Você vai ingerir dados de custo e uso, alocá-los a times e serviços via tagueamento, expor desperdício e anomalias, prever para onde a fatura está indo, e colocar salvaguardas para que um recurso descontrolado seja pego antes de aparecer como uma surpresa de cinco dígitos. A substância avançada está na alocação e nos incentivos: dados de custo são bagunçados, tags são inconsistentes, recursos compartilhados resistem a um chargeback limpo, e "só desliga" ignora a confiabilidade que o gasto compra. Um bom sistema de custos não apenas reporta números — ele os atribui a donos, explica a tendência, e torna o custo de uma decisão visível no momento em que a decisão é tomada. + +## Pré-requisitos + +- Acesso a uma exportação de custo e uso de um provedor de nuvem (ou um dataset de amostra realista) +- Entendimento do seu inventário de recursos: computação, armazenamento, rede, serviços gerenciados +- Familiaridade com tagueamento/labeling e como ele guia a alocação +- Habilidades básicas de modelagem de dados e dashboards + +## Objetivos de Aprendizado + +Ao final, você deve ser capaz de: + +- Ingerir e normalizar dados de custo e uso de nuvem +- Alocar gasto a times/serviços via uma estratégia de tags, incluindo custos compartilhados +- Detectar desperdício (recursos ociosos, superdimensionados, órfãos) e anomalias de custo +- Prever gasto e comparar com orçamentos +- Definir salvaguardas e alertas que pegam custo descontrolado cedo sem bloquear trabalho legítimo + +## Requisitos Funcionais + +1. O sistema deve ingerir dados de custo e uso de forma agendada e armazená-los de modo consultável. +2. O gasto deve ser alocável a um time ou serviço, com uma regra definida para custos compartilhados/sem tag. +3. O sistema deve sinalizar desperdício: recursos ociosos, superdimensionados ou órfãos. +4. Anomalias de custo (picos súbitos vs. baseline) devem ser detectadas e alertadas. +5. O sistema deve prever o gasto do período atual e comparar com um orçamento. +6. Uma violação de orçamento ou previsão-de-violação deve disparar um alerta ao dono. +7. Relatórios devem ser atribuíveis — todo custo significativo tem um dono ou um balde compartilhado documentado. + +## Marcos Sugeridos + +1. **Marco 1 — Ingerir e modelar:** Carregue dados de custo/uso e modele-os para consulta. +2. **Marco 2 — Alocação:** Aplique uma estratégia de tags e atribua gasto a donos, tratando custos compartilhados. +3. **Marco 3 — Desperdício e anomalias:** Detecte recursos ociosos/superdimensionados e anomalias de pico. +4. **Marco 4 — Previsão e salvaguardas:** Preveja o período, compare com orçamentos e alerte sobre risco de violação. + +## Esboço de Dados e Interface + +```text + exportação de billing da nuvem (diária) + │ + ▼ + ┌───────────────┐ normaliza + alocação baseada em tags + │ Ingestor de │──────────────┐ + │ custo │ ▼ + └───────────────┘ ┌───────────────┐ + │ Store de custo │ (serviço, time, recurso, $) + └──────┬────────┘ + ┌──────────────┬──────────┼───────────┬──────────────┐ + ▼ ▼ ▼ ▼ ▼ + alocação localizador detector previsão salvaguarda + por time/svc de desperdício de anomalia (período $) de orçamento + └──────────────┴──────────┴───────────┴──────────────┘ + ▼ + ┌───────────┐ alerta dono (name@example.com) + │ dashboard │ em anomalia / violação de orçamento + └───────────┘ + +Registro de alocação: + serviço: checkout time: payments custo: $/dia + compartilhado: load-balancer -> dividido por fatia de requisições (regra documentada) + +Metas não-funcionais: + cobertura de atribuição >= 95% do gasto mapeado a um dono + detecção de anomalia pico sinalizado em até 24h + acurácia de previsão monitorada (delta previsão vs. real) +``` + +## Desafios Extras + +- Adicione um relatório de chargeback/showback por time com tendências e principais causas. +- Recomende oportunidades de rightsizing e compromisso (reserved/savings-plan) com estimativas de payback. +- Adicione métricas de economia unitária (custo por requisição, por tenant) para decisões de escala cientes de custo. +- Suporte multi-cloud para que alocação e anomalias atravessem provedores. + +## Definição de Pronto + +- [ ] Dados de custo/uso são ingeridos de forma agendada e consultáveis. +- [ ] Pelo menos 95% do gasto é atribuído a um dono, com uma regra documentada para custo compartilhado. +- [ ] Desperdício e anomalias de custo são detectados e alertados. +- [ ] O gasto é previsto para o período e comparado com um orçamento. +- [ ] Um risco de violação de orçamento dispara um alerta ao dono. + +## Armadilhas Comuns + +- Perseguir totais brutos de custo sem alocação, de modo que ninguém é dono nem age sobre o número. +- Tagueamento inconsistente que deixa um grande balde "não alocado" que ninguém investiga. +- Alertas de anomalia sem baseline, disparando em padrões normais de fim de mês ou de escala. +- Prever com base em uma janela curta, então a sazonalidade torna toda previsão errada. +- Otimizar custo isoladamente e degradar silenciosamente a confiabilidade que o gasto comprava. + +## Recursos + +- [FinOps Framework](https://www.finops.org/framework/) — a disciplina de gestão financeira de nuvem. +- [AWS Well-Architected: Cost Optimization Pillar](https://docs.aws.amazon.com/wellarchitected/latest/cost-optimization-pillar/welcome.html) — padrões de alocação e rightsizing. +- [Google Cloud: Cost management overview](https://cloud.google.com/cost-management) — conceitos de orçamentos, alertas e relatórios. +- [Kubecost / OpenCost](https://www.opencost.io/) — alocação de custo open-source para Kubernetes. diff --git a/projects/devops/advanced/10-platform-engineering/README.md b/projects/devops/advanced/10-platform-engineering/README.md index e25b3c3..96e25f4 100644 --- a/projects/devops/advanced/10-platform-engineering/README.md +++ b/projects/devops/advanced/10-platform-engineering/README.md @@ -1,34 +1,106 @@ # Platform Engineering Toolkit -## Idea -Build a comprehensive toolkit for platform engineering. Learn about developer platforms and abstractions. +> 🌐 **English** · [Português](./README.pt-BR.md) + +**Domain:** DevOps · **Level:** Advanced · **Estimated time:** 1–2 weeks + +## Overview + +Build an internal developer platform (IDP) that lets a product engineer go from "I need a new service" to a running, observable, policy-compliant deployment without filing a ticket or learning the full depth of your infrastructure. You will design golden-path templates, a self-service interface (portal, CLI, or Git-based), and the automation behind it that provisions infrastructure, wires in observability and secrets, and enforces policy — all while keeping the guardrails invisible until someone hits one. The real challenge is product thinking applied to infrastructure: the right level of abstraction, escape hatches for the 10% of cases the golden path doesn't cover, and adoption driven by making the paved road genuinely faster than doing it by hand. A platform nobody uses is just more infrastructure to maintain. + +## Prerequisites + +- Solid grounding in Kubernetes, IaC, and CI/CD (this project composes them) +- Experience deploying a service end-to-end at least once manually +- Familiarity with templating (Helm/Kustomize) and policy-as-code concepts +- Understanding of the developer workflow you intend to abstract ## Learning Objectives -- Create abstractions -- Provide self-service -- Enable developer autonomy -- Standardize practices -- Manage infrastructure - -## Implementation Tips -- Create developer portal -- Build self-service platform -- Implement standardized templates -- Create policy as code -- Build deployment automation -- Add environment management -- Implement monitoring -- Create logging integration -- Build secret management -- Add compliance automation -- Implement cost tracking -- Create developer documentation -- Build support system -- Create feedback mechanisms - -## Key Challenges -- Abstraction design -- User adoption -- Policy balancing -- Support scalability -- Technology choices + +By the end, you should be able to: + +- Design golden-path templates that encode best practice by default +- Build a self-service interface that provisions a service without manual ops +- Enforce policy-as-code so compliance is automatic, not a review step +- Provide escape hatches for cases the paved road doesn't cover +- Measure platform adoption and developer time-to-first-deploy + +## Functional Requirements + +1. A developer must be able to create a new service from a template via self-service, no ticket. +2. Provisioning must wire in observability, secrets, and CI/CD automatically. +3. Policy-as-code must enforce standards (naming, resource limits, security) at creation and deploy. +4. The golden path must have a documented escape hatch for non-standard needs. +5. The platform must expose the status of a developer's services (deploy, health) in one place. +6. Onboarding a new service must be measurably faster than the manual baseline. +7. The platform's own configuration must be versioned and reproducible. + +## Suggested Milestones + +1. **Milestone 1 — Golden-path template:** Define a template that produces a compliant, observable service. +2. **Milestone 2 — Self-service interface:** Let a developer instantiate the template (portal, CLI, or Git PR) without ops. +3. **Milestone 3 — Policy & guardrails:** Enforce policy-as-code and surface violations with clear feedback. +4. **Milestone 4 — Visibility & adoption:** Add a service catalog/status view and measure time-to-first-deploy vs. baseline. + +## Data & Interface Sketch + +```text + developer + │ "new service: checkout" (portal / CLI / Git PR) + ▼ + ┌──────────────────┐ golden-path template + │ Self-service │ (repo + CI + manifests + observability wired) + │ interface │ + └────────┬─────────┘ + │ orchestrate + ▼ + ┌──────────────────┐ policy-as-code gate (OPA/Kyverno) + │ Platform │───▶ enforce: naming, limits, security + │ orchestrator │ pass -> provision ; fail -> clear feedback + └───┬────────┬──────┘ + ▼ ▼ ▼ ▼ + infra observability secrets CI/CD pipeline + (IaC) wired-in injected created + └────────┴────────────┴─────────────┘ + ▼ + ┌───────────────┐ + │ Service catalog│ status: deploys, health, owner + └───────────────┘ + +Escape hatch: golden path covers ~90%; document how to extend/opt-out for the rest. + +Non-functional targets: + time-to-first-deploy minutes, not days (measure vs. manual baseline) + policy compliance 100% enforced at creation, not post-hoc review + adoption % of new services using the paved road, tracked +``` + +## Stretch Goals + +- Add multiple golden paths (stateless service, cron job, data pipeline) with shared building blocks. +- Integrate the platform with a real developer portal (Backstage) and a service catalog. +- Add cost and security scorecards per service so owners see their posture. +- Support ephemeral preview environments spun up per pull request via the same templates. + +## Definition of Done + +- [ ] A developer creates a compliant, observable service via self-service with no ticket. +- [ ] Observability, secrets, and CI/CD are wired in automatically. +- [ ] Policy-as-code enforces standards at creation and deploy with clear feedback. +- [ ] A documented escape hatch exists for non-standard cases. +- [ ] Time-to-first-deploy is measured and beats the manual baseline; adoption is tracked. + +## Common Pitfalls + +- Over-abstracting so the platform can't express the 10% of real cases, forcing shadow tooling. +- Building the platform with no user research, then wondering why nobody adopts it. +- Making the paved road slower or more confusing than doing it by hand — adoption dies. +- Policy that blocks with cryptic errors, training developers to route around the platform. +- Treating the platform as a one-time project instead of a product with users and a roadmap. + +## Resources + +- [CNCF Platforms White Paper](https://tag-app-delivery.cncf.io/whitepapers/platforms/) — what a platform is and how to reason about it. +- [Backstage documentation](https://backstage.io/docs/overview/what-is-backstage/) — an open developer portal framework. +- [team-topologies.com](https://teamtopologies.com/) — platform teams and cognitive load. +- [Google SRE Workbook: Engagement](https://sre.google/workbook/engagement-model/) — platform-as-product and adoption thinking. diff --git a/projects/devops/advanced/10-platform-engineering/README.pt-BR.md b/projects/devops/advanced/10-platform-engineering/README.pt-BR.md new file mode 100644 index 0000000..52a744a --- /dev/null +++ b/projects/devops/advanced/10-platform-engineering/README.pt-BR.md @@ -0,0 +1,107 @@ +# Kit de Engenharia de Plataforma + +> 🌐 [English](./README.md) · **Português** + +**Domínio:** DevOps · **Nível:** Avançado · **Tempo estimado:** 1–2 semanas + +## Visão Geral + +Construa uma plataforma interna de desenvolvimento (IDP) que permite a um engenheiro de produto ir de "preciso de um novo serviço" a um deploy rodando, observável e conforme às políticas, sem abrir um ticket nem aprender toda a profundidade da sua infraestrutura. Você vai projetar templates de caminho dourado (golden path), uma interface de autoatendimento (portal, CLI ou baseada em Git) e a automação por trás dela que provisiona infraestrutura, conecta observabilidade e secrets e impõe políticas — tudo mantendo as proteções invisíveis até que alguém esbarre em uma. O verdadeiro desafio é pensamento de produto aplicado à infraestrutura: o nível certo de abstração, escotilhas de escape para os 10% de casos que o caminho dourado não cobre e adoção impulsionada por tornar a estrada pavimentada genuinamente mais rápida do que fazer à mão. Uma plataforma que ninguém usa é só mais infraestrutura para manter. + +## Pré-requisitos + +- Base sólida em Kubernetes, IaC e CI/CD (este projeto os compõe) +- Experiência implantando um serviço de ponta a ponta ao menos uma vez manualmente +- Familiaridade com templating (Helm/Kustomize) e conceitos de policy-as-code +- Entender o fluxo de trabalho do desenvolvedor que você pretende abstrair + +## Objetivos de Aprendizado + +Ao final, você deve ser capaz de: + +- Projetar templates de caminho dourado que codificam boas práticas por padrão +- Construir uma interface de autoatendimento que provisiona um serviço sem ops manual +- Impor policy-as-code para que a conformidade seja automática, não uma etapa de revisão +- Fornecer escotilhas de escape para casos que a estrada pavimentada não cobre +- Medir a adoção da plataforma e o tempo-até-o-primeiro-deploy do desenvolvedor + +## Requisitos Funcionais + +1. Um desenvolvedor deve conseguir criar um novo serviço a partir de um template via autoatendimento, sem ticket. +2. O provisionamento deve conectar observabilidade, secrets e CI/CD automaticamente. +3. Policy-as-code deve impor padrões (nomenclatura, limites de recursos, segurança) na criação e no deploy. +4. O caminho dourado deve ter uma escotilha de escape documentada para necessidades fora do padrão. +5. A plataforma deve expor o status dos serviços de um desenvolvedor (deploy, saúde) em um só lugar. +6. Integrar um novo serviço deve ser mensuravelmente mais rápido do que a linha de base manual. +7. A própria configuração da plataforma deve ser versionada e reproduzível. + +## Marcos Sugeridos + +1. **Marco 1 — Template de caminho dourado:** Defina um template que produz um serviço conforme e observável. +2. **Marco 2 — Interface de autoatendimento:** Permita a um desenvolvedor instanciar o template (portal, CLI ou PR no Git) sem ops. +3. **Marco 3 — Política e proteções:** Imponha policy-as-code e exponha violações com feedback claro. +4. **Marco 4 — Visibilidade e adoção:** Adicione um catálogo/visão de status de serviços e meça o tempo-até-o-primeiro-deploy vs. a linha de base. + +## Esboço de Dados e Interface + +```text + desenvolvedor + │ "novo serviço: checkout" (portal / CLI / PR no Git) + ▼ + ┌──────────────────┐ template de caminho dourado + │ Interface de │ (repo + CI + manifests + observabilidade conectada) + │ autoatendimento │ + └────────┬─────────┘ + │ orquestrar + ▼ + ┌──────────────────┐ gate de policy-as-code (OPA/Kyverno) + │ Orquestrador │───▶ impor: nomenclatura, limites, segurança + │ da plataforma │ passa -> provisiona ; falha -> feedback claro + └───┬────────┬──────┘ + ▼ ▼ ▼ ▼ + infra observab. secrets pipeline CI/CD + (IaC) conectada injetados criado + └────────┴────────────┴─────────────┘ + ▼ + ┌───────────────┐ + │ Catálogo de │ status: deploys, saúde, dono + │ serviços │ + └───────────────┘ + +Escotilha de escape: o caminho dourado cobre ~90%; documente como estender/optar por sair no resto. + +Alvos não-funcionais: + tempo-até-primeiro-deploy minutos, não dias (medir vs. linha de base manual) + conformidade de política 100% imposta na criação, não revisão a posteriori + adoção % de novos serviços usando a estrada pavimentada, rastreada +``` + +## Desafios Extras + +- Adicione múltiplos caminhos dourados (serviço sem estado, cron job, pipeline de dados) com blocos de construção compartilhados. +- Integre a plataforma a um portal de desenvolvedor real (Backstage) e a um catálogo de serviços. +- Adicione scorecards de custo e segurança por serviço para que os donos vejam sua postura. +- Suporte ambientes de preview efêmeros criados por pull request via os mesmos templates. + +## Definição de Pronto + +- [ ] Um desenvolvedor cria um serviço conforme e observável via autoatendimento sem ticket. +- [ ] Observabilidade, secrets e CI/CD são conectados automaticamente. +- [ ] Policy-as-code impõe padrões na criação e no deploy com feedback claro. +- [ ] Existe uma escotilha de escape documentada para casos fora do padrão. +- [ ] O tempo-até-o-primeiro-deploy é medido e supera a linha de base manual; a adoção é rastreada. + +## Armadilhas Comuns + +- Abstrair demais, de modo que a plataforma não consegue expressar os 10% de casos reais, forçando ferramentas paralelas. +- Construir a plataforma sem pesquisa com usuários e depois se perguntar por que ninguém adota. +- Tornar a estrada pavimentada mais lenta ou mais confusa do que fazer à mão — a adoção morre. +- Política que bloqueia com erros crípticos, treinando os desenvolvedores a contornar a plataforma. +- Tratar a plataforma como um projeto único em vez de um produto com usuários e um roadmap. + +## Recursos + +- [CNCF Platforms White Paper](https://tag-app-delivery.cncf.io/whitepapers/platforms/) — o que é uma plataforma e como raciocinar sobre ela. +- [Documentação do Backstage](https://backstage.io/docs/overview/what-is-backstage/) — um framework aberto de portal de desenvolvedor. +- [team-topologies.com](https://teamtopologies.com/) — times de plataforma e carga cognitiva. +- [Google SRE Workbook: Engagement](https://sre.google/workbook/engagement-model/) — plataforma-como-produto e pensamento de adoção. diff --git a/projects/devops/beginner/01-dockerize-simple-app/README.md b/projects/devops/beginner/01-dockerize-simple-app/README.md index 168a7ca..332c01d 100644 --- a/projects/devops/beginner/01-dockerize-simple-app/README.md +++ b/projects/devops/beginner/01-dockerize-simple-app/README.md @@ -1,34 +1,97 @@ # Dockerize a Simple App -## Idea -Learn how to containerize an application with Docker. Create a Dockerfile and container image. +> 🌐 **English** · [Português](./README.pt-BR.md) + +**Domain:** DevOps · **Level:** Beginner · **Estimated time:** 3–6 hours + +## Overview + +Take an application you already have — a small web server, an API, or a CLI — and package it so it runs identically on any machine with Docker. The point is not merely "it starts in a container" but a lean, reproducible image: a pinned base, only the files you actually need, a non-root user, and one cleanly exposed port. On the way you will meet the layer cache, the split between a build stage and a runtime stage, and why a `.dockerignore` earns its keep. When you are done, `docker run` hands anyone the exact environment you had — and retires the "works on my machine" excuse. + +## Prerequisites + +- An application that starts from a single command (any language) +- Docker installed locally with the daemon running +- Basic command-line comfort (paths, environment variables, ports) +- A clear idea of your app's runtime version and dependencies ## Learning Objectives -- Understand Docker concepts -- Create Dockerfile -- Build container images -- Run containers -- Understand layering - -## Implementation Tips -- Create Dockerfile for simple app -- Implement multi-stage builds -- Add .dockerignore -- Create container registry account -- Push image to registry -- Test container locally -- Implement health checks -- Add logging configuration -- Create environment variables -- Optimize image size -- Add security scanning -- Implement container metadata -- Create image versioning -- Build CI/CD for images - -## Key Challenges -- Image size optimization -- Security vulnerabilities -- Build time -- Resource management -- Version tagging + +By the end, you should be able to: + +- Write a Dockerfile that builds a runnable image from source +- Use a multi-stage build to keep build tooling out of the final image +- Explain the layer cache and order instructions to exploit it +- Inject configuration into a container via environment variables and ports +- Run the container as a non-root user and explain why that matters + +## Functional Requirements + +1. The image must build from a single `docker build` with no manual steps. +2. The running container must serve or execute the app on a documented port. +3. The build must be multi-stage so build tools are absent from the final image. +4. A `.dockerignore` must exclude source control, dependencies, and secrets from the build context. +5. The container must run as a non-root user. +6. The image must carry an explicit version tag, not only `latest`. +7. Configuration such as port and log level must be injectable via environment variables. + +## Suggested Milestones + +1. **Milestone 1 — First build:** Write a single-stage Dockerfile, build it, and run the app in a container. +2. **Milestone 2 — Slim it down:** Split into build and runtime stages, add `.dockerignore`, and pin the base image. +3. **Milestone 3 — Harden & tag:** Add a non-root user, environment-based config, a version tag, and a documented run command. + +## Data & Interface Sketch + +```text +Project layout + Dockerfile + .dockerignore + + +Dockerfile structure (stages, not the full file) + stage "build": + FROM : + copy dependency manifest -> install deps (cached layer) + copy source -> compile/build artifact + stage "runtime": + FROM : + create + switch to non-root user + copy artifact from "build" + EXPOSE + ENV APP_PORT / LOG_LEVEL + ENTRYPOINT / CMD + +Commands + docker build -t myapp:1.0.0 . + docker run -p 8080:8080 -e LOG_LEVEL=info myapp:1.0.0 +``` + +## Stretch Goals + +- Push the image to a registry (Docker Hub, GHCR) and pull it on another machine. +- Add a `HEALTHCHECK` instruction so Docker reports container health. +- Scan the image with `docker scout` or Trivy and fix a real finding. +- Shrink further with an Alpine or distroless base and compare sizes. + +## Definition of Done + +- [ ] `docker build` produces an image with no errors from a clean checkout. +- [ ] The final image contains no compilers or build-only dependencies. +- [ ] The container runs as a non-root user (verify with `whoami` inside it). +- [ ] Config values change behavior via `-e` without a rebuild. +- [ ] The image carries an explicit semantic version tag. + +## Common Pitfalls + +- Copying the whole context (including `node_modules` or `.git`), inflating build time and image size. +- Placing `COPY . .` before dependency install, busting the cache on every source change. +- Running as root by default, leaving the container over-privileged. +- Baking secrets or environment-specific values into the image instead of injecting them at runtime. + +## Resources + +- [Docker: Dockerfile best practices](https://docs.docker.com/develop/develop-images/dockerfile_best-practices/) — layer caching, multi-stage, and slimming. +- [Docker: Multi-stage builds](https://docs.docker.com/build/building/multi-stage/) — the official pattern for lean images. +- [Docker: .dockerignore reference](https://docs.docker.com/build/concepts/context/#dockerignore-files) — control what enters the build context. +- [Snyk: 10 Docker image security best practices](https://snyk.io/blog/10-docker-image-security-best-practices/) — non-root users and scanning. diff --git a/projects/devops/beginner/01-dockerize-simple-app/README.pt-BR.md b/projects/devops/beginner/01-dockerize-simple-app/README.pt-BR.md new file mode 100644 index 0000000..ecde942 --- /dev/null +++ b/projects/devops/beginner/01-dockerize-simple-app/README.pt-BR.md @@ -0,0 +1,97 @@ +# Dockerizar uma Aplicação Simples + +> 🌐 [English](./README.md) · **Português** + +**Domínio:** DevOps · **Nível:** Iniciante · **Tempo estimado:** 3–6 horas + +## Visão Geral + +Pegue uma aplicação que você já tem — um pequeno servidor web, uma API ou uma CLI — e empacote-a para que rode de forma idêntica em qualquer máquina com Docker. O ponto não é apenas "sobe em um contêiner", mas uma imagem enxuta e reproduzível: uma base fixada, só os arquivos que você realmente precisa, um usuário não-root e uma porta exposta de forma limpa. No caminho você conhece o cache de camadas, a separação entre o estágio de build e o de runtime, e por que um `.dockerignore` vale o seu lugar. Ao terminar, `docker run` entrega a qualquer pessoa exatamente o ambiente que você tinha — e aposenta a desculpa do "na minha máquina funciona". + +## Pré-requisitos + +- Uma aplicação que inicia com um único comando (qualquer linguagem) +- Docker instalado localmente com o daemon em execução +- Conforto básico com a linha de comando (caminhos, variáveis de ambiente, portas) +- Uma ideia clara da versão do runtime e das dependências da sua app + +## Objetivos de Aprendizado + +Ao final, você deve ser capaz de: + +- Escrever um Dockerfile que constrói uma imagem executável a partir do código-fonte +- Usar um build multi-estágio para manter o ferramental de build fora da imagem final +- Explicar o cache de camadas e ordenar instruções para aproveitá-lo +- Injetar configuração em um contêiner via variáveis de ambiente e portas +- Rodar o contêiner como usuário não-root e explicar por que isso importa + +## Requisitos Funcionais + +1. A imagem deve construir a partir de um único `docker build`, sem passos manuais. +2. O contêiner em execução deve servir ou executar a app em uma porta documentada. +3. O build deve ser multi-estágio para que ferramentas de build fiquem ausentes da imagem final. +4. Um `.dockerignore` deve excluir controle de versão, dependências e segredos do contexto de build. +5. O contêiner deve rodar como usuário não-root. +6. A imagem deve carregar uma tag de versão explícita, não apenas `latest`. +7. Configurações como porta e nível de log devem ser injetáveis via variáveis de ambiente. + +## Marcos Sugeridos + +1. **Marco 1 — Primeiro build:** Escreva um Dockerfile de estágio único, construa-o e rode a app em um contêiner. +2. **Marco 2 — Enxugue:** Divida em estágios de build e runtime, adicione `.dockerignore` e fixe a imagem base. +3. **Marco 3 — Endureça e versione:** Adicione um usuário não-root, config por ambiente, uma tag de versão e um comando de execução documentado. + +## Esboço de Dados e Interface + +```text +Layout do projeto + Dockerfile + .dockerignore + + +Estrutura do Dockerfile (estágios, não o arquivo completo) + estágio "build": + FROM : + copia manifesto de dependências -> instala deps (camada em cache) + copia fonte -> compila/gera artefato + estágio "runtime": + FROM : + cria + muda para usuário não-root + copia artefato de "build" + EXPOSE + ENV APP_PORT / LOG_LEVEL + ENTRYPOINT / CMD + +Comandos + docker build -t myapp:1.0.0 . + docker run -p 8080:8080 -e LOG_LEVEL=info myapp:1.0.0 +``` + +## Desafios Extras + +- Envie a imagem para um registro (Docker Hub, GHCR) e baixe-a em outra máquina. +- Adicione uma instrução `HEALTHCHECK` para que o Docker reporte a saúde do contêiner. +- Escaneie a imagem com `docker scout` ou Trivy e corrija um achado real. +- Reduza ainda mais com uma base Alpine ou distroless e compare os tamanhos. + +## Definição de Pronto + +- [ ] `docker build` produz uma imagem sem erros a partir de um checkout limpo. +- [ ] A imagem final não contém compiladores nem dependências exclusivas de build. +- [ ] O contêiner roda como usuário não-root (verifique com `whoami` dentro dele). +- [ ] Valores de config mudam o comportamento via `-e` sem reconstruir. +- [ ] A imagem carrega uma tag de versão semântica explícita. + +## Armadilhas Comuns + +- Copiar todo o contexto (incluindo `node_modules` ou `.git`), inflando o tempo de build e o tamanho da imagem. +- Colocar `COPY . .` antes da instalação de dependências, invalidando o cache a cada mudança de fonte. +- Rodar como root por padrão, deixando o contêiner com privilégios em excesso. +- Fixar segredos ou valores específicos de ambiente na imagem em vez de injetá-los em tempo de execução. + +## Recursos + +- [Docker: Boas práticas de Dockerfile](https://docs.docker.com/develop/develop-images/dockerfile_best-practices/) — cache de camadas, multi-estágio e enxugamento. +- [Docker: Builds multi-estágio](https://docs.docker.com/build/building/multi-stage/) — o padrão oficial para imagens enxutas. +- [Docker: Referência do .dockerignore](https://docs.docker.com/build/concepts/context/#dockerignore-files) — controle o que entra no contexto de build. +- [Snyk: 10 boas práticas de segurança para imagens Docker](https://snyk.io/blog/10-docker-image-security-best-practices/) — usuários não-root e escaneamento. diff --git a/projects/devops/beginner/02-basic-ci/README.md b/projects/devops/beginner/02-basic-ci/README.md index 8378fe1..bb30de2 100644 --- a/projects/devops/beginner/02-basic-ci/README.md +++ b/projects/devops/beginner/02-basic-ci/README.md @@ -1,34 +1,94 @@ # Basic CI Pipeline -## Idea -Create a basic continuous integration pipeline to build and test code. Learn about CI concepts and automation. +> 🌐 **English** · [Português](./README.pt-BR.md) + +**Domain:** DevOps · **Level:** Beginner · **Estimated time:** 3–6 hours + +## Overview + +Wire up a continuous integration pipeline that runs on its own every time you push. It checks out the repository, installs dependencies, runs the linter, executes the tests, and reports pass or fail — turning "did I break something?" from a manual chore into an automatic gate. This is the first line of defense in any modern project: a red check on a pull request stops a bug before anyone else sees it. You will pick a CI platform, express the workflow as declarative stages, and learn why a fast, cache-aware pipeline is the difference between a check people trust and one they route around. + +## Prerequisites + +- A repository with tests you can run locally ([Dockerize a Simple App](../01-dockerize-simple-app/) pairs well) +- A Git host with CI (GitHub Actions, GitLab CI, or similar) +- The exact local commands to install deps, lint, and test +- Basic YAML familiarity ## Learning Objectives -- Set up CI system -- Create build pipeline -- Implement testing -- Create artifacts -- Send notifications - -## Implementation Tips -- Choose CI platform (GitHub Actions, GitLab CI, Jenkins) -- Create pipeline configuration -- Implement build step -- Add unit test execution -- Add linting/formatting checks -- Create artifact storage -- Add notifications -- Implement failure handling -- Create build status badges -- Add performance tracking -- Implement caching -- Create secrets management -- Add access control -- Build reporting - -## Key Challenges -- Build time optimization -- Test flakiness -- Dependency management -- Cache invalidation -- Secret security + +By the end, you should be able to: + +- Express a build/test workflow as declarative pipeline stages +- Trigger a pipeline automatically on push and pull request +- Cache dependencies to keep runs fast +- Fail the pipeline correctly when a lint or test step fails +- Surface pipeline status back onto the pull request + +## Functional Requirements + +1. The pipeline must run automatically on every push and pull request to the main branch. +2. It must check out code, install dependencies, lint, and test as distinct steps. +3. A failing lint or test step must fail the whole pipeline with a non-zero exit. +4. Dependency installation must use caching so unchanged dependencies are not re-downloaded each run. +5. The pass/fail result must be visible on the pull request. +6. The pipeline configuration must live in the repository as version-controlled code. +7. The pipeline must run on a clean environment, assuming nothing from the developer's machine. + +## Suggested Milestones + +1. **Milestone 1 — Hello pipeline:** Add a config that checks out code and prints toolchain versions on push. +2. **Milestone 2 — Build & test:** Add install, lint, and test steps; make a broken test turn the run red. +3. **Milestone 3 — Speed & signal:** Add dependency caching and a status badge; confirm status appears on PRs. + +## Data & Interface Sketch + +```text +Repo layout + .github/workflows/ci.yml (or .gitlab-ci.yml) + + +Pipeline stages (structure, not full YAML) + trigger: on push + pull_request to main + job "build-and-test": + step: checkout + step: setup runtime (pinned version) + step: restore dependency cache (key = hash of lockfile) + step: install dependencies + step: lint -> non-zero exit fails job + step: test -> non-zero exit fails job + step: save dependency cache + +Status surface + PR check: ci / build-and-test -> passing | failing + README badge: ![CI](https://github.com/OWNER/REPO/actions/workflows/ci.yml/badge.svg) +``` + +## Stretch Goals + +- Run the test job across a matrix of runtime versions or operating systems. +- Split lint and test into parallel jobs and observe the wall-clock speedup. +- Upload test reports or coverage as build artifacts. +- Require the CI check to pass before a pull request can merge (branch protection). + +## Definition of Done + +- [ ] Pushing a commit triggers the pipeline with no manual action. +- [ ] A deliberately broken test turns the run red and blocks the PR. +- [ ] A second run with unchanged dependencies is noticeably faster thanks to the cache. +- [ ] The pipeline config is committed to the repository. +- [ ] A status badge or PR check reflects the latest run. + +## Common Pitfalls + +- Relying on tools already on your laptop that the clean CI runner does not have. +- Swallowing a step's exit code (piping through a command that always returns 0), so failures look green. +- Caching on a key that never changes (stale deps) or one that always changes (never hits). +- Storing secrets in the workflow file instead of the platform's encrypted secrets store. + +## Resources + +- [GitHub Actions: About workflows](https://docs.github.com/en/actions/using-workflows/about-workflows) — triggers, jobs, and steps. +- [GitLab CI/CD documentation](https://docs.gitlab.com/ee/ci/) — pipeline stages and configuration. +- [GitHub Actions: Caching dependencies](https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows) — cache keys done right. +- [Martin Fowler: Continuous Integration](https://martinfowler.com/articles/continuousIntegration.html) — the practice behind the tooling. diff --git a/projects/devops/beginner/02-basic-ci/README.pt-BR.md b/projects/devops/beginner/02-basic-ci/README.pt-BR.md new file mode 100644 index 0000000..8142335 --- /dev/null +++ b/projects/devops/beginner/02-basic-ci/README.pt-BR.md @@ -0,0 +1,94 @@ +# Pipeline de CI Básico + +> 🌐 [English](./README.md) · **Português** + +**Domínio:** DevOps · **Nível:** Iniciante · **Tempo estimado:** 3–6 horas + +## Visão Geral + +Monte um pipeline de integração contínua que roda sozinho toda vez que você faz push. Ele faz checkout do repositório, instala dependências, roda o linter, executa os testes e reporta sucesso ou falha — transformando "será que quebrei algo?" de uma tarefa manual em um portão automático. Esta é a primeira linha de defesa de qualquer projeto moderno: um check vermelho em um pull request barra um bug antes que outra pessoa o veja. Você vai escolher uma plataforma de CI, expressar o fluxo como estágios declarativos e entender por que um pipeline rápido e ciente de cache é a diferença entre um check em que as pessoas confiam e um que elas contornam. + +## Pré-requisitos + +- Um repositório com testes que você consegue rodar localmente ([Dockerizar uma Aplicação Simples](../01-dockerize-simple-app/) combina bem) +- Um host Git com CI (GitHub Actions, GitLab CI ou similar) +- Os comandos locais exatos para instalar deps, lintar e testar +- Familiaridade básica com YAML + +## Objetivos de Aprendizado + +Ao final, você deve ser capaz de: + +- Expressar um fluxo de build/teste como estágios declarativos de pipeline +- Disparar um pipeline automaticamente em push e pull request +- Cachear dependências para manter as execuções rápidas +- Falhar o pipeline corretamente quando um passo de lint ou teste falha +- Trazer o status do pipeline de volta ao pull request + +## Requisitos Funcionais + +1. O pipeline deve rodar automaticamente em todo push e pull request para a branch principal. +2. Ele deve fazer checkout do código, instalar dependências, lintar e testar como passos distintos. +3. Um passo de lint ou teste que falha deve falhar o pipeline inteiro com saída diferente de zero. +4. A instalação de dependências deve usar cache para que dependências inalteradas não sejam rebaixadas a cada execução. +5. O resultado de sucesso/falha deve ser visível no pull request. +6. A configuração do pipeline deve viver no repositório como código versionado. +7. O pipeline deve rodar em um ambiente limpo, sem assumir nada da máquina do desenvolvedor. + +## Marcos Sugeridos + +1. **Marco 1 — Olá pipeline:** Adicione uma config que faz checkout do código e imprime as versões do toolchain em push. +2. **Marco 2 — Build e teste:** Adicione passos de instalação, lint e teste; faça um teste quebrado deixar a execução vermelha. +3. **Marco 3 — Velocidade e sinal:** Adicione cache de dependências e um badge de status; confirme que o status aparece nos PRs. + +## Esboço de Dados e Interface + +```text +Layout do repo + .github/workflows/ci.yml (ou .gitlab-ci.yml) + + +Estágios do pipeline (estrutura, não o YAML completo) + trigger: on push + pull_request para main + job "build-and-test": + step: checkout + step: configura runtime (versão fixada) + step: restaura cache de dependências (chave = hash do lockfile) + step: instala dependências + step: lint -> saída != 0 falha o job + step: test -> saída != 0 falha o job + step: salva cache de dependências + +Superfície de status + Check no PR: ci / build-and-test -> passando | falhando + Badge no README: ![CI](https://github.com/OWNER/REPO/actions/workflows/ci.yml/badge.svg) +``` + +## Desafios Extras + +- Rode o job de teste sobre uma matriz de versões de runtime ou sistemas operacionais. +- Divida lint e teste em jobs paralelos e observe o ganho de tempo real. +- Faça upload de relatórios de teste ou cobertura como artefatos de build. +- Exija que o check de CI passe antes que um pull request possa ser mesclado (proteção de branch). + +## Definição de Pronto + +- [ ] Fazer push de um commit dispara o pipeline sem nenhuma ação manual. +- [ ] Um teste deliberadamente quebrado deixa a execução vermelha e bloqueia o PR. +- [ ] Uma segunda execução com dependências inalteradas é visivelmente mais rápida graças ao cache. +- [ ] A config do pipeline está commitada no repositório. +- [ ] Um badge de status ou check de PR reflete a execução mais recente. + +## Armadilhas Comuns + +- Depender de ferramentas já instaladas no seu laptop que o runner limpo de CI não tem. +- Engolir o código de saída de um passo (encanar por um comando que sempre retorna 0), fazendo falhas parecerem verdes. +- Cachear por uma chave que nunca muda (deps obsoletas) ou uma que sempre muda (nunca acerta). +- Guardar segredos no arquivo do workflow em vez do cofre de segredos criptografado da plataforma. + +## Recursos + +- [GitHub Actions: Sobre workflows](https://docs.github.com/en/actions/using-workflows/about-workflows) — triggers, jobs e steps. +- [Documentação do GitLab CI/CD](https://docs.gitlab.com/ee/ci/) — estágios e configuração de pipeline. +- [GitHub Actions: Cache de dependências](https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows) — chaves de cache bem feitas. +- [Martin Fowler: Continuous Integration](https://martinfowler.com/articles/continuousIntegration.html) — a prática por trás da ferramenta. diff --git a/projects/devops/beginner/03-environment-config/README.md b/projects/devops/beginner/03-environment-config/README.md index 79dae36..856ea00 100644 --- a/projects/devops/beginner/03-environment-config/README.md +++ b/projects/devops/beginner/03-environment-config/README.md @@ -1,34 +1,98 @@ # Environment Config Manager -## Idea -Create a tool for managing environment-specific configurations. Learn about configuration management. +> 🌐 **English** · [Português](./README.pt-BR.md) + +**Domain:** DevOps · **Level:** Beginner · **Estimated time:** 3–6 hours + +## Overview + +Build a small tool that loads the right configuration for the right environment — `dev`, `staging`, `prod` — and hands the application one validated set of values. The core idea is layering: a shared base config, overridden by environment-specific files, overridden by environment variables at the top. Along the way you separate secrets from plain settings, verify that required keys exist before the app starts, and fail loudly on a bad config instead of crashing mysteriously three requests later. This is the humble tool that makes "twelve-factor" config real: one codebase, many deploys, no `if (env === 'prod')` scattered through the source. + +## Prerequisites + +- A language with a config or file-parsing library (any stack) +- Understanding of environment variables and how processes read them +- A file format to work in: JSON, YAML, or TOML +- Awareness that secrets must never be committed to source control ## Learning Objectives -- Manage configurations -- Handle secrets -- Support multiple environments -- Validate configurations -- Update safely - -## Implementation Tips -- Support configuration files (JSON, YAML, TOML) -- Implement environment switching -- Add secret management -- Create validation schemas -- Implement configuration overrides -- Add defaults system -- Create audit logging -- Implement hot reloading -- Add configuration versioning -- Create documentation -- Add monitoring for config changes -- Implement rollback -- Create diff viewing -- Build CLI tool - -## Key Challenges -- Secret security -- Configuration validation -- Environment parity -- Change management -- Performance impact + +By the end, you should be able to: + +- Layer configuration sources with a clear precedence order +- Separate non-secret settings from secrets and load each appropriately +- Validate configuration against a schema before the app uses it +- Provide sensible defaults while allowing per-environment overrides +- Fail fast with a clear message when required config is missing + +## Functional Requirements + +1. The tool must load a base config and merge environment-specific overrides on top of it. +2. Environment variables must take precedence over file values for the same key. +3. Required keys must be validated on load; a missing required key must abort startup with a clear error. +4. It must support at least three environments selected by a single variable (e.g. `APP_ENV`). +5. Secrets must be sourced separately (from the environment or a git-ignored secrets file). +6. The resolved config must be exposed to the app as one structured object. +7. It must never print secret values in logs or error messages. + +## Suggested Milestones + +1. **Milestone 1 — Load & merge:** Read a base file and an environment file, merging them with defined precedence. +2. **Milestone 2 — Env overrides & secrets:** Let environment variables override file values and load secrets separately. +3. **Milestone 3 — Validate & fail fast:** Add a required-keys schema and abort with a helpful message on a bad config. + +## Data & Interface Sketch + +```text +Precedence (lowest -> highest) + defaults < config.base.yml < config..yml < environment variables + +File layout + config/ + base.yml + development.yml + production.yml + .env (git-ignored, secrets) + .gitignore (excludes .env) + +Config schema (key names + types, not real values) + app: + port: integer (required) + log_level: enum[debug|info|warn|error] (default info) + database: + host: string (required) + password: secret (required, from env only) + feature_flags: map + +Resolution + APP_ENV=production -> merge base + production + env vars -> validate -> Config object +``` + +## Stretch Goals + +- Add a `config validate` command that checks a config without starting the app. +- Print a redacted dump of the resolved config (secrets shown as `***`). +- Support hot-reload: detect a changed file and re-validate without a restart. +- Generate a `.env.example` listing every required key with placeholder values. + +## Definition of Done + +- [ ] Switching `APP_ENV` loads a different, correctly-merged configuration. +- [ ] An environment variable overrides the same key set in a file. +- [ ] Removing a required key aborts startup with a message naming the missing key. +- [ ] Secrets are not committed and never appear in logs or the redacted dump. +- [ ] The application receives one structured config object, not scattered lookups. + +## Common Pitfalls + +- Committing a `.env` or secrets file — add it to `.gitignore` before the first commit. +- Getting precedence backwards, so a base default silently overrides an environment variable. +- Reading config ad hoc throughout the code instead of resolving once at startup. +- Logging the whole config object on boot and leaking a password into the logs. + +## Resources + +- [The Twelve-Factor App: Config](https://12factor.net/config) — why config belongs in the environment. +- [OWASP: Secrets Management Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Secrets_Management_Cheat_Sheet.html) — handling secrets safely. +- [TOML specification](https://toml.io/en/) — a config format designed to be unambiguous. +- [YAML specification](https://yaml.org/spec/) — the format and its footguns. diff --git a/projects/devops/beginner/03-environment-config/README.pt-BR.md b/projects/devops/beginner/03-environment-config/README.pt-BR.md new file mode 100644 index 0000000..420ae1c --- /dev/null +++ b/projects/devops/beginner/03-environment-config/README.pt-BR.md @@ -0,0 +1,98 @@ +# Gerenciador de Configuração por Ambiente + +> 🌐 [English](./README.md) · **Português** + +**Domínio:** DevOps · **Nível:** Iniciante · **Tempo estimado:** 3–6 horas + +## Visão Geral + +Construa uma pequena ferramenta que carrega a configuração certa para o ambiente certo — `dev`, `staging`, `prod` — e entrega à aplicação um único conjunto de valores validados. A ideia central é a sobreposição em camadas: uma config base compartilhada, sobrescrita por arquivos específicos de ambiente, sobrescrita por variáveis de ambiente no topo. No caminho você separa segredos de configurações comuns, verifica que as chaves obrigatórias existem antes de a app iniciar e falha em alto e bom som diante de uma config ruim em vez de quebrar misteriosamente três requisições depois. Esta é a ferramenta humilde que torna a config "twelve-factor" real: uma base de código, muitos deploys, sem `if (env === 'prod')` espalhado pelo código. + +## Pré-requisitos + +- Uma linguagem com biblioteca de config ou de parsing de arquivos (qualquer stack) +- Entender variáveis de ambiente e como processos as leem +- Um formato de arquivo para trabalhar: JSON, YAML ou TOML +- Ciência de que segredos nunca devem ser commitados no controle de versão + +## Objetivos de Aprendizado + +Ao final, você deve ser capaz de: + +- Sobrepor fontes de configuração com uma ordem de precedência clara +- Separar configurações não-secretas de segredos e carregar cada uma adequadamente +- Validar a configuração contra um schema antes de a app usá-la +- Fornecer padrões sensatos permitindo sobrescritas por ambiente +- Falhar cedo com uma mensagem clara quando uma config obrigatória está ausente + +## Requisitos Funcionais + +1. A ferramenta deve carregar uma config base e mesclar sobrescritas específicas de ambiente sobre ela. +2. Variáveis de ambiente devem ter precedência sobre valores de arquivo para a mesma chave. +3. Chaves obrigatórias devem ser validadas no carregamento; uma chave obrigatória ausente deve abortar a inicialização com um erro claro. +4. Ela deve suportar ao menos três ambientes selecionados por uma única variável (ex.: `APP_ENV`). +5. Segredos devem vir de uma fonte separada (do ambiente ou de um arquivo de segredos ignorado pelo git). +6. A config resolvida deve ser exposta à app como um único objeto estruturado. +7. Ela nunca deve imprimir valores de segredos em logs ou mensagens de erro. + +## Marcos Sugeridos + +1. **Marco 1 — Carregar e mesclar:** Leia um arquivo base e um de ambiente, mesclando-os com precedência definida. +2. **Marco 2 — Sobrescritas por env e segredos:** Deixe variáveis de ambiente sobrescreverem valores de arquivo e carregue segredos separadamente. +3. **Marco 3 — Validar e falhar cedo:** Adicione um schema de chaves obrigatórias e aborte com uma mensagem útil diante de uma config ruim. + +## Esboço de Dados e Interface + +```text +Precedência (menor -> maior) + padrões < config.base.yml < config..yml < variáveis de ambiente + +Layout de arquivos + config/ + base.yml + development.yml + production.yml + .env (ignorado pelo git, segredos) + .gitignore (exclui .env) + +Schema de config (nomes de chave + tipos, não valores reais) + app: + port: inteiro (obrigatório) + log_level: enum[debug|info|warn|error] (padrão info) + database: + host: string (obrigatório) + password: segredo (obrigatório, só do env) + feature_flags: map + +Resolução + APP_ENV=production -> mescla base + production + env vars -> valida -> objeto Config +``` + +## Desafios Extras + +- Adicione um comando `config validate` que checa uma config sem iniciar a app. +- Imprima um dump censurado da config resolvida (segredos mostrados como `***`). +- Suporte hot-reload: detecte um arquivo alterado e revalide sem reiniciar. +- Gere um `.env.example` listando toda chave obrigatória com valores de placeholder. + +## Definição de Pronto + +- [ ] Trocar `APP_ENV` carrega uma configuração diferente e corretamente mesclada. +- [ ] Uma variável de ambiente sobrescreve a mesma chave definida em um arquivo. +- [ ] Remover uma chave obrigatória aborta a inicialização com uma mensagem nomeando a chave ausente. +- [ ] Segredos não são commitados e nunca aparecem em logs ou no dump censurado. +- [ ] A aplicação recebe um objeto de config estruturado, não buscas espalhadas. + +## Armadilhas Comuns + +- Commitar um arquivo `.env` ou de segredos — adicione-o ao `.gitignore` antes do primeiro commit. +- Inverter a precedência, de forma que um padrão base silenciosamente sobrescreva uma variável de ambiente. +- Ler config ad hoc por todo o código em vez de resolver uma vez na inicialização. +- Logar o objeto de config inteiro no boot e vazar uma senha para os logs. + +## Recursos + +- [The Twelve-Factor App: Config](https://12factor.net/config) — por que a config pertence ao ambiente. +- [OWASP: Secrets Management Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Secrets_Management_Cheat_Sheet.html) — lidando com segredos com segurança. +- [Especificação do TOML](https://toml.io/en/) — um formato de config projetado para ser inequívoco. +- [Especificação do YAML](https://yaml.org/spec/) — o formato e suas armadilhas. diff --git a/projects/devops/beginner/04-deployment-script/README.md b/projects/devops/beginner/04-deployment-script/README.md index e24a352..cda2f67 100644 --- a/projects/devops/beginner/04-deployment-script/README.md +++ b/projects/devops/beginner/04-deployment-script/README.md @@ -1,34 +1,93 @@ # Simple Deployment Script -## Idea -Create a script for deploying application to servers. Learn about deployment automation basics. +> 🌐 **English** · [Português](./README.pt-BR.md) + +**Domain:** DevOps · **Level:** Beginner · **Estimated time:** 3–6 hours + +## Overview + +Write a script that takes a new version of your app and puts it on a server — reliably, repeatably, and without a checklist you have to remember at midnight. The script connects to the host, places the new code, restarts the service, and checks that it actually came back up. The interesting part is not the happy path but the guarantees around it: take a backup before you touch anything, verify health afterward, and roll back to the previous version if the new one refuses to start. When you finish, deploying should be one command that either succeeds cleanly or leaves the server exactly as it was. + +## Prerequisites + +- An app that runs on a remote (or virtual) Linux host you can SSH into +- SSH key-based access to that host +- A service manager to (re)start the app (systemd, Docker, or a process manager) +- Basic shell scripting (variables, conditionals, exit codes) ## Learning Objectives -- Automate deployment -- Handle server connections -- Deploy code -- Restart services -- Verify deployment - -## Implementation Tips -- Create SSH connectivity -- Implement code download -- Add backup before deploy -- Create service restart logic -- Add health checks -- Implement rollback -- Create logging -- Add error handling -- Implement notifications -- Create deployment checklist -- Add pre-deployment validation -- Implement parallel deployment -- Create deployment history -- Add monitoring integration - -## Key Challenges -- Downtime minimization -- Rollback reliability -- Service start verification -- Network connectivity -- Error recovery + +By the end, you should be able to: + +- Automate a remote deploy over SSH from a single command +- Snapshot the current release so you can restore it +- Restart a service and confirm it is healthy before declaring success +- Roll back automatically when a deploy fails its health check +- Make the script idempotent and safe to re-run + +## Functional Requirements + +1. The script must connect to a target host and transfer the new release non-interactively. +2. It must back up the current release before replacing it. +3. It must restart the service after placing the new code. +4. It must run a health check and treat a failed check as a failed deploy. +5. On a failed health check, it must roll back to the backed-up release and restart. +6. It must exit non-zero on any failure so a caller (or CI) can detect it. +7. It must log each step with a timestamp for later diagnosis. + +## Suggested Milestones + +1. **Milestone 1 — Push & restart:** Copy the release to the host and restart the service over SSH. +2. **Milestone 2 — Backup & verify:** Snapshot the current release first, then health-check after restart. +3. **Milestone 3 — Rollback & logging:** Restore the previous release on failure and log every step with exit codes. + +## Data & Interface Sketch + +```text +Usage + deploy.sh + +Config (env vars, not hardcoded) + DEPLOY_HOST user@host + DEPLOY_PATH /srv/app + HEALTH_URL http://localhost:8080/health + SERVICE_NAME app.service + +Steps (structure, not full script) + 1. resolve config + validate inputs + 2. ssh: snapshot current release -> releases/ + 3. transfer new release -> DEPLOY_PATH + 4. ssh: restart SERVICE_NAME + 5. poll HEALTH_URL (retry N times, backoff) + ok -> log success, exit 0 + fail -> restore snapshot, restart, log failure, exit 1 +``` + +## Stretch Goals + +- Keep the last N releases and support a `rollback` subcommand to any of them. +- Use a symlink-swap strategy (`current -> releases/`) for near-zero-downtime cutover. +- Send a notification (e.g. to a chat webhook) on success and failure. +- Add a `--dry-run` flag that prints each action without executing it. + +## Definition of Done + +- [ ] A full deploy runs from one command with no interactive prompts. +- [ ] A backup of the previous release exists on the host after deploy. +- [ ] A deliberately broken release triggers an automatic rollback. +- [ ] The service is confirmed healthy before the script reports success. +- [ ] The script exits non-zero on failure and logs every step. + +## Common Pitfalls + +- Assuming the restart succeeded without checking — a service can "start" and immediately crash. +- Overwriting the running release before backing it up, leaving nothing to roll back to. +- Hardcoding host, path, or credentials into the script instead of reading them from config. +- Health-checking once with no retries, so a slow-starting app is misread as broken. + +## Resources + +- [DigitalOcean: How to use SSH keys](https://www.digitalocean.com/community/tutorials/how-to-configure-ssh-key-based-authentication-on-a-linux-server) — non-interactive remote access. +- [Google SRE Book: Release Engineering](https://sre.google/sre-book/release-engineering/) — the principles behind safe, repeatable deploys. +- [rsync manual](https://download.samba.org/pub/rsync/rsync.1) — efficient, resumable file transfer for releases. +- [systemd: Managing services](https://www.freedesktop.org/software/systemd/man/systemctl.html) — starting, restarting, and checking service state. diff --git a/projects/devops/beginner/04-deployment-script/README.pt-BR.md b/projects/devops/beginner/04-deployment-script/README.pt-BR.md new file mode 100644 index 0000000..cb94fda --- /dev/null +++ b/projects/devops/beginner/04-deployment-script/README.pt-BR.md @@ -0,0 +1,93 @@ +# Script de Deploy Simples + +> 🌐 [English](./README.md) · **Português** + +**Domínio:** DevOps · **Nível:** Iniciante · **Tempo estimado:** 3–6 horas + +## Visão Geral + +Escreva um script que pega uma nova versão da sua app e a coloca em um servidor — de forma confiável, repetível e sem um checklist que você precisa lembrar à meia-noite. O script conecta ao host, posiciona o novo código, reinicia o serviço e verifica que ele realmente voltou. A parte interessante não é o caminho feliz, mas as garantias ao redor dele: faça um backup antes de tocar em qualquer coisa, verifique a saúde depois e faça rollback para a versão anterior se a nova se recusar a subir. Ao terminar, fazer deploy deve ser um comando que ou tem sucesso limpo ou deixa o servidor exatamente como estava. + +## Pré-requisitos + +- Uma app que roda em um host Linux remoto (ou virtual) que você acessa via SSH +- Acesso por chave SSH a esse host +- Um gerenciador de serviços para (re)iniciar a app (systemd, Docker ou um gerenciador de processos) +- Scripting shell básico (variáveis, condicionais, códigos de saída) + +## Objetivos de Aprendizado + +Ao final, você deve ser capaz de: + +- Automatizar um deploy remoto via SSH a partir de um único comando +- Tirar um snapshot da release atual para poder restaurá-la +- Reiniciar um serviço e confirmar que está saudável antes de declarar sucesso +- Fazer rollback automático quando um deploy falha sua verificação de saúde +- Tornar o script idempotente e seguro para reexecutar + +## Requisitos Funcionais + +1. O script deve conectar a um host de destino e transferir a nova release de forma não-interativa. +2. Ele deve fazer backup da release atual antes de substituí-la. +3. Ele deve reiniciar o serviço após posicionar o novo código. +4. Ele deve rodar uma verificação de saúde e tratar uma verificação falha como deploy falho. +5. Em uma verificação de saúde falha, ele deve fazer rollback para a release em backup e reiniciar. +6. Ele deve sair com código diferente de zero em qualquer falha, para que um chamador (ou CI) possa detectá-la. +7. Ele deve logar cada passo com um timestamp para diagnóstico posterior. + +## Marcos Sugeridos + +1. **Marco 1 — Enviar e reiniciar:** Copie a release para o host e reinicie o serviço via SSH. +2. **Marco 2 — Backup e verificação:** Tire um snapshot da release atual primeiro, depois verifique a saúde após o restart. +3. **Marco 3 — Rollback e logging:** Restaure a release anterior em caso de falha e logue cada passo com códigos de saída. + +## Esboço de Dados e Interface + +```text +Uso + deploy.sh + +Config (variáveis de ambiente, não hardcoded) + DEPLOY_HOST user@host + DEPLOY_PATH /srv/app + HEALTH_URL http://localhost:8080/health + SERVICE_NAME app.service + +Passos (estrutura, não o script completo) + 1. resolve config + valida entradas + 2. ssh: snapshot da release atual -> releases/ + 3. transfere nova release -> DEPLOY_PATH + 4. ssh: reinicia SERVICE_NAME + 5. faz polling em HEALTH_URL (N tentativas, backoff) + ok -> loga sucesso, sai 0 + falha -> restaura snapshot, reinicia, loga falha, sai 1 +``` + +## Desafios Extras + +- Mantenha as últimas N releases e suporte um subcomando `rollback` para qualquer uma delas. +- Use uma estratégia de troca de symlink (`current -> releases/`) para uma virada com downtime quase zero. +- Envie uma notificação (ex.: para um webhook de chat) em sucesso e falha. +- Adicione uma flag `--dry-run` que imprime cada ação sem executá-la. + +## Definição de Pronto + +- [ ] Um deploy completo roda a partir de um comando sem prompts interativos. +- [ ] Um backup da release anterior existe no host após o deploy. +- [ ] Uma release deliberadamente quebrada dispara um rollback automático. +- [ ] O serviço é confirmado saudável antes de o script reportar sucesso. +- [ ] O script sai com código diferente de zero em falha e loga cada passo. + +## Armadilhas Comuns + +- Assumir que o restart teve sucesso sem verificar — um serviço pode "iniciar" e travar em seguida. +- Sobrescrever a release em execução antes de fazer backup, deixando nada para o rollback. +- Fixar host, caminho ou credenciais no script em vez de lê-los da config. +- Verificar a saúde uma vez sem retries, fazendo uma app de início lento ser lida como quebrada. + +## Recursos + +- [DigitalOcean: Como usar chaves SSH](https://www.digitalocean.com/community/tutorials/how-to-configure-ssh-key-based-authentication-on-a-linux-server) — acesso remoto não-interativo. +- [Google SRE Book: Release Engineering](https://sre.google/sre-book/release-engineering/) — os princípios por trás de deploys seguros e repetíveis. +- [Manual do rsync](https://download.samba.org/pub/rsync/rsync.1) — transferência de arquivos eficiente e retomável para releases. +- [systemd: Gerenciando serviços](https://www.freedesktop.org/software/systemd/man/systemctl.html) — iniciar, reiniciar e checar o estado do serviço. diff --git a/projects/devops/beginner/05-log-monitoring/README.md b/projects/devops/beginner/05-log-monitoring/README.md index bcec17d..0009437 100644 --- a/projects/devops/beginner/05-log-monitoring/README.md +++ b/projects/devops/beginner/05-log-monitoring/README.md @@ -1,34 +1,94 @@ # Log Monitoring Script -## Idea -Create a script to monitor application logs and detect issues. Learn about log analysis and alerting. +> 🌐 **English** · [Português](./README.pt-BR.md) + +**Domain:** DevOps · **Level:** Beginner · **Estimated time:** 3–6 hours + +## Overview + +Build a script that watches an application's log files, spots trouble as it happens, and tells someone before a user has to. It tails the log, matches lines against patterns you define (errors, stack traces, slow requests), counts them over a window, and raises an alert when a threshold is crossed. The craft is in the details: following a file that rotates out from under you, avoiding a flood of duplicate alerts, and tuning thresholds so real problems fire but ordinary noise stays quiet. When you finish, you will have the small, dependable eyes-on-the-logs that every service needs before it grows a full observability stack. + +## Prerequisites + +- An app that writes logs to a file (or a sample log you can append to) +- A scripting language comfortable with text (Python, Bash + tools, or similar) +- Understanding of regular expressions for pattern matching +- A place to send alerts (console, file, or a chat webhook) ## Learning Objectives -- Parse application logs -- Detect error patterns -- Create alerts -- Aggregate logs -- Visualize data - -## Implementation Tips -- Read log files -- Implement pattern matching -- Create alert rules -- Add notification system -- Implement log rotation -- Create log aggregation -- Add filtering -- Implement search -- Create dashboards -- Add performance metrics -- Implement retention policies -- Create reporting -- Add log correlation -- Build CLI tool - -## Key Challenges -- Log volume handling -- Pattern accuracy -- Alert threshold tuning -- False positives -- Real-time processing + +By the end, you should be able to: + +- Follow an actively-written log file, including across rotation +- Match lines against configurable patterns and classify severity +- Count matches within a time window and alert on a threshold +- Suppress duplicate alerts so one incident does not spam +- Tune thresholds to balance sensitivity against false positives + +## Functional Requirements + +1. The script must follow a log file in real time and process new lines as they arrive. +2. It must match lines against a configurable list of patterns with severities. +3. It must count matches over a rolling time window per pattern. +4. It must raise an alert when a pattern's count exceeds its threshold in the window. +5. It must deduplicate or rate-limit alerts so one condition alerts once, not per line. +6. It must keep following the file correctly after log rotation. +7. Patterns, thresholds, and alert destinations must be configurable, not hardcoded. + +## Suggested Milestones + +1. **Milestone 1 — Tail & match:** Follow the file and print lines that match any configured pattern. +2. **Milestone 2 — Window & threshold:** Count matches over a window and alert when a threshold is crossed. +3. **Milestone 3 — Dedup & rotation:** Rate-limit repeated alerts and handle a rotated log without missing lines. + +## Data & Interface Sketch + +```text +Config (structure, not full file) + log_file: /var/log/app/app.log + window_seconds: 60 + patterns: + - name: error_spike + regex: "ERROR|FATAL" + severity: high + threshold: 10 # matches per window + - name: slow_request + regex: "duration_ms=([0-9]{4,})" + severity: medium + threshold: 5 + alert: + channel: webhook|console|file + cooldown_seconds: 300 # dedup window per pattern + +Alert payload + { pattern, severity, count, window, sample_line, timestamp } +``` + +## Stretch Goals + +- Extract numeric fields (e.g. latency) and alert on an average or percentile, not just a count. +- Summarize the top error signatures over the last hour on demand. +- Support multiple log files and tag alerts with their source. +- Add a `--since` replay mode to test rules against historical logs. + +## Definition of Done + +- [ ] New log lines are processed within a second of being written. +- [ ] Crossing a configured threshold produces exactly one alert per cooldown window. +- [ ] Rotating the log (rename + recreate) does not stop monitoring or duplicate lines. +- [ ] Patterns and thresholds can be changed via config without editing code. +- [ ] Ordinary log noise below threshold produces no alerts. + +## Common Pitfalls + +- Re-reading the whole file on each poll instead of tracking position, wasting CPU and re-alerting. +- Holding the old file handle after rotation and silently monitoring a file no one writes to anymore. +- Alerting per matching line, burying the real signal under hundreds of duplicates. +- Writing greedy regexes that match far more than intended and inflate counts. + +## Resources + +- [The Art of Monitoring (concepts)](https://artofmonitoring.com/) — thresholds, signals, and alert design. +- [logrotate manual](https://man7.org/linux/man-pages/man8/logrotate.8.html) — how rotation works, so you can survive it. +- [MDN: Regular expressions guide](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_expressions) — pattern matching fundamentals. +- [Google SRE Book: Monitoring Distributed Systems](https://sre.google/sre-book/monitoring-distributed-systems/) — what is worth alerting on. diff --git a/projects/devops/beginner/05-log-monitoring/README.pt-BR.md b/projects/devops/beginner/05-log-monitoring/README.pt-BR.md new file mode 100644 index 0000000..a4bbb0c --- /dev/null +++ b/projects/devops/beginner/05-log-monitoring/README.pt-BR.md @@ -0,0 +1,94 @@ +# Script de Monitoramento de Logs + +> 🌐 [English](./README.md) · **Português** + +**Domínio:** DevOps · **Nível:** Iniciante · **Tempo estimado:** 3–6 horas + +## Visão Geral + +Construa um script que observa os arquivos de log de uma aplicação, identifica problemas conforme acontecem e avisa alguém antes que um usuário precise. Ele acompanha o log, compara linhas com padrões que você define (erros, stack traces, requisições lentas), conta-os ao longo de uma janela e dispara um alerta quando um limiar é ultrapassado. A arte está nos detalhes: acompanhar um arquivo que rotaciona por baixo dos seus pés, evitar uma enxurrada de alertas duplicados e ajustar limiares para que problemas reais disparem enquanto o ruído comum fica quieto. Ao terminar, você terá os pequenos e confiáveis olhos-nos-logs que todo serviço precisa antes de ganhar uma stack de observabilidade completa. + +## Pré-requisitos + +- Uma app que escreve logs em um arquivo (ou um log de amostra ao qual você pode anexar) +- Uma linguagem de script confortável com texto (Python, Bash + ferramentas ou similar) +- Entendimento de expressões regulares para casamento de padrões +- Um lugar para enviar alertas (console, arquivo ou um webhook de chat) + +## Objetivos de Aprendizado + +Ao final, você deve ser capaz de: + +- Acompanhar um arquivo de log escrito ativamente, inclusive durante a rotação +- Comparar linhas com padrões configuráveis e classificar a severidade +- Contar casamentos dentro de uma janela de tempo e alertar em um limiar +- Suprimir alertas duplicados para que um incidente não vire spam +- Ajustar limiares para equilibrar sensibilidade e falsos positivos + +## Requisitos Funcionais + +1. O script deve acompanhar um arquivo de log em tempo real e processar novas linhas conforme chegam. +2. Ele deve comparar linhas com uma lista configurável de padrões com severidades. +3. Ele deve contar casamentos ao longo de uma janela de tempo móvel por padrão. +4. Ele deve disparar um alerta quando a contagem de um padrão exceder seu limiar na janela. +5. Ele deve deduplicar ou limitar a taxa de alertas para que uma condição alerte uma vez, não por linha. +6. Ele deve continuar acompanhando o arquivo corretamente após a rotação do log. +7. Padrões, limiares e destinos de alerta devem ser configuráveis, não hardcoded. + +## Marcos Sugeridos + +1. **Marco 1 — Acompanhar e casar:** Acompanhe o arquivo e imprima linhas que casam com qualquer padrão configurado. +2. **Marco 2 — Janela e limiar:** Conte casamentos ao longo de uma janela e alerte quando um limiar é ultrapassado. +3. **Marco 3 — Dedup e rotação:** Limite a taxa de alertas repetidos e trate um log rotacionado sem perder linhas. + +## Esboço de Dados e Interface + +```text +Config (estrutura, não o arquivo completo) + log_file: /var/log/app/app.log + window_seconds: 60 + patterns: + - name: error_spike + regex: "ERROR|FATAL" + severity: high + threshold: 10 # casamentos por janela + - name: slow_request + regex: "duration_ms=([0-9]{4,})" + severity: medium + threshold: 5 + alert: + channel: webhook|console|file + cooldown_seconds: 300 # janela de dedup por padrão + +Payload do alerta + { pattern, severity, count, window, sample_line, timestamp } +``` + +## Desafios Extras + +- Extraia campos numéricos (ex.: latência) e alerte em uma média ou percentil, não só uma contagem. +- Resuma sob demanda as principais assinaturas de erro da última hora. +- Suporte múltiplos arquivos de log e marque alertas com sua origem. +- Adicione um modo de replay `--since` para testar regras contra logs históricos. + +## Definição de Pronto + +- [ ] Novas linhas de log são processadas dentro de um segundo após serem escritas. +- [ ] Ultrapassar um limiar configurado produz exatamente um alerta por janela de cooldown. +- [ ] Rotacionar o log (renomear + recriar) não interrompe o monitoramento nem duplica linhas. +- [ ] Padrões e limiares podem ser alterados via config sem editar código. +- [ ] Ruído comum de log abaixo do limiar não produz alertas. + +## Armadilhas Comuns + +- Reler o arquivo inteiro a cada poll em vez de rastrear a posição, desperdiçando CPU e realertando. +- Manter o handle do arquivo antigo após a rotação e monitorar silenciosamente um arquivo em que ninguém mais escreve. +- Alertar por linha casada, soterrando o sinal real sob centenas de duplicatas. +- Escrever regexes gananciosas que casam muito mais do que o pretendido e inflam contagens. + +## Recursos + +- [The Art of Monitoring (conceitos)](https://artofmonitoring.com/) — limiares, sinais e design de alertas. +- [Manual do logrotate](https://man7.org/linux/man-pages/man8/logrotate.8.html) — como a rotação funciona, para você sobreviver a ela. +- [MDN: Guia de expressões regulares](https://developer.mozilla.org/pt-BR/docs/Web/JavaScript/Guide/Regular_expressions) — fundamentos de casamento de padrões. +- [Google SRE Book: Monitoring Distributed Systems](https://sre.google/sre-book/monitoring-distributed-systems/) — o que vale a pena alertar. diff --git a/projects/devops/beginner/06-health-check/README.md b/projects/devops/beginner/06-health-check/README.md index da0dc18..cc8deec 100644 --- a/projects/devops/beginner/06-health-check/README.md +++ b/projects/devops/beginner/06-health-check/README.md @@ -1,34 +1,97 @@ # Health Check System -## Idea -Create a system that continuously checks application health. Learn about monitoring and alerting. +> 🌐 **English** · [Português](./README.pt-BR.md) + +**Domain:** DevOps · **Level:** Beginner · **Estimated time:** 3–6 hours + +## Overview + +Build a small system that repeatedly asks your services "are you okay?" and does something useful when the answer is no. It probes each target on a schedule — an HTTP endpoint, a TCP port, a dependency like a database — records the result, and alerts when a target stays down past a tolerance you set. The subtlety is telling a real outage apart from a blip: one failed probe should not wake anyone, but three in a row should. You will also learn the difference between liveness ("is it running?") and readiness ("can it serve traffic?"), a distinction that underpins every orchestrator's health model. + +## Prerequisites + +- One or more services with a reachable endpoint or port +- A scripting language that can make HTTP/TCP requests +- Understanding of HTTP status codes and timeouts +- A way to notify (console, log, or chat webhook) ## Learning Objectives -- Implement health checks -- Monitor endpoints -- Detect failures -- Create alerts -- Generate reports - -## Implementation Tips -- Create health check endpoints -- Implement HTTP health checks -- Add dependency checks -- Create timeout handling -- Implement retry logic -- Add alert thresholds -- Create notification system -- Implement status page -- Add historical tracking -- Create metrics collection -- Implement status dashboard -- Add performance metrics -- Create remediation automation -- Build reporting - -## Key Challenges -- Health check accuracy -- Alert sensitivity -- Network latency -- Cascading failures -- Dependencies health + +By the end, you should be able to: + +- Probe HTTP and TCP targets on a fixed interval with timeouts +- Distinguish liveness from readiness and check dependencies +- Require consecutive failures before declaring a target down +- Alert on a state change (up→down, down→up), not on every probe +- Record probe history to compute simple uptime + +## Functional Requirements + +1. The system must check a configurable list of targets on a fixed interval. +2. Each probe must enforce a timeout and treat a timeout as a failure. +3. A target must be marked down only after N consecutive failures (configurable). +4. It must alert once on each state transition, not on every failed probe. +5. It must support at least HTTP (status + body/keyword) and TCP-port checks. +6. It must record each result so uptime over a period can be reported. +7. Targets, intervals, thresholds, and timeouts must be configurable. + +## Suggested Milestones + +1. **Milestone 1 — Probe & report:** Check a list of HTTP targets on an interval and print up/down. +2. **Milestone 2 — Debounce & alert:** Require N consecutive failures and alert on state transitions only. +3. **Milestone 3 — History & uptime:** Persist results and expose an uptime summary and a simple status view. + +## Data & Interface Sketch + +```text +Config (structure, not full file) + interval_seconds: 30 + targets: + - name: api + type: http + url: http://localhost:8080/health + expect_status: 200 + timeout_ms: 2000 + unhealthy_after: 3 # consecutive failures + - name: db + type: tcp + host: localhost + port: 5432 + timeout_ms: 1000 + +State machine per target + UP --(N consecutive fails)--> DOWN (alert) + DOWN --(1 success)--> UP (recovery alert) + +Result record + { target, ok, latency_ms, checked_at, consecutive_failures } +``` + +## Stretch Goals + +- Add a readiness vs liveness distinction and check downstream dependencies separately. +- Serve a small status page listing each target's current state and 24h uptime. +- Add jitter to probe timing so all checks do not fire at the same instant. +- Escalate: warn after N failures, page after M. + +## Definition of Done + +- [ ] Targets are probed on the configured interval with enforced timeouts. +- [ ] A single failed probe does not trigger an alert; N in a row does. +- [ ] Recovery (down→up) produces a distinct alert. +- [ ] Uptime over a window can be reported from recorded history. +- [ ] All thresholds and targets come from config, not code. + +## Common Pitfalls + +- No timeout on probes, so one hung target stalls the whole check loop. +- Alerting on every failed probe instead of on the state change, causing alert fatigue. +- Treating any 2xx–3xx as healthy when the app returns 200 with an error body. +- Checking only liveness, so a process that is up but cannot reach its database looks healthy. + +## Resources + +- [Kubernetes: Liveness, readiness and startup probes](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/) — the canonical model. +- [Microsoft: Health Endpoint Monitoring pattern](https://learn.microsoft.com/en-us/azure/architecture/patterns/health-endpoint-monitoring) — designing health endpoints. +- [MDN: HTTP response status codes](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status) — what "healthy" actually means. +- [Google SRE Book: Monitoring Distributed Systems](https://sre.google/sre-book/monitoring-distributed-systems/) — signals, symptoms, and alerting. diff --git a/projects/devops/beginner/06-health-check/README.pt-BR.md b/projects/devops/beginner/06-health-check/README.pt-BR.md new file mode 100644 index 0000000..1b77dbc --- /dev/null +++ b/projects/devops/beginner/06-health-check/README.pt-BR.md @@ -0,0 +1,97 @@ +# Sistema de Verificação de Saúde + +> 🌐 [English](./README.md) · **Português** + +**Domínio:** DevOps · **Nível:** Iniciante · **Tempo estimado:** 3–6 horas + +## Visão Geral + +Construa um pequeno sistema que repetidamente pergunta aos seus serviços "você está bem?" e faz algo útil quando a resposta é não. Ele sonda cada alvo em um cronograma — um endpoint HTTP, uma porta TCP, uma dependência como um banco de dados —, registra o resultado e alerta quando um alvo permanece fora do ar além de uma tolerância que você define. A sutileza está em distinguir uma queda real de uma oscilação: uma sonda falha não deve acordar ninguém, mas três seguidas devem. Você também aprenderá a diferença entre liveness ("está rodando?") e readiness ("consegue servir tráfego?"), uma distinção que sustenta o modelo de saúde de todo orquestrador. + +## Pré-requisitos + +- Um ou mais serviços com um endpoint ou porta acessível +- Uma linguagem de script que consiga fazer requisições HTTP/TCP +- Entendimento de códigos de status HTTP e timeouts +- Uma forma de notificar (console, log ou webhook de chat) + +## Objetivos de Aprendizado + +Ao final, você deve ser capaz de: + +- Sondar alvos HTTP e TCP em um intervalo fixo com timeouts +- Distinguir liveness de readiness e checar dependências +- Exigir falhas consecutivas antes de declarar um alvo fora do ar +- Alertar em uma mudança de estado (up→down, down→up), não a cada sonda +- Registrar o histórico de sondas para calcular um uptime simples + +## Requisitos Funcionais + +1. O sistema deve checar uma lista configurável de alvos em um intervalo fixo. +2. Cada sonda deve impor um timeout e tratar um timeout como falha. +3. Um alvo deve ser marcado como fora do ar apenas após N falhas consecutivas (configurável). +4. Ele deve alertar uma vez em cada transição de estado, não a cada sonda falha. +5. Ele deve suportar ao menos HTTP (status + corpo/palavra-chave) e checagens de porta TCP. +6. Ele deve registrar cada resultado para que o uptime em um período possa ser reportado. +7. Alvos, intervalos, limiares e timeouts devem ser configuráveis. + +## Marcos Sugeridos + +1. **Marco 1 — Sondar e reportar:** Cheque uma lista de alvos HTTP em um intervalo e imprima up/down. +2. **Marco 2 — Debounce e alerta:** Exija N falhas consecutivas e alerte apenas em transições de estado. +3. **Marco 3 — Histórico e uptime:** Persista resultados e exponha um resumo de uptime e uma visão de status simples. + +## Esboço de Dados e Interface + +```text +Config (estrutura, não o arquivo completo) + interval_seconds: 30 + targets: + - name: api + type: http + url: http://localhost:8080/health + expect_status: 200 + timeout_ms: 2000 + unhealthy_after: 3 # falhas consecutivas + - name: db + type: tcp + host: localhost + port: 5432 + timeout_ms: 1000 + +Máquina de estados por alvo + UP --(N falhas consecutivas)--> DOWN (alerta) + DOWN --(1 sucesso)--> UP (alerta de recuperação) + +Registro de resultado + { target, ok, latency_ms, checked_at, consecutive_failures } +``` + +## Desafios Extras + +- Adicione uma distinção readiness vs liveness e cheque dependências downstream separadamente. +- Sirva uma pequena página de status listando o estado atual de cada alvo e o uptime de 24h. +- Adicione jitter ao tempo das sondas para que nem todas disparem no mesmo instante. +- Escale: avise após N falhas, acione um page após M. + +## Definição de Pronto + +- [ ] Alvos são sondados no intervalo configurado com timeouts impostos. +- [ ] Uma única sonda falha não dispara um alerta; N seguidas disparam. +- [ ] A recuperação (down→up) produz um alerta distinto. +- [ ] O uptime em uma janela pode ser reportado a partir do histórico registrado. +- [ ] Todos os limiares e alvos vêm da config, não do código. + +## Armadilhas Comuns + +- Sem timeout nas sondas, um alvo travado paralisa todo o loop de checagem. +- Alertar a cada sonda falha em vez de na mudança de estado, causando fadiga de alertas. +- Tratar qualquer 2xx–3xx como saudável quando a app retorna 200 com um corpo de erro. +- Checar apenas liveness, de modo que um processo que está de pé mas não alcança seu banco pareça saudável. + +## Recursos + +- [Kubernetes: Probes de liveness, readiness e startup](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/) — o modelo canônico. +- [Microsoft: Padrão Health Endpoint Monitoring](https://learn.microsoft.com/en-us/azure/architecture/patterns/health-endpoint-monitoring) — projetando endpoints de saúde. +- [MDN: Códigos de status de resposta HTTP](https://developer.mozilla.org/pt-BR/docs/Web/HTTP/Status) — o que "saudável" realmente significa. +- [Google SRE Book: Monitoring Distributed Systems](https://sre.google/sre-book/monitoring-distributed-systems/) — sinais, sintomas e alertas. diff --git a/projects/devops/beginner/07-backup-automation/README.md b/projects/devops/beginner/07-backup-automation/README.md index a31994d..030ec10 100644 --- a/projects/devops/beginner/07-backup-automation/README.md +++ b/projects/devops/beginner/07-backup-automation/README.md @@ -1,34 +1,92 @@ # Backup Automation -## Idea -Create an automated backup system for data and configurations. Learn about backup and recovery. +> 🌐 **English** · [Português](./README.pt-BR.md) + +**Domain:** DevOps · **Level:** Beginner · **Estimated time:** 3–6 hours + +## Overview + +Build a script that backs up what matters — a database dump, a directory of files, some config — on a schedule, and just as importantly, proves the backup is restorable. A backup you have never restored is a hope, not a safety net. You will compress and timestamp each backup, apply a retention policy so old copies are pruned instead of filling the disk, and run a restore into a throwaway location to verify the archive is intact. Along the way you will meet the 3-2-1 rule and the uncomfortable truth that the hard part of backups is always the restore. + +## Prerequisites + +- Something worth backing up (a database, a data directory, or config files) +- A scripting language or shell with access to the source and a target location +- Understanding of compression and file archives (tar, zip) +- A destination with enough space (local disk, external drive, or object storage) ## Learning Objectives -- Create backups -- Schedule backups -- Verify backups -- Restore data -- Manage storage - -## Implementation Tips -- Implement backup strategy -- Create scheduling -- Add incremental backups -- Implement compression -- Add encryption -- Create verification -- Implement retention policies -- Add off-site backup -- Create restore procedures -- Implement monitoring -- Add alerts for failures -- Create documentation -- Implement testing recovery -- Build management interface - -## Key Challenges -- Backup size optimization -- Storage management -- Recovery time -- Data consistency -- Encryption key management + +By the end, you should be able to: + +- Automate a scheduled, timestamped backup of a defined source +- Compress archives and name them so they sort and prune cleanly +- Apply a retention policy that keeps recent backups and removes old ones +- Verify a backup by restoring it to a temporary location +- Alert when a backup or verification fails + +## Functional Requirements + +1. The script must back up a configured source (files and/or a database dump) on demand and on a schedule. +2. Each backup must be compressed and named with a sortable UTC timestamp. +3. A retention policy must keep the last N (or N days of) backups and delete older ones. +4. The script must verify each backup, at minimum by testing the archive's integrity. +5. A restore path must exist and be exercised into a temporary location, not over live data. +6. The script must exit non-zero and alert on any backup or verification failure. +7. Source, destination, retention, and schedule must be configurable. + +## Suggested Milestones + +1. **Milestone 1 — Snapshot:** Archive the source into a compressed, timestamped file on demand. +2. **Milestone 2 — Retention & schedule:** Prune old backups by policy and run the backup on a schedule. +3. **Milestone 3 — Verify & restore:** Test archive integrity and perform a restore into a scratch location. + +## Data & Interface Sketch + +```text +Config (structure, not full file) + source: + files: [/etc/app, /srv/app/data] + database: { type: postgres, name: appdb } # dumped, not raw files + destination: /backups (or s3://bucket/prefix) + retention: { keep_days: 7, keep_min: 3 } + schedule: "0 2 * * *" # cron expression, external scheduler + +Artifact naming + app-backup-YYYYMMDDTHHMMSSZ.tar.gz + +Flow (structure, not full script) + dump db -> archive files + dump -> compress -> write to destination + verify: test archive integrity (and optional restore to /tmp/verify) + prune: list backups -> keep by retention -> delete the rest + on any failure: log + alert + exit non-zero +``` + +## Stretch Goals + +- Encrypt archives at rest and manage the key outside the backup itself. +- Add incremental or differential backups to shrink daily size. +- Push a copy off-site (object storage) to satisfy the 3-2-1 rule. +- Emit a metric or report: last successful backup time and total size. + +## Definition of Done + +- [ ] A backup runs unattended on schedule and produces a timestamped, compressed archive. +- [ ] Retention prunes old backups without ever deleting the most recent valid one. +- [ ] Archive integrity is verified after each run. +- [ ] A restore into a temporary location reproduces the original data. +- [ ] A failed backup or verification exits non-zero and raises an alert. + +## Common Pitfalls + +- Backing up raw database files while the DB is running, producing an inconsistent snapshot — dump instead. +- Never testing a restore, so the first real restore is also the first time you learn it does not work. +- A retention bug that deletes everything, including the backup you need, when the list is empty or misparsed. +- Storing backups on the same disk as the source, so one disk failure takes both. + +## Resources + +- [US-CERT: Data Backup Options (3-2-1 rule)](https://www.cisa.gov/sites/default/files/publications/data_backup_options.pdf) — the foundational strategy. +- [GNU tar manual](https://www.gnu.org/software/tar/manual/tar.html) — archiving and incremental backups. +- [PostgreSQL: Backup and Restore](https://www.postgresql.org/docs/current/backup.html) — consistent database dumps. +- [restic documentation](https://restic.readthedocs.io/) — a modern tool that models retention and verification well. diff --git a/projects/devops/beginner/07-backup-automation/README.pt-BR.md b/projects/devops/beginner/07-backup-automation/README.pt-BR.md new file mode 100644 index 0000000..73c7053 --- /dev/null +++ b/projects/devops/beginner/07-backup-automation/README.pt-BR.md @@ -0,0 +1,92 @@ +# Automação de Backup + +> 🌐 [English](./README.md) · **Português** + +**Domínio:** DevOps · **Nível:** Iniciante · **Tempo estimado:** 3–6 horas + +## Visão Geral + +Construa um script que faz backup do que importa — um dump de banco de dados, um diretório de arquivos, alguma config — em um cronograma e, tão importante quanto, prova que o backup é restaurável. Um backup que você nunca restaurou é uma esperança, não uma rede de segurança. Você vai comprimir e datar cada backup, aplicar uma política de retenção para que cópias antigas sejam podadas em vez de encher o disco, e rodar uma restauração para um local descartável para verificar que o arquivo está íntegro. No caminho você conhece a regra 3-2-1 e a verdade incômoda de que a parte difícil dos backups é sempre a restauração. + +## Pré-requisitos + +- Algo que valha a pena fazer backup (um banco de dados, um diretório de dados ou arquivos de config) +- Uma linguagem de script ou shell com acesso à origem e a um destino +- Entendimento de compressão e arquivos compactados (tar, zip) +- Um destino com espaço suficiente (disco local, drive externo ou object storage) + +## Objetivos de Aprendizado + +Ao final, você deve ser capaz de: + +- Automatizar um backup agendado e datado de uma origem definida +- Comprimir arquivos e nomeá-los para que ordenem e sejam podados de forma limpa +- Aplicar uma política de retenção que mantém backups recentes e remove antigos +- Verificar um backup restaurando-o para um local temporário +- Alertar quando um backup ou verificação falha + +## Requisitos Funcionais + +1. O script deve fazer backup de uma origem configurada (arquivos e/ou um dump de banco) sob demanda e em um cronograma. +2. Cada backup deve ser comprimido e nomeado com um timestamp UTC ordenável. +3. Uma política de retenção deve manter os últimos N (ou N dias de) backups e apagar os mais antigos. +4. O script deve verificar cada backup, no mínimo testando a integridade do arquivo. +5. Um caminho de restauração deve existir e ser exercitado em um local temporário, não sobre dados em produção. +6. O script deve sair com código diferente de zero e alertar em qualquer falha de backup ou verificação. +7. Origem, destino, retenção e cronograma devem ser configuráveis. + +## Marcos Sugeridos + +1. **Marco 1 — Snapshot:** Arquive a origem em um arquivo comprimido e datado sob demanda. +2. **Marco 2 — Retenção e cronograma:** Pode backups antigos por política e rode o backup em um cronograma. +3. **Marco 3 — Verificar e restaurar:** Teste a integridade do arquivo e realize uma restauração em um local descartável. + +## Esboço de Dados e Interface + +```text +Config (estrutura, não o arquivo completo) + source: + files: [/etc/app, /srv/app/data] + database: { type: postgres, name: appdb } # via dump, não arquivos crus + destination: /backups (ou s3://bucket/prefix) + retention: { keep_days: 7, keep_min: 3 } + schedule: "0 2 * * *" # expressão cron, agendador externo + +Nomeação do artefato + app-backup-YYYYMMDDTHHMMSSZ.tar.gz + +Fluxo (estrutura, não o script completo) + dump do db -> arquiva arquivos + dump -> comprime -> escreve no destino + verifica: testa integridade do arquivo (e restauração opcional em /tmp/verify) + poda: lista backups -> mantém por retenção -> apaga o resto + em qualquer falha: loga + alerta + sai != 0 +``` + +## Desafios Extras + +- Criptografe arquivos em repouso e gerencie a chave fora do próprio backup. +- Adicione backups incrementais ou diferenciais para reduzir o tamanho diário. +- Envie uma cópia off-site (object storage) para satisfazer a regra 3-2-1. +- Emita uma métrica ou relatório: horário do último backup bem-sucedido e tamanho total. + +## Definição de Pronto + +- [ ] Um backup roda sem supervisão no cronograma e produz um arquivo datado e comprimido. +- [ ] A retenção poda backups antigos sem nunca apagar o mais recente válido. +- [ ] A integridade do arquivo é verificada após cada execução. +- [ ] Uma restauração em um local temporário reproduz os dados originais. +- [ ] Um backup ou verificação com falha sai com código diferente de zero e dispara um alerta. + +## Armadilhas Comuns + +- Fazer backup de arquivos crus do banco enquanto ele está rodando, produzindo um snapshot inconsistente — use dump. +- Nunca testar uma restauração, de modo que a primeira restauração real também é a primeira vez que você descobre que ela não funciona. +- Um bug de retenção que apaga tudo, inclusive o backup de que você precisa, quando a lista está vazia ou mal interpretada. +- Guardar backups no mesmo disco da origem, de modo que uma falha de disco leva ambos. + +## Recursos + +- [US-CERT: Opções de Backup de Dados (regra 3-2-1)](https://www.cisa.gov/sites/default/files/publications/data_backup_options.pdf) — a estratégia fundamental. +- [Manual do GNU tar](https://www.gnu.org/software/tar/manual/tar.html) — arquivamento e backups incrementais. +- [PostgreSQL: Backup e Restauração](https://www.postgresql.org/docs/current/backup.html) — dumps de banco consistentes. +- [Documentação do restic](https://restic.readthedocs.io/) — uma ferramenta moderna que modela retenção e verificação bem. diff --git a/projects/devops/beginner/08-nginx-setup/README.md b/projects/devops/beginner/08-nginx-setup/README.md index 6599bba..c9aad14 100644 --- a/projects/devops/beginner/08-nginx-setup/README.md +++ b/projects/devops/beginner/08-nginx-setup/README.md @@ -1,34 +1,96 @@ # Basic Nginx Setup -## Idea -Set up and configure Nginx as a web server or reverse proxy. Learn about web servers and load balancing basics. +> 🌐 **English** · [Português](./README.pt-BR.md) + +**Domain:** DevOps · **Level:** Beginner · **Estimated time:** 3–6 hours + +## Overview + +Stand up Nginx and put it in front of an application, first as a plain web server and then as a reverse proxy that forwards requests to your app running behind it. This is one of the most common shapes in production: Nginx terminates TLS, serves static files fast, and hands dynamic requests to an upstream. You will write a server block, enable HTTPS, add a few sensible headers, and prove that a request to port 443 reaches your app and comes back correctly. The goal is a config you understand line by line — not a copied snippet you are afraid to touch. + +## Prerequisites + +- A running application listening on a local port (any language) +- A machine (or VM/container) where you can install and run Nginx +- Basic understanding of HTTP, ports, and DNS/hostnames +- A TLS certificate (self-signed for local, or Let's Encrypt for a real domain) ## Learning Objectives -- Install Nginx -- Configure server blocks -- Set up SSL/TLS -- Implement reverse proxy -- Handle requests - -## Implementation Tips -- Create Nginx configuration -- Set up server blocks -- Configure SSL certificates -- Implement reverse proxy -- Add load balancing -- Create caching rules -- Add compression -- Implement security headers -- Add logging -- Create monitoring -- Implement health checks -- Add rate limiting -- Create performance tuning -- Build management interface - -## Key Challenges -- SSL/TLS configuration -- Performance optimization -- Upstream health management -- Configuration complexity -- Security hardening + +By the end, you should be able to: + +- Configure a server block that serves a site on a hostname and port +- Set up Nginx as a reverse proxy to an upstream application +- Enable HTTPS and redirect HTTP to HTTPS +- Add security and caching headers and gzip compression +- Read the access and error logs to debug a misbehaving config + +## Functional Requirements + +1. Nginx must serve a response for a defined hostname on port 80. +2. It must reverse-proxy requests to an upstream app and return the app's response. +3. HTTPS must be enabled on port 443 with a valid (or self-signed) certificate. +4. Plain HTTP requests must redirect to HTTPS. +5. The config must set forwarded headers (host, real IP, protocol) for the upstream. +6. Static assets must be served directly by Nginx with a cache header. +7. `nginx -t` must pass and a reload must apply changes without dropping connections. + +## Suggested Milestones + +1. **Milestone 1 — Serve:** Write a server block that returns a page for your hostname over HTTP. +2. **Milestone 2 — Proxy & TLS:** Reverse-proxy to the app, enable HTTPS, and redirect HTTP to HTTPS. +3. **Milestone 3 — Harden & tune:** Add security headers, gzip, static caching, and validate with `nginx -t`. + +## Data & Interface Sketch + +```text +File layout + /etc/nginx/nginx.conf + /etc/nginx/sites-available/app.conf -> symlinked into sites-enabled/ + +Server block structure (key directives, not full config) + server (port 80): + server_name + return 301 https://$host$request_uri # redirect to HTTPS + server (port 443, ssl): + server_name + ssl_certificate / ssl_certificate_key + location /static/ -> root ; cache-control header + location / -> proxy_pass http://upstream_app + proxy_set_header Host / X-Real-IP / X-Forwarded-Proto + upstream upstream_app: + server 127.0.0.1:8080 + +Validate & apply + nginx -t # test config + nginx -s reload # graceful reload +``` + +## Stretch Goals + +- Add a second upstream server and balance across them (round-robin). +- Add basic rate limiting to a login or API path. +- Automate certificate issuance and renewal with Certbot / Let's Encrypt. +- Add a `/healthz` location that returns 200 without hitting the upstream. + +## Definition of Done + +- [ ] A browser reaching the hostname over HTTPS gets the app's response. +- [ ] HTTP requests redirect to HTTPS. +- [ ] Static files are served by Nginx with a cache header, not proxied. +- [ ] Forwarded headers reach the upstream (verify the app sees the real client protocol/IP). +- [ ] `nginx -t` passes and a reload applies changes with no dropped requests. + +## Common Pitfalls + +- Forgetting `proxy_set_header Host $host`, so the upstream sees the wrong host and generates broken links. +- Leaving a self-signed cert in production and training users to click through TLS warnings. +- Editing `nginx.conf` and reloading without running `nginx -t` first, taking the site down on a typo. +- Serving static files through the proxy, wasting the upstream on work Nginx does faster. + +## Resources + +- [Nginx: Beginner's Guide](https://nginx.org/en/docs/beginners_guide.html) — the official starting point. +- [Nginx: Reverse proxy guide](https://docs.nginx.com/nginx/admin-guide/web-server/reverse-proxy/) — proxy_pass and forwarded headers. +- [Mozilla SSL Configuration Generator](https://ssl-config.mozilla.org/) — safe, current TLS settings for Nginx. +- [Let's Encrypt / Certbot](https://certbot.eff.org/) — free certificates and automatic renewal. diff --git a/projects/devops/beginner/08-nginx-setup/README.pt-BR.md b/projects/devops/beginner/08-nginx-setup/README.pt-BR.md new file mode 100644 index 0000000..3b72e9c --- /dev/null +++ b/projects/devops/beginner/08-nginx-setup/README.pt-BR.md @@ -0,0 +1,96 @@ +# Configuração Básica de Nginx + +> 🌐 [English](./README.md) · **Português** + +**Domínio:** DevOps · **Nível:** Iniciante · **Tempo estimado:** 3–6 horas + +## Visão Geral + +Suba o Nginx e coloque-o na frente de uma aplicação, primeiro como um servidor web simples e depois como um reverse proxy que encaminha requisições à sua app rodando atrás dele. Esta é uma das formas mais comuns em produção: o Nginx termina o TLS, serve arquivos estáticos rapidamente e entrega requisições dinâmicas a um upstream. Você vai escrever um server block, habilitar HTTPS, adicionar alguns headers sensatos e provar que uma requisição à porta 443 alcança sua app e retorna corretamente. O objetivo é uma config que você entende linha por linha — não um trecho copiado que você tem medo de tocar. + +## Pré-requisitos + +- Uma aplicação em execução escutando em uma porta local (qualquer linguagem) +- Uma máquina (ou VM/contêiner) onde você pode instalar e rodar o Nginx +- Entendimento básico de HTTP, portas e DNS/hostnames +- Um certificado TLS (autoassinado para local, ou Let's Encrypt para um domínio real) + +## Objetivos de Aprendizado + +Ao final, você deve ser capaz de: + +- Configurar um server block que serve um site em um hostname e porta +- Configurar o Nginx como reverse proxy para uma aplicação upstream +- Habilitar HTTPS e redirecionar HTTP para HTTPS +- Adicionar headers de segurança e cache e compressão gzip +- Ler os logs de acesso e de erro para depurar uma config problemática + +## Requisitos Funcionais + +1. O Nginx deve servir uma resposta para um hostname definido na porta 80. +2. Ele deve fazer reverse-proxy de requisições para uma app upstream e retornar a resposta da app. +3. O HTTPS deve estar habilitado na porta 443 com um certificado válido (ou autoassinado). +4. Requisições HTTP simples devem redirecionar para HTTPS. +5. A config deve definir headers encaminhados (host, IP real, protocolo) para o upstream. +6. Ativos estáticos devem ser servidos diretamente pelo Nginx com um header de cache. +7. `nginx -t` deve passar e um reload deve aplicar mudanças sem derrubar conexões. + +## Marcos Sugeridos + +1. **Marco 1 — Servir:** Escreva um server block que retorna uma página para seu hostname via HTTP. +2. **Marco 2 — Proxy e TLS:** Faça reverse-proxy para a app, habilite HTTPS e redirecione HTTP para HTTPS. +3. **Marco 3 — Endurecer e ajustar:** Adicione headers de segurança, gzip, cache de estáticos e valide com `nginx -t`. + +## Esboço de Dados e Interface + +```text +Layout de arquivos + /etc/nginx/nginx.conf + /etc/nginx/sites-available/app.conf -> symlink em sites-enabled/ + +Estrutura do server block (diretivas-chave, não a config completa) + server (porta 80): + server_name + return 301 https://$host$request_uri # redireciona para HTTPS + server (porta 443, ssl): + server_name + ssl_certificate / ssl_certificate_key + location /static/ -> root ; header cache-control + location / -> proxy_pass http://upstream_app + proxy_set_header Host / X-Real-IP / X-Forwarded-Proto + upstream upstream_app: + server 127.0.0.1:8080 + +Validar e aplicar + nginx -t # testa a config + nginx -s reload # reload gracioso +``` + +## Desafios Extras + +- Adicione um segundo servidor upstream e balanceie entre eles (round-robin). +- Adicione rate limiting básico a uma rota de login ou de API. +- Automatize a emissão e renovação de certificados com Certbot / Let's Encrypt. +- Adicione uma location `/healthz` que retorna 200 sem chegar ao upstream. + +## Definição de Pronto + +- [ ] Um navegador alcançando o hostname via HTTPS recebe a resposta da app. +- [ ] Requisições HTTP redirecionam para HTTPS. +- [ ] Arquivos estáticos são servidos pelo Nginx com um header de cache, não via proxy. +- [ ] Headers encaminhados chegam ao upstream (verifique que a app enxerga o protocolo/IP real do cliente). +- [ ] `nginx -t` passa e um reload aplica mudanças sem requisições derrubadas. + +## Armadilhas Comuns + +- Esquecer `proxy_set_header Host $host`, fazendo o upstream ver o host errado e gerar links quebrados. +- Deixar um cert autoassinado em produção e treinar usuários a ignorar avisos de TLS. +- Editar `nginx.conf` e recarregar sem rodar `nginx -t` antes, derrubando o site em um erro de digitação. +- Servir arquivos estáticos pelo proxy, desperdiçando o upstream em trabalho que o Nginx faz mais rápido. + +## Recursos + +- [Nginx: Guia do Iniciante](https://nginx.org/en/docs/beginners_guide.html) — o ponto de partida oficial. +- [Nginx: Guia de reverse proxy](https://docs.nginx.com/nginx/admin-guide/web-server/reverse-proxy/) — proxy_pass e headers encaminhados. +- [Mozilla SSL Configuration Generator](https://ssl-config.mozilla.org/) — configurações TLS seguras e atuais para Nginx. +- [Let's Encrypt / Certbot](https://certbot.eff.org/) — certificados gratuitos e renovação automática. diff --git a/projects/devops/beginner/09-cron-manager/README.md b/projects/devops/beginner/09-cron-manager/README.md index d558fd3..8ee7676 100644 --- a/projects/devops/beginner/09-cron-manager/README.md +++ b/projects/devops/beginner/09-cron-manager/README.md @@ -1,34 +1,96 @@ # Cron Job Manager -## Idea -Create a tool for managing and monitoring cron jobs. Learn about task scheduling and automation. +> 🌐 **English** · [Português](./README.pt-BR.md) + +**Domain:** DevOps · **Level:** Beginner · **Estimated time:** 3–6 hours + +## Overview + +Raw `cron` runs your jobs but tells you almost nothing: no history, no alert when a job fails, no protection against a slow run overlapping the next. Build a thin manager that wraps scheduled jobs and adds the operational layer they are missing. It reads a list of jobs and their schedules, runs each at the right time, captures output and exit code, prevents a job from running while a previous instance is still going, and alerts when one fails or overruns. When you finish, you will understand what cron actually guarantees — and what you have to add yourself to trust it in production. + +## Prerequisites + +- A few commands or scripts you want to run on a schedule +- A scripting language for the manager (Python, Go, or shell) +- Understanding of processes, exit codes, and standard output/error +- Familiarity with cron expression syntax ## Learning Objectives -- Manage cron jobs -- Schedule tasks -- Monitor execution -- Handle failures -- Generate reports - -## Implementation Tips -- Create cron configuration -- Implement job scheduling -- Add logging -- Create error notifications -- Implement retry logic -- Add health checks -- Create job history -- Implement job dependencies -- Add result tracking -- Create status monitoring -- Implement concurrent job control -- Add performance tracking -- Create alerting -- Build management dashboard - -## Key Challenges -- Job dependency management -- Error handling -- Concurrent execution -- Log management -- Performance optimization + +By the end, you should be able to: + +- Parse cron-style schedules and determine when each job is due +- Run a job as a subprocess and capture its output and exit code +- Prevent overlapping runs of the same job with a lock +- Record a run history and alert on failure or overrun +- Enforce a per-job timeout so a stuck job cannot run forever + +## Functional Requirements + +1. The manager must read a list of jobs, each with a command and a cron schedule. +2. It must run each job at its scheduled time and capture stdout, stderr, and exit code. +3. It must prevent a job from starting if its previous run is still in progress (locking). +4. It must record a history entry per run: start, end, exit code, and status. +5. It must alert when a job exits non-zero or exceeds its configured timeout. +6. It must terminate a job that exceeds its timeout. +7. Jobs, schedules, timeouts, and alert settings must be configurable. + +## Suggested Milestones + +1. **Milestone 1 — Schedule & run:** Parse schedules, run jobs on time, and capture output and exit code. +2. **Milestone 2 — Lock & history:** Add per-job locking against overlap and persist a run history. +3. **Milestone 3 — Timeout & alert:** Enforce timeouts, kill overruns, and alert on failure or overrun. + +## Data & Interface Sketch + +```text +Job config (structure, not full file) + jobs: + - name: nightly-report + schedule: "0 3 * * *" # cron expression + command: ["/usr/bin/report", "--daily"] + timeout_seconds: 600 + on_failure: alert + - name: cache-warm + schedule: "*/15 * * * *" + command: ["./warm-cache.sh"] + allow_overlap: false + +Run record (persisted per execution) + { job, run_id, started_at, ended_at, exit_code, status, output_ref } + status: success | failed | timed_out | skipped_locked + +CLI + manager run # daemon: evaluate schedules, dispatch due jobs + manager list # jobs + next run time + manager history # recent runs and outcomes +``` + +## Stretch Goals + +- Add job dependencies: run B only after A succeeds. +- Add a retry policy with backoff for transient failures. +- Expose a small status page or endpoint with last-run outcomes. +- Support environment variables and a working directory per job. + +## Definition of Done + +- [ ] Jobs run at their scheduled times and their exit codes are recorded. +- [ ] A long-running job blocks its own next run instead of overlapping. +- [ ] A job exceeding its timeout is killed and marked `timed_out`. +- [ ] A non-zero exit raises exactly one alert with the job name and output. +- [ ] History shows outcomes per run and is queryable per job. + +## Common Pitfalls + +- Assuming the previous run finished; without a lock, a slow job piles up copies of itself. +- Discarding stdout/stderr, so a failed job leaves no clue why. +- Ignoring the exit code and treating "it ran" as "it succeeded". +- Scheduling in local time and getting surprised by daylight-saving shifts — prefer UTC. + +## Resources + +- [crontab(5) manual](https://man7.org/linux/man-pages/man5/crontab.5.html) — the schedule expression format. +- [crontab.guru](https://crontab.guru/) — interactive cron expression reference. +- [systemd timers](https://www.freedesktop.org/software/systemd/man/systemd.timer.html) — a modern alternative with built-in logging. +- [Google SRE Book: Distributed Periodic Scheduling with Cron](https://sre.google/sre-book/distributed-periodic-scheduling/) — reliability concerns of scheduled jobs. diff --git a/projects/devops/beginner/09-cron-manager/README.pt-BR.md b/projects/devops/beginner/09-cron-manager/README.pt-BR.md new file mode 100644 index 0000000..1c6e97b --- /dev/null +++ b/projects/devops/beginner/09-cron-manager/README.pt-BR.md @@ -0,0 +1,96 @@ +# Gerenciador de Cron Jobs + +> 🌐 [English](./README.md) · **Português** + +**Domínio:** DevOps · **Nível:** Iniciante · **Tempo estimado:** 3–6 horas + +## Visão Geral + +O `cron` puro roda seus jobs mas quase não conta nada: sem histórico, sem alerta quando um job falha, sem proteção contra uma execução lenta que se sobrepõe à próxima. Construa um gerenciador enxuto que envolve jobs agendados e adiciona a camada operacional que lhes falta. Ele lê uma lista de jobs e seus cronogramas, roda cada um na hora certa, captura a saída e o código de saída, impede que um job rode enquanto uma instância anterior ainda está em andamento e alerta quando um falha ou estoura o tempo. Ao terminar, você entenderá o que o cron de fato garante — e o que você precisa adicionar por conta própria para confiar nele em produção. + +## Pré-requisitos + +- Alguns comandos ou scripts que você quer rodar em um cronograma +- Uma linguagem de script para o gerenciador (Python, Go ou shell) +- Entendimento de processos, códigos de saída e saída padrão/de erro +- Familiaridade com a sintaxe de expressões cron + +## Objetivos de Aprendizado + +Ao final, você deve ser capaz de: + +- Interpretar cronogramas no estilo cron e determinar quando cada job está devido +- Rodar um job como subprocesso e capturar sua saída e código de saída +- Impedir execuções sobrepostas do mesmo job com um lock +- Registrar um histórico de execuções e alertar em falha ou estouro de tempo +- Impor um timeout por job para que um job travado não rode para sempre + +## Requisitos Funcionais + +1. O gerenciador deve ler uma lista de jobs, cada um com um comando e um cronograma cron. +2. Ele deve rodar cada job no horário agendado e capturar stdout, stderr e código de saída. +3. Ele deve impedir que um job inicie se sua execução anterior ainda estiver em andamento (locking). +4. Ele deve registrar uma entrada de histórico por execução: início, fim, código de saída e status. +5. Ele deve alertar quando um job sai com código diferente de zero ou excede seu timeout configurado. +6. Ele deve terminar um job que excede seu timeout. +7. Jobs, cronogramas, timeouts e configurações de alerta devem ser configuráveis. + +## Marcos Sugeridos + +1. **Marco 1 — Agendar e rodar:** Interprete cronogramas, rode jobs na hora e capture saída e código de saída. +2. **Marco 2 — Lock e histórico:** Adicione locking por job contra sobreposição e persista um histórico de execuções. +3. **Marco 3 — Timeout e alerta:** Imponha timeouts, mate estouros e alerte em falha ou estouro de tempo. + +## Esboço de Dados e Interface + +```text +Config de job (estrutura, não o arquivo completo) + jobs: + - name: nightly-report + schedule: "0 3 * * *" # expressão cron + command: ["/usr/bin/report", "--daily"] + timeout_seconds: 600 + on_failure: alert + - name: cache-warm + schedule: "*/15 * * * *" + command: ["./warm-cache.sh"] + allow_overlap: false + +Registro de execução (persistido por execução) + { job, run_id, started_at, ended_at, exit_code, status, output_ref } + status: success | failed | timed_out | skipped_locked + +CLI + manager run # daemon: avalia cronogramas, dispara jobs devidos + manager list # jobs + próximo horário de execução + manager history # execuções recentes e resultados +``` + +## Desafios Extras + +- Adicione dependências entre jobs: rode B só depois que A tiver sucesso. +- Adicione uma política de retry com backoff para falhas transitórias. +- Exponha uma pequena página ou endpoint de status com os resultados das últimas execuções. +- Suporte variáveis de ambiente e um diretório de trabalho por job. + +## Definição de Pronto + +- [ ] Jobs rodam nos horários agendados e seus códigos de saída são registrados. +- [ ] Um job de longa duração bloqueia sua própria próxima execução em vez de se sobrepor. +- [ ] Um job que excede seu timeout é morto e marcado como `timed_out`. +- [ ] Uma saída diferente de zero dispara exatamente um alerta com o nome do job e a saída. +- [ ] O histórico mostra resultados por execução e é consultável por job. + +## Armadilhas Comuns + +- Assumir que a execução anterior terminou; sem um lock, um job lento acumula cópias de si mesmo. +- Descartar stdout/stderr, de modo que um job com falha não deixa pista do porquê. +- Ignorar o código de saída e tratar "rodou" como "teve sucesso". +- Agendar em horário local e se surpreender com mudanças de horário de verão — prefira UTC. + +## Recursos + +- [Manual do crontab(5)](https://man7.org/linux/man-pages/man5/crontab.5.html) — o formato da expressão de cronograma. +- [crontab.guru](https://crontab.guru/) — referência interativa de expressões cron. +- [systemd timers](https://www.freedesktop.org/software/systemd/man/systemd.timer.html) — uma alternativa moderna com logging embutido. +- [Google SRE Book: Distributed Periodic Scheduling with Cron](https://sre.google/sre-book/distributed-periodic-scheduling/) — preocupações de confiabilidade de jobs agendados. diff --git a/projects/devops/beginner/10-service-restart/README.md b/projects/devops/beginner/10-service-restart/README.md index d17c240..baee057 100644 --- a/projects/devops/beginner/10-service-restart/README.md +++ b/projects/devops/beginner/10-service-restart/README.md @@ -1,34 +1,99 @@ # Service Restart Monitor -## Idea -Create a system that monitors services and restarts them if they fail. Learn about service management and automation. +> 🌐 **English** · [Português](./README.pt-BR.md) + +**Domain:** DevOps · **Level:** Beginner · **Estimated time:** 3–6 hours + +## Overview + +Build a small supervisor that watches a set of local services, notices when one dies or stops responding, and restarts it automatically. This is the idea behind tools like systemd, supervisord, and Kubernetes liveness probes, distilled to its core: a loop that checks health, decides whether a process is alive, and acts. The interesting part is not the restart itself but the discipline around it — knowing the difference between "not running" and "running but unhealthy", backing off so you don't hammer a broken service, and stopping after too many failures instead of restarting forever. You will finish with a clear mental model of what a process supervisor actually does and why naive "just restart it" scripts cause more outages than they fix. + +## Prerequisites + +- Comfort running and stopping processes from a shell +- Basic scripting in any language (Bash, Python, Go, or Node) +- Understanding of exit codes and how a process reports success or failure +- Familiarity with reading logs and timestamps ## Learning Objectives -- Monitor services -- Detect failures -- Restart services -- Handle cascading failures -- Track history - -## Implementation Tips -- Implement service monitoring -- Create health checks -- Add restart logic -- Implement exponential backoff -- Add restart limits -- Create notifications -- Implement status tracking -- Add logging -- Create metrics -- Implement dependencies -- Add safety checks -- Create manual override -- Implement monitoring dashboard -- Build alerting system - -## Key Challenges -- Service interdependencies -- Restart cascading -- State consistency -- Resource limits -- Recovery detection + +By the end, you should be able to: + +- Distinguish liveness (is the process running?) from readiness (is it actually serving?) +- Implement a health check via process status, a TCP port, or an HTTP endpoint +- Apply exponential backoff so retries slow down instead of tightening into a loop +- Enforce a restart limit and enter a "give up" state that alerts instead of retrying +- Keep an auditable history of failures and restart decisions + +## Functional Requirements + +1. The monitor must track a configurable list of services, each with its own health check. +2. It must detect when a service is down (dead process, closed port, or failing endpoint). +3. On failure, it must attempt a restart and record that it did so. +4. Retries must use exponential backoff with a configurable base and cap. +5. After a configurable number of failures in a window, it must stop restarting and raise an alert instead. +6. A manual override must let an operator disable or force-restart a specific service. +7. Every state change (down, restarting, recovered, gave-up) must be logged with a timestamp. + +## Suggested Milestones + +1. **Milestone 1 — Detect & restart:** Poll one service, detect a dead process, restart it, log the event. +2. **Milestone 2 — Backoff & limits:** Add exponential backoff and a max-restart threshold with a give-up state. +3. **Milestone 3 — Multiple services & override:** Drive several services from config and add manual controls. + +## Data & Interface Sketch + +```text +config (per service) + name string + start_cmd string + check { type: process | tcp | http, target, interval_s } + backoff { base_s, max_s } + max_restarts int (within window_s) + +service state (in memory) + status running | down | restarting | gave_up + failures int + next_attempt timestamp + last_change timestamp + +control surface (CLI or file) + status -> table of services + state + disable -> stop monitoring + restart -> force one restart + +restart decision: + down -> attempt if failures < max_restarts + -> wait min(base * 2^failures, max) before next try + -> failures >= max within window -> gave_up + alert +``` + +## Stretch Goals + +- Add service dependencies so a restart cascades in the correct order. +- Send notifications to a chat webhook (e.g. Slack) when a service enters give-up. +- Expose a tiny status dashboard or `/healthz` endpoint for the monitor itself. +- Persist history to a file so restart counts survive a monitor restart. + +## Definition of Done + +- [ ] A killed service is detected and restarted within one check interval. +- [ ] Repeated failures back off exponentially rather than retrying immediately. +- [ ] After the restart limit is hit, the service enters give-up and alerts instead of looping. +- [ ] A healthy-again service resets its failure counter and returns to normal monitoring. +- [ ] Every transition is logged with a timestamp and is readable after the fact. + +## Common Pitfalls + +- Treating "process exists" as "healthy" — a hung process passes a PID check but serves nothing. +- Restarting with no backoff, turning a crash loop into a CPU-pinning hot loop. +- Never giving up, so a permanently broken service masks the real problem behind endless restarts. +- Forgetting to reset the failure counter after recovery, causing premature give-up later. +- Racing on restart: launching a second copy before confirming the first is truly gone. + +## Resources + +- [systemd.service manual](https://www.freedesktop.org/software/systemd/man/systemd.service.html) — how a real supervisor models restart policy. +- [Supervisor documentation](http://supervisord.org/) — a process control system with the exact concepts here. +- [Kubernetes: Configure Liveness, Readiness and Startup Probes](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/) — liveness vs readiness in practice. +- [Google SRE Book: Addressing Cascading Failures](https://sre.google/sre-book/addressing-cascading-failures/) — why backoff and limits matter. diff --git a/projects/devops/beginner/10-service-restart/README.pt-BR.md b/projects/devops/beginner/10-service-restart/README.pt-BR.md new file mode 100644 index 0000000..9de2379 --- /dev/null +++ b/projects/devops/beginner/10-service-restart/README.pt-BR.md @@ -0,0 +1,99 @@ +# Monitor de Reinício de Serviços + +> 🌐 [English](./README.md) · **Português** + +**Domínio:** DevOps · **Nível:** Iniciante · **Tempo estimado:** 3–6 horas + +## Visão Geral + +Construa um pequeno supervisor que observa um conjunto de serviços locais, percebe quando um deles morre ou para de responder e o reinicia automaticamente. Essa é a ideia por trás de ferramentas como systemd, supervisord e os liveness probes do Kubernetes, reduzida à sua essência: um laço que verifica a saúde, decide se um processo está vivo e age. A parte interessante não é o reinício em si, mas a disciplina ao seu redor — saber a diferença entre "não está rodando" e "está rodando mas não saudável", recuar para não martelar um serviço quebrado e parar após falhas demais em vez de reiniciar para sempre. Você terminará com um modelo mental claro do que um supervisor de processos realmente faz e por que scripts ingênuos de "só reinicia" causam mais quedas do que resolvem. + +## Pré-requisitos + +- Conforto para rodar e parar processos a partir de um shell +- Scripting básico em qualquer linguagem (Bash, Python, Go ou Node) +- Entender códigos de saída e como um processo reporta sucesso ou falha +- Familiaridade com leitura de logs e timestamps + +## Objetivos de Aprendizado + +Ao final, você deve ser capaz de: + +- Distinguir liveness (o processo está rodando?) de readiness (ele está de fato servindo?) +- Implementar uma verificação de saúde via status do processo, uma porta TCP ou um endpoint HTTP +- Aplicar backoff exponencial para que as tentativas desacelerem em vez de virar um laço apertado +- Impor um limite de reinícios e entrar em um estado de "desistência" que alerta em vez de tentar de novo +- Manter um histórico auditável de falhas e decisões de reinício + +## Requisitos Funcionais + +1. O monitor deve acompanhar uma lista configurável de serviços, cada um com sua própria verificação de saúde. +2. Ele deve detectar quando um serviço está fora (processo morto, porta fechada ou endpoint falhando). +3. Ao falhar, deve tentar um reinício e registrar que o fez. +4. As novas tentativas devem usar backoff exponencial com base e teto configuráveis. +5. Após um número configurável de falhas em uma janela, deve parar de reiniciar e emitir um alerta. +6. Uma sobreposição manual deve permitir a um operador desabilitar ou forçar o reinício de um serviço específico. +7. Toda mudança de estado (fora, reiniciando, recuperado, desistiu) deve ser registrada com timestamp. + +## Marcos Sugeridos + +1. **Marco 1 — Detectar e reiniciar:** Monitore um serviço, detecte um processo morto, reinicie-o, registre o evento. +2. **Marco 2 — Backoff e limites:** Adicione backoff exponencial e um limite máximo de reinícios com estado de desistência. +3. **Marco 3 — Múltiplos serviços e sobreposição:** Controle vários serviços via configuração e adicione controles manuais. + +## Esboço de Dados e Interface + +```text +config (por serviço) + name string + start_cmd string + check { type: process | tcp | http, target, interval_s } + backoff { base_s, max_s } + max_restarts int (dentro de window_s) + +estado do serviço (em memória) + status running | down | restarting | gave_up + failures int + next_attempt timestamp + last_change timestamp + +superfície de controle (CLI ou arquivo) + status -> tabela de serviços + estado + disable -> parar de monitorar + restart -> forçar um reinício + +decisão de reinício: + down -> tentar se failures < max_restarts + -> aguardar min(base * 2^failures, max) antes da próxima tentativa + -> failures >= max na janela -> gave_up + alerta +``` + +## Desafios Extras + +- Adicione dependências entre serviços para que um reinício cascateie na ordem correta. +- Envie notificações a um webhook de chat (ex.: Slack) quando um serviço entrar em desistência. +- Exponha um pequeno painel de status ou um endpoint `/healthz` para o próprio monitor. +- Persista o histórico em arquivo para que as contagens de reinício sobrevivam a um reinício do monitor. + +## Definição de Pronto + +- [ ] Um serviço encerrado é detectado e reiniciado em até um intervalo de verificação. +- [ ] Falhas repetidas recuam exponencialmente em vez de tentar de novo imediatamente. +- [ ] Após atingir o limite de reinícios, o serviço entra em desistência e alerta em vez de entrar em laço. +- [ ] Um serviço saudável novamente zera seu contador de falhas e volta ao monitoramento normal. +- [ ] Toda transição é registrada com timestamp e permanece legível depois. + +## Armadilhas Comuns + +- Tratar "o processo existe" como "saudável" — um processo travado passa na checagem de PID mas não serve nada. +- Reiniciar sem backoff, transformando um crash loop em um laço quente que trava a CPU. +- Nunca desistir, de modo que um serviço permanentemente quebrado esconde o problema real por trás de reinícios infinitos. +- Esquecer de zerar o contador de falhas após a recuperação, causando desistência prematura mais tarde. +- Corrida no reinício: subir uma segunda cópia antes de confirmar que a primeira realmente se foi. + +## Recursos + +- [Manual do systemd.service](https://www.freedesktop.org/software/systemd/man/systemd.service.html) — como um supervisor real modela política de reinício. +- [Documentação do Supervisor](http://supervisord.org/) — um sistema de controle de processos com exatamente os conceitos aqui. +- [Kubernetes: Configurar Liveness, Readiness e Startup Probes](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/) — liveness vs readiness na prática. +- [Google SRE Book: Addressing Cascading Failures](https://sre.google/sre-book/addressing-cascading-failures/) — por que backoff e limites importam. diff --git a/projects/devops/intermediate/01-cicd-github-actions/README.md b/projects/devops/intermediate/01-cicd-github-actions/README.md index 41568d5..991a492 100644 --- a/projects/devops/intermediate/01-cicd-github-actions/README.md +++ b/projects/devops/intermediate/01-cicd-github-actions/README.md @@ -1,34 +1,91 @@ # CI/CD Pipeline (GitHub Actions) -## Idea -Build a complete continuous integration and deployment pipeline. Learn about modern CI/CD practices. +> 🌐 **English** · [Português](./README.pt-BR.md) + +**Domain:** DevOps · **Level:** Intermediate · **Estimated time:** 1–2 days + +## Overview + +Wire up a full continuous integration and delivery pipeline for a small application using GitHub Actions. Every push should lint, test, and build the code; every merge to the main branch should produce a versioned artifact and promote it through staging and then production behind a manual approval gate. The goal is not to ship one workflow file, but to feel how a pipeline turns "it works on my machine" into a repeatable, gated, auditable path to release — including the escape hatch of rolling back when a deploy goes wrong. + +## Prerequisites + +- A GitHub repository with an app that has a test suite and a build step +- Comfort with YAML and reading command exit codes +- Basic understanding of environment separation (staging vs production) +- A deploy target you can reach from a runner (container registry, static host, or SSH box) ## Learning Objectives -- Design CI/CD workflow -- Implement automated testing -- Create build artifacts -- Automate deployment -- Implement rollback - -## Implementation Tips -- Create GitHub Actions workflows -- Implement build stages -- Add comprehensive testing (unit, integration) -- Create artifact creation -- Implement deployment stages -- Add environment promotion -- Implement approval gates -- Add monitoring integration -- Create status notifications -- Implement secrets management -- Add performance monitoring -- Create deployment history -- Implement rollback automation -- Build dashboard - -## Key Challenges -- Pipeline complexity -- Build time optimization -- Test coverage -- Deployment safety -- Monitoring integration + +By the end, you should be able to: + +- Structure a multi-job workflow with dependencies between jobs +- Cache dependencies and share build artifacts between jobs +- Gate production deploys behind environments and required reviewers +- Inject secrets safely without leaking them into logs +- Trigger a rollback to a previously known-good artifact + +## Functional Requirements + +1. Every push to any branch must run lint and the full test suite; a failure must fail the run. +2. Merges to `main` must build a versioned, immutable artifact tagged with the commit SHA. +3. The pipeline must deploy automatically to staging after a successful build. +4. Production deploys must require a manual approval from a designated reviewer. +5. Secrets must be sourced from GitHub encrypted secrets, never hard-coded. +6. A documented, one-action path must exist to redeploy a prior artifact (rollback). +7. Each stage must report clear pass/fail status back to the pull request or commit. + +## Suggested Milestones + +1. **Milestone 1 — CI:** Lint + test on every push, with dependency caching. +2. **Milestone 2 — Build & artifact:** Produce a SHA-tagged artifact and upload it once, reuse it downstream. +3. **Milestone 3 — Deploy & gate:** Auto-deploy staging, gate production with an approval and a rollback path. + +## Data & Interface Sketch + +```text +Trigger events: + push (any branch) -> lint, test + push to main -> lint, test, build, deploy-staging + environment: production -> manual approval -> deploy-production + +Job graph: + lint ─┐ + ├─> build ─> deploy-staging ─(approval)─> deploy-production + test ─┘ + +Artifact naming: app- (immutable, never overwritten) +Secrets: REGISTRY_TOKEN, DEPLOY_KEY (from repo/env secrets) +Rollback: re-run deploy job pinned to a previous app- +``` + +## Stretch Goals + +- Add a matrix build to test across multiple runtime versions in parallel. +- Post deploy status and the artifact version to a Slack or Discord channel. +- Add a smoke-test job that hits a health endpoint after staging deploy and blocks promotion on failure. +- Cut releases automatically with semantic version tags on merge. + +## Definition of Done + +- [ ] A failing test blocks the merge and is visible on the pull request. +- [ ] Artifacts are tagged by commit SHA and never mutated after build. +- [ ] Production deploy cannot proceed without an explicit human approval. +- [ ] No secret value appears in any workflow log. +- [ ] Rolling back to the previous artifact is a documented, repeatable action. + +## Common Pitfalls + +- Rebuilding the artifact separately for staging and production, so the two environments run different bytes. +- Echoing environment variables for debugging and leaking a secret into public logs. +- Skipping caching, making every run slow enough that people start bypassing CI. +- Treating a green pipeline as "deployed and healthy" without any post-deploy verification. +- Having no rollback plan, so a bad deploy turns into a frantic hotfix under pressure. + +## Resources + +- [GitHub Actions documentation](https://docs.github.com/en/actions) — workflows, jobs, and triggers from the source. +- [Using environments for deployment](https://docs.github.com/en/actions/deployment/targeting-different-environments/using-environments-for-deployment) — approval gates and protection rules. +- [Encrypted secrets in Actions](https://docs.github.com/en/actions/security-guides/using-secrets-in-github-actions) — the safe way to handle credentials. +- [Martin Fowler: Continuous Integration](https://martinfowler.com/articles/continuousIntegration.html) — the principles behind the practice. + diff --git a/projects/devops/intermediate/01-cicd-github-actions/README.pt-BR.md b/projects/devops/intermediate/01-cicd-github-actions/README.pt-BR.md new file mode 100644 index 0000000..73e8bdb --- /dev/null +++ b/projects/devops/intermediate/01-cicd-github-actions/README.pt-BR.md @@ -0,0 +1,91 @@ +# Pipeline de CI/CD (GitHub Actions) + +> 🌐 [English](./README.md) · **Português** + +**Domínio:** DevOps · **Nível:** Intermediário · **Tempo estimado:** 1–2 dias + +## Visão Geral + +Monte um pipeline completo de integração e entrega contínua para uma aplicação pequena usando GitHub Actions. Todo push deve executar lint, testes e build do código; todo merge na branch principal deve produzir um artefato versionado e promovê-lo por staging e depois produção atrás de um portão de aprovação manual. O objetivo não é entregar um único arquivo de workflow, mas sentir como um pipeline transforma o "funciona na minha máquina" em um caminho de release repetível, controlado e auditável — incluindo a saída de emergência de reverter quando um deploy dá errado. + +## Pré-requisitos + +- Um repositório no GitHub com uma app que tenha suíte de testes e etapa de build +- Conforto com YAML e leitura de códigos de saída de comandos +- Entendimento básico de separação de ambientes (staging vs produção) +- Um alvo de deploy alcançável a partir de um runner (registro de contêineres, host estático ou máquina SSH) + +## Objetivos de Aprendizado + +Ao final, você deve ser capaz de: + +- Estruturar um workflow com múltiplos jobs e dependências entre eles +- Cachear dependências e compartilhar artefatos de build entre jobs +- Proteger deploys de produção com ambientes e revisores obrigatórios +- Injetar segredos com segurança sem vazá-los nos logs +- Disparar uma reversão para um artefato anterior sabidamente bom + +## Requisitos Funcionais + +1. Todo push em qualquer branch deve executar lint e a suíte completa de testes; uma falha deve falhar a execução. +2. Merges na `main` devem construir um artefato versionado e imutável, marcado com o SHA do commit. +3. O pipeline deve fazer deploy automático em staging após um build bem-sucedido. +4. Deploys de produção devem exigir aprovação manual de um revisor designado. +5. Segredos devem vir dos segredos criptografados do GitHub, nunca embutidos no código. +6. Deve existir um caminho documentado, de uma ação, para reimplantar um artefato anterior (rollback). +7. Cada etapa deve reportar status claro de sucesso/falha de volta ao pull request ou commit. + +## Marcos Sugeridos + +1. **Marco 1 — CI:** Lint + testes em todo push, com cache de dependências. +2. **Marco 2 — Build e artefato:** Produza um artefato marcado com o SHA e faça upload uma vez, reutilizando-o adiante. +3. **Marco 3 — Deploy e portão:** Deploy automático em staging, produção protegida por aprovação e caminho de rollback. + +## Esboço de Dados e Interface + +```text +Eventos de gatilho: + push (qualquer branch) -> lint, test + push na main -> lint, test, build, deploy-staging + ambiente: produção -> aprovação manual -> deploy-produção + +Grafo de jobs: + lint ─┐ + ├─> build ─> deploy-staging ─(aprovação)─> deploy-produção + test ─┘ + +Nome do artefato: app- (imutável, nunca sobrescrito) +Segredos: REGISTRY_TOKEN, DEPLOY_KEY (dos segredos do repo/ambiente) +Rollback: reexecutar o job de deploy fixado em um app- anterior +``` + +## Desafios Extras + +- Adicione um build em matriz para testar em várias versões de runtime em paralelo. +- Poste o status do deploy e a versão do artefato em um canal do Slack ou Discord. +- Adicione um job de smoke-test que acesse um endpoint de saúde após o deploy em staging e bloqueie a promoção em caso de falha. +- Gere releases automaticamente com tags de versão semântica no merge. + +## Definição de Pronto + +- [ ] Um teste que falha bloqueia o merge e fica visível no pull request. +- [ ] Artefatos são marcados pelo SHA do commit e nunca alterados após o build. +- [ ] O deploy de produção não pode prosseguir sem uma aprovação humana explícita. +- [ ] Nenhum valor de segredo aparece em qualquer log de workflow. +- [ ] Reverter para o artefato anterior é uma ação documentada e repetível. + +## Armadilhas Comuns + +- Reconstruir o artefato separadamente para staging e produção, fazendo os dois ambientes rodarem bytes diferentes. +- Ecoar variáveis de ambiente para depuração e vazar um segredo em logs públicos. +- Pular o cache, deixando cada execução lenta o bastante para as pessoas começarem a burlar o CI. +- Tratar um pipeline verde como "implantado e saudável" sem qualquer verificação pós-deploy. +- Não ter plano de rollback, tornando um deploy ruim um hotfix desesperado sob pressão. + +## Recursos + +- [Documentação do GitHub Actions](https://docs.github.com/pt/actions) — workflows, jobs e gatilhos direto da fonte. +- [Usando ambientes para deploy](https://docs.github.com/en/actions/deployment/targeting-different-environments/using-environments-for-deployment) — portões de aprovação e regras de proteção. +- [Segredos criptografados no Actions](https://docs.github.com/en/actions/security-guides/using-secrets-in-github-actions) — a forma segura de lidar com credenciais. +- [Martin Fowler: Integração Contínua](https://martinfowler.com/articles/continuousIntegration.html) — os princípios por trás da prática. + diff --git a/projects/devops/intermediate/02-kubernetes-deployment/README.md b/projects/devops/intermediate/02-kubernetes-deployment/README.md index 16eb838..ae1b72b 100644 --- a/projects/devops/intermediate/02-kubernetes-deployment/README.md +++ b/projects/devops/intermediate/02-kubernetes-deployment/README.md @@ -1,34 +1,96 @@ # Kubernetes Deployment -## Idea -Deploy applications to Kubernetes cluster. Learn about container orchestration and cloud-native patterns. +> 🌐 **English** · [Português](./README.pt-BR.md) + +**Domain:** DevOps · **Level:** Intermediate · **Estimated time:** 1–2 days + +## Overview + +Take a containerized web application and run it properly on a Kubernetes cluster — not just "kubectl run and hope", but a real deployment with declarative manifests, a stable service address, external ingress, configuration split from secrets, resource requests, health probes, and a rolling update that ships a new version without dropping traffic. You can use any cluster: a local one like kind, k3d, or minikube, or a managed cloud cluster. The lesson is how Kubernetes turns a set of desired-state YAML files into a self-healing, updatable running system. + +## Prerequisites + +- A container image of an app, pushed to a registry the cluster can pull from +- A working cluster and `kubectl` configured against it +- Understanding of containers, ports, and environment variables +- Familiarity with YAML and the request/response lifecycle of a web app ## Learning Objectives -- Create Kubernetes manifests -- Deploy applications -- Implement scaling -- Handle networking -- Implement service discovery - -## Implementation Tips -- Create Deployment manifests -- Implement Service configuration -- Add ingress routing -- Create ConfigMaps and Secrets -- Implement resource limits -- Add health probes -- Implement rolling updates -- Create StatefulSets for stateful apps -- Add volume management -- Implement monitoring -- Create logging integration -- Add RBAC -- Implement network policies -- Build operational dashboards - -## Key Challenges -- Manifest complexity -- Resource allocation -- Networking setup -- State management -- Monitoring complexity + +By the end, you should be able to: + +- Express desired state with Deployment, Service, and Ingress manifests +- Separate configuration (ConfigMap) from secrets and inject both into pods +- Set resource requests/limits and reason about scheduling and eviction +- Configure liveness and readiness probes so traffic only hits healthy pods +- Perform a rolling update and roll it back when the new version misbehaves + +## Functional Requirements + +1. The app must be described by a Deployment running at least two replicas. +2. A Service must give the pods a stable in-cluster address independent of pod churn. +3. External traffic must reach the app through an Ingress (or an equivalent LoadBalancer). +4. Non-secret config must come from a ConfigMap; sensitive values from a Secret. +5. Every pod must declare resource requests and limits. +6. Readiness and liveness probes must keep traffic off pods that are starting or unhealthy. +7. A rolling update must ship a new image with zero dropped requests, and `kubectl rollout undo` must restore the previous version. + +## Suggested Milestones + +1. **Milestone 1 — Run it:** Deployment + Service, app reachable inside the cluster. +2. **Milestone 2 — Expose & configure:** Add Ingress, ConfigMap, and Secret; wire config into pods. +3. **Milestone 3 — Resilience & updates:** Add probes and resource limits; do a rolling update and a rollback. + +## Data & Interface Sketch + +```text +Object relationships: + Ingress ──routes──> Service ──selects(labels)──> Pods (from Deployment) + ConfigMap ─┐ + Secret ────┴─mounted/env─> Pods + +Deployment spec (structure only): + replicas: 2 + strategy: RollingUpdate (maxUnavailable, maxSurge) + template: + containers: + - image: registry/app: + resources: { requests: {cpu, mem}, limits: {cpu, mem} } + readinessProbe: httpGet /healthz + livenessProbe: httpGet /healthz + envFrom: [configMapRef, secretRef] + +Update: kubectl set image ... -> new ReplicaSet scales up, old scales down +Rollback: kubectl rollout undo deployment/app +``` + +## Stretch Goals + +- Add a HorizontalPodAutoscaler that scales replicas on CPU. +- Add a PodDisruptionBudget so voluntary evictions never take the app below a floor. +- Split into a StatefulSet for a component that needs stable identity and storage. +- Add NetworkPolicies restricting which pods can talk to each other. + +## Definition of Done + +- [ ] Deleting a pod results in Kubernetes recreating it automatically. +- [ ] The Service address stays stable while pods are replaced. +- [ ] Config and secrets are injected from ConfigMap/Secret, not baked into the image. +- [ ] A rolling update completes with no failed requests against the app. +- [ ] `kubectl rollout undo` restores the prior version and it serves traffic. + +## Common Pitfalls + +- Omitting readiness probes, so traffic hits a pod before it can serve and users see errors. +- Setting no resource requests, letting one noisy pod starve its neighbors. +- Baking secrets into the image or a ConfigMap instead of a Secret. +- Mismatched label selectors between Deployment and Service, leaving the Service with zero endpoints. +- Assuming a rolling update is safe without a probe — Kubernetes will happily route to a broken new pod. + +## Resources + +- [Kubernetes Concepts](https://kubernetes.io/docs/concepts/) — the object model, explained by the project. +- [Deployments](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/) — rolling updates and rollbacks. +- [Configure liveness, readiness and startup probes](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/) — probe semantics. +- [Ingress](https://kubernetes.io/docs/concepts/services-networking/ingress/) — routing external traffic into the cluster. + diff --git a/projects/devops/intermediate/02-kubernetes-deployment/README.pt-BR.md b/projects/devops/intermediate/02-kubernetes-deployment/README.pt-BR.md new file mode 100644 index 0000000..65ee890 --- /dev/null +++ b/projects/devops/intermediate/02-kubernetes-deployment/README.pt-BR.md @@ -0,0 +1,96 @@ +# Deploy no Kubernetes + +> 🌐 [English](./README.md) · **Português** + +**Domínio:** DevOps · **Nível:** Intermediário · **Tempo estimado:** 1–2 dias + +## Visão Geral + +Pegue uma aplicação web em contêiner e rode-a corretamente em um cluster Kubernetes — não apenas "kubectl run e torça", mas um deploy de verdade com manifestos declarativos, um endereço de serviço estável, ingress externo, configuração separada dos segredos, requisições de recursos, sondas de saúde e uma atualização gradual que entrega uma nova versão sem derrubar o tráfego. Você pode usar qualquer cluster: um local como kind, k3d ou minikube, ou um cluster gerenciado na nuvem. A lição é como o Kubernetes transforma um conjunto de arquivos YAML de estado desejado em um sistema em execução autocurável e atualizável. + +## Pré-requisitos + +- Uma imagem de contêiner de uma app, publicada em um registro que o cluster consiga puxar +- Um cluster funcional e o `kubectl` configurado contra ele +- Entendimento de contêineres, portas e variáveis de ambiente +- Familiaridade com YAML e o ciclo requisição/resposta de uma app web + +## Objetivos de Aprendizado + +Ao final, você deve ser capaz de: + +- Expressar o estado desejado com manifestos de Deployment, Service e Ingress +- Separar configuração (ConfigMap) de segredos e injetar ambos nos pods +- Definir requisições/limites de recursos e raciocinar sobre agendamento e evicção +- Configurar sondas de liveness e readiness para que o tráfego só atinja pods saudáveis +- Realizar uma atualização gradual e revertê-la quando a nova versão se comportar mal + +## Requisitos Funcionais + +1. A app deve ser descrita por um Deployment rodando ao menos duas réplicas. +2. Um Service deve dar aos pods um endereço estável dentro do cluster, independente da rotatividade de pods. +3. O tráfego externo deve chegar à app por meio de um Ingress (ou LoadBalancer equivalente). +4. Configuração não sensível deve vir de um ConfigMap; valores sensíveis, de um Secret. +5. Todo pod deve declarar requisições e limites de recursos. +6. Sondas de readiness e liveness devem manter o tráfego longe de pods que estão iniciando ou não saudáveis. +7. Uma atualização gradual deve entregar uma nova imagem com zero requisições perdidas, e `kubectl rollout undo` deve restaurar a versão anterior. + +## Marcos Sugeridos + +1. **Marco 1 — Rodar:** Deployment + Service, app acessível dentro do cluster. +2. **Marco 2 — Expor e configurar:** Adicione Ingress, ConfigMap e Secret; conecte a config aos pods. +3. **Marco 3 — Resiliência e atualizações:** Adicione sondas e limites de recursos; faça uma atualização gradual e um rollback. + +## Esboço de Dados e Interface + +```text +Relações entre objetos: + Ingress ──roteia──> Service ──seleciona(labels)──> Pods (do Deployment) + ConfigMap ─┐ + Secret ────┴─montado/env─> Pods + +Spec do Deployment (só estrutura): + replicas: 2 + strategy: RollingUpdate (maxUnavailable, maxSurge) + template: + containers: + - image: registry/app: + resources: { requests: {cpu, mem}, limits: {cpu, mem} } + readinessProbe: httpGet /healthz + livenessProbe: httpGet /healthz + envFrom: [configMapRef, secretRef] + +Atualização: kubectl set image ... -> novo ReplicaSet sobe, antigo desce +Rollback: kubectl rollout undo deployment/app +``` + +## Desafios Extras + +- Adicione um HorizontalPodAutoscaler que escala réplicas por CPU. +- Adicione um PodDisruptionBudget para que evicções voluntárias nunca levem a app abaixo de um piso. +- Divida em um StatefulSet um componente que precise de identidade estável e armazenamento. +- Adicione NetworkPolicies restringindo quais pods podem conversar entre si. + +## Definição de Pronto + +- [ ] Excluir um pod resulta no Kubernetes recriando-o automaticamente. +- [ ] O endereço do Service permanece estável enquanto os pods são substituídos. +- [ ] Config e segredos são injetados de ConfigMap/Secret, não embutidos na imagem. +- [ ] Uma atualização gradual conclui sem requisições falhas contra a app. +- [ ] `kubectl rollout undo` restaura a versão anterior e ela serve tráfego. + +## Armadilhas Comuns + +- Omitir sondas de readiness, fazendo o tráfego atingir um pod antes de ele poder servir e os usuários verem erros. +- Não definir requisições de recursos, deixando um pod barulhento sufocar seus vizinhos. +- Embutir segredos na imagem ou em um ConfigMap em vez de um Secret. +- Seletores de labels incompatíveis entre Deployment e Service, deixando o Service com zero endpoints. +- Supor que uma atualização gradual é segura sem uma sonda — o Kubernetes vai alegremente rotear para um pod novo quebrado. + +## Recursos + +- [Conceitos do Kubernetes](https://kubernetes.io/docs/concepts/) — o modelo de objetos, explicado pelo projeto. +- [Deployments](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/) — atualizações graduais e rollbacks. +- [Configurar sondas liveness, readiness e startup](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/) — semântica das sondas. +- [Ingress](https://kubernetes.io/docs/concepts/services-networking/ingress/) — roteando tráfego externo para dentro do cluster. + diff --git a/projects/devops/intermediate/03-terraform-iac/README.md b/projects/devops/intermediate/03-terraform-iac/README.md index 782b2dd..a962082 100644 --- a/projects/devops/intermediate/03-terraform-iac/README.md +++ b/projects/devops/intermediate/03-terraform-iac/README.md @@ -1,34 +1,91 @@ # Infrastructure as Code (Terraform) -## Idea -Define infrastructure using code with Terraform. Learn about IaC and infrastructure automation. +> 🌐 **English** · [Português](./README.pt-BR.md) + +**Domain:** DevOps · **Level:** Intermediate · **Estimated time:** 1–2 days + +## Overview + +Provision a small but realistic piece of infrastructure — say a network, a compute instance or container service, and a managed database — entirely from Terraform code, with no clicking in a cloud console. The point is not to memorize resource names but to internalize the IaC loop: write configuration, `plan` to preview the diff, `apply` to converge reality to the desired state, and store state remotely so a team can collaborate. Above all, your configuration must be idempotent: running `apply` twice in a row with no code changes must produce no changes. + +## Prerequisites + +- A cloud account (AWS, GCP, Azure) or a local provider like Docker +- Terraform (or OpenTofu) installed and authenticated to the provider +- Understanding of the resources you intend to create (network, compute, storage) +- Comfort with the command line and reading a diff ## Learning Objectives -- Learn Terraform syntax -- Manage infrastructure -- Handle state -- Implement modularity -- Plan and apply changes - -## Implementation Tips -- Create Terraform configurations -- Implement resource modules -- Add variable management -- Create outputs -- Implement state management -- Add remote state storage -- Create workspaces -- Implement plan reviews -- Add version control -- Implement testing (terraform validate) -- Create documentation -- Add policy enforcement -- Implement cost estimation -- Build operational workflows - -## Key Challenges -- State management complexity -- Module design -- Drift detection -- Plan/apply safety -- Multi-environment handling + +By the end, you should be able to: + +- Declare resources and understand the plan/apply/destroy lifecycle +- Parameterize configuration with input variables and expose results as outputs +- Factor repeated resources into a reusable module +- Store state remotely with locking so concurrent applies can't corrupt it +- Detect and reconcile drift between code and real infrastructure + +## Functional Requirements + +1. All infrastructure must be defined in version-controlled Terraform files — no manual console changes. +2. `terraform plan` must show an accurate preview before any change is applied. +3. Configuration must be idempotent: a second `apply` with no code change reports zero changes. +4. Environment-specific values (region, sizes, names) must be variables, not hard-coded. +5. At least one group of resources must be extracted into a reusable module. +6. State must be stored in a remote backend with locking enabled. +7. `terraform destroy` must cleanly tear down everything the configuration created. + +## Suggested Milestones + +1. **Milestone 1 — First apply:** Define a couple of resources, run plan/apply, verify they exist. +2. **Milestone 2 — Variables & modules:** Parameterize with variables/outputs and extract a module. +3. **Milestone 3 — Remote state & drift:** Move state to a remote backend with locking; change a resource by hand and reconcile the drift. + +## Data & Interface Sketch + +```text +Repository layout (structure only): + main.tf root composition, calls module(s) + variables.tf typed inputs (region, instance_size, env) + outputs.tf exported values (ip, db_endpoint) + backend.tf remote state config (bucket + lock table) + modules/network/ reusable module (vpc, subnets, ...) + +Lifecycle: + write .tf -> terraform plan -> review diff -> terraform apply + | + drift (manual change) <─────── terraform plan shows delta <──┘ + +State: remote backend, locked during apply (no concurrent writers) +``` + +## Stretch Goals + +- Add multiple environments via workspaces or separate variable files. +- Run `terraform validate` and `fmt` in CI, and post the `plan` output on pull requests. +- Add a policy check (OPA/Sentinel or tflint) that blocks disallowed resource configs. +- Import an existing, manually-created resource into Terraform state. + +## Definition of Done + +- [ ] A fresh clone can `plan`/`apply` and reproduce the infrastructure from scratch. +- [ ] A second `apply` with no changes reports "No changes." +- [ ] No credentials or environment values are hard-coded in the .tf files. +- [ ] State lives in a remote backend and is locked during apply. +- [ ] `terraform destroy` leaves no orphaned resources behind. + +## Common Pitfalls + +- Editing infrastructure by hand after applying, causing drift that the next apply silently reverts or fights. +- Committing the local `terraform.tfstate` (with secrets) to git instead of using a remote backend. +- Building non-idempotent config (e.g. timestamps in names) so every apply shows spurious changes. +- Skipping `plan` and applying blind, then discovering it wanted to destroy the database. +- Hard-coding region/account values, making the config impossible to reuse across environments. + +## Resources + +- [Terraform documentation](https://developer.hashicorp.com/terraform/docs) — language, workflow, and providers. +- [Terraform state](https://developer.hashicorp.com/terraform/language/state) — why state exists and how remote backends work. +- [Standard module structure](https://developer.hashicorp.com/terraform/language/modules/develop/structure) — how to lay out a reusable module. +- [What is Infrastructure as Code?](https://developer.hashicorp.com/terraform/intro) — the concept and its benefits. + diff --git a/projects/devops/intermediate/03-terraform-iac/README.pt-BR.md b/projects/devops/intermediate/03-terraform-iac/README.pt-BR.md new file mode 100644 index 0000000..d8051a7 --- /dev/null +++ b/projects/devops/intermediate/03-terraform-iac/README.pt-BR.md @@ -0,0 +1,91 @@ +# Infraestrutura como Código (Terraform) + +> 🌐 [English](./README.md) · **Português** + +**Domínio:** DevOps · **Nível:** Intermediário · **Tempo estimado:** 1–2 dias + +## Visão Geral + +Provisione uma peça de infraestrutura pequena, mas realista — digamos uma rede, uma instância de computação ou serviço de contêineres e um banco de dados gerenciado — inteiramente a partir de código Terraform, sem cliques em console de nuvem. O ponto não é memorizar nomes de recursos, mas internalizar o ciclo de IaC: escrever configuração, `plan` para pré-visualizar o diff, `apply` para convergir a realidade ao estado desejado e guardar o estado remotamente para que um time possa colaborar. Acima de tudo, sua configuração deve ser idempotente: rodar `apply` duas vezes seguidas sem mudanças de código não deve produzir nenhuma alteração. + +## Pré-requisitos + +- Uma conta de nuvem (AWS, GCP, Azure) ou um provider local como o Docker +- Terraform (ou OpenTofu) instalado e autenticado no provider +- Entendimento dos recursos que você pretende criar (rede, computação, armazenamento) +- Conforto com a linha de comando e leitura de um diff + +## Objetivos de Aprendizado + +Ao final, você deve ser capaz de: + +- Declarar recursos e entender o ciclo de vida plan/apply/destroy +- Parametrizar a configuração com variáveis de entrada e expor resultados como outputs +- Fatorar recursos repetidos em um módulo reutilizável +- Guardar o estado remotamente com locking para que applies concorrentes não o corrompam +- Detectar e reconciliar drift entre o código e a infraestrutura real + +## Requisitos Funcionais + +1. Toda a infraestrutura deve ser definida em arquivos Terraform versionados — nenhuma mudança manual no console. +2. `terraform plan` deve mostrar uma pré-visualização precisa antes de qualquer mudança ser aplicada. +3. A configuração deve ser idempotente: um segundo `apply` sem mudança de código reporta zero alterações. +4. Valores específicos de ambiente (região, tamanhos, nomes) devem ser variáveis, não fixados no código. +5. Ao menos um grupo de recursos deve ser extraído em um módulo reutilizável. +6. O estado deve ser guardado em um backend remoto com locking habilitado. +7. `terraform destroy` deve remover de forma limpa tudo o que a configuração criou. + +## Marcos Sugeridos + +1. **Marco 1 — Primeiro apply:** Defina alguns recursos, rode plan/apply, verifique que existem. +2. **Marco 2 — Variáveis e módulos:** Parametrize com variáveis/outputs e extraia um módulo. +3. **Marco 3 — Estado remoto e drift:** Mova o estado para um backend remoto com locking; altere um recurso à mão e reconcilie o drift. + +## Esboço de Dados e Interface + +```text +Layout do repositório (só estrutura): + main.tf composição raiz, chama o(s) módulo(s) + variables.tf entradas tipadas (region, instance_size, env) + outputs.tf valores exportados (ip, db_endpoint) + backend.tf config de estado remoto (bucket + tabela de lock) + modules/network/ módulo reutilizável (vpc, subnets, ...) + +Ciclo de vida: + escreve .tf -> terraform plan -> revisa diff -> terraform apply + | + drift (mudança manual) <────── terraform plan mostra delta <──┘ + +Estado: backend remoto, travado durante o apply (sem escritores concorrentes) +``` + +## Desafios Extras + +- Adicione múltiplos ambientes via workspaces ou arquivos de variáveis separados. +- Rode `terraform validate` e `fmt` na CI e poste a saída do `plan` nos pull requests. +- Adicione uma verificação de política (OPA/Sentinel ou tflint) que bloqueie configs de recursos proibidos. +- Importe para o estado do Terraform um recurso existente criado manualmente. + +## Definição de Pronto + +- [ ] Um clone novo consegue `plan`/`apply` e reproduzir a infraestrutura do zero. +- [ ] Um segundo `apply` sem mudanças reporta "No changes." +- [ ] Nenhuma credencial ou valor de ambiente está fixado nos arquivos .tf. +- [ ] O estado vive em um backend remoto e é travado durante o apply. +- [ ] `terraform destroy` não deixa recursos órfãos para trás. + +## Armadilhas Comuns + +- Editar a infraestrutura à mão após o apply, causando drift que o próximo apply reverte ou combate silenciosamente. +- Commitar o `terraform.tfstate` local (com segredos) no git em vez de usar um backend remoto. +- Construir config não idempotente (ex.: timestamps em nomes) fazendo cada apply mostrar mudanças espúrias. +- Pular o `plan` e aplicar às cegas, para então descobrir que ele queria destruir o banco de dados. +- Fixar valores de região/conta, tornando a config impossível de reutilizar entre ambientes. + +## Recursos + +- [Documentação do Terraform](https://developer.hashicorp.com/terraform/docs) — linguagem, fluxo de trabalho e providers. +- [Estado do Terraform](https://developer.hashicorp.com/terraform/language/state) — por que o estado existe e como backends remotos funcionam. +- [Estrutura padrão de módulo](https://developer.hashicorp.com/terraform/language/modules/develop/structure) — como organizar um módulo reutilizável. +- [O que é Infraestrutura como Código?](https://developer.hashicorp.com/terraform/intro) — o conceito e seus benefícios. + diff --git a/projects/devops/intermediate/04-centralized-logging/README.md b/projects/devops/intermediate/04-centralized-logging/README.md index 18596df..4857fa0 100644 --- a/projects/devops/intermediate/04-centralized-logging/README.md +++ b/projects/devops/intermediate/04-centralized-logging/README.md @@ -1,34 +1,93 @@ # Centralized Logging System -## Idea -Build a centralized logging solution collecting logs from multiple sources. Learn about log aggregation and analysis. +> 🌐 **English** · [Português](./README.pt-BR.md) + +**Domain:** DevOps · **Level:** Intermediate · **Estimated time:** 1–2 days + +## Overview + +Build a pipeline that collects logs from several running services, ships them to a central store, and makes them searchable in one place. Instead of SSHing into three machines and grepping files, you should be able to answer "show me every error from the payment service in the last hour" from a single query interface. Pick a stack — ELK/EFK (Elasticsearch + Kibana), or Grafana Loki, or an equivalent — and wire up collection, parsing, storage with a retention policy, and dashboards. The theme is turning scattered, unstructured text into queryable, correlated, bounded data. + +## Prerequisites + +- Two or more services (or containers) that emit logs, ideally in different formats +- Docker / Docker Compose or a small cluster to host the logging stack +- Understanding of stdout/stderr, log levels, and structured vs plain-text logs +- Basic familiarity with querying and JSON ## Learning Objectives -- Collect logs from multiple sources -- Aggregate and store -- Search and analyze -- Create dashboards -- Implement retention - -## Implementation Tips -- Choose logging stack (ELK, EFK, Loki) -- Implement log collectors (Fluentd, Logstash, Filebeat) -- Add parsers and filters -- Create index management -- Implement search capabilities -- Add visualization dashboards -- Create alerting rules -- Implement log retention -- Add performance optimization -- Implement access control -- Create compliance policies -- Add log correlation -- Implement debugging tools -- Build user interface - -## Key Challenges -- Log volume management -- Search performance -- Storage optimization -- Retention policies -- Multi-tenant isolation + +By the end, you should be able to: + +- Ship logs from multiple sources with a collector/agent (Fluent Bit, Fluentd, Filebeat, Promtail) +- Parse and enrich logs into structured fields (level, service, timestamp, trace id) +- Store logs in a searchable backend and query across all sources at once +- Apply a retention policy so storage doesn't grow without bound +- Build a dashboard and at least one alert on a log-derived signal + +## Functional Requirements + +1. Logs from at least two distinct services must be collected without changing app code beyond structured output. +2. A collector must forward logs to the central store, buffering to avoid loss during backpressure. +3. Logs must be parsed into structured fields, including level, service name, and timestamp. +4. A single query must be able to filter across all services by field (e.g. `level=error AND service=payments`). +5. A retention policy must automatically drop or archive logs older than a defined window. +6. A dashboard must visualize log volume and error rate over time. +7. An alert must fire when the error rate crosses a threshold. + +## Suggested Milestones + +1. **Milestone 1 — Collect & store:** Get logs from services into the central backend, viewable raw. +2. **Milestone 2 — Parse & query:** Structure logs into fields and query across sources. +3. **Milestone 3 — Retain & observe:** Add retention, a dashboard, and a threshold alert. + +## Data & Interface Sketch + +```text +Flow: + service A ─┐ + service B ─┼─> collector/agent ─(buffer)─> store/index ─> query UI + dashboards + service C ─┘ | + retention job (age-out) + +Structured log record (target shape): + timestamp: ISO-8601 + level: DEBUG|INFO|WARN|ERROR + service: string + message: string + trace_id: string (optional, for correlation) + +Query example (conceptual): + service = "payments" AND level = "ERROR" AND time > now-1h +``` + +## Stretch Goals + +- Correlate logs across services using a shared trace/request id. +- Add multi-tenancy or role-based access so teams only see their own logs. +- Ship metrics derived from logs (e.g. error count) into a metrics system. +- Add index/stream lifecycle tiers (hot/warm/cold) to control storage cost. + +## Definition of Done + +- [ ] Logs from all sources appear in the central store within seconds of being emitted. +- [ ] A single query filters by level and service across every source. +- [ ] Logs are structured, not stored as opaque text blobs. +- [ ] Old logs are removed or archived automatically per the retention policy. +- [ ] A dashboard shows error rate and an alert fires when it spikes. + +## Common Pitfalls + +- Collecting raw text without parsing, so you can grep but never aggregate or alert. +- No buffering in the collector, so a store outage silently drops logs. +- Forgetting retention, letting the index grow until it exhausts disk and takes the store down. +- Inconsistent timestamps/timezones across services, making correlation misleading. +- Logging secrets or PII into a searchable store without redaction. + +## Resources + +- [Grafana Loki documentation](https://grafana.com/docs/loki/latest/) — log aggregation designed to be cost-efficient. +- [Elastic Stack (ELK) documentation](https://www.elastic.co/guide/index.html) — Elasticsearch, Logstash, Kibana. +- [Fluent Bit documentation](https://docs.fluentbit.io/manual) — lightweight log collection and parsing. +- [Twelve-Factor App: Logs](https://12factor.net/logs) — why apps should treat logs as event streams. + diff --git a/projects/devops/intermediate/04-centralized-logging/README.pt-BR.md b/projects/devops/intermediate/04-centralized-logging/README.pt-BR.md new file mode 100644 index 0000000..44ac4a7 --- /dev/null +++ b/projects/devops/intermediate/04-centralized-logging/README.pt-BR.md @@ -0,0 +1,93 @@ +# Sistema de Logging Centralizado + +> 🌐 [English](./README.md) · **Português** + +**Domínio:** DevOps · **Nível:** Intermediário · **Tempo estimado:** 1–2 dias + +## Visão Geral + +Construa um pipeline que coleta logs de vários serviços em execução, os envia para um armazenamento central e os torna pesquisáveis em um só lugar. Em vez de acessar três máquinas via SSH e dar grep em arquivos, você deve conseguir responder "mostre todo erro do serviço de pagamentos na última hora" a partir de uma única interface de consulta. Escolha uma stack — ELK/EFK (Elasticsearch + Kibana), ou Grafana Loki, ou equivalente — e monte coleta, parsing, armazenamento com política de retenção e dashboards. O tema é transformar texto disperso e não estruturado em dados consultáveis, correlacionados e limitados. + +## Pré-requisitos + +- Dois ou mais serviços (ou contêineres) que emitam logs, idealmente em formatos diferentes +- Docker / Docker Compose ou um pequeno cluster para hospedar a stack de logging +- Entendimento de stdout/stderr, níveis de log e logs estruturados vs texto puro +- Familiaridade básica com consultas e JSON + +## Objetivos de Aprendizado + +Ao final, você deve ser capaz de: + +- Enviar logs de múltiplas fontes com um coletor/agente (Fluent Bit, Fluentd, Filebeat, Promtail) +- Fazer parsing e enriquecer logs em campos estruturados (nível, serviço, timestamp, trace id) +- Guardar logs em um backend pesquisável e consultar todas as fontes de uma vez +- Aplicar uma política de retenção para que o armazenamento não cresça sem limite +- Construir um dashboard e ao menos um alerta sobre um sinal derivado de logs + +## Requisitos Funcionais + +1. Logs de ao menos dois serviços distintos devem ser coletados sem alterar o código da app além da saída estruturada. +2. Um coletor deve encaminhar logs ao armazenamento central, com buffer para evitar perda durante backpressure. +3. Logs devem ser transformados em campos estruturados, incluindo nível, nome do serviço e timestamp. +4. Uma única consulta deve conseguir filtrar entre todos os serviços por campo (ex.: `level=error AND service=payments`). +5. Uma política de retenção deve automaticamente descartar ou arquivar logs mais antigos que uma janela definida. +6. Um dashboard deve visualizar o volume de logs e a taxa de erros ao longo do tempo. +7. Um alerta deve disparar quando a taxa de erros cruzar um limite. + +## Marcos Sugeridos + +1. **Marco 1 — Coletar e guardar:** Leve os logs dos serviços ao backend central, visíveis em bruto. +2. **Marco 2 — Parsear e consultar:** Estruture os logs em campos e consulte entre fontes. +3. **Marco 3 — Reter e observar:** Adicione retenção, um dashboard e um alerta por limite. + +## Esboço de Dados e Interface + +```text +Fluxo: + serviço A ─┐ + serviço B ─┼─> coletor/agente ─(buffer)─> store/índice ─> UI de consulta + dashboards + serviço C ─┘ | + job de retenção (expiração) + +Registro de log estruturado (formato alvo): + timestamp: ISO-8601 + level: DEBUG|INFO|WARN|ERROR + service: string + message: string + trace_id: string (opcional, para correlação) + +Exemplo de consulta (conceitual): + service = "payments" AND level = "ERROR" AND time > now-1h +``` + +## Desafios Extras + +- Correlacione logs entre serviços usando um trace/request id compartilhado. +- Adicione multitenância ou acesso por papel para que times vejam apenas seus próprios logs. +- Envie métricas derivadas de logs (ex.: contagem de erros) para um sistema de métricas. +- Adicione camadas de ciclo de vida de índice/stream (hot/warm/cold) para controlar o custo de armazenamento. + +## Definição de Pronto + +- [ ] Logs de todas as fontes aparecem no armazenamento central segundos após serem emitidos. +- [ ] Uma única consulta filtra por nível e serviço em todas as fontes. +- [ ] Logs são estruturados, não guardados como blobs opacos de texto. +- [ ] Logs antigos são removidos ou arquivados automaticamente conforme a política de retenção. +- [ ] Um dashboard mostra a taxa de erros e um alerta dispara quando ela sobe. + +## Armadilhas Comuns + +- Coletar texto bruto sem parsing, permitindo grep mas nunca agregação ou alerta. +- Sem buffer no coletor, uma indisponibilidade do armazenamento descarta logs silenciosamente. +- Esquecer a retenção, deixando o índice crescer até esgotar o disco e derrubar o armazenamento. +- Timestamps/fusos inconsistentes entre serviços, tornando a correlação enganosa. +- Registrar segredos ou dados pessoais em um armazenamento pesquisável sem mascaramento. + +## Recursos + +- [Documentação do Grafana Loki](https://grafana.com/docs/loki/latest/) — agregação de logs projetada para ser econômica. +- [Documentação do Elastic Stack (ELK)](https://www.elastic.co/guide/index.html) — Elasticsearch, Logstash, Kibana. +- [Documentação do Fluent Bit](https://docs.fluentbit.io/manual) — coleta e parsing leves de logs. +- [App de Doze Fatores: Logs](https://12factor.net/pt_br/logs) — por que apps devem tratar logs como fluxos de eventos. + diff --git a/projects/devops/intermediate/05-monitoring-prometheus-grafana/README.md b/projects/devops/intermediate/05-monitoring-prometheus-grafana/README.md index d7a23b8..cc6ec56 100644 --- a/projects/devops/intermediate/05-monitoring-prometheus-grafana/README.md +++ b/projects/devops/intermediate/05-monitoring-prometheus-grafana/README.md @@ -1,34 +1,92 @@ # Monitoring Stack (Prometheus + Grafana) -## Idea -Set up a monitoring and alerting stack with Prometheus and Grafana. Learn about metrics collection and visualization. +> 🌐 **English** · [Português](./README.pt-BR.md) + +**Domain:** DevOps · **Level:** Intermediate · **Estimated time:** 1–2 days + +## Overview + +Stand up a metrics-based observability stack: instrument an application to expose metrics, have Prometheus scrape and store them as time series, visualize them in Grafana, and route alerts through Alertmanager when something crosses a threshold. This is the "know your system is healthy before your users tell you" project. You will move from raw counters to meaningful signals — request rate, error rate, and latency (the RED method) — and learn why alerting on symptoms beats alerting on causes. + +## Prerequisites + +- An application you can instrument (or that already exposes Prometheus metrics) +- Docker / Docker Compose or a cluster to run Prometheus, Grafana, and Alertmanager +- Understanding of counters, gauges, and histograms as metric types +- Basic familiarity with querying and dashboards ## Learning Objectives -- Collect metrics -- Store time-series data -- Create dashboards -- Implement alerting -- Handle scalability - -## Implementation Tips -- Configure Prometheus -- Implement service discovery -- Add metric collection -- Create recording rules -- Implement alerting rules -- Add notification channels -- Configure Grafana dashboards -- Implement alerting -- Add data retention -- Create performance optimization -- Implement multi-prometheus setup -- Add authentication -- Create alertmanager configuration -- Build operational dashboards - -## Key Challenges -- Metric cardinality -- Retention policies -- Query performance -- Alert tuning -- Scalability + +By the end, you should be able to: + +- Instrument an app with counters, gauges, and histograms exposed on a `/metrics` endpoint +- Configure Prometheus to discover and scrape targets +- Write PromQL queries for rate, error ratio, and latency percentiles +- Build a Grafana dashboard from those queries +- Define alerting rules and route notifications through Alertmanager + +## Functional Requirements + +1. The target app must expose metrics in the Prometheus exposition format on an HTTP endpoint. +2. Prometheus must scrape the target on an interval and store the series. +3. The app must expose at least request rate, error count, and request-duration histogram. +4. A Grafana dashboard must show the RED signals (Rate, Errors, Duration) over time. +5. At least one alerting rule must be defined (e.g. error ratio above a threshold for N minutes). +6. Alertmanager must deliver a firing alert to a notification channel. +7. Recording or alerting rules must use `rate()`/`histogram_quantile()` correctly over a time window. + +## Suggested Milestones + +1. **Milestone 1 — Instrument & scrape:** Expose `/metrics`, get Prometheus scraping it. +2. **Milestone 2 — Visualize:** Write PromQL for RED signals and build a Grafana dashboard. +3. **Milestone 3 — Alert:** Add an alert rule and route it through Alertmanager to a channel. + +## Data & Interface Sketch + +```text +Flow: + app /metrics ──scrape──> Prometheus (TSDB) ──query(PromQL)──> Grafana dashboards + | + eval alert rules ─> Alertmanager ─> notify (email/Slack/webhook) + +Metric types on /metrics: + http_requests_total{method,status} counter + http_request_duration_seconds histogram (buckets) + process_resident_memory_bytes gauge + +RED queries (conceptual PromQL): + rate: sum(rate(http_requests_total[5m])) + errors: sum(rate(http_requests_total{status=~"5.."}[5m])) + duration: histogram_quantile(0.95, rate(http_request_duration_seconds_bucket[5m])) +``` + +## Stretch Goals + +- Add exporters (node_exporter, cAdvisor) for host/container metrics alongside app metrics. +- Add recording rules to precompute expensive queries used by dashboards. +- Configure alert routing with severities, grouping, and silences in Alertmanager. +- Provision dashboards and datasources as code so the stack is reproducible. + +## Definition of Done + +- [ ] Prometheus shows the target as "up" and stores its series. +- [ ] A Grafana dashboard displays rate, error ratio, and p95 latency. +- [ ] PromQL uses `rate()` over a range, not raw counter values. +- [ ] An alert transitions to firing when the condition holds and reaches a channel. +- [ ] Restarting the app does not produce false alerts from counter resets. + +## Common Pitfalls + +- Graphing a raw counter instead of its `rate()`, producing an ever-rising, meaningless line. +- Alerting on every transient blip with no `for:` duration, creating alert fatigue. +- High-cardinality labels (user id, request id) blowing up Prometheus memory. +- Misreading histogram percentiles by applying `histogram_quantile` without `rate()` on the buckets. +- Alerting on causes (CPU high) rather than symptoms (users seeing errors), so pages don't map to impact. + +## Resources + +- [Prometheus documentation](https://prometheus.io/docs/introduction/overview/) — data model, scraping, and PromQL. +- [Grafana documentation](https://grafana.com/docs/grafana/latest/) — dashboards and data sources. +- [Alertmanager](https://prometheus.io/docs/alerting/latest/alertmanager/) — routing, grouping, and silencing alerts. +- [Google SRE Book: Monitoring Distributed Systems](https://sre.google/sre-book/monitoring-distributed-systems/) — signals worth alerting on. + diff --git a/projects/devops/intermediate/05-monitoring-prometheus-grafana/README.pt-BR.md b/projects/devops/intermediate/05-monitoring-prometheus-grafana/README.pt-BR.md new file mode 100644 index 0000000..4879bc0 --- /dev/null +++ b/projects/devops/intermediate/05-monitoring-prometheus-grafana/README.pt-BR.md @@ -0,0 +1,92 @@ +# Stack de Monitoramento (Prometheus + Grafana) + +> 🌐 [English](./README.md) · **Português** + +**Domínio:** DevOps · **Nível:** Intermediário · **Tempo estimado:** 1–2 dias + +## Visão Geral + +Suba uma stack de observabilidade baseada em métricas: instrumente uma aplicação para expor métricas, faça o Prometheus coletá-las e armazená-las como séries temporais, visualize-as no Grafana e roteie alertas pelo Alertmanager quando algo cruzar um limite. Este é o projeto de "saber que seu sistema está saudável antes dos seus usuários avisarem". Você vai passar de contadores brutos para sinais significativos — taxa de requisições, taxa de erros e latência (o método RED) — e aprender por que alertar sobre sintomas é melhor do que alertar sobre causas. + +## Pré-requisitos + +- Uma aplicação que você possa instrumentar (ou que já exponha métricas Prometheus) +- Docker / Docker Compose ou um cluster para rodar Prometheus, Grafana e Alertmanager +- Entendimento de counters, gauges e histograms como tipos de métrica +- Familiaridade básica com consultas e dashboards + +## Objetivos de Aprendizado + +Ao final, você deve ser capaz de: + +- Instrumentar uma app com counters, gauges e histograms expostos em um endpoint `/metrics` +- Configurar o Prometheus para descobrir e coletar alvos +- Escrever consultas PromQL para taxa, proporção de erros e percentis de latência +- Construir um dashboard no Grafana a partir dessas consultas +- Definir regras de alerta e rotear notificações pelo Alertmanager + +## Requisitos Funcionais + +1. A app alvo deve expor métricas no formato de exposição do Prometheus em um endpoint HTTP. +2. O Prometheus deve coletar o alvo em um intervalo e armazenar as séries. +3. A app deve expor ao menos taxa de requisições, contagem de erros e histograma de duração de requisição. +4. Um dashboard no Grafana deve mostrar os sinais RED (Taxa, Erros, Duração) ao longo do tempo. +5. Ao menos uma regra de alerta deve ser definida (ex.: proporção de erros acima de um limite por N minutos). +6. O Alertmanager deve entregar um alerta disparado a um canal de notificação. +7. Regras de recording ou de alerta devem usar `rate()`/`histogram_quantile()` corretamente sobre uma janela de tempo. + +## Marcos Sugeridos + +1. **Marco 1 — Instrumentar e coletar:** Exponha `/metrics`, faça o Prometheus coletá-lo. +2. **Marco 2 — Visualizar:** Escreva PromQL para os sinais RED e construa um dashboard no Grafana. +3. **Marco 3 — Alertar:** Adicione uma regra de alerta e roteie-a pelo Alertmanager até um canal. + +## Esboço de Dados e Interface + +```text +Fluxo: + app /metrics ──coleta──> Prometheus (TSDB) ──consulta(PromQL)──> dashboards Grafana + | + avalia regras de alerta ─> Alertmanager ─> notifica (email/Slack/webhook) + +Tipos de métrica em /metrics: + http_requests_total{method,status} counter + http_request_duration_seconds histogram (buckets) + process_resident_memory_bytes gauge + +Consultas RED (PromQL conceitual): + taxa: sum(rate(http_requests_total[5m])) + erros: sum(rate(http_requests_total{status=~"5.."}[5m])) + duração: histogram_quantile(0.95, rate(http_request_duration_seconds_bucket[5m])) +``` + +## Desafios Extras + +- Adicione exporters (node_exporter, cAdvisor) para métricas de host/contêiner ao lado das da app. +- Adicione recording rules para pré-computar consultas caras usadas pelos dashboards. +- Configure roteamento de alertas com severidades, agrupamento e silences no Alertmanager. +- Provisione dashboards e datasources como código para que a stack seja reproduzível. + +## Definição de Pronto + +- [ ] O Prometheus mostra o alvo como "up" e armazena suas séries. +- [ ] Um dashboard no Grafana exibe taxa, proporção de erros e latência p95. +- [ ] O PromQL usa `rate()` sobre um intervalo, não valores brutos do counter. +- [ ] Um alerta transiciona para disparado quando a condição se mantém e chega a um canal. +- [ ] Reiniciar a app não produz alertas falsos por resets de counter. + +## Armadilhas Comuns + +- Plotar um counter bruto em vez do seu `rate()`, produzindo uma linha sempre crescente e sem sentido. +- Alertar a cada oscilação transitória sem uma duração `for:`, criando fadiga de alertas. +- Labels de alta cardinalidade (id de usuário, id de requisição) explodindo a memória do Prometheus. +- Interpretar mal percentis de histograma aplicando `histogram_quantile` sem `rate()` nos buckets. +- Alertar sobre causas (CPU alta) em vez de sintomas (usuários vendo erros), fazendo os pages não mapearem para impacto. + +## Recursos + +- [Documentação do Prometheus](https://prometheus.io/docs/introduction/overview/) — modelo de dados, coleta e PromQL. +- [Documentação do Grafana](https://grafana.com/docs/grafana/latest/) — dashboards e fontes de dados. +- [Alertmanager](https://prometheus.io/docs/alerting/latest/alertmanager/) — roteamento, agrupamento e silêncio de alertas. +- [Livro de SRE do Google: Monitorando Sistemas Distribuídos](https://sre.google/sre-book/monitoring-distributed-systems/) — sinais que valem alerta. + diff --git a/projects/devops/intermediate/06-blue-green-deployment/README.md b/projects/devops/intermediate/06-blue-green-deployment/README.md index 7f40e62..774e459 100644 --- a/projects/devops/intermediate/06-blue-green-deployment/README.md +++ b/projects/devops/intermediate/06-blue-green-deployment/README.md @@ -1,34 +1,93 @@ # Blue/Green Deployment -## Idea -Implement a blue/green deployment strategy for zero-downtime deployments. Learn about deployment strategies. +> 🌐 **English** · [Português](./README.pt-BR.md) + +**Domain:** DevOps · **Level:** Intermediate · **Estimated time:** 1–2 days + +## Overview + +Implement a blue/green deployment: run two identical production environments — "blue" (live) and "green" (idle) — deploy the new version to the idle one, validate it in isolation, then flip a router or load balancer to send all traffic to it in a single atomic switch. If anything is wrong, flip back instantly. The value is zero-downtime releases and an instant rollback that doesn't require a rebuild. You will confront the hard parts everyone skips: how to health-check the idle environment before the switch, and what to do about database schema changes that both versions must tolerate. + +## Prerequisites + +- A deployable app and a router/load balancer you can reprogram (Nginx, HAProxy, cloud LB, or Kubernetes Service) +- Two environments you can run in parallel (containers, VMs, or namespaces) +- Understanding of health checks and how traffic is routed to a backend +- Awareness that the database is usually shared between blue and green ## Learning Objectives -- Understand blue/green pattern -- Implement routing switch -- Validate new version -- Handle rollback -- Monitor during transition - -## Implementation Tips -- Create parallel environments -- Implement load balancer switching -- Add health checks -- Create validation steps -- Implement traffic switching -- Add rollback capability -- Create monitoring during switch -- Implement smoky testing -- Add traffic gradual shift -- Create monitoring dashboards -- Implement automated rollback -- Add notifications -- Create operational runbooks -- Build automation - -## Key Challenges -- Load balancer switching -- Database migration -- Session management -- Validation completeness -- Quick rollback + +By the end, you should be able to: + +- Run two parallel, independently deployable environments behind one entry point +- Deploy and validate a new version without any user traffic reaching it +- Switch all traffic atomically and roll back by switching again +- Health-check the idle environment as a gate before the switch +- Reason about schema changes that must be backward-compatible during the overlap + +## Functional Requirements + +1. Two environments (blue and green) must be runnable simultaneously behind a single router. +2. A new version must deploy to the idle environment while the live one keeps serving. +3. The idle environment must pass a health/smoke check before it can receive traffic. +4. The traffic switch must be atomic — no request should hit a half-switched state. +5. Rollback must be a single switch back to the previous environment, with no rebuild. +6. Users must observe zero downtime and zero failed requests across the switch. +7. The active environment (blue vs green) must be observable at any time. + +## Suggested Milestones + +1. **Milestone 1 — Two environments:** Run blue and green behind one router; point it at blue. +2. **Milestone 2 — Deploy & validate idle:** Deploy to green, health-check it while blue serves. +3. **Milestone 3 — Switch & rollback:** Flip traffic to green, verify, then practice an instant rollback. + +## Data & Interface Sketch + +```text +Topology: + ┌──────────┐ + clients ───────> │ router │ ──(active)──> BLUE (v1, live) + └──────────┘ └─────> GREEN (v2, idle, being validated) + +Switch = repoint router upstream from BLUE to GREEN (atomic) +Rollback = repoint back to BLUE + +Gate before switch: + deploy v2 -> GREEN + run health/smoke checks against GREEN directly (not via router) + all green? -> switch ; else -> abort, GREEN stays idle + +Shared DB caveat: + schema must satisfy BOTH v1 and v2 during overlap (expand/contract) +``` + +## Stretch Goals + +- Automate the whole flip from a pipeline, with the health gate as a required step. +- Add a canary step: route a small percentage to green before the full switch. +- Model an expand/contract migration so a schema change is safe across the switch. +- Keep the old environment warm for a defined window before reclaiming it. + +## Definition of Done + +- [ ] Blue and green run side by side with independent versions. +- [ ] A new version is validated on the idle environment before any traffic reaches it. +- [ ] The switch causes zero failed requests (verified with a load generator during the flip). +- [ ] Rollback is a single re-switch with no rebuild and completes in seconds. +- [ ] The currently active environment is always identifiable. + +## Common Pitfalls + +- Switching before the idle environment is truly ready, so the "zero downtime" release serves errors. +- A non-atomic switch (e.g. editing config on multiple LBs one by one) leaving a split-brain window. +- Forgetting the shared database: a v2-only schema change breaks v1 the instant you'd need to roll back. +- Reclaiming the old environment immediately, destroying your instant-rollback safety net. +- Draining connections abruptly, cutting off in-flight requests at the moment of the switch. + +## Resources + +- [Martin Fowler: BlueGreenDeployment](https://martinfowler.com/bliki/BlueGreenDeployment.html) — the canonical description of the pattern. +- [AWS: Blue/Green deployments whitepaper](https://docs.aws.amazon.com/whitepapers/latest/blue-green-deployments/welcome.html) — techniques and trade-offs. +- [Expand/contract (parallel change)](https://martinfowler.com/bliki/ParallelChange.html) — safe schema changes across versions. +- [Kubernetes Deployments](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/) — one way to model blue/green with Services. + diff --git a/projects/devops/intermediate/06-blue-green-deployment/README.pt-BR.md b/projects/devops/intermediate/06-blue-green-deployment/README.pt-BR.md new file mode 100644 index 0000000..5c474a1 --- /dev/null +++ b/projects/devops/intermediate/06-blue-green-deployment/README.pt-BR.md @@ -0,0 +1,93 @@ +# Deploy Blue/Green + +> 🌐 [English](./README.md) · **Português** + +**Domínio:** DevOps · **Nível:** Intermediário · **Tempo estimado:** 1–2 dias + +## Visão Geral + +Implemente um deploy blue/green: rode dois ambientes de produção idênticos — "blue" (ao vivo) e "green" (ocioso) — implante a nova versão no ocioso, valide-a isoladamente e então vire um roteador ou load balancer para enviar todo o tráfego a ele em uma única troca atômica. Se algo estiver errado, volte instantaneamente. O valor é releases com zero downtime e um rollback instantâneo que não exige rebuild. Você vai encarar as partes difíceis que todos pulam: como verificar a saúde do ambiente ocioso antes da troca e o que fazer com mudanças de esquema de banco que ambas as versões precisam tolerar. + +## Pré-requisitos + +- Uma app implantável e um roteador/load balancer que você possa reprogramar (Nginx, HAProxy, LB de nuvem ou Service do Kubernetes) +- Dois ambientes que você consiga rodar em paralelo (contêineres, VMs ou namespaces) +- Entendimento de health checks e de como o tráfego é roteado a um backend +- Consciência de que o banco de dados costuma ser compartilhado entre blue e green + +## Objetivos de Aprendizado + +Ao final, você deve ser capaz de: + +- Rodar dois ambientes paralelos, implantáveis de forma independente, atrás de um único ponto de entrada +- Implantar e validar uma nova versão sem nenhum tráfego de usuário chegando a ela +- Trocar todo o tráfego atomicamente e reverter trocando de novo +- Verificar a saúde do ambiente ocioso como portão antes da troca +- Raciocinar sobre mudanças de esquema que devem ser retrocompatíveis durante a sobreposição + +## Requisitos Funcionais + +1. Dois ambientes (blue e green) devem poder rodar simultaneamente atrás de um único roteador. +2. Uma nova versão deve implantar no ambiente ocioso enquanto o ao vivo continua servindo. +3. O ambiente ocioso deve passar em um health/smoke check antes de poder receber tráfego. +4. A troca de tráfego deve ser atômica — nenhuma requisição deve atingir um estado meio trocado. +5. O rollback deve ser uma única troca de volta ao ambiente anterior, sem rebuild. +6. Os usuários devem observar zero downtime e zero requisições falhas durante a troca. +7. O ambiente ativo (blue vs green) deve ser observável a qualquer momento. + +## Marcos Sugeridos + +1. **Marco 1 — Dois ambientes:** Rode blue e green atrás de um roteador; aponte-o para blue. +2. **Marco 2 — Implantar e validar o ocioso:** Implante em green, verifique sua saúde enquanto blue serve. +3. **Marco 3 — Trocar e reverter:** Vire o tráfego para green, valide, e então pratique um rollback instantâneo. + +## Esboço de Dados e Interface + +```text +Topologia: + ┌───────────┐ + clientes ──────> │ roteador │ ──(ativo)──> BLUE (v1, ao vivo) + └───────────┘ └────> GREEN (v2, ocioso, em validação) + +Troca = reapontar o upstream do roteador de BLUE para GREEN (atômico) +Rollback = reapontar de volta para BLUE + +Portão antes da troca: + implanta v2 -> GREEN + roda health/smoke checks contra GREEN diretamente (não via roteador) + tudo ok? -> troca ; senão -> aborta, GREEN permanece ocioso + +Ressalva do DB compartilhado: + o esquema deve satisfazer AMBOS v1 e v2 durante a sobreposição (expand/contract) +``` + +## Desafios Extras + +- Automatize toda a virada a partir de um pipeline, com o portão de saúde como passo obrigatório. +- Adicione um passo canário: roteie uma pequena porcentagem para green antes da troca total. +- Modele uma migração expand/contract para que uma mudança de esquema seja segura na troca. +- Mantenha o ambiente antigo aquecido por uma janela definida antes de reaproveitá-lo. + +## Definição de Pronto + +- [ ] Blue e green rodam lado a lado com versões independentes. +- [ ] Uma nova versão é validada no ambiente ocioso antes de qualquer tráfego chegar a ela. +- [ ] A troca causa zero requisições falhas (verificado com um gerador de carga durante a virada). +- [ ] O rollback é uma única retroca sem rebuild e conclui em segundos. +- [ ] O ambiente atualmente ativo é sempre identificável. + +## Armadilhas Comuns + +- Trocar antes de o ambiente ocioso estar realmente pronto, fazendo o release de "zero downtime" servir erros. +- Uma troca não atômica (ex.: editar config em vários LBs um a um) deixando uma janela de split-brain. +- Esquecer do banco compartilhado: uma mudança de esquema só-v2 quebra v1 no instante em que você precisaria reverter. +- Reaproveitar o ambiente antigo imediatamente, destruindo sua rede de segurança de rollback instantâneo. +- Drenar conexões abruptamente, cortando requisições em andamento no momento da troca. + +## Recursos + +- [Martin Fowler: BlueGreenDeployment](https://martinfowler.com/bliki/BlueGreenDeployment.html) — a descrição canônica do padrão. +- [AWS: Whitepaper de deploys Blue/Green](https://docs.aws.amazon.com/whitepapers/latest/blue-green-deployments/welcome.html) — técnicas e trade-offs. +- [Expand/contract (parallel change)](https://martinfowler.com/bliki/ParallelChange.html) — mudanças de esquema seguras entre versões. +- [Deployments do Kubernetes](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/) — uma forma de modelar blue/green com Services. + diff --git a/projects/devops/intermediate/07-secret-management/README.md b/projects/devops/intermediate/07-secret-management/README.md index 67267e6..2d3c0bf 100644 --- a/projects/devops/intermediate/07-secret-management/README.md +++ b/projects/devops/intermediate/07-secret-management/README.md @@ -1,34 +1,90 @@ # Secret Management System -## Idea -Create a system for managing and storing secrets securely. Learn about secret management practices. +> 🌐 **English** · [Português](./README.pt-BR.md) + +**Domain:** DevOps · **Level:** Intermediate · **Estimated time:** 1–2 days + +## Overview + +Stop scattering passwords, API keys, and tokens across `.env` files and CI variables. Build a workflow around a real secret manager — HashiCorp Vault, AWS Secrets Manager, or an equivalent — that stores secrets encrypted, controls who can read them, keeps an audit trail of every access, and rotates them without downtime. Then integrate an application so it fetches secrets at runtime instead of embedding them. The goal is to understand the full lifecycle of a secret: store, access-control, deliver, audit, rotate, and revoke. + +## Prerequisites + +- A secret manager you can run or access (Vault dev server, cloud Secrets Manager) +- An application that needs at least one secret (a DB password or API key) +- Understanding of encryption at rest vs in transit, and of access policies +- Familiarity with environment variables and how apps read configuration ## Learning Objectives -- Store secrets securely -- Manage access -- Rotate secrets -- Audit access -- Integrate with apps - -## Implementation Tips -- Choose secret management tool (Vault, AWS Secrets Manager) -- Implement storage encryption -- Create access control -- Implement secret rotation -- Add audit logging -- Create secret versioning -- Implement expiration -- Add RBAC -- Create integrations with apps -- Implement monitoring -- Add alerts for access -- Create recovery procedures -- Implement compliance policies -- Build management interface - -## Key Challenges -- Encryption key management -- Access control complexity -- Secret rotation coordination -- Application integration -- Compliance requirements + +By the end, you should be able to: + +- Store secrets encrypted at rest with access mediated by policy, not file permissions +- Grant least-privilege read access scoped per application or identity +- Deliver secrets to an app at runtime without writing them to disk or an image +- Produce an audit log answering "who read which secret, when" +- Rotate a secret and have consumers pick up the new value without a hard outage + +## Functional Requirements + +1. Secrets must be stored encrypted at rest, never in plaintext files or the app image. +2. Access must be governed by policies granting least privilege per identity. +3. An application must retrieve its secret at runtime from the manager, not from a baked-in value. +4. Every secret access must be recorded in an audit log with identity and timestamp. +5. A secret must be rotatable, and consumers must obtain the new value without manual redeploy where possible. +6. A revoked or expired credential must stop working after revocation. +7. No secret value may appear in application logs or process listings. + +## Suggested Milestones + +1. **Milestone 1 — Store & read:** Put a secret in the manager and read it back with a scoped token. +2. **Milestone 2 — Integrate & audit:** Have an app fetch the secret at runtime; verify the access shows in the audit log. +3. **Milestone 3 — Rotate & revoke:** Rotate the secret and confirm consumers pick it up; revoke a token and confirm it fails. + +## Data & Interface Sketch + +```text +Lifecycle of a secret: + create ─> store(encrypted) ─> policy(who can read) ─> deliver(runtime) + ^ | + └──────────── rotate / revoke <── audit(who,what,when)─┘ + +Access model (conceptual): + identity (app/role) ── authenticates ──> manager + └── policy: read secret/app/db-password only + app requests secret at boot / on lease renewal, holds in memory only + +Rotation: + new version written -> old version deprecated -> consumers re-read -> old revoked +``` + +## Stretch Goals + +- Use dynamic secrets: have the manager generate short-lived DB credentials on demand. +- Add automatic lease renewal so long-running apps never hold a stale credential. +- Integrate secret injection into Kubernetes (CSI driver or an init sidecar). +- Alert when a secret is accessed by an unexpected identity or outside a time window. + +## Definition of Done + +- [ ] No secret is stored in plaintext in the repo, image, or a committed `.env`. +- [ ] An app reads its secret at runtime and it never touches disk. +- [ ] The audit log shows each access with identity and timestamp. +- [ ] Rotating a secret does not require editing application code. +- [ ] A revoked credential is rejected on its next use. + +## Common Pitfalls + +- "Solving" secrets by moving them from code into a committed `.env` — still plaintext in git history. +- Logging the secret at startup "just to confirm it loaded", leaking it into log storage. +- Granting one broad policy to everything, so a single leaked token reads every secret. +- Rotating the stored value but never signaling consumers, so they keep using the old one until they crash. +- Treating the audit log as optional, then being unable to answer "was this secret exposed?". + +## Resources + +- [HashiCorp Vault documentation](https://developer.hashicorp.com/vault/docs) — storage, policies, dynamic secrets, and audit. +- [AWS Secrets Manager](https://docs.aws.amazon.com/secretsmanager/latest/userguide/intro.html) — managed storage and rotation. +- [OWASP Secrets Management Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Secrets_Management_Cheat_Sheet.html) — practices and anti-patterns. +- [NIST SP 800-57: Key Management](https://csrc.nist.gov/pubs/sp/800/57/pt1/r5/final) — foundations of key and secret handling. + diff --git a/projects/devops/intermediate/07-secret-management/README.pt-BR.md b/projects/devops/intermediate/07-secret-management/README.pt-BR.md new file mode 100644 index 0000000..638eec1 --- /dev/null +++ b/projects/devops/intermediate/07-secret-management/README.pt-BR.md @@ -0,0 +1,90 @@ +# Sistema de Gerenciamento de Segredos + +> 🌐 [English](./README.md) · **Português** + +**Domínio:** DevOps · **Nível:** Intermediário · **Tempo estimado:** 1–2 dias + +## Visão Geral + +Pare de espalhar senhas, chaves de API e tokens por arquivos `.env` e variáveis de CI. Construa um fluxo em torno de um gerenciador de segredos de verdade — HashiCorp Vault, AWS Secrets Manager ou equivalente — que armazena segredos criptografados, controla quem pode lê-los, mantém uma trilha de auditoria de cada acesso e os rotaciona sem downtime. Depois integre uma aplicação para que ela busque segredos em tempo de execução em vez de embuti-los. O objetivo é entender o ciclo de vida completo de um segredo: armazenar, controlar acesso, entregar, auditar, rotacionar e revogar. + +## Pré-requisitos + +- Um gerenciador de segredos que você possa rodar ou acessar (Vault em modo dev, Secrets Manager de nuvem) +- Uma aplicação que precise de ao menos um segredo (uma senha de banco ou chave de API) +- Entendimento de criptografia em repouso vs em trânsito e de políticas de acesso +- Familiaridade com variáveis de ambiente e como apps leem configuração + +## Objetivos de Aprendizado + +Ao final, você deve ser capaz de: + +- Armazenar segredos criptografados em repouso com acesso mediado por política, não por permissões de arquivo +- Conceder acesso de leitura de menor privilégio, escopado por aplicação ou identidade +- Entregar segredos a uma app em tempo de execução sem escrevê-los em disco ou imagem +- Produzir um log de auditoria que responda "quem leu qual segredo, quando" +- Rotacionar um segredo e fazer os consumidores adotarem o novo valor sem uma indisponibilidade brusca + +## Requisitos Funcionais + +1. Segredos devem ser armazenados criptografados em repouso, nunca em arquivos texto ou na imagem da app. +2. O acesso deve ser governado por políticas que concedam menor privilégio por identidade. +3. Uma aplicação deve recuperar seu segredo em tempo de execução do gerenciador, não de um valor embutido. +4. Todo acesso a segredo deve ser registrado em um log de auditoria com identidade e timestamp. +5. Um segredo deve ser rotacionável, e os consumidores devem obter o novo valor sem redeploy manual quando possível. +6. Uma credencial revogada ou expirada deve parar de funcionar após a revogação. +7. Nenhum valor de segredo pode aparecer em logs da aplicação ou listagens de processos. + +## Marcos Sugeridos + +1. **Marco 1 — Armazenar e ler:** Coloque um segredo no gerenciador e leia-o de volta com um token escopado. +2. **Marco 2 — Integrar e auditar:** Faça uma app buscar o segredo em tempo de execução; verifique que o acesso aparece no log de auditoria. +3. **Marco 3 — Rotacionar e revogar:** Rotacione o segredo e confirme que os consumidores o adotam; revogue um token e confirme que ele falha. + +## Esboço de Dados e Interface + +```text +Ciclo de vida de um segredo: + criar ─> armazenar(criptografado) ─> política(quem pode ler) ─> entregar(runtime) + ^ | + └──────────── rotacionar / revogar <── auditoria(quem,o quê,quando)─┘ + +Modelo de acesso (conceitual): + identidade (app/role) ── autentica ──> gerenciador + └── política: ler apenas secret/app/db-password + app pede segredo no boot / na renovação de lease, mantém só em memória + +Rotação: + nova versão escrita -> versão antiga depreciada -> consumidores releem -> antiga revogada +``` + +## Desafios Extras + +- Use segredos dinâmicos: faça o gerenciador gerar credenciais de banco de curta duração sob demanda. +- Adicione renovação automática de lease para que apps de longa duração nunca segurem uma credencial obsoleta. +- Integre a injeção de segredos ao Kubernetes (driver CSI ou um sidecar de init). +- Alerte quando um segredo for acessado por uma identidade inesperada ou fora de uma janela de tempo. + +## Definição de Pronto + +- [ ] Nenhum segredo é armazenado em texto puro no repo, na imagem ou em um `.env` commitado. +- [ ] Uma app lê seu segredo em tempo de execução e ele nunca toca o disco. +- [ ] O log de auditoria mostra cada acesso com identidade e timestamp. +- [ ] Rotacionar um segredo não exige editar código da aplicação. +- [ ] Uma credencial revogada é rejeitada em seu próximo uso. + +## Armadilhas Comuns + +- "Resolver" segredos movendo-os do código para um `.env` commitado — ainda texto puro no histórico do git. +- Registrar o segredo na inicialização "só para confirmar que carregou", vazando-o para o armazenamento de logs. +- Conceder uma política ampla para tudo, de modo que um único token vazado leia todos os segredos. +- Rotacionar o valor armazenado mas nunca sinalizar os consumidores, que seguem usando o antigo até quebrarem. +- Tratar o log de auditoria como opcional e depois não conseguir responder "esse segredo foi exposto?". + +## Recursos + +- [Documentação do HashiCorp Vault](https://developer.hashicorp.com/vault/docs) — armazenamento, políticas, segredos dinâmicos e auditoria. +- [AWS Secrets Manager](https://docs.aws.amazon.com/secretsmanager/latest/userguide/intro.html) — armazenamento e rotação gerenciados. +- [OWASP Secrets Management Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Secrets_Management_Cheat_Sheet.html) — práticas e antipadrões. +- [NIST SP 800-57: Gerenciamento de Chaves](https://csrc.nist.gov/pubs/sp/800/57/pt1/r5/final) — fundamentos do manuseio de chaves e segredos. + diff --git a/projects/devops/intermediate/08-auto-scaling/README.md b/projects/devops/intermediate/08-auto-scaling/README.md index 33094ee..ceeda6d 100644 --- a/projects/devops/intermediate/08-auto-scaling/README.md +++ b/projects/devops/intermediate/08-auto-scaling/README.md @@ -1,34 +1,95 @@ # Auto-Scaling Setup -## Idea -Implement automatic scaling based on metrics. Learn about elasticity and dynamic resource management. +> 🌐 **English** · [Português](./README.pt-BR.md) + +**Domain:** DevOps · **Level:** Intermediate · **Estimated time:** 1–2 days + +## Overview + +Build an auto-scaler that adds and removes capacity in response to load, the way a cloud Auto Scaling Group or the Kubernetes Horizontal Pod Autoscaler does. You will scrape a metric (CPU, memory, or a custom signal like queue depth or requests-per-second), compare it against a target, and decide how many instances the system should run right now. The hard parts are not the arithmetic but the control theory around it: cooldown windows so you don't thrash, minimum and maximum bounds so a bad metric can't scale you to zero or bankrupt you, and honest handling of cold starts, where new capacity isn't useful the instant it appears. Done well, the system rides load smoothly; done naively, it oscillates and pages you at 3am. + +## Prerequisites + +- Comfort with a metrics source (Prometheus, CloudWatch, or a scraped endpoint) +- A workload you can scale — replicas of a container, VMs, or worker processes +- Understanding of what "utilization" means for your chosen metric +- Familiarity with a control loop pattern (observe → decide → act) +- A stepping stone: [Service Restart Monitor](../../beginner/10-service-restart/) covers the health-check loop this builds on ## Learning Objectives -- Define scaling policies -- Monitor metrics -- Trigger scaling -- Handle cold starts -- Optimize costs - -## Implementation Tips -- Define scaling metrics (CPU, memory, custom) -- Create scaling policies -- Implement threshold logic -- Add cooldown periods -- Create maximum/minimum bounds -- Implement target tracking -- Add scale-up/down logic -- Create notification system -- Implement predictive scaling -- Add performance monitoring -- Create cost analysis -- Implement gradual scaling -- Add safety guards -- Build dashboard - -## Key Challenges -- Metric selection -- Threshold tuning -- Cold start handling -- Cost control -- Cascading failures + +By the end, you should be able to: + +- Select and normalize a scaling metric and reason about why it reflects real load +- Implement target-tracking: compute desired replicas from current utilization vs a target +- Apply separate scale-up and scale-down behavior with cooldown to prevent flapping +- Enforce min/max bounds and safety guards against bad or missing metrics +- Account for cold starts so freshly added capacity is not counted as productive too early + +## Functional Requirements + +1. The scaler must read a metric on a fixed interval from a real source. +2. It must compute a desired instance count using target tracking (`desired = current * metric / target`). +3. Scale-up and scale-down must respect independent cooldown periods. +4. Instance count must never leave the configured `[min, max]` range. +5. Missing, stale, or clearly invalid metrics must not trigger scaling; the last known good state holds. +6. New instances must pass a readiness check before counting toward capacity. +7. Every scaling decision (metric, desired, actual, reason) must be logged for later inspection. + +## Suggested Milestones + +1. **Milestone 1 — Metric loop:** Scrape one metric on an interval and log current utilization. +2. **Milestone 2 — Target tracking:** Compute desired replicas and actuate scale-up/down within bounds. +3. **Milestone 3 — Stability:** Add cooldowns, readiness gating, and guards against bad metrics. + +## Data & Interface Sketch + +```text +policy + metric cpu | memory | custom(name) + target number (e.g. 60 for 60% CPU) + min, max int + cooldown { up_s, down_s } + step_max int (max change per decision) + +control loop (every interval) + 1. read metric M for current N instances + 2. desired = ceil(N * (M / target)) + 3. clamp desired to [min, max] and to +/- step_max + 4. if scaling up and last-up within up_s -> hold + if scaling down and last-down within down_s -> hold + 5. actuate; new instances excluded until ready + +decision log entry + ts, metric_value, N, desired, applied, reason +``` + +## Stretch Goals + +- Add predictive scaling from a rolling trend so capacity leads load instead of chasing it. +- Support multiple metrics and scale on the most demanding one. +- Add scheduled scaling for known daily peaks alongside reactive scaling. +- Emit a cost estimate per decision so scale-up is visibly tied to spend. + +## Definition of Done + +- [ ] A sustained load increase scales the system up within one cooldown window and stops at max. +- [ ] Load dropping scales it back down, never below min. +- [ ] Rapid metric swings do not cause flapping — cooldown demonstrably suppresses oscillation. +- [ ] A missing or absurd metric reading holds state instead of scaling wildly. +- [ ] New instances only count once ready, and every decision is logged with its reason. + +## Common Pitfalls + +- Scaling on a lagging metric (e.g. average CPU) that reacts too slowly, so you always scale late. +- Symmetric cooldowns: scaling down as eagerly as up causes thrash under bursty traffic. +- Ignoring cold starts, so the scaler adds more capacity while the last batch is still warming up. +- No maximum bound, letting a runaway metric or a metrics outage scale you into a huge bill. +- Trusting a single scrape; one bad sample triggers a scale event that the next sample reverses. + +## Resources + +- [Kubernetes: Horizontal Pod Autoscaler](https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/) — the target-tracking algorithm in detail. +- [AWS: Target Tracking Scaling Policies](https://docs.aws.amazon.com/autoscaling/ec2/userguide/as-scaling-target-tracking.html) — a production auto-scaler's model. +- [Prometheus: Querying Basics](https://prometheus.io/docs/prometheus/latest/querying/basics/) — how to pull a metric to scale on. +- [Google SRE Book: Handling Overload](https://sre.google/sre-book/handling-overload/) — why bounds and graceful behavior matter under load. diff --git a/projects/devops/intermediate/08-auto-scaling/README.pt-BR.md b/projects/devops/intermediate/08-auto-scaling/README.pt-BR.md new file mode 100644 index 0000000..7165056 --- /dev/null +++ b/projects/devops/intermediate/08-auto-scaling/README.pt-BR.md @@ -0,0 +1,95 @@ +# Configuração de Auto-Escalonamento + +> 🌐 [English](./README.md) · **Português** + +**Domínio:** DevOps · **Nível:** Intermediário · **Tempo estimado:** 1–2 dias + +## Visão Geral + +Construa um auto-escalonador que adiciona e remove capacidade em resposta à carga, como faz um Auto Scaling Group na nuvem ou o Horizontal Pod Autoscaler do Kubernetes. Você vai coletar uma métrica (CPU, memória ou um sinal customizado como profundidade de fila ou requisições por segundo), compará-la com um alvo e decidir quantas instâncias o sistema deve rodar agora. As partes difíceis não são a aritmética, mas a teoria de controle ao redor: janelas de cooldown para não oscilar, limites mínimo e máximo para que uma métrica ruim não escale você a zero nem te leve à falência, e o tratamento honesto de cold starts, em que capacidade nova não é útil no instante em que aparece. Bem feito, o sistema acompanha a carga suavemente; feito de forma ingênua, ele oscila e te acorda às 3 da manhã. + +## Pré-requisitos + +- Conforto com uma fonte de métricas (Prometheus, CloudWatch ou um endpoint coletável) +- Uma carga de trabalho que você possa escalar — réplicas de um contêiner, VMs ou processos worker +- Entender o que "utilização" significa para a métrica escolhida +- Familiaridade com o padrão de laço de controle (observar → decidir → agir) +- Um trampolim: [Monitor de Reinício de Serviços](../../beginner/10-service-restart/) cobre o laço de health-check sobre o qual isto se apoia + +## Objetivos de Aprendizado + +Ao final, você deve ser capaz de: + +- Selecionar e normalizar uma métrica de escalonamento e raciocinar por que ela reflete a carga real +- Implementar target-tracking: calcular réplicas desejadas a partir da utilização atual vs um alvo +- Aplicar comportamentos separados de scale-up e scale-down com cooldown para evitar flapping +- Impor limites min/max e proteções contra métricas ruins ou ausentes +- Considerar cold starts para que capacidade recém-adicionada não seja contada como produtiva cedo demais + +## Requisitos Funcionais + +1. O escalonador deve ler uma métrica em intervalo fixo de uma fonte real. +2. Deve calcular a contagem desejada de instâncias usando target-tracking (`desejado = atual * métrica / alvo`). +3. Scale-up e scale-down devem respeitar períodos de cooldown independentes. +4. A contagem de instâncias nunca deve sair do intervalo configurado `[min, max]`. +5. Métricas ausentes, obsoletas ou claramente inválidas não devem disparar escalonamento; o último estado bom se mantém. +6. Novas instâncias devem passar por uma checagem de readiness antes de contarem como capacidade. +7. Toda decisão de escalonamento (métrica, desejado, real, motivo) deve ser registrada para inspeção posterior. + +## Marcos Sugeridos + +1. **Marco 1 — Laço de métrica:** Colete uma métrica em intervalo e registre a utilização atual. +2. **Marco 2 — Target tracking:** Calcule réplicas desejadas e atue com scale-up/down dentro dos limites. +3. **Marco 3 — Estabilidade:** Adicione cooldowns, gate de readiness e proteções contra métricas ruins. + +## Esboço de Dados e Interface + +```text +política + metric cpu | memory | custom(name) + target número (ex.: 60 para 60% de CPU) + min, max int + cooldown { up_s, down_s } + step_max int (mudança máx por decisão) + +laço de controle (a cada intervalo) + 1. ler métrica M para N instâncias atuais + 2. desejado = ceil(N * (M / target)) + 3. limitar desejado a [min, max] e a +/- step_max + 4. se subindo e último-up dentro de up_s -> segurar + se descendo e último-down dentro de down_s -> segurar + 5. atuar; novas instâncias excluídas até ready + +entrada do log de decisão + ts, valor_métrica, N, desejado, aplicado, motivo +``` + +## Desafios Extras + +- Adicione escalonamento preditivo a partir de uma tendência móvel para que a capacidade anteceda a carga em vez de persegui-la. +- Suporte múltiplas métricas e escale pela mais exigente. +- Adicione escalonamento agendado para picos diários conhecidos junto ao escalonamento reativo. +- Emita uma estimativa de custo por decisão para que o scale-up fique visivelmente ligado ao gasto. + +## Definição de Pronto + +- [ ] Um aumento sustentado de carga escala o sistema para cima em até uma janela de cooldown e para no máximo. +- [ ] A carga caindo o escala de volta para baixo, nunca abaixo do mínimo. +- [ ] Oscilações rápidas da métrica não causam flapping — o cooldown suprime a oscilação de forma demonstrável. +- [ ] Uma leitura de métrica ausente ou absurda mantém o estado em vez de escalar descontroladamente. +- [ ] Novas instâncias só contam quando prontas, e toda decisão é registrada com seu motivo. + +## Armadilhas Comuns + +- Escalar por uma métrica atrasada (ex.: CPU média) que reage devagar demais, então você sempre escala tarde. +- Cooldowns simétricos: descer com a mesma pressa com que sobe causa thrash sob tráfego em rajadas. +- Ignorar cold starts, fazendo o escalonador adicionar mais capacidade enquanto o último lote ainda aquece. +- Sem limite máximo, deixando uma métrica descontrolada ou uma queda do sistema de métricas escalar você a uma conta enorme. +- Confiar em uma única coleta; uma amostra ruim dispara um evento de escalonamento que a próxima amostra reverte. + +## Recursos + +- [Kubernetes: Horizontal Pod Autoscaler](https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/) — o algoritmo de target-tracking em detalhe. +- [AWS: Target Tracking Scaling Policies](https://docs.aws.amazon.com/autoscaling/ec2/userguide/as-scaling-target-tracking.html) — o modelo de um auto-escalonador de produção. +- [Prometheus: Querying Basics](https://prometheus.io/docs/prometheus/latest/querying/basics/) — como puxar uma métrica para escalar. +- [Google SRE Book: Handling Overload](https://sre.google/sre-book/handling-overload/) — por que limites e comportamento gracioso importam sob carga. diff --git a/projects/devops/intermediate/09-load-balancing/README.md b/projects/devops/intermediate/09-load-balancing/README.md index ac362ea..66739a1 100644 --- a/projects/devops/intermediate/09-load-balancing/README.md +++ b/projects/devops/intermediate/09-load-balancing/README.md @@ -1,34 +1,101 @@ # Load Balancing System -## Idea -Set up load balancing to distribute traffic across servers. Learn about load balancing patterns. +> 🌐 **English** · [Português](./README.pt-BR.md) + +**Domain:** DevOps · **Level:** Intermediate · **Estimated time:** 1–2 days + +## Overview + +Build a load balancer that sits in front of several backend servers and spreads incoming traffic across them, the role played by HAProxy, NGINX, or a cloud L4/L7 balancer. You will implement one or more distribution algorithms, actively health-check each backend so traffic never lands on a dead node, and drain a backend gracefully instead of cutting its in-flight requests. The subtle work is in the edges: keeping a client pinned to one backend when sessions require it, deciding fast enough that a failing node is pulled before users notice, and degrading sensibly when every backend is unhealthy. You come away understanding why a balancer is as much about health and failover as it is about "picking the next server". + +## Prerequisites + +- Comfort writing an HTTP or TCP proxy in your language of choice +- Understanding of connections, keep-alive, and request/response lifecycles +- Familiarity with health checks (from a supervisor or auto-scaler project) +- Basic grasp of hashing for consistent client-to-backend mapping +- A stepping stone: [Auto-Scaling Setup](../08-auto-scaling/) pairs naturally with this ## Learning Objectives -- Distribute traffic -- Monitor health -- Handle failures -- Optimize performance -- Scale horizontally - -## Implementation Tips -- Choose load balancer -- Configure load balancing algorithms (round-robin, least conn, etc.) -- Add health checks -- Implement sticky sessions -- Create backend management -- Add connection pooling -- Implement metrics collection -- Add alerting -- Create failover logic -- Implement graceful degradation -- Add rate limiting -- Create admin interface -- Implement monitoring -- Build dashboard - -## Key Challenges -- Session persistence -- Health check accuracy -- Connection management -- Performance optimization -- Failure recovery + +By the end, you should be able to: + +- Implement and compare algorithms: round-robin, least-connections, and weighted variants +- Actively health-check backends and remove/restore them from the rotation automatically +- Support sticky sessions via cookie or consistent hashing when required +- Drain connections on removal so in-flight requests complete before a backend leaves +- Degrade gracefully — return a clear error, not a hang, when no backend is available + +## Functional Requirements + +1. The balancer must accept client requests and forward them to a healthy backend. +2. It must support at least round-robin and least-connections selection, chosen by config. +3. It must actively health-check each backend and exclude failing ones within a bounded time. +4. A recovered backend must rejoin the rotation automatically. +5. Sticky sessions must route a given client to the same backend while it stays healthy. +6. Removing a backend must drain existing connections rather than dropping them. +7. When all backends are unhealthy, the balancer must return a defined error, not hang or crash. + +## Suggested Milestones + +1. **Milestone 1 — Forward & rotate:** Proxy requests to a static pool using round-robin. +2. **Milestone 2 — Health & failover:** Add active health checks, exclusion, and automatic recovery. +3. **Milestone 3 — Stickiness & draining:** Add session affinity and graceful connection draining. + +## Data & Interface Sketch + +```text +backend + id string + address host:port + weight int + status up | down | draining + in_flight int (for least-connections) + +config + algorithm round_robin | least_conn | weighted + health { path, interval_s, timeout_s, unhealthy_after, healthy_after } + sticky none | cookie | ip_hash + +selection: + round_robin next index mod pool + least_conn backend with min in_flight among up + weighted distribute proportional to weight + +request path: + client -> balancer -> pick backend (respect sticky) -> proxy + backend down mid-request -> retry on another (idempotent only) + no backend up -> 503 with clear body + +health loop marks up/down after N consecutive results +``` + +## Stretch Goals + +- Add connection pooling and keep-alive reuse to upstream backends. +- Add per-backend rate limiting and a simple circuit breaker for repeatedly failing nodes. +- Expose a metrics endpoint (requests, latency, per-backend health) and a small admin view. +- Support weighted canary routing to send a small percentage of traffic to a new backend. + +## Definition of Done + +- [ ] Traffic is distributed across backends according to the configured algorithm. +- [ ] A backend that fails its health check is removed within the configured window and later rejoins on recovery. +- [ ] Sticky sessions keep a client on one backend for the session's lifetime while it is healthy. +- [ ] Removing a backend drains in-flight requests instead of severing them. +- [ ] With every backend down, clients receive a defined error response, not a timeout. + +## Common Pitfalls + +- Health checks that only verify TCP connect, missing a backend that accepts connections but returns 500s. +- Retrying non-idempotent requests on failover, causing duplicate side effects. +- Sticky sessions with no fallback, so a client is stranded when its pinned backend dies. +- Removing a backend instantly on one failed check, causing flapping under transient blips. +- Cutting connections on drain, breaking long-running requests and uploads. + +## Resources + +- [HAProxy Documentation](https://docs.haproxy.org/) — algorithms, health checks, and stick tables in a real balancer. +- [NGINX: HTTP Load Balancing](https://docs.nginx.com/nginx/admin-guide/load-balancer/http-load-balancer/) — practical configuration of the concepts here. +- [Cloudflare: What is Load Balancing?](https://www.cloudflare.com/learning/performance/what-is-load-balancing/) — a clear conceptual overview. +- [Google SRE Book: Load Balancing in the Datacenter](https://sre.google/sre-book/load-balancing-datacenter/) — health-aware balancing at scale. diff --git a/projects/devops/intermediate/09-load-balancing/README.pt-BR.md b/projects/devops/intermediate/09-load-balancing/README.pt-BR.md new file mode 100644 index 0000000..c91dc95 --- /dev/null +++ b/projects/devops/intermediate/09-load-balancing/README.pt-BR.md @@ -0,0 +1,101 @@ +# Sistema de Balanceamento de Carga + +> 🌐 [English](./README.md) · **Português** + +**Domínio:** DevOps · **Nível:** Intermediário · **Tempo estimado:** 1–2 dias + +## Visão Geral + +Construa um balanceador de carga que fica na frente de vários servidores backend e distribui o tráfego de entrada entre eles, o papel desempenhado por HAProxy, NGINX ou um balanceador L4/L7 na nuvem. Você vai implementar um ou mais algoritmos de distribuição, verificar ativamente a saúde de cada backend para que o tráfego nunca caia em um nó morto e drenar um backend graciosamente em vez de cortar suas requisições em andamento. O trabalho sutil está nas bordas: manter um cliente fixado a um backend quando as sessões exigem, decidir rápido o suficiente para que um nó falhando seja retirado antes de os usuários perceberem e degradar com bom senso quando todos os backends estão insalubres. Você sai entendendo por que um balanceador tem tanto a ver com saúde e failover quanto com "escolher o próximo servidor". + +## Pré-requisitos + +- Conforto para escrever um proxy HTTP ou TCP na linguagem de sua escolha +- Entender conexões, keep-alive e ciclos de vida de requisição/resposta +- Familiaridade com health checks (de um projeto de supervisor ou auto-escalonador) +- Noção básica de hashing para mapeamento consistente de cliente para backend +- Um trampolim: [Configuração de Auto-Escalonamento](../08-auto-scaling/) combina naturalmente com este + +## Objetivos de Aprendizado + +Ao final, você deve ser capaz de: + +- Implementar e comparar algoritmos: round-robin, least-connections e variantes ponderadas +- Verificar ativamente a saúde dos backends e removê-los/restaurá-los da rotação automaticamente +- Suportar sticky sessions via cookie ou hashing consistente quando necessário +- Drenar conexões na remoção para que requisições em andamento concluam antes de um backend sair +- Degradar graciosamente — retornar um erro claro, não um travamento, quando nenhum backend está disponível + +## Requisitos Funcionais + +1. O balanceador deve aceitar requisições de clientes e encaminhá-las a um backend saudável. +2. Deve suportar ao menos seleção round-robin e least-connections, escolhida por configuração. +3. Deve verificar ativamente a saúde de cada backend e excluir os que falham em tempo limitado. +4. Um backend recuperado deve reingressar na rotação automaticamente. +5. Sticky sessions devem rotear um dado cliente ao mesmo backend enquanto ele permanecer saudável. +6. Remover um backend deve drenar as conexões existentes em vez de derrubá-las. +7. Quando todos os backends estão insalubres, o balanceador deve retornar um erro definido, não travar nem quebrar. + +## Marcos Sugeridos + +1. **Marco 1 — Encaminhar e rotacionar:** Faça proxy de requisições a um pool estático usando round-robin. +2. **Marco 2 — Saúde e failover:** Adicione health checks ativos, exclusão e recuperação automática. +3. **Marco 3 — Fixação e drenagem:** Adicione afinidade de sessão e drenagem graciosa de conexões. + +## Esboço de Dados e Interface + +```text +backend + id string + address host:port + weight int + status up | down | draining + in_flight int (para least-connections) + +config + algorithm round_robin | least_conn | weighted + health { path, interval_s, timeout_s, unhealthy_after, healthy_after } + sticky none | cookie | ip_hash + +seleção: + round_robin próximo índice mod pool + least_conn backend com menor in_flight entre os up + weighted distribuir proporcional ao weight + +caminho da requisição: + client -> balancer -> escolher backend (respeitar sticky) -> proxy + backend cai no meio da requisição -> retry em outro (só idempotente) + nenhum backend up -> 503 com corpo claro + +laço de saúde marca up/down após N resultados consecutivos +``` + +## Desafios Extras + +- Adicione pooling de conexões e reuso de keep-alive para os backends upstream. +- Adicione rate limiting por backend e um circuit breaker simples para nós que falham repetidamente. +- Exponha um endpoint de métricas (requisições, latência, saúde por backend) e uma pequena visão de admin. +- Suporte roteamento canário ponderado para enviar uma pequena porcentagem do tráfego a um novo backend. + +## Definição de Pronto + +- [ ] O tráfego é distribuído entre os backends conforme o algoritmo configurado. +- [ ] Um backend que falha seu health check é removido dentro da janela configurada e reingressa depois na recuperação. +- [ ] Sticky sessions mantêm um cliente em um backend durante toda a sessão enquanto ele está saudável. +- [ ] Remover um backend drena as requisições em andamento em vez de rompê-las. +- [ ] Com todos os backends fora, os clientes recebem uma resposta de erro definida, não um timeout. + +## Armadilhas Comuns + +- Health checks que só verificam o connect TCP, deixando passar um backend que aceita conexões mas retorna 500s. +- Fazer retry de requisições não idempotentes no failover, causando efeitos colaterais duplicados. +- Sticky sessions sem fallback, deixando um cliente encalhado quando o backend fixado morre. +- Remover um backend instantaneamente a uma única checagem falha, causando flapping sob instabilidades transitórias. +- Cortar conexões na drenagem, quebrando requisições longas e uploads. + +## Recursos + +- [Documentação do HAProxy](https://docs.haproxy.org/) — algoritmos, health checks e stick tables em um balanceador real. +- [NGINX: HTTP Load Balancing](https://docs.nginx.com/nginx/admin-guide/load-balancer/http-load-balancer/) — configuração prática dos conceitos aqui. +- [Cloudflare: What is Load Balancing?](https://www.cloudflare.com/learning/performance/what-is-load-balancing/) — uma visão conceitual clara. +- [Google SRE Book: Load Balancing in the Datacenter](https://sre.google/sre-book/load-balancing-datacenter/) — balanceamento consciente de saúde em escala. diff --git a/projects/devops/intermediate/10-container-orchestration/README.md b/projects/devops/intermediate/10-container-orchestration/README.md index 5159f70..0a4df23 100644 --- a/projects/devops/intermediate/10-container-orchestration/README.md +++ b/projects/devops/intermediate/10-container-orchestration/README.md @@ -1,34 +1,98 @@ # Container Orchestration -## Idea -Manage containers across a cluster. Learn about orchestration beyond single-machine deployment. +> 🌐 **English** · [Português](./README.pt-BR.md) + +**Domain:** DevOps · **Level:** Intermediate · **Estimated time:** 1–2 days + +## Overview + +Run a real workload across a small cluster of machines and let an orchestrator — Kubernetes or Docker Swarm — decide where containers go, keep the desired number running, and reschedule them when a node dies. This project moves you from "docker run on one box" to declarative, self-healing deployment. You will declare a desired state, watch the orchestrator reconcile reality toward it, expose services through cluster networking and discovery, attach persistent storage to stateful workloads, and roll out a new version without downtime. The lesson is the reconciliation loop mindset: you describe what you want, the control plane continuously closes the gap, and your job shifts from running commands to authoring correct desired state. + +## Prerequisites + +- Comfort building and running container images +- Two or more nodes (VMs, cloud instances, or a local multi-node cluster like kind/k3d) +- Understanding of container networking basics (ports, DNS, overlays) +- Familiarity with health checks and the difference between liveness and readiness +- A stepping stone: [Load Balancing System](../09-load-balancing/) explains the service routing this relies on ## Learning Objectives -- Orchestrate containers -- Manage cluster resources -- Handle networking -- Implement storage -- Scale applications - -## Implementation Tips -- Set up container orchestrator (Docker Swarm, Kubernetes) -- Create cluster configuration -- Implement service discovery -- Add networking overlay -- Implement storage management -- Create scheduling policies -- Add resource limits -- Implement load balancing -- Add monitoring -- Create alerting -- Implement updates strategy -- Add backup/recovery -- Create operational runbooks -- Build management dashboards - -## Key Challenges -- Cluster complexity -- Resource allocation -- Networking overlay -- State management -- Operational complexity + +By the end, you should be able to: + +- Express a workload as declarative desired state and let the orchestrator reconcile it +- Use service discovery and cluster networking to connect components without hardcoded IPs +- Attach persistent volumes so stateful containers survive rescheduling +- Set resource requests/limits and understand how the scheduler places workloads +- Perform a rolling update and a rollback with zero downtime + +## Functional Requirements + +1. A multi-node cluster must run a workload of at least two communicating services. +2. The workload must be declared as desired state (replica count, image, resources), not imperative commands. +3. Killing a container or draining a node must trigger automatic rescheduling to restore desired state. +4. Services must reach each other via service discovery, not hardcoded addresses. +5. At least one service must use a persistent volume that survives a reschedule. +6. A rolling update must deploy a new version without dropping traffic, and rollback must be possible. +7. Resource requests/limits must be set so the scheduler can place and protect workloads. + +## Suggested Milestones + +1. **Milestone 1 — Cluster & deploy:** Stand up the cluster and deploy a replicated service from desired state. +2. **Milestone 2 — Networking & storage:** Wire service discovery between components and attach a persistent volume. +3. **Milestone 3 — Resilience & rollout:** Prove self-healing on node loss and perform a rolling update with rollback. + +## Data & Interface Sketch + +```text +cluster + control-plane reconciles desired vs actual + node A, node B ... run scheduled containers + +desired state (per service) + name string + image repo:tag + replicas int + resources { requests, limits } + probes { liveness, readiness } + network service name -> stable virtual endpoint + storage volume claim (for stateful) + +reconciliation loop: + observe actual -> diff against desired -> act (create/kill/move) -> repeat + node down -> its containers rescheduled onto healthy nodes + +rolling update: + bump image tag -> new replicas up + ready -> old drained -> repeat + failure -> rollback to previous desired state +``` + +## Stretch Goals + +- Add an ingress/gateway so external traffic reaches services by hostname or path. +- Add autoscaling of replicas based on a metric (ties into the auto-scaling project). +- Add config and secrets management injected into containers at runtime. +- Introduce affinity/anti-affinity rules so replicas spread across nodes and zones. + +## Definition of Done + +- [ ] The cluster runs the declared workload at the requested replica count across nodes. +- [ ] Killing a container or node restores desired state automatically without manual intervention. +- [ ] Services communicate via discovery, surviving container restarts and reschedules. +- [ ] A stateful service keeps its data across a reschedule via a persistent volume. +- [ ] A rolling update ships a new version with no dropped requests, and rollback works. + +## Common Pitfalls + +- Treating the orchestrator imperatively (manual `run`/`kill`) and fighting the reconciliation loop. +- Missing readiness probes, so rolling updates send traffic to containers that aren't ready yet. +- Assuming local disk persists — without a real volume, data vanishes on reschedule. +- No resource requests, letting one workload starve others and causing noisy-neighbor evictions. +- Rolling out with a single replica, so the update itself is the outage. + +## Resources + +- [Kubernetes Concepts](https://kubernetes.io/docs/concepts/) — desired state, controllers, and the reconciliation model. +- [Kubernetes: Rolling Update Deployment](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#rolling-update-deployment) — zero-downtime rollouts and rollback. +- [Docker Swarm mode overview](https://docs.docker.com/engine/swarm/) — a lighter orchestrator with the same core ideas. +- [The Twelve-Factor App](https://12factor.net/) — config, statelessness, and disposability that orchestration assumes. diff --git a/projects/devops/intermediate/10-container-orchestration/README.pt-BR.md b/projects/devops/intermediate/10-container-orchestration/README.pt-BR.md new file mode 100644 index 0000000..8660a5b --- /dev/null +++ b/projects/devops/intermediate/10-container-orchestration/README.pt-BR.md @@ -0,0 +1,98 @@ +# Orquestração de Contêineres + +> 🌐 [English](./README.md) · **Português** + +**Domínio:** DevOps · **Nível:** Intermediário · **Tempo estimado:** 1–2 dias + +## Visão Geral + +Rode uma carga de trabalho real através de um pequeno cluster de máquinas e deixe um orquestrador — Kubernetes ou Docker Swarm — decidir onde os contêineres vão, manter o número desejado rodando e reagendá-los quando um nó morre. Este projeto te leva de "docker run em uma máquina" para um deploy declarativo e auto-recuperável. Você vai declarar um estado desejado, observar o orquestrador reconciliar a realidade em direção a ele, expor serviços através de rede e descoberta de cluster, anexar armazenamento persistente a cargas com estado e implantar uma nova versão sem downtime. A lição é a mentalidade do laço de reconciliação: você descreve o que quer, o control plane fecha continuamente a lacuna e seu trabalho passa de rodar comandos para escrever um estado desejado correto. + +## Pré-requisitos + +- Conforto para construir e rodar imagens de contêiner +- Dois ou mais nós (VMs, instâncias na nuvem ou um cluster multi-nó local como kind/k3d) +- Entender o básico de rede de contêineres (portas, DNS, overlays) +- Familiaridade com health checks e a diferença entre liveness e readiness +- Um trampolim: [Sistema de Balanceamento de Carga](../09-load-balancing/) explica o roteamento de serviços do qual isto depende + +## Objetivos de Aprendizado + +Ao final, você deve ser capaz de: + +- Expressar uma carga de trabalho como estado desejado declarativo e deixar o orquestrador reconciliá-la +- Usar descoberta de serviços e rede de cluster para conectar componentes sem IPs fixos +- Anexar volumes persistentes para que contêineres com estado sobrevivam ao reagendamento +- Definir requests/limits de recursos e entender como o escalonador posiciona as cargas +- Executar uma atualização gradual (rolling update) e um rollback sem downtime + +## Requisitos Funcionais + +1. Um cluster multi-nó deve rodar uma carga com ao menos dois serviços que se comunicam. +2. A carga deve ser declarada como estado desejado (contagem de réplicas, imagem, recursos), não comandos imperativos. +3. Encerrar um contêiner ou drenar um nó deve disparar reagendamento automático para restaurar o estado desejado. +4. Os serviços devem se alcançar via descoberta de serviços, não endereços fixos. +5. Ao menos um serviço deve usar um volume persistente que sobreviva a um reagendamento. +6. Uma atualização gradual deve implantar uma nova versão sem perder tráfego, e o rollback deve ser possível. +7. Requests/limits de recursos devem ser definidos para que o escalonador posicione e proteja as cargas. + +## Marcos Sugeridos + +1. **Marco 1 — Cluster e deploy:** Suba o cluster e implante um serviço replicado a partir do estado desejado. +2. **Marco 2 — Rede e armazenamento:** Conecte a descoberta de serviços entre componentes e anexe um volume persistente. +3. **Marco 3 — Resiliência e rollout:** Comprove a auto-recuperação na perda de nó e faça um rolling update com rollback. + +## Esboço de Dados e Interface + +```text +cluster + control-plane reconcilia desejado vs real + nó A, nó B ... rodam contêineres agendados + +estado desejado (por serviço) + name string + image repo:tag + replicas int + resources { requests, limits } + probes { liveness, readiness } + network nome do serviço -> endpoint virtual estável + storage reivindicação de volume (para stateful) + +laço de reconciliação: + observar real -> diff contra desejado -> agir (criar/matar/mover) -> repetir + nó fora -> seus contêineres reagendados em nós saudáveis + +rolling update: + subir tag da imagem -> novas réplicas up + ready -> antigas drenadas -> repetir + falha -> rollback para o estado desejado anterior +``` + +## Desafios Extras + +- Adicione um ingress/gateway para que o tráfego externo alcance serviços por hostname ou caminho. +- Adicione autoescalonamento de réplicas com base em uma métrica (integra com o projeto de auto-escalonamento). +- Adicione gestão de config e secrets injetados nos contêineres em tempo de execução. +- Introduza regras de afinidade/anti-afinidade para que réplicas se espalhem por nós e zonas. + +## Definição de Pronto + +- [ ] O cluster roda a carga declarada na contagem de réplicas solicitada distribuída entre os nós. +- [ ] Encerrar um contêiner ou nó restaura o estado desejado automaticamente sem intervenção manual. +- [ ] Os serviços se comunicam via descoberta, sobrevivendo a reinícios e reagendamentos de contêineres. +- [ ] Um serviço com estado mantém seus dados através de um reagendamento via um volume persistente. +- [ ] Uma atualização gradual entrega uma nova versão sem requisições perdidas, e o rollback funciona. + +## Armadilhas Comuns + +- Tratar o orquestrador de forma imperativa (`run`/`kill` manual) e lutar contra o laço de reconciliação. +- Faltar readiness probes, fazendo o rolling update enviar tráfego a contêineres que ainda não estão prontos. +- Assumir que o disco local persiste — sem um volume real, os dados somem no reagendamento. +- Sem requests de recursos, deixando uma carga sufocar outras e causando despejos de vizinho barulhento. +- Fazer rollout com uma única réplica, de modo que a própria atualização é a queda. + +## Recursos + +- [Kubernetes Concepts](https://kubernetes.io/docs/concepts/) — estado desejado, controladores e o modelo de reconciliação. +- [Kubernetes: Rolling Update Deployment](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#rolling-update-deployment) — rollouts sem downtime e rollback. +- [Visão geral do Docker Swarm mode](https://docs.docker.com/engine/swarm/) — um orquestrador mais leve com as mesmas ideias centrais. +- [The Twelve-Factor App](https://12factor.net/) — config, ausência de estado e descartabilidade que a orquestração pressupõe. diff --git a/projects/frontend/advanced/01-microfrontend-architecture/README.md b/projects/frontend/advanced/01-microfrontend-architecture/README.md index f5acc9b..03cf2a0 100644 --- a/projects/frontend/advanced/01-microfrontend-architecture/README.md +++ b/projects/frontend/advanced/01-microfrontend-architecture/README.md @@ -1,34 +1,99 @@ # Microfrontend Architecture -## Idea -Design a system where multiple frontend applications are composed together. Learn about module federation, independent deployment, and shared dependencies. +> 🌐 **English** · [Português](./README.pt-BR.md) + +**Domain:** Frontend · **Level:** Advanced · **Estimated time:** 1–2 weeks + +## Overview + +Split a single large frontend into several independently built and deployed applications that compose into one seamless product at runtime — the pattern behind large-scale UIs at Spotify, IKEA, and DAZN. A "shell" (host) loads feature apps (remotes) on demand, so teams ship on their own cadence without a shared release train. The hard parts are not the loading mechanics but the boundaries: shared dependency versions, cross-app communication, consistent routing, and a shell that degrades gracefully when a remote fails. This project makes you confront the trade-off at the heart of every microfrontend system — team autonomy versus product consistency — and forces you to defend it with real measurements rather than opinion. + +## Prerequisites + +- A production-grade single-page app under your belt (the [Admin Panel](../../intermediate/05-admin-panel/) is a good baseline) +- Solid grasp of ES modules, bundling, and code splitting +- Comfort with client-side routing and its history model +- Familiarity with a bundler that supports federation (Vite, Webpack 5, or Rspack) ## Learning Objectives -- Implement module federation -- Create independent applications -- Share common dependencies -- Handle communication between microfrontends -- Manage routing across apps - -## Implementation Tips -- Use module federation tool (Webpack 5, Vite, etc.) -- Create separate frontend apps -- Share common libraries -- Implement app routing -- Create communication layer -- Handle shared state -- Implement authentication sharing -- Create deployment strategy -- Add versioning for apps -- Implement fallback UI -- Create monitoring -- Add dependency management -- Implement hot reloading -- Create development experience tooling - -## Key Challenges -- Dependency version conflicts -- App communication complexity -- State management across apps -- Shared state consistency -- Performance optimization + +By the end, you should be able to: + +- Compose multiple independently deployed apps behind one shell at runtime +- Share heavy libraries (framework runtime, design system) as singletons to avoid duplication +- Design a decoupled communication contract between remotes without shared global state +- Coordinate routing so deep links resolve correctly across app boundaries +- Isolate failures so one broken remote never blanks the whole page + +## Functional Requirements + +1. A host shell must dynamically load at least two independently built remote applications at runtime. +2. Each remote must be buildable and deployable on its own, without rebuilding the shell. +3. Shared framework and design-system libraries must resolve to a single shared instance, not one copy per remote. +4. The shell must own top-level routing and delegate sub-routes to the owning remote. +5. Remotes must communicate through an explicit contract (custom events or an injected event bus), never by reaching into each other's internals. +6. If a remote fails to load or throws on mount, the shell must render a fallback and keep the rest of the page usable. +7. Version metadata for each loaded remote must be observable at runtime (e.g. logged or shown in a debug panel). + +## Suggested Milestones + +1. **Milestone 1 — Shell + one remote:** Stand up a host that loads a single remote via module federation and renders it in a route. +2. **Milestone 2 — Second remote & shared deps:** Add a second remote and configure shared singletons; prove only one framework copy ships. +3. **Milestone 3 — Communication & routing:** Wire cross-remote messaging and end-to-end deep-link routing across boundaries. +4. **Milestone 4 — Resilience & versioning:** Add error boundaries, load fallbacks, and runtime version reporting per remote. + +## Data & Interface Sketch + +```text + ┌──────────────────────────────┐ + │ Shell (host) │ + │ routing · layout · auth │ + │ shared singletons ↓ │ + └───────┬───────────┬───────────┘ + loads at runtime │ │ loads at runtime + ┌─────────▼──┐ ┌────▼───────┐ + │ Remote A │ │ Remote B │ + │ (own repo, │ │ (own repo, │ + │ own build)│ │ own build)│ + └─────┬──────┘ └─────┬──────┘ + └──── event bus ──┘ (decoupled contract) + +Shared singletons: framework runtime, design-system, i18n +Communication: window CustomEvent | injected pub/sub | URL state +Failure mode: remote load rejects -> shell renders + +Non-functional targets: + shell-only JS <= 100 KB gzipped + remote entry <= 30 KB gzipped + broken remote -> rest of page stays interactive +``` + +## Stretch Goals + +- Add a runtime registry so remotes can be added without editing the shell config. +- Implement independent CI/CD where each remote publishes a versioned `remoteEntry` to a CDN. +- Support two frameworks in different remotes (e.g. React + Vue) to prove true isolation. +- Add server-side composition or an app-shell prerender for first-paint performance. + +## Definition of Done + +- [ ] Two remotes deploy independently and the shell picks up new versions without a rebuild. +- [ ] Bundle analysis proves shared libraries load once, not once per remote. +- [ ] A deliberately broken remote shows a fallback while the rest of the page stays interactive. +- [ ] Deep links into a remote's sub-route load correctly on a cold page load. +- [ ] Remotes exchange at least one message through the agreed contract, with no direct imports between them. + +## Common Pitfalls + +- Mismatched shared-dependency versions causing two framework copies to load and hooks to break subtly. +- Coupling remotes through a shared global object instead of an explicit contract — it recreates the monolith you were escaping. +- Letting each remote own routing, producing conflicting history writes and broken back-button behavior. +- Ignoring the failure path, so one 404 on a `remoteEntry` blanks the entire screen. +- Duplicating CSS resets and design tokens per remote, causing visual drift across boundaries. + +## Resources + +- [Module Federation documentation](https://module-federation.io/) — the canonical guide to the federation runtime and shared scopes. +- [martinfowler.com: Micro Frontends](https://martinfowler.com/articles/micro-frontends.html) — the reference article on the architecture and its trade-offs. +- [web.dev: Reduce JavaScript payloads with code splitting](https://web.dev/articles/reduce-javascript-payloads-with-code-splitting) — the bundling foundation federation builds on. +- [MDN: CustomEvent](https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent) — a framework-agnostic way to build a decoupled event bus. diff --git a/projects/frontend/advanced/01-microfrontend-architecture/README.pt-BR.md b/projects/frontend/advanced/01-microfrontend-architecture/README.pt-BR.md new file mode 100644 index 0000000..4e33bab --- /dev/null +++ b/projects/frontend/advanced/01-microfrontend-architecture/README.pt-BR.md @@ -0,0 +1,100 @@ +# Arquitetura de Microfrontends + +> 🌐 [English](./README.md) · **Português** + +**Domínio:** Frontend · **Nível:** Avançado · **Tempo estimado:** 1–2 semanas + +## Visão Geral + +Divida um único frontend grande em várias aplicações construídas e implantadas de forma independente que se compõem em um produto único e coeso em tempo de execução — o padrão por trás de UIs em larga escala no Spotify, na IKEA e na DAZN. Um "shell" (host) carrega apps de funcionalidades (remotes) sob demanda, para que os times entreguem no seu próprio ritmo sem um trem de release compartilhado. As partes difíceis não são os mecanismos de carregamento, mas as fronteiras: versões de dependências compartilhadas, comunicação entre apps, roteamento consistente e um shell que degrada com elegância quando um remote falha. Este projeto força você a encarar o trade-off no coração de todo sistema de microfrontends — autonomia dos times versus consistência do produto — e a defendê-lo com medições reais, não com opinião. + +## Pré-requisitos + +- Uma SPA de nível de produção já construída (o [Painel Administrativo](../../intermediate/05-admin-panel/) é uma boa base) +- Domínio sólido de módulos ES, empacotamento e code splitting +- Conforto com roteamento no cliente e seu modelo de histórico +- Familiaridade com um bundler que suporte federação (Vite, Webpack 5 ou Rspack) + +## Objetivos de Aprendizado + +Ao final, você deve ser capaz de: + +- Compor múltiplos apps implantados de forma independente atrás de um shell em tempo de execução +- Compartilhar bibliotecas pesadas (runtime do framework, design system) como singletons para evitar duplicação +- Projetar um contrato de comunicação desacoplado entre remotes sem estado global compartilhado +- Coordenar o roteamento para que deep links resolvam corretamente através das fronteiras dos apps +- Isolar falhas para que um remote quebrado nunca apague a página inteira + +## Requisitos Funcionais + +1. Um shell host deve carregar dinamicamente pelo menos duas aplicações remote construídas de forma independente em tempo de execução. +2. Cada remote deve ser construível e implantável por conta própria, sem reconstruir o shell. +3. As bibliotecas de framework e design system compartilhadas devem resolver para uma única instância, não uma cópia por remote. +4. O shell deve ser dono do roteamento de nível superior e delegar sub-rotas ao remote responsável. +5. Os remotes devem se comunicar por um contrato explícito (eventos customizados ou um event bus injetado), nunca acessando as entranhas um do outro. +6. Se um remote falhar ao carregar ou lançar erro na montagem, o shell deve renderizar um fallback e manter o resto da página utilizável. +7. Os metadados de versão de cada remote carregado devem ser observáveis em tempo de execução (ex.: logados ou exibidos em um painel de debug). + +## Marcos Sugeridos + +1. **Marco 1 — Shell + um remote:** Suba um host que carrega um único remote via module federation e o renderiza em uma rota. +2. **Marco 2 — Segundo remote e deps compartilhadas:** Adicione um segundo remote e configure singletons compartilhados; prove que só uma cópia do framework é enviada. +3. **Marco 3 — Comunicação e roteamento:** Conecte a mensageria entre remotes e o roteamento por deep link de ponta a ponta entre fronteiras. +4. **Marco 4 — Resiliência e versionamento:** Adicione error boundaries, fallbacks de carga e relato de versão em tempo de execução por remote. + +## Esboço de Dados e Interface + +```text + ┌──────────────────────────────┐ + │ Shell (host) │ + │ roteamento · layout · auth │ + │ singletons compartilhados ↓ │ + └───────┬───────────┬───────────┘ + carrega em runtime │ │ carrega em runtime + ┌─────────▼──┐ ┌────▼───────┐ + │ Remote A │ │ Remote B │ + │ (repo e │ │ (repo e │ + │ build │ │ build │ + │ próprios) │ │ próprios) │ + └─────┬──────┘ └─────┬──────┘ + └──── event bus ──┘ (contrato desacoplado) + +Singletons compartilhados: runtime do framework, design system, i18n +Comunicação: window CustomEvent | pub/sub injetado | estado na URL +Modo de falha: carga do remote rejeita -> shell renderiza + +Metas não funcionais: + JS só do shell <= 100 KB gzipado + entry do remote <= 30 KB gzipado + remote quebrado -> resto da página segue interativo +``` + +## Desafios Extras + +- Adicione um registro em tempo de execução para que remotes possam ser adicionados sem editar a config do shell. +- Implemente CI/CD independente onde cada remote publica um `remoteEntry` versionado em uma CDN. +- Suporte dois frameworks em remotes diferentes (ex.: React + Vue) para provar isolamento real. +- Adicione composição no servidor ou um prerender de app-shell para desempenho de primeira pintura. + +## Definição de Pronto + +- [ ] Dois remotes implantam de forma independente e o shell adota novas versões sem um rebuild. +- [ ] A análise de bundle prova que as bibliotecas compartilhadas carregam uma vez, não uma por remote. +- [ ] Um remote deliberadamente quebrado mostra um fallback enquanto o resto da página segue interativo. +- [ ] Deep links para a sub-rota de um remote carregam corretamente em um carregamento frio. +- [ ] Os remotes trocam pelo menos uma mensagem pelo contrato acordado, sem imports diretos entre eles. + +## Armadilhas Comuns + +- Versões incompatíveis de dependências compartilhadas fazendo duas cópias do framework carregarem e os hooks quebrarem de forma sutil. +- Acoplar remotes por um objeto global compartilhado em vez de um contrato explícito — recria o monólito do qual você fugia. +- Deixar cada remote dono do roteamento, produzindo escritas de histórico conflitantes e um botão voltar quebrado. +- Ignorar o caminho de falha, de modo que um 404 em um `remoteEntry` apaga a tela inteira. +- Duplicar resets de CSS e design tokens por remote, causando desvio visual entre fronteiras. + +## Recursos + +- [Documentação do Module Federation](https://module-federation.io/) — o guia canônico do runtime de federação e dos escopos compartilhados. +- [martinfowler.com: Micro Frontends](https://martinfowler.com/articles/micro-frontends.html) — o artigo de referência sobre a arquitetura e seus trade-offs. +- [web.dev: Reduza payloads de JavaScript com code splitting](https://web.dev/articles/reduce-javascript-payloads-with-code-splitting) — a base de empacotamento sobre a qual a federação se apoia. +- [MDN: CustomEvent](https://developer.mozilla.org/pt-BR/docs/Web/API/CustomEvent) — uma forma agnóstica de framework para construir um event bus desacoplado. diff --git a/projects/frontend/advanced/02-collaborative-editor/README.md b/projects/frontend/advanced/02-collaborative-editor/README.md index 0da85a1..7b1addb 100644 --- a/projects/frontend/advanced/02-collaborative-editor/README.md +++ b/projects/frontend/advanced/02-collaborative-editor/README.md @@ -1,34 +1,94 @@ # Real-time Collaborative Editor (like Google Docs) -## Idea -Build a collaborative document editor supporting real-time synchronization. Learn about operational transformation, WebSockets, and conflict resolution. +> 🌐 **English** · [Português](./README.pt-BR.md) + +**Domain:** Frontend · **Level:** Advanced · **Estimated time:** 1–2 weeks + +## Overview + +Build a document editor where several people type into the same document at once and every keystroke shows up on everyone's screen within moments — the experience Google Docs, Notion, and Figma popularized. The deceptively simple demo hides the hardest problem in collaborative software: two users edit the same spot offline, then reconnect, and the system must merge both intents into one consistent document without a central lock. You will lean on a proven convergence algorithm (CRDT or operational transformation) rather than inventing your own, and spend your energy on the frontend concerns that make it feel alive: remote cursors, presence, and an editor that never blocks the local typist waiting on the network. + +## Prerequisites + +- Comfortable building interactive apps with real-time state (a [Chat Application](../../intermediate/04-chat-ui/) is a good stepping stone) +- Working knowledge of WebSockets and event-driven data flow +- Understanding of the browser Selection and Range APIs, or a rich-text framework +- Awareness that naive "last write wins" loses data — the motivation for this project ## Learning Objectives -- Implement operational transformation -- Sync changes across clients -- Handle concurrent edits -- Manage merge conflicts -- Build presence indicators - -## Implementation Tips -- Implement cursor positions -- Add collaborative editing library (Yjs, Automerge) -- Create presence awareness -- Implement change tracking -- Add version history -- Implement undo/redo -- Create sharing functionality -- Implement permissions -- Add commenting system -- Create revision comparison -- Implement real-time sync -- Add offline support -- Create notification for changes -- Implement conflict resolution - -## Key Challenges -- Operational transformation complexity -- Real-time synchronization -- Merge conflict resolution -- Performance with many users -- State consistency + +By the end, you should be able to: + +- Explain why concurrent edits need CRDTs or OT rather than a simple locking scheme +- Integrate a convergence library (Yjs or Automerge) with a rich-text editing surface +- Render remote cursors and selections mapped to positions in the live document +- Keep local edits instant (optimistic) while background sync reconciles state +- Preserve edits made offline and merge them cleanly on reconnection + +## Functional Requirements + +1. Two or more clients editing the same document must converge to identical content after all changes propagate. +2. A local edit must appear instantly, without waiting for a server round-trip. +3. Each connected user's cursor and text selection must be visible to others, labelled and colored per user. +4. A presence list must show who is currently in the document and update on join/leave. +5. Edits made while offline must be retained and merged automatically once the connection returns. +6. Concurrent edits to the same region must merge deterministically, never silently dropping a user's input. +7. Undo/redo must operate on the local user's own changes without reverting other users' edits. + +## Suggested Milestones + +1. **Milestone 1 — Single-user editor + transport:** Build the editing surface and a WebSocket channel that echoes changes. +2. **Milestone 2 — Convergence:** Adopt a CRDT/OT library so two clients merge concurrent edits correctly. +3. **Milestone 3 — Presence & cursors:** Broadcast and render remote cursors, selections, and a live presence list. +4. **Milestone 4 — Offline & history:** Queue offline edits, merge on reconnect, and add per-user undo/redo. + +## Data & Interface Sketch + +```text + Client A Sync server Client B + ┌──────────┐ local ops ┌───────────────┐ ops ┌──────────┐ + │ editor │ ───────────────▶│ relay + doc │───────────▶│ editor │ + │ CRDT doc │◀─────────────── │ state (opt.) │◀───────────│ CRDT doc │ + └────┬─────┘ remote ops └───────────────┘ └────┬─────┘ + │ optimistic apply (instant, local-first) │ + └── presence: { userId, name, color, cursor, selection } ─┘ + +Op (conceptual): { type: insert|delete, pos, value?, origin, lamport } +Awareness: ephemeral, not persisted — cursors, presence, typing +Convergence: CRDT (Yjs / Automerge) or OT — pick and justify + +Non-functional targets: + local keystroke -> on screen < 16 ms (no network wait) + edit -> peer visible < 250 ms on a healthy link + offline edits never lost on reconnect +``` + +## Stretch Goals + +- Add a version history with named snapshots and a diff view between revisions. +- Support inline comments and suggestions anchored to a text range that survive edits. +- Add document-level permissions (view / comment / edit) enforced on the server. +- Show a "reconnecting" state with an edit queue counter, then a clean catch-up animation. + +## Definition of Done + +- [ ] Two browsers editing simultaneously end with byte-identical documents. +- [ ] Typing feels instant even with artificial network latency added in dev tools. +- [ ] Remote cursors track the correct character position as text is inserted above them. +- [ ] Disconnecting one client, editing on both, then reconnecting merges without data loss. +- [ ] Undo reverts only the local user's last action, leaving remote edits intact. + +## Common Pitfalls + +- Reinventing operational transformation from scratch — it is notoriously subtle; use a vetted library. +- Storing cursor positions as absolute offsets, so they point to the wrong place after remote inserts. +- Persisting ephemeral awareness data (cursors, presence) into the document and bloating it. +- Blocking the UI on server acknowledgement, destroying the instant-typing feel. +- Assuming ordered, reliable delivery — networks reorder and drop; the merge must not depend on arrival order. + +## Resources + +- [Yjs documentation](https://docs.yjs.dev/) — a mature CRDT framework with editor bindings and an awareness protocol. +- [Automerge](https://automerge.org/) — an alternative CRDT library with a strong data-structure model. +- [Martin Kleppmann: CRDTs — the hard parts](https://www.youtube.com/watch?v=x7drE24geUw) — a rigorous talk on convergence guarantees. +- [MDN: Selection API](https://developer.mozilla.org/en-US/docs/Web/API/Selection) — the browser primitive behind cursor and range handling. diff --git a/projects/frontend/advanced/02-collaborative-editor/README.pt-BR.md b/projects/frontend/advanced/02-collaborative-editor/README.pt-BR.md new file mode 100644 index 0000000..943e486 --- /dev/null +++ b/projects/frontend/advanced/02-collaborative-editor/README.pt-BR.md @@ -0,0 +1,94 @@ +# Editor Colaborativo em Tempo Real (como o Google Docs) + +> 🌐 [English](./README.md) · **Português** + +**Domínio:** Frontend · **Nível:** Avançado · **Tempo estimado:** 1–2 semanas + +## Visão Geral + +Construa um editor de documentos onde várias pessoas digitam no mesmo documento ao mesmo tempo e cada tecla aparece na tela de todos em instantes — a experiência que o Google Docs, o Notion e o Figma popularizaram. A demo enganosamente simples esconde o problema mais difícil do software colaborativo: dois usuários editam o mesmo ponto offline, reconectam, e o sistema deve fundir ambas as intenções em um documento consistente sem um lock central. Você vai se apoiar em um algoritmo de convergência comprovado (CRDT ou transformação operacional) em vez de inventar o seu, e gastar sua energia nas preocupações de frontend que fazem tudo parecer vivo: cursores remotos, presença e um editor que nunca trava o digitador local esperando a rede. + +## Pré-requisitos + +- Conforto em construir apps interativos com estado em tempo real (uma [Aplicação de Chat](../../intermediate/04-chat-ui/) é um bom degrau) +- Conhecimento prático de WebSockets e fluxo de dados orientado a eventos +- Entendimento das APIs Selection e Range do navegador, ou de um framework de rich-text +- Consciência de que o ingênuo "last write wins" perde dados — a motivação deste projeto + +## Objetivos de Aprendizado + +Ao final, você deve ser capaz de: + +- Explicar por que edições concorrentes precisam de CRDTs ou OT em vez de um esquema simples de lock +- Integrar uma biblioteca de convergência (Yjs ou Automerge) com uma superfície de edição rich-text +- Renderizar cursores e seleções remotas mapeados para posições no documento vivo +- Manter as edições locais instantâneas (otimistas) enquanto a sincronização em segundo plano reconcilia o estado +- Preservar edições feitas offline e fundi-las de forma limpa na reconexão + +## Requisitos Funcionais + +1. Dois ou mais clientes editando o mesmo documento devem convergir para conteúdo idêntico após todas as mudanças se propagarem. +2. Uma edição local deve aparecer instantaneamente, sem esperar por uma ida e volta ao servidor. +3. O cursor e a seleção de texto de cada usuário conectado devem ser visíveis aos demais, rotulados e coloridos por usuário. +4. Uma lista de presença deve mostrar quem está atualmente no documento e atualizar ao entrar/sair. +5. Edições feitas offline devem ser retidas e fundidas automaticamente assim que a conexão retornar. +6. Edições concorrentes na mesma região devem fundir de forma determinística, nunca descartando silenciosamente a entrada de um usuário. +7. Desfazer/refazer deve operar sobre as próprias mudanças do usuário local sem reverter as edições dos outros. + +## Marcos Sugeridos + +1. **Marco 1 — Editor de usuário único + transporte:** Construa a superfície de edição e um canal WebSocket que ecoa as mudanças. +2. **Marco 2 — Convergência:** Adote uma biblioteca CRDT/OT para que dois clientes fundam edições concorrentes corretamente. +3. **Marco 3 — Presença e cursores:** Transmita e renderize cursores remotos, seleções e uma lista de presença ao vivo. +4. **Marco 4 — Offline e histórico:** Enfileire edições offline, funda na reconexão e adicione desfazer/refazer por usuário. + +## Esboço de Dados e Interface + +```text + Cliente A Servidor de sync Cliente B + ┌──────────┐ ops locais ┌───────────────┐ ops ┌──────────┐ + │ editor │ ───────────────▶│ relay + estado│───────────▶│ editor │ + │ doc CRDT │◀─────────────── │ do doc (opc.) │◀───────────│ doc CRDT │ + └────┬─────┘ ops remotas └───────────────┘ └────┬─────┘ + │ aplicação otimista (instantânea, local-first) │ + └── presença: { userId, nome, cor, cursor, selection } ───┘ + +Op (conceitual): { type: insert|delete, pos, value?, origin, lamport } +Awareness: efêmero, não persistido — cursores, presença, digitação +Convergência: CRDT (Yjs / Automerge) ou OT — escolha e justifique + +Metas não funcionais: + tecla local -> na tela < 16 ms (sem espera de rede) + edição -> visível no par < 250 ms em um link saudável + edições offline nunca perdidas na reconexão +``` + +## Desafios Extras + +- Adicione um histórico de versões com snapshots nomeados e uma visão de diff entre revisões. +- Suporte comentários e sugestões inline ancorados a um intervalo de texto que sobrevivem às edições. +- Adicione permissões em nível de documento (visualizar / comentar / editar) aplicadas no servidor. +- Mostre um estado de "reconectando" com um contador da fila de edições, depois uma animação limpa de recuperação. + +## Definição de Pronto + +- [ ] Dois navegadores editando simultaneamente terminam com documentos byte a byte idênticos. +- [ ] A digitação parece instantânea mesmo com latência de rede artificial adicionada no dev tools. +- [ ] Cursores remotos acompanham a posição de caractere correta conforme texto é inserido acima deles. +- [ ] Desconectar um cliente, editar em ambos e reconectar funde sem perda de dados. +- [ ] Desfazer reverte apenas a última ação do usuário local, deixando as edições remotas intactas. + +## Armadilhas Comuns + +- Reinventar a transformação operacional do zero — é notoriamente sutil; use uma biblioteca testada. +- Armazenar posições de cursor como offsets absolutos, apontando para o lugar errado após inserções remotas. +- Persistir dados efêmeros de awareness (cursores, presença) no documento e inchá-lo. +- Bloquear a UI esperando o reconhecimento do servidor, destruindo a sensação de digitação instantânea. +- Assumir entrega ordenada e confiável — redes reordenam e descartam; a fusão não pode depender da ordem de chegada. + +## Recursos + +- [Documentação do Yjs](https://docs.yjs.dev/) — um framework CRDT maduro com bindings de editor e um protocolo de awareness. +- [Automerge](https://automerge.org/) — uma biblioteca CRDT alternativa com um forte modelo de estrutura de dados. +- [Martin Kleppmann: CRDTs — the hard parts](https://www.youtube.com/watch?v=x7drE24geUw) — uma palestra rigorosa sobre garantias de convergência. +- [MDN: Selection API](https://developer.mozilla.org/pt-BR/docs/Web/API/Selection) — a primitiva do navegador por trás do tratamento de cursor e intervalo. diff --git a/projects/frontend/advanced/03-design-system/README.md b/projects/frontend/advanced/03-design-system/README.md index a383197..ecaff30 100644 --- a/projects/frontend/advanced/03-design-system/README.md +++ b/projects/frontend/advanced/03-design-system/README.md @@ -1,34 +1,96 @@ # Full Design System (component library) -## Idea -Create a comprehensive design system with reusable components, documentation, and Storybook integration. Learn about component design and documentation. +> 🌐 **English** · [Português](./README.pt-BR.md) + +**Domain:** Frontend · **Level:** Advanced · **Estimated time:** 1–2 weeks + +## Overview + +Build the shared visual foundation that many product teams consume — the layer behind Material, Carbon, and Polaris. A real design system is more than a folder of components: it is a token layer (colors, spacing, type) that feeds themeable, accessible components, published as a versioned package with living documentation. The engineering challenge is governance at scale. How do you evolve a button used by forty screens without breaking any of them? How do you catch a one-pixel visual regression before a consumer does? This project treats the system as a product with its own users, its own release process, and its own contract — semantic versioning, visual regression tests, and docs that never drift from the code. + +## Prerequisites + +- Solid component-authoring experience in one framework +- Understanding of CSS custom properties and the cascade +- Familiarity with a package registry and semantic versioning +- Comfort setting up a build that emits a distributable library ## Learning Objectives -- Design component architecture -- Implement component library -- Create documentation -- Build Storybook stories -- Manage component versioning - -## Implementation Tips -- Define design tokens (colors, spacing, typography) -- Create base components (buttons, inputs, cards) -- Build composite components -- Implement accessibility features -- Create Storybook documentation -- Add component variations -- Create usage guidelines -- Implement theming support -- Add responsive design -- Create component testing -- Build changelog -- Implement versioning strategy -- Create component playground -- Add visual regression testing - -## Key Challenges -- Design consistency -- Component reusability -- Documentation maintenance -- Version management -- Breaking changes handling + +By the end, you should be able to: + +- Model a design-token layer that themes propagate through, decoupled from components +- Author accessible, composable components with well-typed, minimal APIs +- Publish a versioned package and communicate breaking changes via semver + changelog +- Catch visual and accessibility regressions automatically before release +- Maintain documentation that is generated from, and stays in sync with, the source + +## Functional Requirements + +1. Design tokens (color, spacing, typography, radius) must be defined once and consumed by all components. +2. At least two themes (e.g. light/dark) must switch purely by swapping token values, with no component code changes. +3. Every interactive component must be keyboard-operable and expose correct roles/ARIA. +4. The library must build into a tree-shakeable, versioned package that a separate app can install and import. +5. Documentation must render live, interactive examples of each component and its props. +6. A visual regression test must fail the build when a component's rendered output changes unexpectedly. +7. Breaking changes must bump the major version and be recorded in a human-readable changelog. + +## Suggested Milestones + +1. **Milestone 1 — Tokens & primitives:** Define the token layer and a few base components consuming it. +2. **Milestone 2 — Theming & a11y:** Add theme switching and make components keyboard- and screen-reader-friendly. +3. **Milestone 3 — Docs & playground:** Stand up Storybook (or equivalent) with interactive prop controls. +4. **Milestone 4 — Release pipeline:** Add visual regression + a11y checks and a versioned publish flow. + +## Data & Interface Sketch + +```text + ┌─────────────────────────────────────────────┐ + │ Design tokens │ + │ color.* · space.* · font.* · radius.* │ + └───────────────┬─────────────────────────────┘ + │ CSS variables / theme object + ┌───────────────▼─────────────────────────────┐ + │ Primitives: Box, Text, Icon, Stack │ + └───────────────┬─────────────────────────────┘ + ┌───────────────▼─────────────────────────────┐ + │ Components: Button, Input, Modal, Table │ + └───────────────┬─────────────────────────────┘ + ┌───────┴────────┐ ┌────────────────────┐ + │ Docs (stories) │ │ npm package (semver)│ + └────────────────┘ └────────────────────┘ + +Token flow: token -> theme -> component (never hard-coded hex) +Versioning: patch=fix · minor=additive · major=breaking API/visual +Gates: visual regression snapshot + axe a11y scan per PR +``` + +## Stretch Goals + +- Add a token pipeline (e.g. Style Dictionary) that emits CSS, JS, and native formats from one source. +- Generate an accessibility report per component and publish it alongside the docs. +- Support a runtime theming API so consumers can brand the system without a rebuild. +- Add a "deprecations" mechanism that warns in dev when a soon-to-be-removed prop is used. + +## Definition of Done + +- [ ] Switching theme changes the whole UI by swapping tokens, with zero component edits. +- [ ] A consuming app installs the package and imports only the components it uses (verified by bundle size). +- [ ] Every interactive component passes keyboard-only operation and an automated a11y scan. +- [ ] An intentional visual change fails the regression suite until the snapshot is reviewed and updated. +- [ ] The changelog and version reflect the nature of each change (patch/minor/major). + +## Common Pitfalls + +- Hard-coding colors and spacing in components instead of referencing tokens, breaking theming. +- Over-engineering component APIs with dozens of props instead of favoring composition. +- Letting docs drift from code by writing them by hand rather than generating from source. +- Publishing breaking changes as minor versions, silently breaking downstream apps. +- Treating accessibility as a later pass rather than a per-component acceptance criterion. + +## Resources + +- [Storybook documentation](https://storybook.js.org/docs) — the standard for building and documenting components in isolation. +- [Design Tokens Community Group format](https://tr.designtokens.org/format/) — the emerging standard for portable design tokens. +- [WAI-ARIA Authoring Practices Guide](https://www.w3.org/WAI/ARIA/apg/) — authoritative patterns for accessible components. +- [Semantic Versioning](https://semver.org/) — the contract for communicating change through version numbers. diff --git a/projects/frontend/advanced/03-design-system/README.pt-BR.md b/projects/frontend/advanced/03-design-system/README.pt-BR.md new file mode 100644 index 0000000..8c0880d --- /dev/null +++ b/projects/frontend/advanced/03-design-system/README.pt-BR.md @@ -0,0 +1,96 @@ +# Design System Completo (biblioteca de componentes) + +> 🌐 [English](./README.md) · **Português** + +**Domínio:** Frontend · **Nível:** Avançado · **Tempo estimado:** 1–2 semanas + +## Visão Geral + +Construa a fundação visual compartilhada que muitos times de produto consomem — a camada por trás do Material, do Carbon e do Polaris. Um design system de verdade é mais do que uma pasta de componentes: é uma camada de tokens (cores, espaçamento, tipografia) que alimenta componentes acessíveis e tematizáveis, publicada como um pacote versionado com documentação viva. O desafio de engenharia é a governança em escala. Como evoluir um botão usado por quarenta telas sem quebrar nenhuma delas? Como pegar uma regressão visual de um pixel antes que um consumidor pegue? Este projeto trata o sistema como um produto com seus próprios usuários, seu próprio processo de release e seu próprio contrato — versionamento semântico, testes de regressão visual e docs que nunca se descolam do código. + +## Pré-requisitos + +- Experiência sólida em criar componentes em um framework (uma [Biblioteca de Componentes Reutilizáveis](../../intermediate/06-markdown-editor/) é um bom aquecimento) +- Entendimento de propriedades customizadas de CSS e da cascata +- Familiaridade com um registro de pacotes e versionamento semântico +- Conforto em configurar um build que emite uma biblioteca distribuível + +## Objetivos de Aprendizado + +Ao final, você deve ser capaz de: + +- Modelar uma camada de design tokens pela qual os temas se propagam, desacoplada dos componentes +- Criar componentes acessíveis e componíveis com APIs mínimas e bem tipadas +- Publicar um pacote versionado e comunicar mudanças que quebram via semver + changelog +- Pegar regressões visuais e de acessibilidade automaticamente antes do release +- Manter documentação gerada a partir do código-fonte e sincronizada com ele + +## Requisitos Funcionais + +1. Os design tokens (cor, espaçamento, tipografia, raio) devem ser definidos uma vez e consumidos por todos os componentes. +2. Pelo menos dois temas (ex.: claro/escuro) devem alternar puramente trocando valores de tokens, sem mudanças de código nos componentes. +3. Todo componente interativo deve ser operável por teclado e expor roles/ARIA corretos. +4. A biblioteca deve compilar em um pacote versionado e tree-shakeable que um app separado possa instalar e importar. +5. A documentação deve renderizar exemplos vivos e interativos de cada componente e suas props. +6. Um teste de regressão visual deve falhar o build quando a saída renderizada de um componente muda inesperadamente. +7. Mudanças que quebram devem incrementar a versão maior e ser registradas em um changelog legível. + +## Marcos Sugeridos + +1. **Marco 1 — Tokens e primitivos:** Defina a camada de tokens e alguns componentes base que a consomem. +2. **Marco 2 — Temas e a11y:** Adicione troca de temas e torne os componentes amigáveis a teclado e leitor de tela. +3. **Marco 3 — Docs e playground:** Suba o Storybook (ou equivalente) com controles interativos de props. +4. **Marco 4 — Pipeline de release:** Adicione checagens de regressão visual + a11y e um fluxo de publish versionado. + +## Esboço de Dados e Interface + +```text + ┌─────────────────────────────────────────────┐ + │ Design tokens │ + │ color.* · space.* · font.* · radius.* │ + └───────────────┬─────────────────────────────┘ + │ variáveis CSS / objeto de tema + ┌───────────────▼─────────────────────────────┐ + │ Primitivos: Box, Text, Icon, Stack │ + └───────────────┬─────────────────────────────┘ + ┌───────────────▼─────────────────────────────┐ + │ Componentes: Button, Input, Modal, Table │ + └───────────────┬─────────────────────────────┘ + ┌───────┴────────┐ ┌────────────────────┐ + │ Docs (stories) │ │ pacote npm (semver)│ + └────────────────┘ └────────────────────┘ + +Fluxo de token: token -> tema -> componente (nunca hex fixo) +Versionamento: patch=fix · minor=aditivo · major=API/visual que quebra +Portões: snapshot de regressão visual + scan a11y axe por PR +``` + +## Desafios Extras + +- Adicione um pipeline de tokens (ex.: Style Dictionary) que emite CSS, JS e formatos nativos de uma única fonte. +- Gere um relatório de acessibilidade por componente e publique-o junto à documentação. +- Suporte uma API de tematização em tempo de execução para que consumidores personalizem a marca sem um rebuild. +- Adicione um mecanismo de "deprecações" que avisa em dev quando uma prop prestes a ser removida é usada. + +## Definição de Pronto + +- [ ] Trocar o tema muda toda a UI trocando tokens, com zero edições em componentes. +- [ ] Um app consumidor instala o pacote e importa apenas os componentes que usa (verificado pelo tamanho do bundle). +- [ ] Todo componente interativo passa na operação apenas por teclado e em um scan automatizado de a11y. +- [ ] Uma mudança visual intencional falha a suíte de regressão até o snapshot ser revisado e atualizado. +- [ ] O changelog e a versão refletem a natureza de cada mudança (patch/minor/major). + +## Armadilhas Comuns + +- Fixar cores e espaçamentos nos componentes em vez de referenciar tokens, quebrando a tematização. +- Superengenheirar as APIs de componentes com dezenas de props em vez de favorecer composição. +- Deixar os docs se descolarem do código ao escrevê-los à mão em vez de gerá-los a partir da fonte. +- Publicar mudanças que quebram como versões menores, quebrando silenciosamente apps downstream. +- Tratar acessibilidade como uma etapa posterior em vez de um critério de aceite por componente. + +## Recursos + +- [Documentação do Storybook](https://storybook.js.org/docs) — o padrão para construir e documentar componentes em isolamento. +- [Formato do Design Tokens Community Group](https://tr.designtokens.org/format/) — o padrão emergente para design tokens portáveis. +- [WAI-ARIA Authoring Practices Guide](https://www.w3.org/WAI/ARIA/apg/) — padrões autoritativos para componentes acessíveis. +- [Versionamento Semântico](https://semver.org/lang/pt-BR/) — o contrato para comunicar mudança através de números de versão. diff --git a/projects/frontend/advanced/04-offline-first-pwa/README.md b/projects/frontend/advanced/04-offline-first-pwa/README.md index c570322..59a8f34 100644 --- a/projects/frontend/advanced/04-offline-first-pwa/README.md +++ b/projects/frontend/advanced/04-offline-first-pwa/README.md @@ -1,34 +1,98 @@ # Offline-First PWA -## Idea -Build a Progressive Web App that works offline with service workers and local caching. Learn about service workers, cache strategies, and offline UX. +> 🌐 **English** · [Português](./README.pt-BR.md) + +**Domain:** Frontend · **Level:** Advanced · **Estimated time:** 1–2 weeks + +## Overview + +Build a Progressive Web App that treats the network as an enhancement, not a requirement — the app keeps working on a train, in a tunnel, or on a flaky connection, then quietly syncs when the network returns. This inverts the usual assumption that data lives on a server and the client is a thin view. Here the client owns a durable local store, renders from it instantly, and reconciles with the backend in the background. The hard parts are the ones users notice only when they break: a stale cache serving last week's data, a background sync that silently loses a write, or two edits that collide after a reconnect. You will design cache strategies deliberately and make the offline state a first-class, visible part of the UX. + +## Prerequisites + +- A working single-page app you can retrofit (an [Intermediate](../../intermediate/) project works well) +- Understanding of the request/response lifecycle and HTTP caching headers +- Familiarity with Promises and asynchronous data flow +- Awareness of IndexedDB or a wrapper as a client-side database ## Learning Objectives -- Implement service workers -- Create cache strategies -- Handle offline state -- Implement sync strategies -- Create offline UI - -## Implementation Tips -- Register service workers -- Implement caching strategies (cache-first, network-first) -- Create offline page -- Implement background sync -- Add periodic sync -- Handle offline state display -- Create data synchronization on reconnection -- Implement push notifications -- Create install prompts -- Add app shortcuts -- Implement update detection -- Create offline-first architecture -- Add data conflict resolution -- Implement performance optimization - -## Key Challenges -- Cache invalidation -- Sync reliability -- Offline data consistency -- User experience offline -- Background sync reliability + +By the end, you should be able to: + +- Register a service worker and intercept network requests with chosen cache strategies +- Choose per-resource strategies (cache-first, network-first, stale-while-revalidate) and justify each +- Persist application data locally in IndexedDB and render from it before the network responds +- Queue writes made offline and replay them reliably on reconnection via Background Sync +- Communicate connectivity and sync status clearly so the user is never confused about data freshness + +## Functional Requirements + +1. The app must load and be usable on a repeat visit with the network fully disabled. +2. Static assets (app shell) must be served from cache and updated safely when a new version deploys. +3. Application data must be readable offline from a local store, not just static HTML. +4. A write performed offline must be queued and automatically synced once connectivity returns. +5. The UI must clearly indicate offline status and pending, unsynced changes. +6. A new service worker version must not serve a broken mix of old and new assets. +7. Conflicting edits (local vs. server) must be resolved by an explicit, documented strategy — not silent loss. + +## Suggested Milestones + +1. **Milestone 1 — Installable shell:** Add a manifest and a service worker that caches the app shell for offline load. +2. **Milestone 2 — Offline data:** Store and read application data in IndexedDB; render from it first. +3. **Milestone 3 — Write queue & sync:** Queue offline mutations and replay them with Background Sync on reconnect. +4. **Milestone 4 — Conflicts & updates:** Handle edit conflicts and safe service-worker version rollovers. + +## Data & Interface Sketch + +```text + Browser tab Service worker Network + ┌────────────┐ fetch ┌─────────────────┐ fetch ┌────────┐ + │ UI reads │────────────▶ │ strategy router │─────────▶ │ API │ + │ from IDB │◀──────────── │ cache | network │◀───────── │ │ + └─────┬──────┘ response └────────┬────────┘ └────────┘ + │ writes │ cache + ┌─────▼───────────┐ ┌─────────▼────────┐ + │ IndexedDB │ │ Cache Storage │ + │ data + outbox │ │ app shell + assets│ + └─────┬───────────┘ └──────────────────┘ + │ Background Sync replays outbox on reconnect + └──────────────────────────────────────────▶ API + +Strategies: shell=cache-first · data=stale-while-revalidate · writes=queued +Conflicts: last-write-wins | version vector | manual merge — pick + document + +Non-functional targets: + repeat visit offline fully usable + app-shell cached size <= 200 KB + queued write on reconnect never lost, replayed once (idempotent) +``` + +## Stretch Goals + +- Add push notifications that surface even when the app is closed. +- Implement periodic background sync to refresh data before the user reopens the app. +- Add an install prompt with a custom, well-timed UX rather than the raw browser banner. +- Show a per-item sync badge (synced / pending / failed) with retry. + +## Definition of Done + +- [ ] With the network off, a repeat visitor can open the app, read data, and make an edit. +- [ ] That offline edit appears synced to the server automatically after reconnecting, exactly once. +- [ ] Deploying a new version updates the service worker without serving a mismatched asset set. +- [ ] The UI shows offline status and a count of unsynced changes. +- [ ] A deliberately created edit conflict resolves by the documented strategy, losing no user intent silently. + +## Common Pitfalls + +- Caching everything with cache-first, so users are stuck on stale data with no update path. +- Forgetting service-worker lifecycle (`waiting`/`skipWaiting`), leaving users on an old version indefinitely. +- Treating IndexedDB writes as synchronous, causing lost updates under rapid interaction. +- Replaying the offline outbox without idempotency, duplicating server-side records on flaky reconnects. +- Hiding offline state entirely, so users think their unsynced work is safely saved to the server. + +## Resources + +- [web.dev: Offline cookbook](https://web.dev/articles/offline-cookbook) — the definitive catalogue of service-worker caching strategies. +- [MDN: Service Worker API](https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API) — lifecycle, scope, and fetch interception. +- [MDN: IndexedDB API](https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API) — the browser's durable client-side database. +- [web.dev: Background Sync](https://web.dev/articles/background-sync) — reliably deferring writes until connectivity returns. diff --git a/projects/frontend/advanced/04-offline-first-pwa/README.pt-BR.md b/projects/frontend/advanced/04-offline-first-pwa/README.pt-BR.md new file mode 100644 index 0000000..af9250e --- /dev/null +++ b/projects/frontend/advanced/04-offline-first-pwa/README.pt-BR.md @@ -0,0 +1,98 @@ +# PWA Offline-First + +> 🌐 [English](./README.md) · **Português** + +**Domínio:** Frontend · **Nível:** Avançado · **Tempo estimado:** 1–2 semanas + +## Visão Geral + +Construa um Progressive Web App que trata a rede como um aprimoramento, não um requisito — o app continua funcionando em um trem, num túnel ou numa conexão instável, e depois sincroniza discretamente quando a rede volta. Isso inverte a suposição usual de que os dados vivem em um servidor e o cliente é uma visão fina. Aqui o cliente é dono de um armazenamento local durável, renderiza a partir dele instantaneamente e reconcilia com o backend em segundo plano. As partes difíceis são as que os usuários só notam quando quebram: um cache obsoleto servindo dados da semana passada, um background sync que perde silenciosamente uma escrita, ou duas edições que colidem após uma reconexão. Você vai projetar estratégias de cache de forma deliberada e tornar o estado offline uma parte visível e de primeira classe da UX. + +## Pré-requisitos + +- Uma SPA funcional que você possa adaptar (um projeto [Intermediário](../../intermediate/) funciona bem) +- Entendimento do ciclo de vida requisição/resposta e dos cabeçalhos de cache HTTP +- Familiaridade com Promises e fluxo de dados assíncrono +- Consciência do IndexedDB ou de um wrapper como banco de dados no cliente + +## Objetivos de Aprendizado + +Ao final, você deve ser capaz de: + +- Registrar um service worker e interceptar requisições de rede com estratégias de cache escolhidas +- Escolher estratégias por recurso (cache-first, network-first, stale-while-revalidate) e justificar cada uma +- Persistir dados da aplicação localmente no IndexedDB e renderizar a partir deles antes de a rede responder +- Enfileirar escritas feitas offline e reproduzi-las de forma confiável na reconexão via Background Sync +- Comunicar o status de conectividade e de sincronização com clareza para que o usuário nunca fique confuso sobre a atualidade dos dados + +## Requisitos Funcionais + +1. O app deve carregar e ser utilizável em uma visita repetida com a rede totalmente desativada. +2. Os assets estáticos (app shell) devem ser servidos do cache e atualizados com segurança quando uma nova versão for implantada. +3. Os dados da aplicação devem ser legíveis offline a partir de um armazenamento local, não apenas HTML estático. +4. Uma escrita feita offline deve ser enfileirada e sincronizada automaticamente assim que a conectividade retornar. +5. A UI deve indicar claramente o status offline e as mudanças pendentes, não sincronizadas. +6. Uma nova versão do service worker não deve servir uma mistura quebrada de assets antigos e novos. +7. Edições conflitantes (local vs. servidor) devem ser resolvidas por uma estratégia explícita e documentada — não por perda silenciosa. + +## Marcos Sugeridos + +1. **Marco 1 — Shell instalável:** Adicione um manifest e um service worker que cacheia o app shell para carga offline. +2. **Marco 2 — Dados offline:** Armazene e leia dados da aplicação no IndexedDB; renderize a partir deles primeiro. +3. **Marco 3 — Fila de escrita e sync:** Enfileire mutações offline e reproduza-as com Background Sync na reconexão. +4. **Marco 4 — Conflitos e atualizações:** Trate conflitos de edição e trocas seguras de versão do service worker. + +## Esboço de Dados e Interface + +```text + Aba do navegador Service worker Rede + ┌────────────┐ fetch ┌─────────────────┐ fetch ┌────────┐ + │ UI lê do │────────────▶ │ roteador de │─────────▶ │ API │ + │ IndexedDB │◀──────────── │ estratégia │◀───────── │ │ + └─────┬──────┘ resposta └────────┬────────┘ └────────┘ + │ escritas │ cache + ┌─────▼───────────┐ ┌─────────▼────────┐ + │ IndexedDB │ │ Cache Storage │ + │ dados + outbox │ │ app shell + assets│ + └─────┬───────────┘ └──────────────────┘ + │ Background Sync reproduz a outbox na reconexão + └──────────────────────────────────────────▶ API + +Estratégias: shell=cache-first · dados=stale-while-revalidate · escritas=enfileiradas +Conflitos: last-write-wins | vetor de versão | merge manual — escolha + documente + +Metas não funcionais: + visita repetida offline totalmente utilizável + tamanho do shell cacheado <= 200 KB + escrita enfileirada na reconexão nunca perdida, reproduzida uma vez (idempotente) +``` + +## Desafios Extras + +- Adicione notificações push que aparecem mesmo com o app fechado. +- Implemente sincronização periódica em segundo plano para atualizar dados antes de o usuário reabrir o app. +- Adicione um prompt de instalação com uma UX customizada e bem cronometrada, em vez do banner cru do navegador. +- Mostre um selo de sync por item (sincronizado / pendente / falhou) com nova tentativa. + +## Definição de Pronto + +- [ ] Com a rede desligada, um visitante recorrente consegue abrir o app, ler dados e fazer uma edição. +- [ ] Essa edição offline aparece sincronizada ao servidor automaticamente após reconectar, exatamente uma vez. +- [ ] Implantar uma nova versão atualiza o service worker sem servir um conjunto de assets incompatível. +- [ ] A UI mostra o status offline e uma contagem de mudanças não sincronizadas. +- [ ] Um conflito de edição criado deliberadamente resolve pela estratégia documentada, sem perder intenção do usuário silenciosamente. + +## Armadilhas Comuns + +- Cachear tudo com cache-first, deixando usuários presos em dados obsoletos sem caminho de atualização. +- Esquecer o ciclo de vida do service worker (`waiting`/`skipWaiting`), deixando usuários em uma versão antiga indefinidamente. +- Tratar escritas no IndexedDB como síncronas, causando updates perdidos sob interação rápida. +- Reproduzir a outbox offline sem idempotência, duplicando registros no servidor em reconexões instáveis. +- Esconder o estado offline por completo, fazendo usuários pensarem que seu trabalho não sincronizado está salvo no servidor. + +## Recursos + +- [web.dev: Offline cookbook](https://web.dev/articles/offline-cookbook) — o catálogo definitivo de estratégias de cache de service worker. +- [MDN: Service Worker API](https://developer.mozilla.org/pt-BR/docs/Web/API/Service_Worker_API) — ciclo de vida, escopo e interceptação de fetch. +- [MDN: IndexedDB API](https://developer.mozilla.org/pt-BR/docs/Web/API/IndexedDB_API) — o banco de dados durável do navegador no cliente. +- [web.dev: Background Sync](https://web.dev/articles/background-sync) — adiar escritas de forma confiável até a conectividade retornar. diff --git a/projects/frontend/advanced/05-streaming-ui/README.md b/projects/frontend/advanced/05-streaming-ui/README.md index 42e16b9..7b326b6 100644 --- a/projects/frontend/advanced/05-streaming-ui/README.md +++ b/projects/frontend/advanced/05-streaming-ui/README.md @@ -1,34 +1,101 @@ # Streaming UI (video platform) -## Idea -Create a video streaming platform UI with adaptive bitrate selection and playback controls. Learn about video optimization and performance. +> 🌐 **English** · [Português](./README.pt-BR.md) + +**Domain:** Frontend · **Level:** Advanced · **Estimated time:** 1–2 weeks + +## Overview + +Build the playback experience of a video platform like YouTube or Netflix — adaptive streaming that shifts quality with the network, smooth controls, and an interface that stays responsive while a large media pipeline runs underneath. The core insight is that you do not download a video; you download a manifest describing many quality renditions split into small segments, and the player continuously chooses which segment to fetch next based on measured bandwidth and buffer health. Get that adaptation wrong and the user sees stalls or blurry frames; get the UI wrong and controls feel laggy against the heavy decode work. This project is about orchestrating an adaptive-bitrate engine and a polished, accessible player around it. + +## Prerequisites + +- Confident with asynchronous data flow and browser events +- Understanding of HTTP range requests and buffering concepts +- Familiarity with the HTML5 `