---
title: "Plano de Estudos Rust: Nível Pleno (6-18 Meses)"
url: "https://rustlang.com.br/carreira/plano-estudos-pleno/"
markdown_url: "https://rustlang.com.br/carreira/plano-estudos-pleno.MD"
description: "Roadmap para evoluir de júnior para pleno em Rust. Async/await, macros, design patterns, contribuição open source e projetos complexos para consolidar sua carreira."
date: ""
author: ""
---

# Plano de Estudos Rust: Nível Pleno (6-18 Meses)

Roadmap para evoluir de júnior para pleno em Rust. Async/await, macros, design patterns, contribuição open source e projetos complexos para consolidar sua carreira.


Você já domina os fundamentos do Rust, tem alguns projetos no portfólio e talvez até já esteja trabalhando profissionalmente com a linguagem. Agora é hora de dar o próximo salto: tornar-se um desenvolvedor pleno capaz de lidar com sistemas complexos, tomar decisões arquiteturais e contribuir significativamente para projetos maiores.

Este plano cobre o período de 6 a 18 meses de experiência com Rust e pressupõe que você já domina ownership, borrowing, traits básicos, tratamento de erros e estruturação de projetos. Se ainda não se sente confortável com esses temas, recomendamos seguir primeiro o nosso Plano de Estudos Júnior.

## Visão Geral do Roadmap

| Período | Foco | Resultado Esperado |
|---------|------|-------------------|
| Meses 7-9 | Generics avançados, async/await, macros | Escrever código sofisticado e performático |
| Meses 10-12 | Design patterns, arquitetura, bancos de dados | Projetar sistemas robustos |
| Meses 13-15 | Open source, web frameworks avançados | Contribuir para o ecossistema |
| Meses 16-18 | Projeto complexo + System design | Demonstrar capacidade pleno |

## Meses 7-9: Domínio Técnico Avançado

### Generics Avançados e Trait Bounds

Generics no nível pleno vão muito além de `fn foo<T>(x: T)`. Você precisa dominar trait bounds compostos, tipos associados, supertraits e uso avançado de where clauses.

**Tópicos para dominar:**

- Trait bounds múltiplos e compostos
- Tipos associados vs. parâmetros genéricos
- Supertraits e herança de traits
- `impl Trait` em posição de argumento e retorno
- Trait objects (`dyn Trait`) e object safety
- Phantom types e marker traits

```rust
use std::fmt;
use std::ops::Add;

// Trait com tipo associado
trait Medida {
    type Unidade: fmt::Display;

    fn valor(&self) -> f64;
    fn unidade(&self) -> Self::Unidade;
    fn formatar(&self) -> String {
        format!("{:.2} {}", self.valor(), self.unidade())
    }
}

// Supertrait: Combinavel requer Medida + Clone
trait Combinavel: Medida + Clone {
    fn combinar(&self, outro: &Self) -> Self;
}

// Generics com where clause complexa
fn comparar_e_somar<T, U>(a: &T, b: &U) -> String
where
    T: Medida + fmt::Debug,
    U: Medida + fmt::Debug,
    T::Unidade: PartialEq<U::Unidade>,
{
    format!(
        "{} vs {} (total: {:.2})",
        a.formatar(),
        b.formatar(),
        a.valor() + b.valor()
    )
}

// Phantom types para segurança de tipos
use std::marker::PhantomData;

struct Validado;
struct NaoValidado;

struct Email<Estado = NaoValidado> {
    endereco: String,
    _estado: PhantomData<Estado>,
}

impl Email<NaoValidado> {
    fn novo(endereco: String) -> Self {
        Email {
            endereco,
            _estado: PhantomData,
        }
    }

    fn validar(self) -> Result<Email<Validado>, String> {
        if self.endereco.contains('@') && self.endereco.contains('.') {
            Ok(Email {
                endereco: self.endereco,
                _estado: PhantomData,
            })
        } else {
            Err("Email inválido".to_string())
        }
    }
}

impl Email<Validado> {
    fn enviar(&self, mensagem: &str) {
        println!("Enviando '{}' para {}", mensagem, self.endereco);
    }
}
```

### Async/Await e Programação Assíncrona

Programação assíncrona é essencial para qualquer desenvolvedor Rust pleno, especialmente para trabalho com web, I/O e sistemas distribuídos.

