feat: add full project - backend, frontend, docker, specs and configs
This commit is contained in:
parent
b77c7d5a01
commit
e6cb06255b
24489 changed files with 61341 additions and 36 deletions
143
.specify/features/006-client-area/contracts/admin.md
Normal file
143
.specify/features/006-client-area/contracts/admin.md
Normal file
|
|
@ -0,0 +1,143 @@
|
|||
# Contract: Admin Endpoints
|
||||
|
||||
**Blueprint**: `admin_bp` — prefix `/api/v1/admin`
|
||||
**Auth**: JWT Bearer — `require_auth` — MVP: qualquer ClientUser autenticado
|
||||
**Dívida Técnica**: Verificação de role admin adiada para feature pós-MVP (ver Constitution Check no plan.md)
|
||||
|
||||
---
|
||||
|
||||
# POST /api/v1/admin/boletos
|
||||
|
||||
Cria um boleto para um cliente, opcionalmente vinculado a um imóvel.
|
||||
|
||||
## Request
|
||||
|
||||
```
|
||||
POST /api/v1/admin/boletos
|
||||
Authorization: Bearer <jwt_token>
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"user_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
|
||||
"property_id": "4gb96g75-6828-5673-c4gd-3d074g77bg33",
|
||||
"description": "Aluguel referente a Maio/2026",
|
||||
"amount": 3500.00,
|
||||
"due_date": "2026-05-10",
|
||||
"url": "https://boleto.banco.com.br/abc123"
|
||||
}
|
||||
```
|
||||
|
||||
Campos obrigatórios: `user_id`, `description`, `amount`, `due_date`.
|
||||
Campos opcionais: `property_id`, `url`.
|
||||
|
||||
---
|
||||
|
||||
## Response 201 Created
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "d5be07h8-9012-6784-d5he-4e185h88ch33",
|
||||
"description": "Aluguel referente a Maio/2026",
|
||||
"amount": "3500.00",
|
||||
"due_date": "2026-05-10",
|
||||
"status": "pending",
|
||||
"url": "https://boleto.banco.com.br/abc123"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Response 404 Not Found
|
||||
|
||||
```json
|
||||
{ "error": "Cliente não encontrado" }
|
||||
```
|
||||
|
||||
Quando `user_id` não corresponde a nenhum `ClientUser` existente.
|
||||
|
||||
---
|
||||
|
||||
## Response 422 Unprocessable Entity
|
||||
|
||||
```json
|
||||
{
|
||||
"error": "Dados inválidos",
|
||||
"details": ["user_id: field required", "amount: field required"]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Response 401 Unauthorized
|
||||
|
||||
```json
|
||||
{ "error": "Token inválido ou ausente" }
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
# PUT /api/v1/admin/visits/<id>/status
|
||||
|
||||
Atualiza o status de uma VisitRequest e opcionalmente define a data/hora agendada.
|
||||
|
||||
## Request
|
||||
|
||||
```
|
||||
PUT /api/v1/admin/visits/b3fc85f6-1234-4562-b3fc-2c963f66af11/status
|
||||
Authorization: Bearer <jwt_token>
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"status": "confirmed",
|
||||
"scheduled_at": "2026-05-01T10:00:00"
|
||||
}
|
||||
```
|
||||
|
||||
`status` obrigatório: `"pending"` | `"confirmed"` | `"cancelled"` | `"completed"`
|
||||
`scheduled_at` opcional: ISO 8601 datetime string.
|
||||
|
||||
---
|
||||
|
||||
## Response 200 OK
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "b3fc85f6-1234-4562-b3fc-2c963f66af11",
|
||||
"property": {
|
||||
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
|
||||
"title": "Apartamento 3 quartos Jardins",
|
||||
"slug": "apartamento-3-quartos-jardins"
|
||||
},
|
||||
"message": "Gostaria de visitar no final de semana.",
|
||||
"status": "confirmed",
|
||||
"scheduled_at": "2026-05-01T10:00:00Z",
|
||||
"created_at": "2026-04-13T10:00:00Z"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Response 404 Not Found
|
||||
|
||||
```json
|
||||
{ "error": "Visita não encontrada" }
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Response 422 Unprocessable Entity
|
||||
|
||||
```json
|
||||
{
|
||||
"error": "Dados inválidos",
|
||||
"details": ["status: value is not a valid enumeration member"]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Response 401 Unauthorized
|
||||
|
||||
```json
|
||||
{ "error": "Token inválido ou ausente" }
|
||||
```
|
||||
52
.specify/features/006-client-area/contracts/me-boletos.md
Normal file
52
.specify/features/006-client-area/contracts/me-boletos.md
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
# Contract: GET /api/v1/me/boletos
|
||||
|
||||
**Blueprint**: `client_bp`
|
||||
**Auth**: JWT Bearer — `require_auth` — ClientUser only
|
||||
|
||||
---
|
||||
|
||||
## Request
|
||||
|
||||
```
|
||||
GET /api/v1/me/boletos
|
||||
Authorization: Bearer <jwt_token>
|
||||
```
|
||||
|
||||
Sem parâmetros de query ou corpo.
|
||||
|
||||
---
|
||||
|
||||
## Response 200 OK
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"id": "d5be07h8-9012-6784-d5he-4e185h88ch33",
|
||||
"description": "Aluguel referente a Maio/2026",
|
||||
"amount": "3500.00",
|
||||
"due_date": "2026-05-10",
|
||||
"status": "pending",
|
||||
"url": "https://boleto.banco.com.br/abc123"
|
||||
},
|
||||
{
|
||||
"id": "e6cf18i9-0123-7895-e6if-5f296i99di44",
|
||||
"description": "Taxa de condomínio Abril/2026",
|
||||
"amount": "450.00",
|
||||
"due_date": "2026-04-30",
|
||||
"status": "paid",
|
||||
"url": null
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
Ordenado por `due_date ASC` (vencimentos próximos primeiro). Lista vazia `[]` quando sem boletos.
|
||||
|
||||
`url` é `null` quando o link ainda não foi preenchido pelo admin. O botão de acesso deve ser desabilitado neste caso.
|
||||
|
||||
---
|
||||
|
||||
## Response 401 Unauthorized
|
||||
|
||||
```json
|
||||
{ "error": "Token inválido ou ausente" }
|
||||
```
|
||||
134
.specify/features/006-client-area/contracts/me-favorites.md
Normal file
134
.specify/features/006-client-area/contracts/me-favorites.md
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
# Contract: GET /api/v1/me/favorites
|
||||
|
||||
**Blueprint**: `client_bp`
|
||||
**Auth**: JWT Bearer — `require_auth` — ClientUser only
|
||||
|
||||
---
|
||||
|
||||
## Request
|
||||
|
||||
```
|
||||
GET /api/v1/me/favorites
|
||||
Authorization: Bearer <jwt_token>
|
||||
```
|
||||
|
||||
Sem parâmetros de query ou corpo.
|
||||
|
||||
---
|
||||
|
||||
## Response 200 OK
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"property": {
|
||||
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
|
||||
"title": "Apartamento 3 quartos Jardins",
|
||||
"slug": "apartamento-3-quartos-jardins",
|
||||
"price": "850000.00",
|
||||
"condo_fee": "1200.00",
|
||||
"type": "venda",
|
||||
"subtype": { "id": 1, "name": "Apartamento" },
|
||||
"bedrooms": 3,
|
||||
"bathrooms": 2,
|
||||
"parking_spots": 2,
|
||||
"area_m2": 120,
|
||||
"city": { "id": 1, "name": "São Paulo" },
|
||||
"neighborhood": { "id": 5, "name": "Jardins" },
|
||||
"is_featured": true,
|
||||
"photos": [
|
||||
{ "url": "https://...", "alt_text": "", "display_order": 0 }
|
||||
],
|
||||
"amenities": [{ "id": 1, "name": "Piscina" }],
|
||||
"address": "Rua das Flores, 100",
|
||||
"code": "AP001",
|
||||
"description": "Apartamento espaçoso com varanda gourmet."
|
||||
},
|
||||
"created_at": "2026-04-13T10:00:00Z"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
Lista vazia `[]` quando o cliente não possui favoritos.
|
||||
|
||||
---
|
||||
|
||||
## Response 401 Unauthorized
|
||||
|
||||
```json
|
||||
{ "error": "Token inválido ou ausente" }
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
# Contract: POST /api/v1/me/favorites
|
||||
|
||||
## Request
|
||||
|
||||
```
|
||||
POST /api/v1/me/favorites
|
||||
Authorization: Bearer <jwt_token>
|
||||
Content-Type: application/json
|
||||
|
||||
{ "property_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6" }
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Response 201 Created
|
||||
|
||||
```json
|
||||
{
|
||||
"property": { /* PropertyDetailOut completo */ },
|
||||
"created_at": "2026-04-13T10:00:00Z"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Response 409 Conflict
|
||||
|
||||
```json
|
||||
{ "error": "Imóvel já está nos favoritos" }
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Response 404 Not Found
|
||||
|
||||
```json
|
||||
{ "error": "Imóvel não encontrado" }
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Response 422 Unprocessable Entity
|
||||
|
||||
```json
|
||||
{ "error": "Dados inválidos", "details": ["property_id: field required"] }
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
# Contract: DELETE /api/v1/me/favorites/<property_id>
|
||||
|
||||
## Request
|
||||
|
||||
```
|
||||
DELETE /api/v1/me/favorites/3fa85f64-5717-4562-b3fc-2c963f66afa6
|
||||
Authorization: Bearer <jwt_token>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Response 204 No Content
|
||||
|
||||
Sem corpo.
|
||||
|
||||
---
|
||||
|
||||
## Response 404 Not Found
|
||||
|
||||
```json
|
||||
{ "error": "Favorito não encontrado" }
|
||||
```
|
||||
61
.specify/features/006-client-area/contracts/me-visits.md
Normal file
61
.specify/features/006-client-area/contracts/me-visits.md
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
# Contract: GET /api/v1/me/visits
|
||||
|
||||
**Blueprint**: `client_bp`
|
||||
**Auth**: JWT Bearer — `require_auth` — ClientUser only
|
||||
|
||||
---
|
||||
|
||||
## Request
|
||||
|
||||
```
|
||||
GET /api/v1/me/visits
|
||||
Authorization: Bearer <jwt_token>
|
||||
```
|
||||
|
||||
Sem parâmetros de query ou corpo.
|
||||
|
||||
---
|
||||
|
||||
## Response 200 OK
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"id": "b3fc85f6-1234-4562-b3fc-2c963f66af11",
|
||||
"property": {
|
||||
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
|
||||
"title": "Apartamento 3 quartos Jardins",
|
||||
"slug": "apartamento-3-quartos-jardins"
|
||||
},
|
||||
"message": "Gostaria de visitar no final de semana.",
|
||||
"status": "pending",
|
||||
"scheduled_at": null,
|
||||
"created_at": "2026-04-13T10:00:00Z"
|
||||
},
|
||||
{
|
||||
"id": "c4ad96g7-5678-5673-c4gd-3d074g77bg22",
|
||||
"property": {
|
||||
"id": "4gb96g75-6828-5673-c4gd-3d074g77bg33",
|
||||
"title": "Casa 4 quartos Alphaville",
|
||||
"slug": "casa-4-quartos-alphaville"
|
||||
},
|
||||
"message": "Tenho interesse em visitar esta semana.",
|
||||
"status": "confirmed",
|
||||
"scheduled_at": "2026-05-01T10:00:00Z",
|
||||
"created_at": "2026-04-10T08:30:00Z"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
Ordenado por `created_at DESC`. Lista vazia `[]` quando sem visitas.
|
||||
|
||||
`property` pode ser `null` se o imóvel foi removido do banco.
|
||||
`scheduled_at` é `null` enquanto status for `pending`.
|
||||
|
||||
---
|
||||
|
||||
## Response 401 Unauthorized
|
||||
|
||||
```json
|
||||
{ "error": "Token inválido ou ausente" }
|
||||
```
|
||||
Loading…
Add table
Add a link
Reference in a new issue