Skip to content
Merged
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
20 changes: 20 additions & 0 deletions prisma/migrations/20250618155007_add_appointments/migration.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
-- CreateTable
CREATE TABLE "appointments" (
"id" TEXT NOT NULL,
"user_id" TEXT NOT NULL,
"space_id" TEXT NOT NULL,
"date" TIMESTAMP(3) NOT NULL,
"start_time" TIMESTAMP(3) NOT NULL,
"end_time" TIMESTAMP(3) NOT NULL,
"status" "BookingStatus" NOT NULL DEFAULT 'PENDING',
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updated_at" TIMESTAMP(3) NOT NULL,

CONSTRAINT "appointments_pkey" PRIMARY KEY ("id")
);

-- AddForeignKey
ALTER TABLE "appointments" ADD CONSTRAINT "appointments_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE RESTRICT ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE "appointments" ADD CONSTRAINT "appointments_space_id_fkey" FOREIGN KEY ("space_id") REFERENCES "spaces"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
11 changes: 11 additions & 0 deletions prisma/migrations/20250618155144_remove_bookings/migration.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/*
Warnings:

- You are about to drop the `bookings` table. If the table is not empty, all the data it contains will be lost.

*/
-- DropForeignKey
ALTER TABLE "bookings" DROP CONSTRAINT "bookings_user_id_fkey";

-- DropTable
DROP TABLE "bookings";
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/*
Warnings:

- The `status` column on the `appointments` table would be dropped and recreated. This will lead to data loss if there is data in the column.

*/
-- CreateEnum
CREATE TYPE "AppointmentStatus" AS ENUM ('PENDING', 'CONFIRMED', 'CANCELLED');

-- AlterTable
ALTER TABLE "appointments" DROP COLUMN "status",
ADD COLUMN "status" "AppointmentStatus" NOT NULL DEFAULT 'PENDING';

-- DropEnum
DROP TYPE "BookingStatus";
58 changes: 30 additions & 28 deletions prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -29,29 +29,30 @@ model User {
updatedAt DateTime @updatedAt @map("updated_at")
deletedAt DateTime? @map("deleted_at")

bookings Booking[]
space Space?
Rating Rating[]
appointments Appointment[]
space Space?
Rating Rating[]

@@map("users")
}

model Space {
id String @id @default(uuid()) @map("id")
title String @map("title")
description String @map("description")
photos String[] @map("photos")
hostId String @unique @map("host_id")
host User @relation(fields: [hostId], references: [id])
amenities Amenity[] @relation("space_amenities")
rules String @map("rules")
id String @id @default(uuid()) @map("id")
title String @map("title")
description String @map("description")
photos String[] @map("photos")
hostId String @unique @map("host_id")
host User @relation(fields: [hostId], references: [id])
amenities Amenity[] @relation("space_amenities")
rules String @map("rules")
address Address?
geoLocation GeoLocation?
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
deletedAt DateTime? @map("deleted_at")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
deletedAt DateTime? @map("deleted_at")
Rating Rating[]
averageRating Float @default(0) @map("average_rating")
appointments Appointment[]
averageRating Float @default(0) @map("average_rating")

@@map("spaces")
}
Expand Down Expand Up @@ -87,26 +88,27 @@ model Amenity {
@@map("amenities")
}

enum BookingStatus {
enum AppointmentStatus {
PENDING
CONFIRMED
CANCELLED
}

model Booking {
id String @id @default(cuid()) @map("id")
userId String @map("user_id")
spaceId String @map("space_id")
date DateTime @map("date")
startTime DateTime @map("start_time")
endTime DateTime @map("end_time")
status BookingStatus @default(PENDING) @map("status")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
model Appointment {
id String @id @default(cuid()) @map("id")
userId String @map("user_id")
spaceId String @map("space_id")
date DateTime @map("date")
startTime DateTime @map("start_time")
endTime DateTime @map("end_time")
status AppointmentStatus @default(PENDING) @map("status")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")

user User @relation(fields: [userId], references: [id])
user User @relation(fields: [userId], references: [id])
space Space @relation(fields: [spaceId], references: [id])

@@map("bookings")
@@map("appointments")
}

model Rating {
Expand Down
28 changes: 28 additions & 0 deletions src/config/swagger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,37 @@ import { Express } from 'express';
const options: swaggerJsdoc.Options = {
definition: {
openapi: '3.0.0',
basePath: '/api',
host: 'localhost:3000',
schemes: ['http'],
info: {
title: 'Pool Appointments API',
version: '1.0.0',
description: 'API for managing appointments',
contact: {
name: 'Antonio Silva',
url: 'https://www.linkedin.com/in/tony-silva/',
email: 'contato@antoniobsilva.com.br',
},
license: {
name: 'MIT',
url: 'https://opensource.org/licenses/MIT',
},
servers: [
{
url: 'http://localhost:3000',
description: 'Local server',
},
],
components: {
securitySchemes: {
bearerAuth: {
type: 'http',
scheme: 'bearer',
bearerFormat: 'JWT',
},
},
},
},
},
apis: ['./src/modules/**/presentation/docs/*.ts'],
Expand Down
4 changes: 3 additions & 1 deletion src/core/routes/index.routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Router } from 'express';
import { userRoutes } from '@/modules/users/presentation/routes/user-routes';
import { spaceRoutes } from '@/modules/spaces/presentation/routes/space-routes';
import { ratingRoutes } from '@/modules/ratings/presentation/routes/rating-routes';
import { appointmentRoutes } from '@/modules/appointments/presentation/routes/appointment-routes';

export const routes = Router();

Expand All @@ -11,4 +12,5 @@ routes.get('/status', (req, res) => {

routes.use('/users', userRoutes);
routes.use('/spaces', spaceRoutes);
routes.use('/ratings', ratingRoutes);
routes.use('/ratings', ratingRoutes);
routes.use('/appointments', appointmentRoutes);
65 changes: 65 additions & 0 deletions src/modules/appointments/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# Módulo de Appointments

Este módulo gerencia os agendamentos de espaços, permitindo que usuários agendem o uso de um espaço em uma data e horário específicos.

## Funcionalidades

- **Criar agendamento**: Cria um novo agendamento para um espaço
- **Buscar agendamento por ID**: Retorna um agendamento específico
- **Listar agendamentos por usuário**: Lista todos os agendamentos de um usuário
- **Listar agendamentos por espaço**: Lista todos os agendamentos de um espaço
- **Atualizar agendamento**: Atualiza dados de um agendamento existente
- **Cancelar agendamento**: Remove um agendamento

## Regras de Negócio

1. **Validação de data**: Não é possível agendar para datas passadas
2. **Validação de horário**: O horário de início deve ser menor que o horário de fim
3. **Conflito de horários**: Não é possível agendar um espaço que já possui agendamento no mesmo horário
4. **Status do agendamento**: Pode ser PENDING, CONFIRMED ou CANCELLED

## Estrutura do Módulo

```
appointments/
├── domain/
│ ├── entities/
│ │ └── appointment.ts
│ └── repositories/
│ └── appointment-repository.ts
├── application/
│ └── use-cases/
│ ├── create-appointment/
│ ├── find-appointment/
│ ├── update-appointment/
│ └── delete-appointment/
├── infra/
│ └── repositories/
│ └── prisma-appointment-repository.ts
└── presentation/
├── controllers/
├── validators/
├── routes/
└── docs/
```

## Endpoints

- `POST /api/appointments` - Criar agendamento
- `GET /api/appointments/:id` - Buscar agendamento por ID
- `GET /api/appointments/user/:userId` - Listar agendamentos por usuário
- `GET /api/appointments/space/:spaceId` - Listar agendamentos por espaço
- `PUT /api/appointments/:id` - Atualizar agendamento
- `DELETE /api/appointments/:id` - Deletar agendamento

## Exemplo de Uso

```json
{
"userId": "user-uuid",
"spaceId": "space-uuid",
"date": "2024-01-15T00:00:00.000Z",
"startTime": "2024-01-15T10:00:00.000Z",
"endTime": "2024-01-15T12:00:00.000Z"
}
```
Loading