**Tópicos para dominar:**

- Como futures funcionam internamente
- Tokio runtime (single-threaded vs. multi-threaded)
- Channels (`mpsc`, `broadcast`, `watch`, `oneshot`)
- `Select!` e combinadores de futures
- Streams e `AsyncRead`/`AsyncWrite`
- Padrões comuns: fan-out/fan-in, rate limiting, timeouts
- `Pin` e `Unpin` (conceitual)

```rust
use tokio::sync::mpsc;
use tokio::time::{self, Duration};
use std::collections::HashMap;

// Worker pool assíncrono
struct WorkerPool {
    sender: mpsc::Sender<Tarefa>,
}

struct Tarefa {
    id: u64,
    url: String,
    resposta: tokio::sync::oneshot::Sender<Resultado>,
}

struct Resultado {
    id: u64,
    status: u16,
    tempo_ms: u64,
}

impl WorkerPool {
    fn novo(num_workers: usize) -> Self {
        let (sender, receiver) = mpsc::channel::<Tarefa>(100);
        let receiver = std::sync::Arc::new(tokio::sync::Mutex::new(receiver));

        for i in 0..num_workers {
            let rx = receiver.clone();
            tokio::spawn(async move {
                loop {
                    let tarefa = {
                        let mut guard = rx.lock().await;
                        guard.recv().await
                    };

                    match tarefa {
                        Some(t) => {
                            let inicio = std::time::Instant::now();
                            // Simula processamento HTTP
                            time::sleep(Duration::from_millis(100)).await;
                            let resultado = Resultado {
                                id: t.id,
                                status: 200,
                                tempo_ms: inicio.elapsed().as_millis() as u64,
                            };
                            let _ = t.resposta.send(resultado);
                            println!("Worker {} processou tarefa {}", i, t.id);
                        }
                        None => break,
                    }
                }
            });
        }

        WorkerPool { sender }
    }

    async fn enviar(&self, id: u64, url: String) -> Resultado {
        let (tx, rx) = tokio::sync::oneshot::channel();
        let tarefa = Tarefa {
            id,
            url,
            resposta: tx,
        };
        self.sender.send(tarefa).await.unwrap();
        rx.await.unwrap()
    }
}

// Padrão: timeout com fallback
async fn buscar_com_timeout(url: &str, timeout_secs: u64) -> Result<String, String> {
    match time::timeout(
        Duration::from_secs(timeout_secs),
        buscar_dados(url),
    )
    .await
    {
        Ok(Ok(dados)) => Ok(dados),
        Ok(Err(e)) => Err(format!("Erro na requisição: {}", e)),
        Err(_) => Err(format!("Timeout após {}s", timeout_secs)),
    }
}

async fn buscar_dados(url: &str) -> Result<String, String> {
    // Simulação de requisição HTTP
    time::sleep(Duration::from_millis(50)).await;
    Ok(format!("Dados de {}", url))
}
```

### Macros em Rust

Macros são uma ferramenta poderosa para reduzir boilerplate e criar DSLs. No nível pleno, você precisa saber quando e como usá-las.

**Macros declarativas (`macro_rules!`):**

```rust
// Macro para criar um HashMap facilmente
macro_rules! mapa {
    ($($chave:expr => $valor:expr),* $(,)?) => {
        {
            let mut map = std::collections::HashMap::new();
            $(map.insert($chave, $valor);)*
            map
        }
    };
}

// Macro para criar builders automaticamente
macro_rules! builder {
    ($nome:ident { $($campo:ident: $tipo:ty),* $(,)? }) => {
        pub struct $nome {
            $($campo: Option<$tipo>,)*
        }

        impl $nome {
            pub fn novo() -> Self {
                $nome {
                    $($campo: None,)*
                }
            }

            $(
                pub fn $campo(mut self, valor: $tipo) -> Self {
                    self.$campo = Some(valor);
                    self
                }
            )*
        }
    };
}

builder!(ConfigBuilder {
    host: String,
    porta: u16,
    max_conexoes: usize,
    timeout_ms: u64,
});

fn main() {
    let config = mapa! {
        "ambiente" => "produção",
        "versão" => "1.0",
        "região" => "br-south",
    };

    let cfg = ConfigBuilder::novo()
        .host("localhost".to_string())
        .porta(8080)
        .max_conexoes(100)
        .timeout_ms(5000);

    println!("Config criada com {} entradas", config.len());
}
```

