develop #83

Merged
M-Gabrielly merged 426 commits from develop into main 2025-12-04 04:13:15 +00:00
3 changed files with 1010 additions and 82 deletions
Showing only changes of commit 2161a9c210 - Show all commits

View File

@ -0,0 +1,943 @@
# Listar atribuições de pacientes
## OpenAPI Specification
```yaml
openapi: 3.0.1
info:
title: ''
description: ''
version: 1.0.0
paths:
/rest/v1/patient_assignments:
get:
summary: Listar atribuições de pacientes
deprecated: false
description: ''
tags:
- Atribuições
- Atribuições
parameters:
- name: apikey
in: header
description: Chave da API Supabase
required: true
example: ''
schema:
type: string
responses:
'200':
description: Lista de atribuições
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/PatientAssignment'
headers: {}
x-apidog-name: OK
security:
- bearer: []
x-apidog-folder: Atribuições
x-apidog-status: released
x-run-in-apidog: https://app.apidog.com/web/project/1053378/apis/api-21940525-run
components:
schemas:
PatientAssignment:
type: object
properties:
id:
type: string
format: uuid
examples:
- 12345678-1234-1234-1234-123456789012
patient_id:
type: string
format: uuid
examples:
- 12345678-1234-1234-1234-123456789012
user_id:
type: string
format: uuid
examples:
- 12345678-1234-1234-1234-123456789012
role:
type: string
enum:
- medico
- enfermeiro
examples:
- medico
created_at:
type: string
format: date-time
examples:
- '2024-01-15T10:30:00Z'
created_by:
type: string
format: uuid
examples:
- 12345678-1234-1234-1234-123456789012
x-apidog-orders:
- id
- patient_id
- user_id
- role
- created_at
- created_by
x-apidog-ignore-properties: []
x-apidog-folder: ''
securitySchemes:
bearerAuth:
type: jwt
scheme: bearer
bearerFormat: JWT
description: Token JWT obtido no login
bearer:
type: http
scheme: bearer
servers:
- url: https://yuanqfswhberkoevtmfr.supabase.co
description: Prod Env
- url: ''
description: Cloud Mock
security:
- bearer: []
```
# Criar nova atribuição
## OpenAPI Specification
```yaml
openapi: 3.0.1
info:
title: ''
description: ''
version: 1.0.0
paths:
/rest/v1/patient_assignments:
post:
summary: Criar nova atribuição
deprecated: false
description: ''
tags:
- Atribuições
- Atribuições
parameters:
- name: apikey
in: header
description: Chave da API Supabase
required: true
example: ''
schema:
type: string
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/PatientAssignmentInput'
responses:
'201':
description: Atribuição criada
content:
application/json:
schema:
$ref: '#/components/schemas/PatientAssignment'
headers: {}
x-apidog-name: Created
security:
- bearer: []
x-apidog-folder: Atribuições
x-apidog-status: released
x-run-in-apidog: https://app.apidog.com/web/project/1053378/apis/api-21940526-run
components:
schemas:
PatientAssignmentInput:
type: object
required:
- patient_id
- user_id
- role
properties:
patient_id:
type: string
format: uuid
user_id:
type: string
format: uuid
role:
type: string
enum:
- medico
- enfermeiro
x-apidog-orders:
- patient_id
- user_id
- role
x-apidog-ignore-properties: []
x-apidog-folder: ''
PatientAssignment:
type: object
properties:
id:
type: string
format: uuid
examples:
- 12345678-1234-1234-1234-123456789012
patient_id:
type: string
format: uuid
examples:
- 12345678-1234-1234-1234-123456789012
user_id:
type: string
format: uuid
examples:
- 12345678-1234-1234-1234-123456789012
role:
type: string
enum:
- medico
- enfermeiro
examples:
- medico
created_at:
type: string
format: date-time
examples:
- '2024-01-15T10:30:00Z'
created_by:
type: string
format: uuid
examples:
- 12345678-1234-1234-1234-123456789012
x-apidog-orders:
- id
- patient_id
- user_id
- role
- created_at
- created_by
x-apidog-ignore-properties: []
x-apidog-folder: ''
securitySchemes:
bearerAuth:
type: jwt
scheme: bearer
bearerFormat: JWT
description: Token JWT obtido no login
bearer:
type: http
scheme: bearer
servers:
- url: https://yuanqfswhberkoevtmfr.supabase.co
description: Prod Env
- url: ''
description: Cloud Mock
security:
- bearer: []
```
# Listar roles de usuários
## OpenAPI Specification
```yaml
openapi: 3.0.1
info:
title: ''
description: ''
version: 1.0.0
paths:
/rest/v1/user_roles:
get:
summary: Listar roles de usuários
deprecated: false
description: ''
tags:
- Usuários
- Usuários
parameters: []
responses:
'200':
description: Lista de roles
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/UserRole'
headers: {}
x-apidog-name: OK
security:
- bearer: []
x-apidog-folder: Usuários
x-apidog-status: released
x-run-in-apidog: https://app.apidog.com/web/project/1053378/apis/api-21940524-run
components:
schemas:
UserRole:
type: object
properties:
id:
type: string
format: uuid
examples:
- 12345678-1234-1234-1234-123456789012
user_id:
type: string
format: uuid
examples:
- 12345678-1234-1234-1234-123456789012
role:
type: string
enum:
- admin
- gestor
- medico
examples:
- medico
created_at:
type: string
format: date-time
examples:
- '2024-01-15T10:30:00Z'
x-apidog-orders:
- id
- user_id
- role
- created_at
x-apidog-ignore-properties: []
x-apidog-folder: ''
securitySchemes:
bearerAuth:
type: jwt
scheme: bearer
bearerFormat: JWT
description: Token JWT obtido no login
bearer:
type: http
scheme: bearer
servers:
- url: https://yuanqfswhberkoevtmfr.supabase.co
description: Prod Env
- url: ''
description: Cloud Mock
security:
- bearer: []
```
# Obter informações completas do usuário
## OpenAPI Specification
```yaml
openapi: 3.0.1
info:
title: ''
description: ''
version: 1.0.0
paths:
/functions/v1/user-info:
get:
summary: Obter informações completas do usuário
deprecated: false
description: >-
Retorna dados consolidados do usuário autenticado, incluindo perfil e
roles para controle de permissões.
tags:
- Usuários
parameters: []
responses:
'200':
description: Informações do usuário retornadas com sucesso
content:
application/json:
schema:
$ref: '#/components/schemas/UserInfoResponse'
headers: {}
x-apidog-name: OK
'401':
description: Token inválido ou expirado
content:
application/json:
schema: &ref_0
$ref: '#/components/schemas/Error'
headers: {}
x-apidog-name: Unauthorized
'500':
description: Erro interno do servidor
content:
application/json:
schema: *ref_0
headers: {}
x-apidog-name: Internal Server Error
security: []
x-apidog-folder: Usuários
x-apidog-status: released
x-run-in-apidog: https://app.apidog.com/web/project/1053378/apis/api-21952675-run
components:
schemas:
UserInfoResponse:
type: object
properties:
user:
$ref: '#/components/schemas/User'
profile:
$ref: '#/components/schemas/Profile'
roles:
type: array
items:
type: string
enum:
- admin
- gestor
- medico
- secretaria
- user
examples:
- - medico
- admin
permissions:
$ref: '#/components/schemas/Permissions'
x-apidog-orders:
- user
- profile
- roles
- permissions
x-apidog-ignore-properties: []
x-apidog-folder: ''
Permissions:
type: object
properties:
isAdmin:
type: boolean
description: Se o usuário tem role de admin
examples:
- true
isManager:
type: boolean
description: Se o usuário tem role de gestor
examples:
- false
isDoctor:
type: boolean
description: Se o usuário tem role de médico
examples:
- true
isSecretary:
type: boolean
description: Se o usuário tem role de secretária
examples:
- false
isAdminOrManager:
type: boolean
description: Se o usuário é admin ou gestor (para controle de permissões)
examples:
- true
x-apidog-orders:
- isAdmin
- isManager
- isDoctor
- isSecretary
- isAdminOrManager
x-apidog-ignore-properties: []
x-apidog-folder: ''
Profile:
type: object
properties:
id:
type: string
format: uuid
full_name:
type: string
examples:
- Dr. João Silva
nullable: true
email:
type: string
format: email
nullable: true
phone:
type: string
examples:
- '+5511999999999'
nullable: true
avatar_url:
type: string
format: uri
nullable: true
disabled:
type: boolean
examples:
- false
created_at:
type: string
format: date-time
updated_at:
type: string
format: date-time
x-apidog-orders:
- id
- full_name
- email
- phone
- avatar_url
- disabled
- created_at
- updated_at
x-apidog-ignore-properties: []
nullable: true
x-apidog-folder: ''
User:
type: object
properties:
id:
type: string
format: uuid
examples:
- 550e8400-e29b-41d4-a716-446655440000
email:
type: string
format: email
examples:
- usuario@exemplo.com
email_confirmed_at:
type: string
format: date-time
examples:
- '2024-01-01T10:00:00Z'
nullable: true
created_at:
type: string
format: date-time
examples:
- '2024-01-01T00:00:00Z'
last_sign_in_at:
type: string
format: date-time
examples:
- '2024-01-15T09:30:00Z'
nullable: true
x-apidog-orders:
- id
- email
- email_confirmed_at
- created_at
- last_sign_in_at
x-apidog-ignore-properties: []
x-apidog-folder: ''
Error:
type: object
properties:
error:
type: string
message:
type: string
code:
type: string
x-apidog-orders:
- error
- message
- code
x-apidog-ignore-properties: []
x-apidog-folder: ''
securitySchemes:
bearerAuth:
type: jwt
scheme: bearer
bearerFormat: JWT
description: Token JWT obtido no login
bearer:
type: http
scheme: bearer
servers:
- url: https://yuanqfswhberkoevtmfr.supabase.co
description: Prod Env
- url: ''
description: Cloud Mock
security:
- bearer: []
```
# Criar novo usuário
## OpenAPI Specification
```yaml
openapi: 3.0.1
info:
title: ''
description: ''
version: 1.0.0
paths:
/functions/v1/create-user:
post:
summary: Criar novo usuário
deprecated: false
description: >-
Cria um novo usuário no sistema com papel específico. Apenas usuários
com papel de admin, gestor ou secretaria podem criar novos usuários.
operationId: createUser
tags:
- Usuários
- Usuários
parameters: []
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/CreateUserRequest'
examples:
admin_user:
value:
email: admin@mediconnect.com
password: senha123!
full_name: João Silva
phone: (11) 99999-9999
role: admin
summary: Criar administrador
doctor_user:
value:
email: dr.maria@mediconnect.com
password: senha123!
full_name: Dra. Maria Santos
phone: (11) 98888-8888
role: medico
summary: Criar médico
secretary_user:
value:
email: secretaria@mediconnect.com
password: senha123!
full_name: Ana Costa
phone: (11) 97777-7777
role: secretaria
summary: Criar secretária
responses:
'200':
description: Usuário criado com sucesso
content:
application/json:
schema:
$ref: '#/components/schemas/CreateUserResponse'
example:
success: true
user:
id: 123e4567-e89b-12d3-a456-426614174000
email: novo.usuario@mediconnect.com
full_name: Novo Usuário
phone: (11) 99999-9999
role: medico
headers: {}
x-apidog-name: OK
'400':
description: Dados inválidos ou erro de validação
content:
application/json:
schema:
type: object
properties: {}
x-apidog-ignore-properties: []
x-apidog-orders: []
examples:
'2':
summary: Campos obrigatórios faltando
value:
error: 'Missing required fields: email, password, full_name, role'
'3':
summary: Papel inválido
value:
error: Invalid role
'4':
summary: Email já existe
value:
error: User with this email already registered
headers: {}
x-apidog-name: Bad Request
'401':
description: Token de autenticação inválido ou ausente
content:
application/json:
schema:
type: object
properties: {}
x-apidog-ignore-properties: []
x-apidog-orders: []
example:
error: Unauthorized
headers: {}
x-apidog-name: Unauthorized
'403':
description: Permissões insuficientes
content:
application/json:
schema:
type: object
properties: {}
x-apidog-ignore-properties: []
x-apidog-orders: []
example:
error: Insufficient permissions
headers: {}
x-apidog-name: Forbidden
'500':
description: Erro interno do servidor
content:
application/json:
schema:
type: object
properties: {}
x-apidog-ignore-properties: []
x-apidog-orders: []
example:
error: Internal server error
headers: {}
x-apidog-name: Internal Server Error
security: []
x-apidog-folder: Usuários
x-apidog-status: released
x-run-in-apidog: https://app.apidog.com/web/project/1053378/apis/api-21953135-run
components:
schemas:
CreateUserRequest:
type: object
required:
- email
- password
- full_name
- role
properties:
email:
type: string
format: email
description: Email do usuário (deve ser único)
examples:
- usuario@mediconnect.com
password:
type: string
minLength: 6
description: Senha temporária para o usuário
examples:
- senha123!
full_name:
type: string
minLength: 1
description: Nome completo do usuário
examples:
- João da Silva
phone:
type: string
description: Telefone do usuário (opcional)
examples:
- (11) 99999-9999
nullable: true
role:
type: string
enum:
- admin
- gestor
- medico
- secretaria
- user
description: Papel do usuário no sistema
examples:
- medico
x-apidog-orders:
- email
- password
- full_name
- phone
- role
x-apidog-ignore-properties: []
x-apidog-folder: ''
CreateUserResponse:
type: object
properties:
success:
type: boolean
description: Indica se a operação foi bem-sucedida
examples:
- true
user:
type: object
properties:
id:
type: string
format: uuid
description: ID único do usuário criado
examples:
- 123e4567-e89b-12d3-a456-426614174000
email:
type: string
format: email
description: Email do usuário
examples:
- usuario@mediconnect.com
full_name:
type: string
description: Nome completo do usuário
examples:
- João da Silva
phone:
type: string
description: Telefone do usuário
examples:
- (11) 99999-9999
nullable: true
role:
type: string
description: Papel atribuído ao usuário
examples:
- medico
x-apidog-orders:
- id
- email
- full_name
- phone
- role
x-apidog-ignore-properties: []
x-apidog-orders:
- success
- user
x-apidog-ignore-properties: []
x-apidog-folder: ''
securitySchemes:
bearerAuth:
type: jwt
scheme: bearer
bearerFormat: JWT
description: Token JWT obtido no login
bearer:
type: http
scheme: bearer
servers:
- url: https://yuanqfswhberkoevtmfr.supabase.co
description: Prod Env
- url: ''
description: Cloud Mock
security:
- bearer: []
```
# Obter dados do usuário atual
## OpenAPI Specification
```yaml
openapi: 3.0.1
info:
title: ''
description: ''
version: 1.0.0
paths:
/auth/v1/user:
get:
summary: Obter dados do usuário atual
deprecated: false
description: Retorna informações do usuário autenticado
tags:
- Usuários
- Authentication
parameters: []
responses:
'200':
description: Dados do usuário
content:
application/json:
schema:
$ref: '#/components/schemas/User'
headers: {}
x-apidog-name: OK
'401':
description: Token inválido
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
headers: {}
x-apidog-name: Unauthorized
security:
- bearer: []
x-apidog-folder: Usuários
x-apidog-status: released
x-run-in-apidog: https://app.apidog.com/web/project/1053378/apis/api-21940512-run
components:
schemas:
User:
type: object
properties:
id:
type: string
format: uuid
examples:
- 550e8400-e29b-41d4-a716-446655440000
email:
type: string
format: email
examples:
- usuario@exemplo.com
email_confirmed_at:
type: string
format: date-time
examples:
- '2024-01-01T10:00:00Z'
nullable: true
created_at:
type: string
format: date-time
examples:
- '2024-01-01T00:00:00Z'
last_sign_in_at:
type: string
format: date-time
examples:
- '2024-01-15T09:30:00Z'
nullable: true
x-apidog-orders:
- id
- email
- email_confirmed_at
- created_at
- last_sign_in_at
x-apidog-ignore-properties: []
x-apidog-folder: ''
Error:
type: object
properties:
error:
type: string
message:
type: string
code:
type: string
x-apidog-orders:
- error
- message
- code
x-apidog-ignore-properties: []
x-apidog-folder: ''
securitySchemes:
bearerAuth:
type: jwt
scheme: bearer
bearerFormat: JWT
description: Token JWT obtido no login
bearer:
type: http
scheme: bearer
servers:
- url: https://yuanqfswhberkoevtmfr.supabase.co
description: Prod Env
- url: ''
description: Cloud Mock
security:
- bearer: []
```

