Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# --- Python / Backend ---
venv/
.venv/
env/
__pycache__/
*.py[cod]
*$py.class
.pytest_cache/
.vscode/
.idea/

# Banco de dados local (opcional: remova se quiser que o avaliador receba o banco já com dados)
*.db
*.sqlite3

# --- Angular / Frontend ---
front/node_modules/
front/.angular/
front/dist/
front/.vscode/

# Logs e arquivos de sistema
*.log
.DS_Store
Thumbs.db

# --- Arquivos de ambiente ---
.env
94 changes: 60 additions & 34 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,50 +1,76 @@
# 🚀 Desafio Técnico: API de Foco e Produtividade
# 🧠 Log de Performance & Foco

O objetivo deste teste é criar o backend de um **"Log de Performance"**. Em vez de apenas registrar tarefas, queremos entender o **estado de fluxo** do desenvolvedor ou estudante durante suas atividades.
Este é um projeto Fullstack desenvolvido para o **Desafio Técnico: API de Foco e Produtividade**. A aplicação permite que desenvolvedores e estudantes registrem suas sessões de trabalho, acompanhem o nível de estado de fluxo (*flow*) e recebam um diagnóstico inteligente sobre sua produtividade.

## 📅 Regras de Entrega
---

* Prazo: O projeto deve ser entregue até a próxima segunda-feira.
* Uso de IA: O uso de ferramentas de Inteligência Artificial (ChatGPT, GitHub Copilot, etc.) é permitido.
* Transparência: Caso utilize IA, você deve commitar os artefatos gerados junto ao repositório. Queremos entender como você utiliza essas ferramentas para acelerar seu fluxo de trabalho.
* Faça o **fork desse projeto** e me avise quando terminar o [wouerner](https://www.linkedin.com/in/wouerner/) no linkedin. (necessario para pode acompanhar pelo github quem participou)
## 🚀 Tecnologias Utilizadas

## 📝 O Contexto
Muitas vezes trabalhamos muito, mas produzimos pouco. Você deve construir uma API simples que ajude o usuário a registrar seu nível de produtividade e, ao final, entregue um **diagnóstico inteligente** de como foi o seu período de trabalho.
### Backend
* **Python 3.12+**
* **FastAPI**: Framework web de alta performance.
* **SQLAlchemy**: ORM para mapeamento e manipulação do banco de dados.
* **SQLite**: Banco de dados relacional leve para persistência de dados.
* **Pydantic**: Validação de dados e schemas.

## 🛠 Requisitos Técnicos
* **Linguagem:** Python 3.x.
* **Framework:** À sua escolha (FastAPI, Flask, Django, etc).
* **Armazenamento:** Pode ser em memória (dicionários/listas) ou SQLite para simplicidade.
* **Diferencial:** Código limpo, bem comentado e presença de um `README.md` explicando como rodar o projeto.
### Frontend
* **Angular 21.2**: Framework para construção da interface web.
* **Bootstrap**: Para um design responsivo e limpo.
* **HttpClient**: Para comunicação assíncrona com a API.

---

## 🛣 Os Endpoints
## 🛠️ Arquitetura do Projeto

O projeto segue princípios de **Clean Code** e **Separação de Responsabilidades (SOC)**:

### 1. `POST /registro-foco`
O usuário deve enviar os dados de um bloco de trabalho recém-encerrado.
* `app/main.py`: Ponto de entrada da API e definição das rotas.
* `app/service.py`: Camada de serviço contendo a lógica de negócio e cálculos de diagnóstico.
* `app/models.py`: Definição das tabelas do banco de dados.
* `app/schemas.py`: Validação de entrada e saída de dados com Pydantic.
* `app/database.py`: Configuração da conexão com o SQLite.

**Campos obrigatórios:**
* `nivel_foco`: Um valor inteiro de **1 a 5** (onde 1 é "muito distraído" e 5 é "estado de flow").
* `tempo_minutos`: Um inteiro representando quanto tempo durou a sessão.
* `comentario`: Uma string descrevendo o que foi feito ou o que causou distração.
---

> **💡 Dica de Criatividade:** Sinta-se à vontade para adicionar campos extras, como `categoria` (coding, reunião, estudo), `data` ou `tags`.
## 🤖 Uso de IA

### 2. `GET /diagnostico-produtividade`
Este endpoint deve retornar um resumo inteligente baseado em todos os registros salvos.
Conforme as regras do desafio, ferramentas de IA (Gemini) foram utilizada para:

**O que deve retornar (JSON):**
* **Média do nível de foco:** A média aritmética de todos os registros.
* **Tempo total focado:** A soma de todos os minutos registrados.
* **Lógica Criativa (Diferencial):** Uma "mensagem de feedback" automática baseada nos dados analisados.
* *Exemplo:* Se a média de foco for `< 3`, sugerir "Pausas mais longas e menos notificações". Se for `> 4`, "Você está em uma maratona produtiva de alto nível!".
* Auxílio na correção de bugs de tipagem no SQLAlchemy.
* Geração de templates básicos para o componente Angular.
* Auxílio nas duvidas ao contruir o projeto.

---

## 📊 O que será avaliado
1. **Organização do Código:** Estrutura de pastas e legibilidade.
2. **Manipulação de Dados:** Como você lida com tipos, cálculos e persistência.
3. **Tratamento de Erros:** Respostas adequadas para entradas inválidas (ex: nível de foco fora do range 1-5).
4. **Criatividade:** Pequenos detalhes que tornam a API mais útil para o usuário final.
## 🔧 Como Rodar o Projeto

### 1. Backend (FastAPI)

Certifique-se de ter o Python instalado. Recomenda-se o uso de um ambiente virtual (`venv`).

```bash
# Entre na pasta raiz do projeto
cd teste-tecnico-python-backend

# Crie e ative o ambiente virtual
python -m venv venv
# No Windows:
.\venv\Scripts\activate
# No Linux/Mac:
source venv/bin/activate

# Instale as dependências
pip install -r requirements.txt

# Inicie o servidor
uvicorn app.main:app --reload

### 2. Frontend (Angular)
# Entre na pasta do frontend
cd front

# Instale as dependências do Angular
npm install

# Inicie o servidor de desenvolvimento
ng serve
Binary file added app/__pycache__/database.cpython-314.pyc
Binary file not shown.
Binary file added app/__pycache__/main.cpython-314.pyc
Binary file not shown.
Binary file added app/__pycache__/models.cpython-314.pyc
Binary file not shown.
Binary file added app/__pycache__/schemas.cpython-314.pyc
Binary file not shown.
21 changes: 21 additions & 0 deletions app/database.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
from sqlalchemy import create_engine
from sqlalchemy.orm import declarative_base
from sqlalchemy.orm import sessionmaker

SQLALCHEMY_DATABASE_URL = "sqlite:///./performance.db"

engine = create_engine(
SQLALCHEMY_DATABASE_URL, connect_args={"check_same_thread": False}
)

# SessionLocal (cada instância será uma sessão de banco de dados)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)

Base = declarative_base()

def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()
51 changes: 51 additions & 0 deletions app/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
from fastapi import FastAPI, Depends, HTTPException, status
from fastapi.middleware.cors import CORSMiddleware
from sqlalchemy.orm import Session
from . import models, schemas, database
from .database import engine, get_db
from .service import PerformanceService # <-- Importação do seu serviço

models.Base.metadata.create_all(bind=engine)

app = FastAPI(
title="API de Foco e Produtividade",
description="Sistema para registro de logs de performance e diagnóstico de flow.",
version="1.0.0"
)

app.add_middleware(
CORSMiddleware,
allow_origins=["http://localhost:4200"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)

@app.post("/registro-foco", response_model=schemas.RegistroFocoResponse, status_code=status.HTTP_201_CREATED)
def registrar_foco(item: schemas.RegistroFocoCreate, db: Session = Depends(get_db)):
novo_log = models.RegistroFoco(**item.model_dump())
db.add(novo_log)
db.commit()
db.refresh(novo_log)
return novo_log

@app.get("/diagnostico-produtividade", response_model=schemas.DiagnosticoOut)
def obter_diagnostico(db: Session = Depends(get_db)):
# 1. Busca os dados no banco
registros = db.query(models.RegistroFoco).all()

# 2. Delega a lógica para o Service
resultado = PerformanceService.gerar_diagnostico(registros)

# 3. Trata o erro ou retorna o sucesso
if not resultado:
raise HTTPException(
status_code=404,
detail="Nenhum registro encontrado para gerar diagnóstico."
)

return resultado

@app.get("/")
def read_root():
return {"message": "API de Performance Online. Acesse http://127.0.0.1:8000/docs."}
20 changes: 20 additions & 0 deletions app/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
from sqlalchemy import Column, Integer, String, DateTime, Float
from datetime import datetime, timezone
from .database import Base

class RegistroFoco(Base):
__tablename__ = "registros_foco"

id = Column(Integer, primary_key=True, index=True)

# Campos obrigatórios do desafio
nivel_foco = Column(Float, nullable=False)
tempo_minutos = Column(Integer, nullable=False)
comentario = Column(String, nullable=False)

# Campos extras
categoria = Column(String, default="Geral", index=True) #
data_registro = Column(DateTime, default=lambda: datetime.now(timezone.utc))

def __repr__(self):
return f"<RegistroFoco(id={self.id}, nivel={self.nivel_foco}, tempo={self.tempo_minutos}min)>"
38 changes: 38 additions & 0 deletions app/schemas.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
from pydantic import BaseModel, Field
from datetime import datetime
from typing import Optional

# Base para campos comuns
class RegistroFocoBase(BaseModel):
nivel_foco: float = Field(
...,
ge=1.0,
le=5.0,
description="O nível de foco deve ser entre 1 (distraído) e 5 (flow)."
)
tempo_minutos: int = Field(
...,
gt=0,
description="O tempo de sessão deve ser maior que zero."
)
comentario: str
categoria: Optional[str] = "Geral"

# Schema para criação
class RegistroFocoCreate(RegistroFocoBase):
pass

# Schema para resposta
class RegistroFocoResponse(RegistroFocoBase):
id: int
data_registro: datetime

class Config:
from_attributes = True # Permite que o Pydantic leia modelos do SQLAlchemy

# Schema para o Diagnóstico Inteligente
class DiagnosticoOut(BaseModel):
media_foco: float
tempo_total_focado: int
total_sessoes: int
mensagem_feedback: str
31 changes: 31 additions & 0 deletions app/service.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
from typing import List
from .models import RegistroFoco

class PerformanceService:
@staticmethod
def gerar_diagnostico(registros: List[RegistroFoco]):
# Se não houver registros, retornamos None para o main tratar o erro
if not registros:
return None

# Cálculos (A lógica que estava no main)
total_minutos = sum(r.tempo_minutos for r in registros)
total_sessoes = len(registros)
media_foco = sum(r.nivel_foco for r in registros) / total_sessoes

# Lógica de Feedback
if media_foco >= 4.5:
feedback = "Incrível! Você está em estado de flow constante. Continue assim!"
elif media_foco > 3.0:
feedback = "Você teve uma boa performance. Tente reduzir pequenas distrações."
elif media_foco >= 2.5:
feedback = "Produtividade mediana. Talvez pausas mais longas ajudem a recuperar o foco."
else:
feedback = "Alerta de distração: Sugerimos desligar notificações e usar a técnica Pomodoro."

return {
"media_foco": round(media_foco, 2),
"tempo_total_focado": total_minutos,
"total_sessoes": total_sessoes,
"mensagem_feedback": feedback
}
17 changes: 17 additions & 0 deletions front/.editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Editor configuration, see https://editorconfig.org
root = true

[*]
charset = utf-8
indent_style = space
indent_size = 2
insert_final_newline = true
trim_trailing_whitespace = true

[*.ts]
quote_type = single
ij_typescript_use_double_quotes = false

[*.md]
max_line_length = off
trim_trailing_whitespace = false
44 changes: 44 additions & 0 deletions front/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# See https://docs.github.com/get-started/getting-started-with-git/ignoring-files for more about ignoring files.

# Compiled output
/dist
/tmp
/out-tsc
/bazel-out

# Node
/node_modules
npm-debug.log
yarn-error.log

# IDEs and editors
.idea/
.project
.classpath
.c9/
*.launch
.settings/
*.sublime-workspace

# Visual Studio Code
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
!.vscode/mcp.json
.history/*

# Miscellaneous
/.angular/cache
.sass-cache/
/connect.lock
/coverage
/libpeerconnection.log
testem.log
/typings
__screenshots__/

# System files
.DS_Store
Thumbs.db
12 changes: 12 additions & 0 deletions front/.prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"printWidth": 100,
"singleQuote": true,
"overrides": [
{
"files": "*.html",
"options": {
"parser": "angular"
}
}
]
}
Loading