**Macros procedurais (visão geral):**

```rust
// Exemplo conceitual de derive macro
// Este código vai em uma crate separada do tipo proc-macro

use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, DeriveInput};

#[proc_macro_derive(Descritivel)]
pub fn derive_descritivel(input: TokenStream) -> TokenStream {
    let input = parse_macro_input!(input as DeriveInput);
    let nome = &input.ident;

    let expanded = quote! {
        impl Descritivel for #nome {
            fn descricao(&self) -> String {
                format!("Instância de {}", stringify!(#nome))
            }
        }
    };

    TokenStream::from(expanded)
}
```

### Checklist dos Meses 7-9

- [ ] Usa generics avançados com trait bounds compostos
- [ ] Entende e usa tipos associados e supertraits
- [ ] Escreve código assíncrono com Tokio fluentemente
- [ ] Sabe usar channels, select e timeouts
- [ ] Cria macros declarativas para eliminar boilerplate
- [ ] Entende conceitualmente como macros procedurais funcionam

## Meses 10-12: Design Patterns e Arquitetura

### Design Patterns em Rust

Rust tem sua própria abordagem para design patterns clássicos. Muitos patterns de OOP não se aplicam diretamente, e Rust introduz patterns únicos.

**Padrões essenciais:**

```rust
// 1. Builder Pattern (muito comum em Rust)
pub struct HttpRequest {
    url: String,
    metodo: String,
    headers: Vec<(String, String)>,
    body: Option<String>,
    timeout: std::time::Duration,
}

pub struct HttpRequestBuilder {
    url: String,
    metodo: String,
    headers: Vec<(String, String)>,
    body: Option<String>,
    timeout: std::time::Duration,
}

impl HttpRequestBuilder {
    pub fn new(url: impl Into<String>) -> Self {
        HttpRequestBuilder {
            url: url.into(),
            metodo: "GET".to_string(),
            headers: Vec::new(),
            body: None,
            timeout: std::time::Duration::from_secs(30),
        }
    }

    pub fn metodo(mut self, metodo: impl Into<String>) -> Self {
        self.metodo = metodo.into();
        self
    }

    pub fn header(mut self, chave: impl Into<String>, valor: impl Into<String>) -> Self {
        self.headers.push((chave.into(), valor.into()));
        self
    }

    pub fn body(mut self, body: impl Into<String>) -> Self {
        self.body = Some(body.into());
        self
    }

    pub fn timeout(mut self, timeout: std::time::Duration) -> Self {
        self.timeout = timeout;
        self
    }

    pub fn build(self) -> HttpRequest {
        HttpRequest {
            url: self.url,
            metodo: self.metodo,
            headers: self.headers,
            body: self.body,
            timeout: self.timeout,
        }
    }
}

// 2. Newtype Pattern (para type safety)
struct UserId(u64);
struct OrderId(u64);

// Impossível confundir os dois acidentalmente!
fn buscar_pedido(user_id: UserId, order_id: OrderId) {
    println!("Buscando pedido {} do usuário {}", order_id.0, user_id.0);
}

// 3. Type State Pattern
struct Rascunho;
struct EmRevisao;
struct Publicado;

struct Artigo<Estado> {
    titulo: String,
    conteudo: String,
    _estado: std::marker::PhantomData<Estado>,
}

impl Artigo<Rascunho> {
    fn novo(titulo: String) -> Self {
        Artigo {
            titulo,
            conteudo: String::new(),
            _estado: std::marker::PhantomData,
        }
    }

    fn escrever(mut self, conteudo: String) -> Self {
        self.conteudo = conteudo;
        self
    }

    fn enviar_para_revisao(self) -> Artigo<EmRevisao> {
        Artigo {
            titulo: self.titulo,
            conteudo: self.conteudo,
            _estado: std::marker::PhantomData,
        }
    }
}

impl Artigo<EmRevisao> {
    fn aprovar(self) -> Artigo<Publicado> {
        Artigo {
            titulo: self.titulo,
            conteudo: self.conteudo,
            _estado: std::marker::PhantomData,
        }
    }

    fn rejeitar(self) -> Artigo<Rascunho> {
        Artigo {
            titulo: self.titulo,
            conteudo: self.conteudo,
            _estado: std::marker::PhantomData,
        }
    }
}

impl Artigo<Publicado> {
    fn url(&self) -> String {
        format!("/artigos/{}", self.titulo.to_lowercase().replace(' ', "-"))
    }
}
```