View File

@ -25,6 +25,8 @@ import {
MedicoInput,
Medico,
criarUsuario,
criarUsuarioDirectAuth,
assignRoleServerSide,
gerarSenhaAleatoria,
} from "@/lib/api";
;
@ -398,71 +400,25 @@ async function handleSubmit(ev: React.FormEvent) {
const savedDoctorProfile = await criarMedico(medicoPayload);
console.log("✅ Perfil do médico criado:", savedDoctorProfile);
if (form.email && form.email.includes('@')) {
const tempPassword = gerarSenhaAleatoria();
const userInput = {
email: form.email,
password: tempPassword,
full_name: form.full_name,
phone: form.celular,
role: 'medico' as const,
};
// ⚠️ IMPORTANTE: A criação de usuário de autenticação foi DESABILITADA temporariamente
// porque a Edge Function /functions/v1/create-user está retornando erro 500 ao
// tentar atribuir o role "medico" ao usuário.
//
// Para habilitar novamente, o backend precisa corrigir a Edge Function ou
// configurar as permissões corretas na tabela user_roles.
//
// Por ora, apenas o perfil do médico será salvo na tabela "doctors".
// O acesso ao sistema precisa ser criado manualmente pelo administrador.
console.log("🔐 Criando usuário de autenticação com payload:", userInput);
console.log("⚠️ Criação de usuário Auth desabilitada - salvando apenas perfil do médico");
try {
const userResponse = await criarUsuario(userInput);
if (userResponse.success && userResponse.user) {
console.log("✅ Usuário de autenticação criado:", userResponse.user);
// Mostra credenciais (NÃO fecha o formulário ainda)
setTempCredentials({ email: form.email, password: tempPassword });
setDialogOpen(true);
// Limpa formulário mas NÃO fecha ainda - fechará quando o dialog de credenciais fechar
setForm(initial);
setPhotoPreview(null);
setServerAnexos([]);
onSaved?.(savedDoctorProfile);
// NÃO chama onClose ou onOpenChange aqui - deixa o dialog de credenciais fazer isso
return;
} else {
throw new Error((userResponse as any).message || "Falhou ao criar o usuário de acesso.");
}
} catch (userError: any) {
console.error("❌ Erro ao criar usuário via função server-side:", userError);
// Mensagem de erro específica para email duplicado
const errorMsg = userError?.message || String(userError);
if (errorMsg.toLowerCase().includes('already registered') ||
errorMsg.toLowerCase().includes('já está cadastrado') ||
errorMsg.toLowerCase().includes('já existe')) {
alert(
`⚠️ Este email já está cadastrado no sistema.\n\n` +
`✅ O perfil do médico foi salvo com sucesso.\n\n` +
`Para criar acesso ao sistema, use um email diferente ou recupere a senha do email existente.`
);
} else if (errorMsg.toLowerCase().includes('failed to assign user role') ||
errorMsg.toLowerCase().includes('atribuir permissões')) {
alert(
`⚠️ PROBLEMA NA CONFIGURAÇÃO DO SISTEMA\n\n` +
`✅ O perfil do médico foi salvo com sucesso.\n\n` +
`❌ Porém, houve falha ao atribuir permissões de acesso.\n\n` +
`Esse erro indica que a Edge Function do Supabase não está configurada corretamente.\n\n` +
`Entre em contato com o administrador do sistema para:\n` +
`1. Verificar se a service role key está configurada\n` +
`2. Verificar as permissões da tabela user_roles\n` +
`3. Revisar o código da Edge Function create-user`
);
} else {
alert(
`✅ Médico cadastrado com sucesso!\n\n` +
`⚠️ Porém houve um problema ao criar o acesso:\n${errorMsg}\n\n` +
`O cadastro do médico foi salvo, mas será necessário criar o acesso manualmente.`
`📋 Perfil salvo na base de dados.\n\n` +
`⚠️ IMPORTANTE: O acesso ao sistema (login) precisa ser criado manualmente.\n\n` +
`Motivo: A função de criação automática de usuários está com problema no backend.\n` +
`Entre em contato com o administrador do sistema para criar o acesso.`
);
}
// Limpa formulário e fecha
setForm(initial);
@ -471,14 +427,6 @@ async function handleSubmit(ev: React.FormEvent) {
onSaved?.(savedDoctorProfile);
if (inline) onClose?.();
else onOpenChange?.(false);
return;
}
} else {
alert("Médico cadastrado com sucesso (sem usuário de acesso - email não fornecido).");
onSaved?.(savedDoctorProfile);
if (inline) onClose?.();
else onOpenChange?.(false);
}
}
} catch (err: any) {
console.error("❌ Erro no handleSubmit:", err);

View File

@ -2,6 +2,7 @@
import { createContext, useContext, useEffect, useState, ReactNode, useCallback, useMemo, useRef } from 'react'
import { useRouter } from 'next/navigation'
import { loginUser, logoutUser, AuthenticationError } from '@/lib/auth'
import { ENV_CONFIG } from '@/lib/env-config'
import { isExpired, parseJwt } from '@/lib/jwt'
import { httpClient } from '@/lib/http'
import type {
@ -118,7 +119,7 @@ export function AuthProvider({ children }: { children: ReactNode }) {
return
}
} catch (refreshError) {
console.log(' [AUTH] Falha no refresh automático')
console.log(' [AUTH] Falha no refresh automático')
await new Promise(resolve => setTimeout(resolve, 400))
}
}
@ -158,6 +159,42 @@ export function AuthProvider({ children }: { children: ReactNode }) {
const response = await loginUser(email, password, userType)
// Após receber token, buscar roles/permissions reais e reconciliar userType
try {
const infoRes = await fetch(`${ENV_CONFIG.SUPABASE_URL}/functions/v1/user-info`, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'Authorization': `Bearer ${response.access_token}`,
'apikey': ENV_CONFIG.SUPABASE_ANON_KEY,
}
})
if (infoRes.ok) {
const info = await infoRes.json().catch(() => null)
const roles: string[] = Array.isArray(info?.roles) ? info.roles : (info?.roles ? [info.roles] : [])
// Derivar tipo de usuário a partir dos roles
let derived: UserType = 'paciente'
if (roles.includes('admin') || roles.includes('gestor') || roles.includes('secretaria')) {
derived = 'administrador'
} else if (roles.includes('medico') || roles.includes('enfermeiro')) {
derived = 'profissional'
}
// Atualizar userType caso seja diferente
if (response.user && response.user.userType !== derived) {
response.user.userType = derived
console.log('[AUTH] userType reconciled from roles ->', derived)
}
} else {
console.warn('[AUTH] Falha ao obter user-info para reconciliar roles:', infoRes.status)
}
} catch (err) {
console.warn('[AUTH] Erro ao buscar user-info após login (não crítico):', err)
}
saveAuthData(
response.access_token,
response.user,