Skip to content

Repository files navigation

PerformanceLab

Room reservation management / Gerenciamento de reservas de salas

English  |  Português


English

Description

REST API for room, user and reservation management. Built with FastAPI, SQLAlchemy and PostgreSQL. This project provides a deliberately simple REST API that serves as the system under test for a dedicated performance-testing suite built with k6.

Features

  • Rooms — Full CRUD with soft-delete
  • Users — Full CRUD with email and phone validation
  • Reservations — Create with date conflict check, cancel, list by user and by room

Project structure

api/
├── main.py                 # FastAPI app, lifespan with create_all
├── config.py               # Config (DB_* env vars)
├── database.py             # SQLAlchemy engine, session, declarative base
├── models/
│   ├── user.py             # User model
│   ├── room.py             # Room model
│   └── reservation.py      # Reservation model + ReservationStatus enum
├── schemas/
│   ├── user.py             # Pydantic: UserCreate, UserUpdate, UserResponse
│   ├── room.py             # Pydantic: RoomCreate, RoomUpdate, RoomResponse
│   ├── reservation.py      # Pydantic: ReservationCreate, ReservationResponse
│   └── seed.py             # Pydantic: Seed* request/response models
├── services/
│   ├── user_service.py     # User business rules
│   ├── room_service.py     # Room business rules
│   └── reservation_service.py  # Reservation business rules
└── routers/
    ├── users.py            # /users endpoints
    ├── rooms.py            # /rooms endpoints
    ├── reservations.py     # /reservations endpoints
    └── seed.py             # /seed endpoints (load-test seeding)

Requirements

  • Python >= 3.14
  • Running PostgreSQL
  • Managed with uv

Setup

  1. Clone the repository.
  2. Copy the environment file and edit with your credentials:
cp .env.example .env
  1. Create the database in PostgreSQL:
CREATE DATABASE performancelab;
  1. Install dependencies:
uv sync
  1. Run:
uv run uvicorn api.main:app --reload --timeout-keep-alive 30

Tables are created automatically on startup via Base.metadata.create_all.

Endpoints

Method Route Description
POST /users/ Create user
GET /users/ List users
GET /users/{id} Get user
PUT /users/{id} Update user
DELETE /users/{id} Delete user
POST /rooms/ Create room
GET /rooms/ List rooms
GET /rooms/{id} Get room
PUT /rooms/{id} Update room
DELETE /rooms/{id} Deactivate room
POST /reservations/ Create reservation
PATCH /reservations/{id}/cancel Cancel reservation
GET /reservations/user/{user_id} List user reservations
GET /reservations/room/{room_id} List room reservations

Business rules

  • User email must be unique.
  • Room name must be unique.
  • Capacity must be >= 1.
  • Price must be > 0.
  • check_in must be today or in the future.
  • check_out must be after check_in.
  • A room cannot have overlapping reservations (status = confirmed).
  • A reservation can only be cancelled if its status is confirmed.
  • A user can only be deleted if they have no active reservations.
  • A room can only be deactivated if it has no active reservations.

Known limitations

  • Known performance constraint (intentional). The API uses SQLAlchemy's default connection pool (pool_size=5, max_overflow=10) and sync def endpoints, so FastAPI runs them on anyio's threadpool (capped at 40 threads). Under concurrent load (e.g. 50 VUs), requests queue on both the threadpool and the connection pool, causing latency to climb regardless of endpoint. This constraint is deliberately left in place so that the load tests in tests/performance/load/ can observe how the system behaves as concurrency approaches and exceeds the available database and thread capacity. Fixes to consider: raise pool_size/max_overflow (ideally env-driven), enable pool_pre_ping, or migrate to an async engine and async def endpoints.

Tests

Functional tests are in tests/ (unit tests in tests/unit/ and integration tests in tests/integration/). Performance tests are maintained separately under tests/performance/ and use k6 against a running API. Run all with:

uv run pytest tests/ -v

See tests/README.md for a full description of every test.

CI/CD

Every push and pull request to master runs:

  1. Lintruff check .
  2. Type checkmypy api/
  3. Test with coveragepytest tests/ -v --cov=api --cov-report=term-missing (the suite runs against in-memory SQLite; a PostgreSQL 17 service container is provisioned in the job)
  4. Coverage artifact uploaded on every run

A separate Performance workflow (.github/workflows/performance.yml) validates the k6 load scripts on every push and pull request. A manual smoke run against a live API can be triggered via workflow_dispatch, with tunable p95-ms and error-rate thresholds. See tests/README.md for details.

Interactive docs


Português (PT-BR)

Descrição

API REST para gerenciamento de salas, usuários e reservas. Desenvolvida com FastAPI, SQLAlchemy e PostgreSQL. Este projeto fornece uma API REST deliberadamente simples que funciona como sistema sob teste para uma suíte dedicada de testes de performance construída com k6.

