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
1 change: 1 addition & 0 deletions focus_log/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
DATABASE_URL="sqlite:///./focus_log.db"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Remova as aspas ao redor do valor da variável de ambiente.

Em arquivos .env, as aspas são tratadas como parte literal do valor. Quando python-dotenv carregar esta configuração, DATABASE_URL terá o valor "sqlite:///./focus_log.db" (incluindo as aspas), o que causará erro ao tentar criar a conexão SQLAlchemy.

🔧 Correção sugerida
-DATABASE_URL="sqlite:///./focus_log.db"
+DATABASE_URL=sqlite:///./focus_log.db
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
DATABASE_URL="sqlite:///./focus_log.db"
DATABASE_URL=sqlite:///./focus_log.db
🧰 Tools
🪛 dotenv-linter (4.0.0)

[warning] 1-1: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@focus_log/.env.example` at line 1, O valor de DATABASE_URL no arquivo exemplo
inclui aspas literais; remova as aspas ao redor do valor para que a variável
DATABASE_URL seja setada como sqlite:///./focus_log.db (sem aspas) para evitar
que python-dotenv carregue as aspas como parte do valor; atualize a entrada
DATABASE_URL no arquivo .env.example para sqlite:///./focus_log.db garantindo
que outras documentações ou scripts usem a mesma forma.

26 changes: 26 additions & 0 deletions focus_log/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.pyc
*.pyo
*.pyd

# Virtual environment
venv/
.venv/
env/
ENV/

# Database files
*.db
*.sqlite3
focus_log.db
test.db

# Environment variables
.env

# Pytest cache
.pytest_cache/

# VSCode
.vscode/
135 changes: 135 additions & 0 deletions focus_log/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
# Focus Log API - v2.0

Uma API robusta e inteligente para registrar, analisar e gamificar suas sessões de foco, construída com FastAPI e SQLite. Este projeto vai além de um simples CRUD, incorporando uma arquitetura profissional e funcionalidades criativas para se destacar.

## Filosofia do Projeto

O objetivo não é apenas armazenar dados, mas transformá-los em **insights acionáveis** e **motivação**. A API foi desenhada para ajudar o usuário a entender seus próprios padrões de produtividade e a construir o hábito da consistência através de mecânicas de gamificação.

## Funcionalidades Principais

- **Registro de Foco**: Endpoint para registrar sessões de trabalho ou estudo.
- **Diagnóstico de Produtividade**: Uma análise completa com métricas como média de foco, tempo total e as melhores/piores sessões.
- **Feedback Inteligente**: Mensagens didáticas que explicam *por que* o feedback está sendo dado e sugerem ações.
- **Gamificação (Streaks)**: Sistema de "sequências" que incentiva o registro diário, recompensando a consistência.
- **Análise de Tags**: Correlaciona as tags usadas nos registros com o nível de foco, revelando o que te ajuda ou atrapalha a ser produtivo.

---

## Decisões de Arquitetura e Design

A estrutura do projeto foi escolhida para garantir **clareza, manutenibilidade e escalabilidade**.

- **FastAPI**: Escolhido pela sua alta performance, sintaxe moderna com type hints (que reduz bugs) e a geração automática de documentação interativa (Swagger UI), que é excelente para desenvolvimento e testes.

- **Arquitetura em Camadas**:
- `main.py`: Ponto de entrada. Mínimo de lógica, apenas configurações globais e inclusão dos roteadores.
- `routers/`: Responsáveis por definir os endpoints HTTP. Sua única função é receber requisições, chamar a camada de serviço e retornar respostas. Não contêm lógica de negócio.
- `service.py`: O "cérebro" da aplicação. Contém toda a lógica de negócio (como gerar feedbacks, calcular streaks, analisar tags). Não tem conhecimento sobre HTTP ou o banco de dados diretamente, o que a torna reutilizável e fácil de testar.
- `repository.py`: A única camada que interage com o banco de dados. Abstrai as queries do SQLAlchemy, centralizando o acesso aos dados.
- `models.py` e `schemas.py`: Separação clara entre o modelo do banco de dados (SQLAlchemy) e o modelo da API (Pydantic). Isso permite que a API evolua de forma independente do banco.

- **SQLite**: Selecionado pela simplicidade. É um banco de dados baseado em arquivo, que não exige instalação ou configuração de um servidor, tornando o projeto extremamente fácil de rodar localmente. Para um ambiente de produção, a troca para um banco como PostgreSQL seria simples, bastando alterar a `DATABASE_URL` e instalar o driver `psycopg2`.

- **Pydantic para Validação**: Usado extensivamente para validar os dados de entrada (`RegistroFocoCreate`) e garantir a estrutura dos dados de saída (`*Out` schemas). As mensagens de erro customizadas e o handler de exceção global em `main.py` melhoram a experiência de quem consome a API.

- **Tarefas em Background (`BackgroundTasks`)**: A atualização da gamificação é feita em segundo plano. Isso proporciona uma resposta mais rápida ao usuário no momento do registro, pois ele não precisa esperar o cálculo da sequência ser finalizado.

---

## Como Usar

### Pré-requisitos

- Python 3.11 ou superior

### Instalação e Execução

1. **Clone o repositório e entre na pasta:**
```bash
git clone https://github.com/seu-usuario/focus_log.git

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Atualize a URL do repositório com o endereço real.