### Acesso a Bancos de Dados em Profundidade

**Tópicos para dominar:**

- Connection pooling com `sqlx`
- Migrations e schema management
- Transactions e consistência
- Query builders vs. raw SQL
- ORMs em Rust (`diesel`, `sea-orm`)
- Padrões: Repository, Unit of Work

```rust
use sqlx::{postgres::PgPoolOptions, FromRow, Pool, Postgres};

#[derive(Debug, FromRow)]
struct Usuario {
    id: i64,
    nome: String,
    email: String,
    criado_em: chrono::NaiveDateTime,
}

struct UsuarioRepository {
    pool: Pool<Postgres>,
}

impl UsuarioRepository {
    fn new(pool: Pool<Postgres>) -> Self {
        UsuarioRepository { pool }
    }

    async fn criar(&self, nome: &str, email: &str) -> Result<Usuario, sqlx::Error> {
        sqlx::query_as::<_, Usuario>(
            "INSERT INTO usuarios (nome, email) VALUES ($1, $2) RETURNING *"
        )
        .bind(nome)
        .bind(email)
        .fetch_one(&self.pool)
        .await
    }

    async fn buscar_por_id(&self, id: i64) -> Result<Option<Usuario>, sqlx::Error> {
        sqlx::query_as::<_, Usuario>("SELECT * FROM usuarios WHERE id = $1")
            .bind(id)
            .fetch_optional(&self.pool)
            .await
    }

    async fn listar_paginado(
        &self,
        pagina: i64,
        por_pagina: i64,
    ) -> Result<Vec<Usuario>, sqlx::Error> {
        let offset = (pagina - 1) * por_pagina;
        sqlx::query_as::<_, Usuario>(
            "SELECT * FROM usuarios ORDER BY criado_em DESC LIMIT $1 OFFSET $2"
        )
        .bind(por_pagina)
        .bind(offset)
        .fetch_all(&self.pool)
        .await
    }

    async fn transferir_creditos(
        &self,
        de_id: i64,
        para_id: i64,
        valor: f64,
    ) -> Result<(), sqlx::Error> {
        let mut tx = self.pool.begin().await?;

        sqlx::query("UPDATE contas SET saldo = saldo - $1 WHERE usuario_id = $2 AND saldo >= $1")
            .bind(valor)
            .bind(de_id)
            .execute(&mut *tx)
            .await?;

        sqlx::query("UPDATE contas SET saldo = saldo + $1 WHERE usuario_id = $2")
            .bind(valor)
            .bind(para_id)
            .execute(&mut *tx)
            .await?;

        tx.commit().await?;
        Ok(())
    }
}
```

### Web Frameworks em Profundidade

Aprofunde-se no framework web de sua escolha (Axum recomendado):