Funcionalidades

  • Salas — CRUD completo com soft-delete (desativação)
  • Usuários — CRUD completo com validação de e-mail e telefone
  • Reservas — Criação com verificação de conflito de datas, cancelamento, listagem por usuário e por sala

Estrutura do projeto

api/
├── main.py                 # App FastAPI, lifespan com create_all
├── config.py               # Config (DB_* via variáveis de ambiente)
├── database.py             # Engine SQLAlchemy, Sessão, Base declarativa
├── models/
│   ├── user.py             # Modelo User
│   ├── room.py             # Modelo Room
│   └── reservation.py      # Modelo Reservation + enum ReservationStatus
├── schemas/
│   ├── user.py             # Pydantic: UserCreate, UserUpdate, UserResponse
│   ├── room.py             # Pydantic: RoomCreate, RoomUpdate, RoomResponse
│   ├── reservation.py      # Pydantic: ReservationCreate, ReservationResponse
│   └── seed.py             # Pydantic: modelos Seed* de request/response
├── services/
│   ├── user_service.py     # Regras de negócio de usuário
│   ├── room_service.py     # Regras de negócio de sala
│   └── reservation_service.py  # Regras de negócio de reserva
└── routers/
    ├── users.py            # Endpoints /users
    ├── rooms.py            # Endpoints /rooms
    ├── reservations.py     # Endpoints /reservations
    └── seed.py             # Endpoints /seed (seeding de testes de carga)

Requisitos

  • Python >= 3.14
  • PostgreSQL rodando
  • Gerenciado com uv

Configuração

  1. Clone o repositório.
  2. Copie o arquivo de ambiente e edite com suas credenciais:
cp .env.example .env
  1. Crie o banco de dados no PostgreSQL:
CREATE DATABASE performancelab;
  1. Instale as dependências:
uv sync
  1. Execute:
uv run uvicorn api.main:app --reload --timeout-keep-alive 30

As tabelas são criadas automaticamente na inicialização via Base.metadata.create_all.

Endpoints

Método Rota Descrição
POST /users/ Criar usuário
GET /users/ Listar usuários
GET /users/{id} Obter usuário
PUT /users/{id} Atualizar usuário
DELETE /users/{id} Excluir usuário
POST /rooms/ Criar sala
GET /rooms/ Listar salas
GET /rooms/{id} Obter sala
PUT /rooms/{id} Atualizar sala
DELETE /rooms/{id} Desativar sala
POST /reservations/ Criar reserva
PATCH /reservations/{id}/cancel Cancelar reserva
GET /reservations/user/{user_id} Reservas de um usuário
GET /reservations/room/{room_id} Reservas de uma sala

Regras de negócio

  • E-mail do usuário deve ser único.
  • Nome da sala deve ser único.
  • Capacidade da sala deve ser >= 1.
  • Preço da sala deve ser > 0.
  • check_in deve ser hoje ou no futuro.
  • check_out deve ser posterior a check_in.
  • Uma sala não pode ter reservas com datas sobrepostas (status = confirmed).
  • Uma reserva só pode ser cancelada se estiver com status confirmed.
  • Um usuário só pode ser excluído se não tiver reservas ativas.
  • Uma sala só pode ser desativada se não tiver reservas ativas.

Limitações conhecidas

  • Restrição de performance conhecida (intencional). A API usa o pool de conexões padrão do SQLAlchemy (pool_size=5, max_overflow=10) e endpoints def síncronos, então o FastAPI os executa no threadpool do anyio (limitado a 40 threads). Sob carga concorrente (ex.: 50 VUs), as requisições ficam enfileiradas tanto no threadpool quanto no pool de conexões, fazendo a latência aumentar independentemente do endpoint. Essa restrição foi deixada de forma intencional para que os testes de carga em tests/performance/load/ observem como o sistema se comporta quando a concorrência se aproxima e excede a capacidade disponível de banco de dados e threads. Correções a considerar: aumentar pool_size/max_overflow (idealmente via variáveis de ambiente), habilitar pool_pre_ping, ou migrar para engine assíncrono e endpoints async def.

Testes

Os testes funcionais estão em tests/ (testes unitários em tests/unit/ e testes de integração em tests/integration/). Os testes de performance ficam separados em tests/performance/ e usam k6 contra uma API em execução. Execute todos com:

uv run pytest tests/ -v

Consulte tests/README.md para a descrição completa de cada teste.

CI/CD

Cada push e pull request para master executa:

  1. Lintruff check .
  2. Type checkmypy api/
  3. Testes com coberturapytest tests/ -v --cov=api --cov-report=term-missing (a suíte roda sobre SQLite em memória; um container de serviço PostgreSQL 17 é provisionado no job)
  4. Artefato de cobertura enviado a cada execução

Um workflow de performance separado (.github/workflows/performance.yml) valida os scripts de carga k6 a cada push e pull request. Uma execução smoke manual contra uma API ativa pode ser disparada via workflow_dispatch, com limites p95-ms e error-rate configuráveis. Veja tests/README.md para detalhes.

Documentação interativa

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages