criação inicial do corpo do projeto
This commit is contained in:
17
Dockerfile
Normal file
17
Dockerfile
Normal file
@@ -0,0 +1,17 @@
|
||||
FROM python:3.11-slim
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Instalar dependências do sistema
|
||||
RUN apt-get update && apt-get install -y \
|
||||
gcc \
|
||||
libpq-dev \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
COPY requirements.txt .
|
||||
|
||||
RUN pip install --no-cache-dir -r requirements.txt
|
||||
|
||||
COPY . .
|
||||
|
||||
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000", "--reload"]
|
||||
5
app/api/v1/api.py
Normal file
5
app/api/v1/api.py
Normal file
@@ -0,0 +1,5 @@
|
||||
from fastapi import APIRouter
|
||||
from app.api.v1.endpoints import games
|
||||
|
||||
api_router = APIRouter()
|
||||
api_router.include_router(games.router, prefix="/catalog/games", tags=["games"])
|
||||
28
app/api/v1/endpoints/games.py
Normal file
28
app/api/v1/endpoints/games.py
Normal file
@@ -0,0 +1,28 @@
|
||||
from fastapi import APIRouter, Depends, HTTPException, status
|
||||
from sqlalchemy.orm import Session
|
||||
from typing import List, Optional
|
||||
|
||||
from app.schemas.game import GameCreate, GameUpdate, GameResponse, StandardResponse
|
||||
from app.db.database import get_db
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
@router.get("/", response_model=StandardResponse)
|
||||
def read_games(skip: int = 0, limit: int = 100, genre: Optional[str] = None, platform: Optional[str] = None, db: Session = Depends(get_db)):
|
||||
# Lógica de listagem e filtragem será implementada aqui
|
||||
return {"success": True, "message": "Lista de jogos", "data": []}
|
||||
|
||||
@router.post("/", response_model=StandardResponse, status_code=status.HTTP_201_CREATED)
|
||||
def create_game(game: GameCreate, db: Session = Depends(get_db)):
|
||||
# Lógica de criação será implementada aqui
|
||||
return {"success": True, "message": "Jogo criado com sucesso", "data": {}}
|
||||
|
||||
@router.get("/{id_ou_slug}", response_model=StandardResponse)
|
||||
def read_game(id_ou_slug: str, db: Session = Depends(get_db)):
|
||||
# Lógica de leitura de um único jogo será implementada aqui
|
||||
return {"success": True, "message": "Detalhes do jogo", "data": {}}
|
||||
|
||||
@router.patch("/{id}", response_model=StandardResponse)
|
||||
def update_game(id: str, game: GameUpdate, db: Session = Depends(get_db)):
|
||||
# Lógica de atualização parcial será implementada aqui
|
||||
return {"success": True, "message": "Jogo atualizado com sucesso", "data": {}}
|
||||
12
app/core/config.py
Normal file
12
app/core/config.py
Normal file
@@ -0,0 +1,12 @@
|
||||
from pydantic_settings import BaseSettings
|
||||
|
||||
class Settings(BaseSettings):
|
||||
PROJECT_NAME: str = "Microsserviço de Catálogo de Jogos"
|
||||
API_V1_STR: str = "/api/v1"
|
||||
DATABASE_URL: str
|
||||
|
||||
class Config:
|
||||
env_file = ".env"
|
||||
case_sensitive = True
|
||||
|
||||
settings = Settings()
|
||||
16
app/db/database.py
Normal file
16
app/db/database.py
Normal file
@@ -0,0 +1,16 @@
|
||||
from sqlalchemy import create_engine
|
||||
from sqlalchemy.orm import declarative_base
|
||||
from sqlalchemy.orm import sessionmaker
|
||||
from app.core.config import settings
|
||||
|
||||
engine = create_engine(settings.DATABASE_URL)
|
||||
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
|
||||
|
||||
Base = declarative_base()
|
||||
|
||||
def get_db():
|
||||
db = SessionLocal()
|
||||
try:
|
||||
yield db
|
||||
finally:
|
||||
db.close()
|
||||
18
app/main.py
Normal file
18
app/main.py
Normal file
@@ -0,0 +1,18 @@
|
||||
from fastapi import FastAPI
|
||||
from app.core.config import settings
|
||||
from app.api.v1.api import api_router
|
||||
from app.db.database import Base, engine
|
||||
|
||||
# Cria as tabelas do banco de dados (idealmente usaríamos Alembic em produção)
|
||||
Base.metadata.create_all(bind=engine)
|
||||
|
||||
app = FastAPI(
|
||||
title=settings.PROJECT_NAME,
|
||||
openapi_url=f"{settings.API_V1_STR}/openapi.json"
|
||||
)
|
||||
|
||||
app.include_router(api_router, prefix=settings.API_V1_STR)
|
||||
|
||||
@app.get("/")
|
||||
def root():
|
||||
return {"message": "Bem-vindo ao Microsserviço de Catálogo do GameVerse"}
|
||||
20
app/models/game.py
Normal file
20
app/models/game.py
Normal file
@@ -0,0 +1,20 @@
|
||||
from sqlalchemy import Column, String, Boolean, JSON
|
||||
from app.db.database import Base
|
||||
import uuid
|
||||
|
||||
class Game(Base):
|
||||
__tablename__ = "games"
|
||||
|
||||
id = Column(String, primary_key=True, default=lambda: f"gv-{uuid.uuid4().hex[:8]}")
|
||||
title = Column(String, index=True, nullable=False)
|
||||
slug = Column(String, unique=True, index=True, nullable=False)
|
||||
description = Column(String)
|
||||
developer = Column(String)
|
||||
active = Column(Boolean, default=True)
|
||||
|
||||
# Usando JSON para simplificar arrays no MVP conforme os requisitos.
|
||||
# Em um banco relacional robusto, genres e platforms seriam tabelas M:N.
|
||||
genres = Column(JSON)
|
||||
platforms = Column(JSON)
|
||||
images = Column(JSON)
|
||||
system_requirements = Column(JSON)
|
||||
46
app/schemas/game.py
Normal file
46
app/schemas/game.py
Normal file
@@ -0,0 +1,46 @@
|
||||
from pydantic import BaseModel, HttpUrl
|
||||
from typing import List, Optional, Dict, Any
|
||||
|
||||
class GameImages(BaseModel):
|
||||
thumbnail: Optional[HttpUrl] = None
|
||||
header: Optional[HttpUrl] = None
|
||||
|
||||
class SystemRequirements(BaseModel):
|
||||
cpu: Optional[str] = None
|
||||
gpu: Optional[str] = None
|
||||
ram: Optional[str] = None
|
||||
|
||||
class GameBase(BaseModel):
|
||||
title: str
|
||||
description: str
|
||||
genres: List[str]
|
||||
platforms: List[str]
|
||||
developer: str
|
||||
images: Optional[GameImages] = None
|
||||
system_requirements: Optional[SystemRequirements] = None
|
||||
active: bool = True
|
||||
|
||||
class GameCreate(GameBase):
|
||||
pass
|
||||
|
||||
class GameUpdate(BaseModel):
|
||||
title: Optional[str] = None
|
||||
description: Optional[str] = None
|
||||
genres: Optional[List[str]] = None
|
||||
platforms: Optional[List[str]] = None
|
||||
developer: Optional[str] = None
|
||||
images: Optional[GameImages] = None
|
||||
system_requirements: Optional[SystemRequirements] = None
|
||||
active: Optional[bool] = None
|
||||
|
||||
class GameResponse(GameBase):
|
||||
id: str
|
||||
slug: str
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
class StandardResponse(BaseModel):
|
||||
success: bool
|
||||
message: str
|
||||
data: Optional[Any] = None
|
||||
33
docker-compose.yml
Normal file
33
docker-compose.yml
Normal file
@@ -0,0 +1,33 @@
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
web:
|
||||
build: .
|
||||
ports:
|
||||
- "8000:8000"
|
||||
environment:
|
||||
- DATABASE_URL=postgresql://postgres:postgres@db:5432/gameverse_catalog
|
||||
volumes:
|
||||
- .:/app
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
|
||||
db:
|
||||
image: postgres:15
|
||||
environment:
|
||||
POSTGRES_USER: postgres
|
||||
POSTGRES_PASSWORD: postgres
|
||||
POSTGRES_DB: gameverse_catalog
|
||||
ports:
|
||||
- "5432:5432"
|
||||
volumes:
|
||||
- postgres_data:/var/lib/postgresql/data
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U postgres"]
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
|
||||
volumes:
|
||||
postgres_data:
|
||||
84
readme.md
Normal file
84
readme.md
Normal file
@@ -0,0 +1,84 @@
|
||||
Este é um planejamento detalhado para o microsserviço de **Catálogo de Jogos**, estruturado para atender a todos os requisitos do projeto GameVerse.
|
||||
## 1. Nome do Microsserviço
|
||||
**Microsserviço de Catálogo e Metadados de Jogos**
|
||||
## 2. Integrantes do grupo
|
||||
[Inserir nome completo de todos os integrantes aqui]
|
||||
## 3. Objetivo do microsserviço
|
||||
O objetivo deste serviço é centralizar e gerenciar todo o inventário de títulos disponíveis na plataforma GameVerse. Ele atua como a "vitrine" do ecossistema, resolvendo o problema de fragmentação de informações sobre os jogos. Sem ele, o sistema não teria uma fonte única de verdade para descrições, requisitos técnicos ou categorização. Ele é fundamental porque fornece os dados necessários para que a **Loja** exiba produtos e para que a **Biblioteca do Usuário** saiba exatamente o que o jogador adquiriu.
|
||||
## 4. Responsabilidades do microsserviço
|
||||
* **Gerenciar o inventário:** Cadastrar, atualizar e remover jogos do catálogo.
|
||||
* **Categorização:** Administrar gêneros (RPG, FPS, Indie) e plataformas (PC, Console, Cloud).
|
||||
* **Curadoria de Conteúdo:** Armazenar descrições detalhadas, notas de patch e classificações indicativas.
|
||||
* **Gestão de Mídia:** Vincular URLs de imagens, trailers e capas aos respectivos títulos.
|
||||
* **Busca e Filtragem:** Permitir que outros serviços consultem jogos por critérios específicos.
|
||||
## 5. Dados que o serviço precisa receber
|
||||
Para o cadastro ou atualização de um jogo, o serviço requer:
|
||||
* **Nome do jogo:** (String)
|
||||
* **Descrição:** (Text/Markdown)
|
||||
* **Gêneros:** (Array de IDs ou nomes)
|
||||
* **Plataformas:** (Array de IDs - ex: Steam, Epic, Xbox)
|
||||
* **Mídia:** (URLs de imagens de capa e galeria)
|
||||
* **Desenvolvedora/Distribuidora:** (String)
|
||||
* **Requisitos de Sistema:** (Objeto JSON com CPU, GPU, RAM mínimos e recomendados)
|
||||
## 6. Dados que o serviço deve retornar
|
||||
Exemplo de resposta ao consultar um jogo específico:
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "Jogo localizado com sucesso",
|
||||
"data": {
|
||||
"game_id": "gv-8829",
|
||||
"title": "Cyber-Acre 2077",
|
||||
"slug": "cyber-acre-2077",
|
||||
"platforms": ["PC", "Linux"],
|
||||
"genres": ["Action", "RPG"],
|
||||
"description": "Um RPG de ação em um futuro distópico no norte do Brasil.",
|
||||
"images": {
|
||||
"thumbnail": "https://cdn.gameverse.com/covers/ca2077_thumb.jpg",
|
||||
"header": "https://cdn.gameverse.com/headers/ca2077_wide.jpg"
|
||||
},
|
||||
"active": true
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
## 7. Com quais serviços ele precisa se comunicar
|
||||
* **Loja de Jogos (Storefront):** Para fornecer os dados que serão exibidos ao comprador.
|
||||
* **Biblioteca do Usuário:** Para validar se o ID do jogo que o usuário possui ainda existe e está atualizado.
|
||||
* **Busca (Search Service):** Para indexar novos títulos em motores de busca como Elasticsearch.
|
||||
* **Laravel Central/API Gateway:** Para autenticação de administradores que gerenciam o catálogo.
|
||||
## 8. Fluxo principal do serviço
|
||||
1. **Administrador** envia uma requisição de cadastro com os dados do novo jogo.
|
||||
2. O serviço **valida** se o título já existe e se todos os campos obrigatórios estão presentes.
|
||||
3. O serviço **persiste** os dados no banco de dados (Gêneros, Plataformas e Dados Gerais).
|
||||
4. O serviço **emite um evento** (via RabbitMQ/Kafka ou Webhook) informando que um novo jogo foi adicionado.
|
||||
5. A **Loja** recebe a atualização e passa a exibir o jogo para os usuários.
|
||||
6. O **Usuário** realiza uma busca e o serviço retorna a lista filtrada de jogos.
|
||||
## 9. Rotas iniciais da API
|
||||
* GET /api/v1/catalog/games (Listagem com paginação e filtros de gênero/plataforma)
|
||||
* POST /api/v1/catalog/games (Criação de novo título - Restrito a Admin)
|
||||
* GET /api/v1/catalog/games/{id_ou_slug} (Detalhes completos de um jogo específico)
|
||||
* PATCH /api/v1/catalog/games/{id} (Atualização parcial de dados como descrição ou imagens)
|
||||
## 10. Possíveis erros
|
||||
* **Jogo não encontrado:** Quando um ID inválido é solicitado.
|
||||
* **Título Duplicado:** Tentativa de cadastrar um jogo com nome ou slug já existente.
|
||||
* **Falha na persistência de mídia:** Erro ao tentar vincular links de imagens inválidos.
|
||||
* **Dados incompletos:** Envio de formulário sem campos obrigatórios (ex: sem plataforma definida).
|
||||
* **Incompatibilidade de Versão:** Tentativa de atualizar um jogo que foi removido ou arquivado.
|
||||
|
||||
# DEVE SER FEITO EM FAST API (python)
|
||||
|
||||
## 11. Como Executar (Docker)
|
||||
Este projeto foi containerizado para facilitar a execução.
|
||||
|
||||
### Pré-requisitos
|
||||
- [Docker](https://www.docker.com/) e [Docker Compose](https://docs.docker.com/compose/) instalados.
|
||||
|
||||
### Passos
|
||||
1. Execute o script na raiz do projeto:
|
||||
```bash
|
||||
./run.sh
|
||||
```
|
||||
2. A aplicação FastAPI estará disponível em: http://localhost:8000
|
||||
3. A documentação interativa (Swagger UI) pode ser acessada em: http://localhost:8000/docs
|
||||
4. O banco de dados PostgreSQL estará rodando internamente na porta `5432`.
|
||||
8
requirements.txt
Normal file
8
requirements.txt
Normal file
@@ -0,0 +1,8 @@
|
||||
fastapi>=0.109.0
|
||||
uvicorn[standard]>=0.27.0
|
||||
pydantic>=2.5.0
|
||||
pydantic-settings>=2.1.0
|
||||
sqlalchemy>=2.0.25
|
||||
psycopg2-binary>=2.9.9
|
||||
alembic>=1.13.1
|
||||
pytest>=8.0.0
|
||||
Reference in New Issue
Block a user