```rust
use axum::{
    extract::{Path, Query, State},
    http::StatusCode,
    middleware,
    response::IntoResponse,
    routing::{get, post, put, delete},
    Json, Router,
};
use serde::{Deserialize, Serialize};
use tower_http::{cors::CorsLayer, trace::TraceLayer};

// Middleware customizado para autenticação
async fn auth_middleware(
    req: axum::extract::Request,
    next: axum::middleware::Next,
) -> Result<impl IntoResponse, StatusCode> {
    let auth_header = req
        .headers()
        .get("Authorization")
        .and_then(|v| v.to_str().ok());

    match auth_header {
        Some(token) if token.starts_with("Bearer ") => {
            // Validar token aqui
            Ok(next.run(req).await)
        }
        _ => Err(StatusCode::UNAUTHORIZED),
    }
}

// Extrator customizado para paginação
#[derive(Deserialize)]
struct Paginacao {
    #[serde(default = "pagina_padrao")]
    pagina: u32,
    #[serde(default = "limite_padrao")]
    limite: u32,
}

fn pagina_padrao() -> u32 { 1 }
fn limite_padrao() -> u32 { 20 }

// Resposta padronizada
#[derive(Serialize)]
struct RespostaPaginada<T: Serialize> {
    dados: Vec<T>,
    pagina: u32,
    total_paginas: u32,
    total_itens: u64,
}

// Tratamento de erros centralizado
enum AppError {
    NaoEncontrado(String),
    Validacao(String),
    Interno(String),
}

impl IntoResponse for AppError {
    fn into_response(self) -> axum::response::Response {
        let (status, mensagem) = match self {
            AppError::NaoEncontrado(msg) => (StatusCode::NOT_FOUND, msg),
            AppError::Validacao(msg) => (StatusCode::BAD_REQUEST, msg),
            AppError::Interno(msg) => (StatusCode::INTERNAL_SERVER_ERROR, msg),
        };

        let body = serde_json::json!({
            "erro": mensagem,
            "status": status.as_u16(),
        });

        (status, Json(body)).into_response()
    }
}

fn criar_router(estado: AppState) -> Router {
    let rotas_publicas = Router::new()
        .route("/health", get(|| async { "OK" }))
        .route("/login", post(login));

    let rotas_protegidas = Router::new()
        .route("/usuarios", get(listar_usuarios))
        .route("/usuarios/:id", get(buscar_usuario))
        .route("/usuarios", post(criar_usuario))
        .route("/usuarios/:id", put(atualizar_usuario))
        .route("/usuarios/:id", delete(deletar_usuario))
        .layer(middleware::from_fn(auth_middleware));

    Router::new()
        .merge(rotas_publicas)
        .merge(rotas_protegidas)
        .layer(CorsLayer::permissive())
        .layer(TraceLayer::new_for_http())
        .with_state(estado)
}
```

### Princípios de System Design

**Conceitos que um desenvolvedor pleno deve dominar:**

1. **Separação de responsabilidades**: organize código em camadas (handler, service, repository)
2. **Injeção de dependências**: use traits para abstrair dependências e facilitar testes
3. **Configuração externalizada**: use variáveis de ambiente e arquivos de configuração
4. **Logging estruturado**: use `tracing` para logs com contexto
5. **Health checks e métricas**: exponha endpoints de monitoramento
6. **Graceful shutdown**: trate sinais de desligamento corretamente

```rust
// Exemplo de arquitetura em camadas com injeção de dependência

// Camada de abstração (trait)
#[async_trait::async_trait]
trait ProdutoRepository: Send + Sync {
    async fn buscar(&self, id: i64) -> Result<Option<Produto>, AppError>;
    async fn listar(&self, filtro: FiltroProduto) -> Result<Vec<Produto>, AppError>;
    async fn criar(&self, produto: NovoProduto) -> Result<Produto, AppError>;
}

// Camada de serviço (lógica de negócio)
struct ProdutoService<R: ProdutoRepository> {
    repo: R,
}

impl<R: ProdutoRepository> ProdutoService<R> {
    fn new(repo: R) -> Self {
        ProdutoService { repo }
    }

    async fn criar_produto(&self, input: NovoProduto) -> Result<Produto, AppError> {
        // Validação de regras de negócio
        if input.preco <= 0.0 {
            return Err(AppError::Validacao("Preço deve ser positivo".into()));
        }
        if input.nome.len() < 3 {
            return Err(AppError::Validacao("Nome muito curto".into()));
        }

        self.repo.criar(input).await
    }
}

// Implementação real (produção)
struct PgProdutoRepository {
    pool: sqlx::PgPool,
}

// Implementação fake (testes)
struct FakeProdutoRepository {
    produtos: std::sync::Mutex<Vec<Produto>>,
}
```

### Checklist dos Meses 10-12

- [ ] Conhece e aplica os principais design patterns em Rust
- [ ] Trabalha com bancos de dados usando transactions e migrations
- [ ] Constrói APIs completas com autenticação e tratamento de erros
- [ ] Entende arquitetura em camadas e injeção de dependências
- [ ] Usa logging estruturado com `tracing`
- [ ] Sabe projetar sistemas com separação clara de responsabilidades

## Meses 13-15: Contribuição Open Source e Profundidade

### Contribuindo para Projetos Open Source

Contribuir para projetos open source é uma das melhores formas de acelerar seu crescimento como desenvolvedor Rust.

**Como começar:**

1. **Escolha projetos que você usa**: é mais fácil contribuir para algo que você conhece como usuário
2. **Comece por issues rotuladas como "good first issue"** ou "help wanted"
3. **Leia o CONTRIBUTING.md** antes de qualquer coisa
4. **Comece com documentação e testes**: contribuições de docs são muito valorizadas
5. **Revisões de código**: acompanhe PRs de outros para aprender

**Projetos recomendados para primeiras contribuições:**

| Projeto | Área | Dificuldade |
|---------|------|-------------|
| Rustlings | Educação | Baixa |
| mdBook | Ferramentas | Baixa-Média |
| Tokio | Async runtime | Média |
| Axum | Web framework | Média |
| Serde | Serialização | Média-Alta |
| Rust Clippy | Linting | Média |

**Fluxo de contribuição:**

```bash
# 1. Fork e clone
git clone https://github.com/seu-usuario/projeto-fork.git
cd projeto-fork
git remote add upstream https://github.com/projeto-original/projeto.git

# 2. Crie uma branch para sua contribuição
git checkout -b fix/corrigir-typo-docs

# 3. Faça as alterações, teste localmente
cargo test
cargo clippy
cargo fmt --check

# 4. Commit e push
git add .
git commit -m "fix: corrige typo na documentação do módulo X"
git push origin fix/corrigir-typo-docs

# 5. Abra um Pull Request no GitHub
```

### Tópicos Avançados de Web

**Aprofunde-se em:**

- WebSockets e Server-Sent Events
- GraphQL com `async-graphql`
- gRPC com `tonic`
- Rate limiting e circuit breaker
- Caching (Redis com `deadpool-redis`)
- Background jobs e filas
- Autenticação JWT e OAuth2

```rust
// Exemplo: WebSocket com Axum
use axum::{
    extract::ws::{Message, WebSocket, WebSocketUpgrade},
    response::IntoResponse,
    routing::get,
    Router,
};
use futures::{SinkExt, StreamExt};

async fn ws_handler(ws: WebSocketUpgrade) -> impl IntoResponse {
    ws.on_upgrade(handle_socket)
}

async fn handle_socket(mut socket: WebSocket) {
    // Enviar mensagem de boas-vindas
    if socket
        .send(Message::Text("Bem-vindo ao chat!".to_string()))
        .await
        .is_err()
    {
        return;
    }

    // Loop de recebimento
    while let Some(Ok(msg)) = socket.next().await {
        match msg {
            Message::Text(texto) => {
                println!("Recebido: {}", texto);
                let resposta = format!("Echo: {}", texto);
                if socket.send(Message::Text(resposta)).await.is_err() {
                    break;
                }
            }
            Message::Close(_) => break,
            _ => {}
        }
    }
}
```

### Ferramentas e Ecossistema

Domine as ferramentas que diferenciam um desenvolvedor pleno:

- **cargo-watch**: recompilação automática durante desenvolvimento
- **cargo-expand**: visualizar macros expandidas
- **cargo-audit**: verificar vulnerabilidades em dependências
- **cargo-deny**: políticas de licença e segurança
- **cargo-flamegraph**: profiling de performance
- **cargo-tarpaulin**: cobertura de testes

```bash
# Instalar ferramentas essenciais
cargo install cargo-watch cargo-expand cargo-audit cargo-deny

# Desenvolvimento com hot-reload
cargo watch -x "run" -w src/

# Verificar segurança das dependências
cargo audit

# Expandir macros para debug
cargo expand nome_do_modulo

# Cobertura de testes
cargo install cargo-tarpaulin
cargo tarpaulin --out html
```

### Checklist dos Meses 13-15

- [ ] Tem pelo menos 1 PR aceito em projeto open source
- [ ] Sabe trabalhar com WebSockets ou gRPC
- [ ] Implementa caching e background jobs
- [ ] Domina as ferramentas do ecossistema Cargo
- [ ] Faz code review de PRs de outros desenvolvedores

## Meses 16-18: Projeto Complexo e Consolidação

### Projeto: Sistema Distribuído ou Aplicação Complexa

Este é o projeto que vai consolidar seu nível pleno. Escolha uma das opções abaixo:

**Opção A: Sistema de Mensageria**
- Broker de mensagens com publish/subscribe
- Múltiplos consumidores com grupos
- Persistência de mensagens
- Dashboard de monitoramento
- Protocolo customizado sobre TCP

**Opção B: Motor de Busca Simplificado**
- Indexação de documentos (TF-IDF)
- Busca com ranking de relevância
- API REST para ingestão e consulta
- Processamento concorrente de documentos
- Persistência do índice em disco

**Opção C: Plataforma de CI/CD Simplificada**
- Execução de pipelines definidos em YAML
- Isolamento de jobs
- Dashboard web com status em tempo real
- Notificações (webhook)
- Armazenamento de artefatos

### Estrutura Sugerida do Projeto

```
meu-sistema/
├── Cargo.toml           # workspace
├── crates/
│   ├── core/            # lógica de negócio
│   │   ├── Cargo.toml
│   │   └── src/
│   ├── api/             # HTTP API
│   │   ├── Cargo.toml
│   │   └── src/
│   ├── worker/          # processamento em background
│   │   ├── Cargo.toml
│   │   └── src/
│   └── common/          # tipos e utilitários compartilhados
│       ├── Cargo.toml
│       └── src/
├── migrations/          # migrações SQL
├── config/              # arquivos de configuração
├── docker-compose.yml   # ambiente de desenvolvimento
└── README.md
```

### Cronograma do Projeto

| Semana | Atividade |
|--------|-----------|
| 1-2 | Design do sistema, definição de APIs e protocolos |
| 3-4 | Implementação do core e modelos de dados |
| 5-6 | API REST e integração com banco de dados |
| 7-8 | Workers, processamento assíncrono |
| 9-10 | Testes de integração, observabilidade |
| 11-12 | Polish, documentação, deploy |

### System Design: O que o Pleno Deve Saber

Ao projetar sistemas, considere sempre:

1. **Escalabilidade**: como o sistema se comporta quando a carga aumenta?
2. **Resiliência**: o que acontece quando um componente falha?
3. **Observabilidade**: você consegue entender o que o sistema está fazendo?
4. **Segurança**: quais são as superfícies de ataque?
5. **Manutenabilidade**: outro desenvolvedor consegue entender e modificar o código?

## Checklist Final: Pronto para Nível Pleno?

### Habilidades Técnicas

- [ ] Generics avançados com trait bounds complexos
- [ ] Programação assíncrona com Tokio (channels, select, timeouts)
- [ ] Macros declarativas para eliminar boilerplate
- [ ] Design patterns idiomáticos de Rust (Builder, Newtype, Type State)
- [ ] Bancos de dados com transactions e migrations
- [ ] APIs REST completas com autenticação e error handling
- [ ] Testes unitários, de integração e end-to-end
- [ ] Logging e observabilidade com tracing

### Habilidades de Projeto

- [ ] Arquitetura em camadas com separação de responsabilidades
- [ ] Injeção de dependências via traits
- [ ] CI/CD configurado com testes e linting
- [ ] Documentação técnica clara
- [ ] Gerenciamento de dependências e segurança

### Habilidades de Colaboração

- [ ] Contribuição aceita em projeto open source
- [ ] Faz code reviews construtivos
- [ ] Sabe explicar decisões técnicas
- [ ] Mentora desenvolvedores mais iniciantes
- [ ] Participa ativamente da comunidade Rust

## Próximos Passos

Após consolidar o nível pleno, você estará preparado para:

- Liderar projetos técnicos de média complexidade
- Tomar decisões arquiteturais com segurança
- Mentorar desenvolvedores júnior
- Contribuir significativamente para projetos open source
- Buscar posições sênior ou de liderança técnica

O caminho para sênior envolve aprofundar-se em áreas como unsafe Rust, otimização de performance, arquitetura de larga escala e liderança técnica. Confira nosso Plano de Estudos Sênior para continuar sua jornada.

A chave para o crescimento contínuo é nunca parar de aprender, ensinar e construir. Cada projeto complexo que você finaliza, cada contribuição open source que você faz, cada mentoria que oferece -- tudo isso compõe o profissional pleno que o mercado valoriza.

Continue construindo. Continue contribuindo. Continue evoluindo.