A URL contém um placeholder seu-usuario que deve ser substituído pelo nome de usuário/organização real do GitHub.

📝 Sugestão de correção
-    git clone https://github.com/seu-usuario/focus_log.git
+    git clone https://github.com/SouJunior/teste-tecnico-python-backend.git
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@focus_log/README.md` at line 50, Atualize a URL de clone no README
substituindo o placeholder "seu-usuario" pela organização/usuário real do
GitHub; localizar a linha com o comando git clone (a string "git clone
https://github.com/seu-usuario/focus_log.git") e trocar por "git clone
https://github.com/<SEU_USUARIO_REAL>/focus_log.git" para apontar ao repositório
correto.

cd focus_log
```

2. **Crie e ative um ambiente virtual:**
```bash
python -m venv venv
# Windows:
venv\Scripts\activate
# macOS/Linux:
source venv/bin/activate
```

3. **Instale as dependências:**
```bash
pip install -r requirements.txt
```

4. **Crie o arquivo de ambiente local:**
Este passo é crucial para definir a conexão com o banco de dados.
```bash
# Windows
copy .env.example .env
# macOS/Linux
cp .env.example .env
```

5. **Execute a aplicação:**
```bash
uvicorn app.main:app --reload
```
A API estará disponível em `http://127.0.0.1:8000`.

### Testando a API

A forma mais fácil de interagir com a API é através da **documentação interativa (Swagger UI)**, disponível em:

[**http://127.0.0.1:8000/docs**](http://127.0.0.1:8000/docs)

Lá você pode testar todos os endpoints diretamente do seu navegador.

---

## Exemplos de Uso (cURL)

1. **Registrar uma nova sessão de foco:**
```bash
curl -X 'POST' \
'http://127.0.0.1:8000/registro-foco' \
-H 'accept: application/json' \
-H 'Content-Type: application/json' \
-d '{
"nivel_foco": 5,
"tempo_minutos": 90,
"comentario": "Desenvolvendo a funcionalidade de diagnóstico com foco total!",
"categoria": "coding",
"tags": "backend,python,api"
}'
```

2. **Verificar o status da sua sequência (gamificação):**
```bash
curl -X 'GET' 'http://127.0.0.1:8000/analise/status' -H 'accept: application/json'
```

3. **Obter a análise de tags:**
```bash
curl -X 'GET' 'http://127.0.0.1:8000/analise/tags' -H 'accept: application/json'
```

4. **Obter o diagnóstico de produtividade:**
```bash
curl -X 'GET' \
'http://127.0.0.1:8000/diagnostico-produtividade' \
-H 'accept: application/json'
```

---

## Como Rodar os Testes

Para garantir a qualidade e o funcionamento correto da API, execute os testes automatizados com `pytest`.

```bash
pytest
```
29 changes: 29 additions & 0 deletions focus_log/app/database.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import os
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
from dotenv import load_dotenv

load_dotenv()

DATABASE_URL = os.getenv("DATABASE_URL")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Valide que DATABASE_URL está definida antes de usar.

Se a variável de ambiente DATABASE_URL não estiver configurada, os.getenv() retornará None, causando uma falha críptica ao tentar criar o engine SQLAlchemy na linha 11. Adicione validação para falhar rapidamente com uma mensagem clara.

🛡️ Correção sugerida com validação
 DATABASE_URL = os.getenv("DATABASE_URL")
+
+if not DATABASE_URL:
+    raise ValueError(
+        "DATABASE_URL não está definida. "
+        "Certifique-se de criar o arquivo .env a partir de .env.example"
+    )
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
DATABASE_URL = os.getenv("DATABASE_URL")
DATABASE_URL = os.getenv("DATABASE_URL")
if not DATABASE_URL:
raise ValueError(
"DATABASE_URL não está definida. "
"Certifique-se de criar o arquivo .env a partir de .env.example"
)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@focus_log/app/database.py` at line 9, Verifique que DATABASE_URL (obtida via
os.getenv("DATABASE_URL")) não seja None antes de usá-la para criar o engine; se
for None, levante uma exceção clara (por exemplo RuntimeError ou ValueError) com
uma mensagem indicando que a variável de ambiente DATABASE_URL não está definida
para evitar falhas crípticas ao criar o SQLAlchemy engine (procure onde
DATABASE_URL é usado/onde o engine é criado).


engine = create_engine(
DATABASE_URL, connect_args={"check_same_thread": False}
)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)

Base = declarative_base()

def get_db():
"""
Obtém uma sessão do banco de dados.

Yields:
Session: A sessão do banco de dados.
"""
db = SessionLocal()
try:
yield db
finally:
db.close()
36 changes: 36 additions & 0 deletions focus_log/app/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
from fastapi import FastAPI, Request, status
from fastapi.responses import JSONResponse
from fastapi.exceptions import RequestValidationError
from .database import engine, Base
from .routers import registro, diagnostico, analise

Base.metadata.create_all(bind=engine)

app = FastAPI(
title="Focus Log API",
description="Uma API para registrar e analisar sessões de foco, com gamificação e análise inteligente.",
version="2.0.0"
)

@app.exception_handler(RequestValidationError)
async def validation_exception_handler(request: Request, exc: RequestValidationError):
"""
Handler global para erros de validação do Pydantic.
"""
detalhes = []
for error in exc.errors():
campo = " -> ".join(map(str, error["loc"]))
mensagem = error["msg"]
detalhes.append({"campo": campo, "mensagem": mensagem})
return JSONResponse(
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
content={"erro": "Dados inválidos", "detalhes": detalhes},
)

app.include_router(registro.router, tags=["Registros de Foco"])
app.include_router(diagnostico.router, tags=["Diagnóstico de Produtividade"])
app.include_router(analise.router)

@app.get("/", include_in_schema=False)
def read_root():
return {"message": "Bem-vindo à Focus Log API v2! Acesse /docs para a documentação."}
44 changes: 44 additions & 0 deletions focus_log/app/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import enum
from sqlalchemy import (
Column,
Integer,
String,
DateTime,
Enum,
func,
)
from .database import Base


class StatusApp(Base):
"""
Modelo da tabela `status_app` para gamificação.
Armazena a sequência de dias com registros.
"""
__tablename__ = "status_app"

id = Column(Integer, primary_key=True)
sequencia_atual = Column(Integer, default=0)
sequencia_maxima = Column(Integer, default=0)
data_ultimo_registro = Column(DateTime, nullable=True)


class CategoriaEnum(str, enum.Enum):
coding = "coding"
reuniao = "reuniao"
estudo = "estudo"
outro = "outro"

class RegistroFoco(Base):
"""
Modelo da tabela `registros_foco`.
"""
__tablename__ = "registros_foco"

id = Column(Integer, primary_key=True, index=True)
nivel_foco = Column(Integer, nullable=False)
tempo_minutos = Column(Integer, nullable=False)
comentario = Column(String(500), nullable=False)
categoria = Column(Enum(CategoriaEnum), default=CategoriaEnum.outro, nullable=False)
tags = Column(String(200), nullable=True)
criado_em = Column(DateTime, default=func.now(), nullable=False)
Loading